一道JavaScript面试题:理解Function

2017.3.27更新
今天在刷题的时候,忽然发现以前已经有人在讨论这道题了,并且还涉及到了运算符优先级的问题,这是本身一开始没有想到的。(其实有人也说:程序写多了,天然记住了什么状况下会发生什么样的事情,可是为何会发生这样的事情,可能问起来一时还真回答不了。我就属于这种状态,因此一开始并无考虑到运算符优先级的问题)。javascript

关于该问题的讨论:java


今天看到的一道面试题,感受对理解JavaScript的Function以及原型链和闭包颇有帮助。本身并试着讲述一下本身的理解,欢迎拍砖。函数

题目:

function Foo() {
    getName = function() {
        alert(1);
    }
    return this;
}
Foo.getName = function() {
    alert(2);
}
Foo.prototype.getName = function() {
    alert(3);
}
var getName = function() {
    alert(4);
};
function getName() {
    alert(5);
}
//调用部分
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();

请问上述代码的输出结果是什么?this

2,4,1,1,2,3,3prototype

分析

  1. Foo.getName():函数调用输出2很好理解,直接调用的Foo.getName();code

  2. getName():函数调用输出为4,这和变量提高有关系了,由于在函数调用分为两个步骤,第一进入上下文阶段,第二为执行阶段。进入上下文时,会获取arguments函数声明变量声明。只有在执行阶段才会进行变量赋值,而第四个是函数表达式,第五个为函数声明,因此他们等同于下面的形式:对象

    • 进入上下文阶段:function getName(){alert(5);}

    • 执行阶段(将以前的getName函数给覆盖掉了):getName=function(){alert(4);}
      因此无论怎么调用,答案中都应该不会出现5。

  3. Foo().getName()与第二次getName():第三个函数调用开始有迷惑性了。最后调用的getName函数,实际上是全局的getName。第二次调用就成了Foo()函数中的那个,由于其前面没有var,也就是说这个getName并非一个私有变量,而是全局变量,因此将以前的全局中的getName函数在执行Foo()时会被覆盖掉了。所以下一次再执行getName方法的结果就变成了1,而不是以前的4了。

    另外也跟new关键字有关,由于Foo()前没有使用new,因此不会建立新的对象,并且 Foo的调用应该属于函数调用,因此返回的this实际上是window对象,而不是Foo实 例(并无建立)。

  4. new Foo.getName():调用实际上是建立了一个Foo.getName的新的实例(函数自己也是Object),在建立对象的过程当中执行到了alert(2)语句,因此就输出为2;

  5. new Foo().getName():调用是先根据Foo.prototyoe建立一个Foo的实例,调用getName方法时,由于自身没有getName方法,会去原型链上找,最后调用到Foo.prototype.getName,因此就是输出为3;

  6. new new Foo().getName():第七个就是第五和第六个的结合,先建立一个Foo实例,而后再建立Foo实例的getName函数(也就是Foo.prototype.getName)的实例。在建立的过程当中,执行到alert(3)语句,因此输出3。

变化

经过修改Foo()函数体,能够呈现出不一样的调用变化。

  • Foo函数体内的getName前加上vargetName变成了私有变量),答案会变成:2,4,4,4,2,3,3

  • Foo函数体内的getName前加上thisgetName变成了属性),答案会变成:2,4,1,1,2,1,1

相关文章
相关标签/搜索