面试题 题目-答案-扩展

一、下列代码中 当foo是什么值的时候 会执行alert("foo!")
A."false"     B."true"      C.1       D.0    E.-1   F.'  '    G.undefined   H.null    I.NaN     J.false     K.{}    L.[]  
if (!foo) {
        alert("foo!")
    }
分析一下: 
   js中的 "  !  " 是什么  这个我们知道是取反,对于布尔类型会将其值true和false互换,那对于非boolean类型呢 ?

对于非boolean类型,js会将值先转换成boolean类型,而后取反。0、null、NaN、undefined、"" 转成布尔值为false 其他则一律返回true;(那么!!呢?就是 取反在取反)

那么为什么{} 和 [] 不是false呢?

 空数组或者是空对象都是 object 那么作为条件就会转成true  !true===false所以无法输出

答案: D  F  G  H  L  J  

 

二、请将一下属性按照盒模型由内而外的顺序排序

A.padding   B.border   C.height   D.margin    

分析一下 盒子模型有两种 标准盒子模型和IE盒子模型又称怪异盒子

 

 答案:C   A   B   D   (标准)  和    A   B   C  D  (怪异)

三、要在十秒后调用checkState,下列写法哪个是正确的?

A. window.setTimeout(checkState(),10)
B. window.setTimeout(checkState,10)
C. window.setTimeout(checkState(),10000)
D. window.setTimeout(checkState,10000)

 分析:先回忆一下setTimeout 再来做这道题 

语法:

setInterval(function, milliseconds, param1, param2, ...)  
第一个参数:必需。要调用一个代码串,也可以是一个函数。
第二个参数:必需。周期性执行或调用 code/function 之间的时间间隔,以毫秒计。
param1,param2...: 选填传递给函数的其他参数
   //代码串
    setTimeout(function () { alert("Hello"); }, 3000);

    //函数
    var fn = function () {
                alert("Hello");
            }
    setTimeout(fn, 3000);

    //函数调用
    var fn = function () {
                alert("Hello");
            }
    setTimeout("fn()", 3000);

 

  C会立即执行 

 

答案:D 

四、下面哪种方式可以删除节点elm
 A.elm.parentNode.removeChild(elm
B.document.createElement(
'fragment').appendChild(elm) C.elm.parentNode.deleteChild(elm) D.elm.parentNode.remove(elm)
分析:删除节点的方式
<div id="box">
    <p id="p1">这是一个段落</p>
    <p id="p2">第二个段落</p>
</div>
<script>
    var p1=document.getElementById("p1");
  //直接找到这个元素删除 p1.remove(); //或者要删除的子节点的父节点删除子节点 p1.parentNode.removeChild(p1); </script>
答案:A

扩展一下dom的操作
   // 创建:
    createDocumentFragment()    //创建一个DOM片段
    //创建一个具体的元素
    createElement()   
    //创建一个文本节点
    createTextNode()  
    //添加节点
    appendChild()
    //举例
    var node = document.createElement("LI");
    var textnode = document.createTextNode("Water");
    node.appendChild(textnode);
    document.getElementById("myList").appendChild(node);


    // 移出:  
    removeChild()
    remove()

    /*
        替换
        node.replaceChild(newnode,oldnode)
        newnode    你要插入的节点对象。
        oldnode    你要移除的节点对象
    */
    replaceChild()  
    document.getElementById("myList").replaceChild(newnode,oldnode);

    
     /*
        插入
        node.insertBefore(newnode,existingnode)
        newnode    你要插入的节点对象。
        existingnode    可选。在其之前插入新节点的子节点。如果未规定,则 insertBefore 方法会在结尾插入 newnode。
    */
insertBefore() document.getElementById("myList").insertBefore(newItem,existingItem); //末尾插入节点 document.getElementById("myList").appendChild(newItem) /* 插入 node.insertBefore(deep) deep (boolean) 可选。该方法将复制并返回调用它的节点的副本。如果传递给它的参数是 true,它还将递归复制当前节点的所有子孙节点。否则,它只复制当前节点。 */
cloneNode(true)
  var node=document.getElementById("myList2").lastChild.cloneNode(true);
  document.getElementById("myList1").appendChild(node);

五、下列表达式的结果是true的有:
A.typeof(null)==='object'
B.''==false
C.Function instanceof Object
D.[].constructor === Array

 

分析:
先看B选项
string(字符串类型)和number作比较的时候,string会先转化成number。此时字符串0转化为了数字0,即: 0 == 0;
0是false 1是true  所以 " " == false为真 
==在比较的时候可以转换数据类型,===严格比较,只要类型不匹配就返回flase。
所以" "是string 0是number false是boolean 当它们的比较用===则都为false
 
接下来看一下 

typeof  操作符返回一个字符串,表示未经计算的操作数的类型。

//number
typeof(42)  
typeof 42

// string
typeof ''
typeof String(1)      //String 将任意值转换为字符串,比 toString 更安全
typeof  (3).toString()

//boolean
typeof false
typeof !!(1)   // 两次调用 ! (逻辑非) 操作符相当于 Boolean()

//undefined
var str 
typeof str

typeof declaredButUndefinedVariabl     //声明但未定义变量
typeof undeclaredVariable             //不可声明变量

//function
typeof function() {}

//object
typeof {a: 1}
typeof null 
/*
在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。
对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),
因此,null 的类型标签是 0,typeof null 也因此返回 "object"
*/

//使用new操作符  除 Function 外的所有构造函数的类型都是 'object'

var str = new String('String');
var num = new Number(100);
typeof str; // 返回 'object'
typeof num; // 返回 'object'

var func = new Function();
typeof func; // 返回 'function'

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

语法 :object instanceof constructor (object-某个实例对象  constructor某个构造函数)
function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}
var auto = new Car('Honda', 'Accord', 1998);

auto instanceof Car;       //true
auto instanceof Object;   //true

/*
如果表达式 obj instanceof Foo 返回 true,
则并不意味着该表达式会永远返回 true,因为 Foo.prototype 属性的值有可能会改变,
改变之后的值很有可能不存在于 obj 的原型链上,这时原表达式的值就会成为 false。
举例如下
*/
// 定义构造函数
function C(){} 

var o = new C();
o instanceof C; // true

C.prototype instanceof Object // true,同上

C.prototype = {};
var o2 = new C();

o2 instanceof C; // true

/*这里给o重新继承
o = new C();
在执行下一句就是true了*/

o instanceof C; // false,C.prototype 指向了一个空对象,这个空对象不在 o 的原型链上.

constructor 属性返回对创建此对象的数组函数的引用。 这个我也不是很理解这句话的意思等我以后会了再来补充 如果有会的也可以评论教我~~

 语法:object.constructor    

 test='123';
 test.constructor == String

 test=456;
 test.constructor == Number

 test={};
 test.constructor == Object

 test=[];
 test.constructor == Array

 test=true;
 test.constructor == Boolean

 test=new Date();
 test.constructor == Date

 

答案  A B C D

 六、关于数组的说法不正确的是?

A.对数组里数据的排序可以用sort函数,如果排序效果非预期,可以给sort函数加一个排序函数的参数
B.reverse用于数组数据的倒叙排序
C.向数组的最后位置加一个新元素,可以用pop方法
D.unshift方法用于删除数组第一个元素;

 分析:

sort()

    /*
        sort() 方法用于对数组的元素进行排序。
        语法  arrayObject.sort(sortby)
        sortby    可选。规定排序顺序。必须是函数。
    */
    // 调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。
    // 按字母顺序 a-z 排列
    arr=["George","John","Thomas","James","Adrew", "Martin"]
    arr.sort()
  
//数字排序
    // 无参数
    arr1=["10","5","40","25","100", "1"]
    arr1.sort()
    //有参数 a-b  按照数值大小 -升序
    arr1.sort((a,b)=>{
        return a-b;
    })
    // 有参数 b-a 按照数值大小 -降序
    arr1.sort((a,b)=>{
        return b-a;
    })

  
  实际应用中可以通过对象的某一个属性进行排序
  例如:按照person数组中对象的age属性排序
let person = [{
        name: "小可爱",
        age: 12
    }, {
        name: "陈怡baby",
        age: 22
    }, {
        name: "小仙女",
        age: 18
    }]

function sequencing(property) {
   return function (a, b) {
        return a[property] -  b[property];
    }
}
console.log(person.sort(sequencing('age')))

  

 reverse()

/*
        reverse() 方法用于颠倒数组中元素的顺序。
        arrayObject.reverse()  该方法会改变原来的数组,而不会创建新的数组。
    */

    arr = [3,5,7,42,65]
    arr.reverse()
  
    // 扩展:将数组扁平化并去除其中重复数据,最终得到一个升序且不重复的数组
    var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];
    // 分析一下:先转成一维数组然后去重最后排序 
    [...new Set(arr.flat(Infinity))].sort((a,b)=>{ return a-b})  
    // 或者:
    Array.from(new Set(arr.flat(Infinity))).sort((a,b)=>{ return a-b})


    /*
        flat()默认只会“拉平”一层,
        如果想要“拉平”多层的嵌套数组,可以将flat()方法的参数写成一个整数,表示想要拉平的层数
        如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。
    */
        let arr1 = [1,2,[3,[4]]];
    // 常用
    /* 
        toString() 方法可把数组转换为字符串,并返回结果。
        join() 方法用于把数组中的所有元素放入一个字符串。元素是通过指定的分隔符进行分隔的。
        split() 方法用于把一个字符串分割成字符串数组。
    */
        let arr2 = arr1.toString().split(',');  // ["1", "2", "3", "4"]
        let arr3 = arr1.join().split(',');   // ["1", "2", "3", "4"]
    // 但是缺点是 把数组中的每一项都变成了字符串
    // 数组map方法做一个类型转换 arr3一样不做展示
        arr2.map(item => Number(item))      // [1, 2, 3, 4]

    // 有了es6以后一步搞定
        arr1.flat(Infinity)

 选择C D都是对数组的操作 一起总结

回忆一下数组增删的操作 数组的基本操作不做举例

 

 

 答案:A B

七、以下代码运行后,控制台输出结果是:

var num = 100;
    function fn (){
        var num = num+1;
        return num;
    }
    console.log(fn())

A.101 B.1 C.undefined D.NaN

 函数外部申明num全局变量 函数内部也声明了一个num局部变量 但是var还存在变量提升

改写:

var num = 100;
    function fn (){
        var num;
        num= num+1;         // undefined + 1
        return num; 
    }
    console.log(fn())   //NAN

    var num = 100;
    function fn (){
        num= num+1;       //内部没有num全局找   
        return num; 
    }
    console.log(fn())   //101

    那么let没有变量提升改用let呢?   let不存在变量提升所有 无法再初始化前访问
      

 答案:D

八、下面哪个不属于Promise的状态

    A.Resolved
    B.Unfulfilled //未完成
    C.Rejected  //拒绝
    D.Pause    //暂停

 

Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和Rejected(已失败)。同一时间只能存在一种状态,且状态一旦改变就不能再变。

答案:B D

九、代码运行输出结果是:

  var Core = {
        title:"Core",
        show:function(){
            return this.title
        }
    }
    title = 'window'
    fn = Core.show;
    fn();

    A.Core  B.window   C.不确定

 这是this指向的问题  this指向当前的函数 当前函数是全局的所以windows.title 

var Core = {
        title:"Core",
        show:function(){
            return this.title
        }
    }
    fn = Core.show;
    fn();  //undefined 因为windows里面没有title属性

 

 答案 : B

十、以下代码输出什么结果,为什么?

var getFn = function () {
        var arrs = [];
        for (var i = 0; i < 3; i++) {
            arrs.push(function () {
                return i;
            })
        }
        return arrs;
    }

    var fns = getFn();
    console.log(fns[0]()+fns[1]())

按照我们正常的推算 i分别push为 0  1  2   那么打印的就是 0+1 为1  但是控制台可以看一下 这输出的是6

for循环中设置循环变量的部位是一个父作用域,循环体内部是个子作用域。

每次子作用域中的i改变的时候 污染了父作用域中全局变量 i 最后一次i不符合条件的时候是3 所以全局也被修改成了三   fn[0],fn[1],fn[2]  都是3  

改写:

  //用闭包改写  输出1
    var getFn = function () {
        var arrs = [];
        for (var i = 0; i < 3; i++) {
            (function (i) {
                arrs.push(function () {
                    return i;
                })
            })(i)
        }
        return arrs;
    }
  
// 用let 输出1 var getFn = function () { var arrs = []; for (let i = 0; i < 3; i++) { arrs.push(function () { return i; }) } return arrs; }

 十一、以下代码输出顺序?

   console.log(1);
    new Promise(function(resolve,reject){
        reject(true);
        window.setTimeout(function(){
            resolve(false);
        },0)
    }).then(function(){
        console.log(2)
    },function(){
        console.log(3)
    })
    console.log(4)

答案:1 4 3

 promise 基础

new Promise(
  function (resolve, reject) {
    // 一段耗时的异步操作
    resolve('成功') // 数据处理完成
    // reject('失败') // 数据处理出错
  }
).then(
  (res) => {console.log(res)},  // 成功
  (err) => {console.log(err)} // 失败
)

对应看一下题目
1.答应1 先执行
2.promise是异步所以不影响 4 的打印
3.执行promise的时候 里面有reject() 和 resolve() 但是成功的resolve在setTimeout中及时调用时间为0立即调用但是他依然是异步要等待
  所以这时候的状态先走一步变成了reject() promise同一时间只能存在一种状态,且状态一旦改变就不能再变。因此就是失败了
 按照上面语法打印为 1 4 3
new Promise(resolve => {
  setTimeout(() => {
    resolve('hello')
  }, 3000)
}).then(res => {
  console.log(res)
})


 


 执行的那一刻就进入了 pending状态 三秒后输出hello

//一般失败都是放在catch中写法如下
new Promise(function(resolve,reject){
        reject(false);
        resolve(true);
    }).then(function(res){
     console.log(res)
}).catch(function(res){ console.log(res) }).finally(function(){ console.log('成功失败都有我') })

 

new Promise(function(resolve,reject){
        resolve(true);
        reject(false);
    }).then(function(res){
     console.log(res)
    }).catch(function(res){
        console.log(res)
    }).finally(function(){
        console.log('成功失败都有我')
    })

总结: 
  1.reject() 和 resolve()谁先执行状态就是谁的 不会再改变

  2. .then()中是正确回调

  3. .catch()中是错误信息

  4. .finally()中 无论失败还是成功都会执行

 十二、  最后一个编程题~~~~~~~~~~~~~~

编写一个javascript函数fn,该函数有一个参数n(number),其返回值是一个数组,该数组是n个随机且不重复的整数,且整数取值范围是[2,32];

先写一个 

  function fn(n,min,max){}

  fn(n,min,max)

想想我们的随机数公式  :  Math.floor(Math.random() * (min - max + 1) + max);

n次循环 然后创建一个[]第一次追加进去 其余的判断里面有没有追加过的 如果有就i-- 多一次循环   思路有了 整合一下

function fn(n,min,max) {      
    
 if(typeof n !== 'number'){
          return "参数请输入数字"
      }
        let arrs = [];
        for (let i = 0; i < n; i++) {
            let rand = Math.floor(Math.random() * (min - max + 1) + max);
            if (arrs.length == 0) {
                arrs.push(rand)
            } else {
                if (arrs.indexOf(rand) != -1) {
                    i--;
                } else {
                    arrs.push(rand)
                }
            }
        }
        return arrs;
    }
    console.log(fn(5,2,32))

 通过这些题学习了很多   到这里就结束了~~~~~~~~~~~~~

 

posted @ 2019-11-28 17:18  啾啾啾啾一口  阅读(621)  评论(1编辑  收藏  举报