zoukankan      html  css  js  c++  java
  • js面试代码中的“坑”

    1.typeof 对类型的判断

    (function()  {    
        return typeof arguments;
        }
     )();
    

      答案:"Object"

      解释:arguments是一个伪数组,是JavaScript内置对象。

    2.函数的声明

    var f = function g(){
        return 23;
    };    
    typeof g();
    

      答案:会报错。Uncaught ReferenceError: g is not defined

      解释:因为在这里function g(){return 23;};只是作为一个带有名字函数表达式,不是函数的声明。函数实际上是绑定到变量f,不是g。如果想调用这个函数,应该通过f()进行调用。

    3.delete方法

    (function(x){
        delete x;
        return x;    
    })(1);
    

      答案:1

      解释:delete是用来删除对象中的某个属性的方法,并不能直接删除变量。

    4.变量的声明和赋值

    var y = 1, x = y = typeof x;    
    x;
    

      答案:"undefined"

      解释:解析这段代码时,会先进行变量声明的提升,即var y;var x; 然后真正执行代码的时候,y先是被赋值为1,然后x=y=typeof x可以进行一下拆分:

         因为x被声明还未被赋值,所以x为undefined,自然typeof x的结果为 "undefined"。=赋值是从右向左执行的,所以先是y = "undefined",再是x=y,

         理所当然,x的结果就是字符串类型的"undefined"。

    5.自调用函数传函数参数

    (function f(f){
        return typeof f();
    })(function(){ return 1; });
    

      答案:"number"

      解释:这段代码中是将函数function(){ return 1; }作为参数传给了自调用函数进行使用。对自调用函数内部return typeof f() ,f是传递过来的参数,先对它加了()进行函数调用,执行结果为1,;然后 typeof 1 的结果自然就是"number"了。

    6.自调用函数和arguments对象

    var foo = {
        bar: function() { 
           return this.baz; 
        },
        baz: 1    
    };    
    (function(){
        return typeof arguments[0]();    
    })(foo.bar);
    

      答案:"undefined"

      解释:arguments是用来存放函数实参的伪数组对象。

         在执行自调用函数function(){return typeof arguments[0](); 的时候,argunments[0]()实际上就是(function() { return this.baz;})(),这就需要理解this的指向问题了,我们传参foo.bar时实际上是传递的foo对象中bar属性所对应的属性值,即只是函数体function() { return this.baz;},需要理解的就是这只是一个普通函数,其this的指向对应的是window,并不是foo。又因为window中并没有属性baz,执行结果自然是undefined,再通过typeof检测其类型,最终结果就是"undefined"。

         可以结合下面的代码进行理解,下面代码的结果也是"undefined"。

    var foo = {
        bar: function(){ return this.baz; },
        baz: 1
     }
    f = foo.bar;
    typeof f();

    7.逗号操作符

    var f = (
        function f(){ return "1"; },
        function g(){ return 2; }
    )();
    typeof f;
    

      答案:"number"

      解释:逗号操作符的使用可以很混淆,用下面这段代码说明它的行为:

    var x = (1, 2, 3);
    x;

      x的值是3,这表明,当有一系列的组合在一起,并由逗号分隔的表达式,它们从左到右进行计算,但只有最后一个表达式的结果保存。由于同样的原因,这个问题可以改写为减少混乱:

    var f = (function g(){ return 2; })();
    typeof f;

    8.函数声明

    var x = 1;
    if (function f(){}) {
        x += typeof f;
    }
    x;
    

      答案:"1undefined"

      解释:同第二题一样,if()括号中的只能算是函数表达式,并不是说函数的声明,所以,用typeof检测 f 时,结果为undefined

    9.预解析

    (function f(){
        function f(){ return 1; }
        return f();
        function f(){ return 2; }
    })();
    

      答案:2

      解释:在执行return之前,函数声明会在任何表达式被解析和求值之前先被解析和求值,即使你的声明在代码的最后一行,它也会在同作用域内第一个表达式之前被解析/求值。题目中函数提升了两次,第二次把第一次覆盖了。

    10.创建对象,new关键字

    function f(){ return f; }
    new f() instanceof f;
    

      答案:false

      解释:值得注意的是 instanceof 检测的是原型。

         对于new关键字,做了几件事:1.创建空对象。2.让this指向当前对象。3.执行构造函数内部代码。4.默认如果没有覆盖这个空对象的话,返回this(当前对象)。

         我们在看 f() 返回了 return f;构造函数本身在 new 的过程中会返回一个表示该对象的实例。但是函数的返回值(这是返回的是构造函数本身)覆盖了这个实例,这个new 就形同虚设。

         如果f的形式为 function f(){return this}或function f(){}结果就应该是true了。

    11.数组,typeof

    var x = [typeof x, typeof y][1];
    typeof typeof x;
    

      答案:"string"

      解释:这题目比较简单,注意下返回类型即可。x = [ , ][1];即 x = typeof y = ‘undefind’。然后再typeof typeof x必然就是"string"了。

    12.对象

    function(foo){
        return typeof foo.bar;
    })({ foo: { bar: 1 } });
    

      答案:"undefined"

      解释:这个特别有误导性,要仔细看,{ foo: { bar: 1 } }传给了函数作为实参,所以要想取到bar的值应该是 foo.foo.bar,实参的foo里面并没有一个叫做bar的属性,只有属性foo

    13.函数作用域,new关键字

    function setName(obj) {
      obj.name = 'zs'
      var obj = new Object()
      obj.name = 'ls'
    }
    var obj = new Object()
    setName(obj)
    console.log(obj.name)

      答案:'zs'

      解释:代码执行时从第6行开始看,先是创建了一个obj对象。

         在执行函数setName(obj)时,第2行处给这个对象新增了name属性,并赋值为‘zs’。

         执行到第3行处是,又新创建了一个名为obj的对象,因为对象的存储方式,所以两者并不冲突,也不指向同一个位置。这时候我们执行到第4行代码处是在给这个新对象添加属性并赋值为‘ls’,原始obj对象的属性值没有被修改。

         执行完函数后,又会继续执行第8行,这时候因为函数局部作用域的限制,只能访问到在函数外部定义的obj(第一个obj),所以输出的结果也就是‘zs’了。

         另外如果是下面这种情况,结果就是'ls'了

    function setName(obj) {
        obj.name = 'zs'
        var obj = new Object()
        obj.name = 'ls'
        return obj
    }
    var obj = new Object()
    obj = setName(obj)
    console.log(obj.name)

    14.闭包 

    var arr = [];
    for(var i=0;i<3;i++) {
        arr[i] = function() {
            console.log(i)
        }
    }
    arr[0]();
    arr[1]();
    arr[2]();
    

      答案:3  3  3

      解释:从上面的代码可以看到,在for循环遍历的过程中,只是给数组中存入了三个函数,该函数提供了在控制台中打印 i 的功能。而等到函数真正被调用执行时,i 的值早就已经变为了3,这时候再打印结果就只能全都是3了。

      另外,如果想要输出 1  2  3 的结果,就需要进行如下的函数闭包操作,即在遍历的时候就将 i 的值传递到函数内部在内存中存储起来,再调用的时候就可以输出1  2  3 了。

    var arr = [];
        for(var i=0;i<3;i++) {
            arr[i] = (function(n) {
                // 这个位置是闭包环境
                return function() {
                    console.log(n)
              }
        })(i);
    }
    arr[0]();
    arr[1]();
    arr[2]();        
  • 相关阅读:
    OA系统权限管理设计方案【转】
    UML类图几种关系的总结
    在pl/sql中使用exp/imp工具实现oracle数据导出/导入
    page 的范围
    JSP页面跳转的五种方法
    Start with...Connect By
    秒杀系统架构
    对系统负载的理解
    sort(7)
    cat(6)
  • 原文地址:https://www.cnblogs.com/belongs-to-qinghua/p/11161180.html
Copyright © 2011-2022 走看看