资讯专栏INFORMATION COLUMN

一道JavaScript面试题:理解Function

UsherChen / 779人阅读

摘要:关于该问题的讨论今天看到的一道面试题,感觉对理解的以及原型链和闭包很有帮助。自己并试着讲述一下自己的理解,欢迎拍砖。进入上下文时,会获取,函数声明,变量声明。

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

关于该问题的讨论:

https://segmentfault.com/q/10...

https://segmentfault.com/a/11...

https://segmentfault.com/a/11...

今天看到的一道面试题,感觉对理解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();

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

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

分析

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

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

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

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

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

另外也跟new关键字有关,因为Foo()前没有使用new,所以不会创建新的对象,而且 Foo的调用应该属于函数调用,所以返回的this其实是window对象,而不是Foo实 例(并没有创建)。

new Foo.getName():调用其实是创建了一个Foo.getName的新的实例(函数本身也是Object),在创建对象的过程中执行到了alert(2)语句,所以就输出为2;

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

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/82203.html

相关文章

  • 一道面试谈谈函数柯里化(Currying)

    摘要:忍者秘籍一书中,对于柯里化的定义如下在一个函数中首先填充几个参数然后再返回一个新函数的技术称为柯里化。回到我们的题目本身,其实根据测试用例我们可以发现,函数的要求就是接受单一函数,例如但是与柯里化不同之处在于,柯里化返回的一个新函数。   欢迎大家再一次来到我的文章专栏:从面试题中我们能学到什么,各位同行小伙伴是否已经开始了悠闲的春节假期呢?在这里提前祝大家鸡年大吉吧~哈哈,之前有人说...

    cppprimer 评论0 收藏0
  • JavaScript中的map方法,以及一道js面试

    摘要:今天看见一道面试题答案是多少答案是对方法不太了解就去搜了一下,里面也包含了对这道面试题的详解。方法返回一个由原数组中的每个元素调用一个指定方法后返回值组成的新数组。使用方法处理数组时,数组元素的范围在方法第一次调用之前就已经确定了。 今天看见一道面试题:[1,2,3].map(parseInt)答案是多少?答案是[1,NaN,NaN] 对map()方法不太了解就去搜了一下:Array....

    LittleLiByte 评论0 收藏0
  • 「前端面试系列4」this的原理以及用法

    摘要:但是有一个总的原则那就是总会指向,调用函数的那个对象。作为对象方法的调用函数作为某个对象的方法调用,这时就指这个上级对象。 showImg(https://segmentfault.com/img/bVbnvF7?w=750&h=422); 这是前端面试题系列的第 4 篇,你可能错过了前面的篇章,可以在这里找到: 伪类与伪元素的区别及实战 如何实现一个圣杯布局? 今日头条 面试题和思...

    fnngj 评论0 收藏0
  • 一道面试引发的思考 --- 理解 new 运算符

    摘要:首先,我先去上搜索了的定义运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。 今天看到一道面试题,如下,问: 实例化 Person 过程中,Person返回什么(或者 p 等于什么)? function Person(name) { this.name = name return name; } let p = new Person(Tom); 说实...

    shengguo 评论0 收藏0
  • 一道前端面试引发的思考

    摘要:直接开始题目是厉害了说句实话开发中谁写成这样保证会被打死。不过面试就是面试,有面试官的考量点。官方是这么说的。结果完美,不过小姐姐的意思是数组的方法会自动触发数组的。 直接开始题目是 if(a==1 && a==2 && a==3){ alert(厉害了) } 说句实话开发中谁写成这样保证会被打死。 不过面试就是面试,有面试官的考量点。 我理解的点有两个 1、隐式类型转换 先说...

    gaomysion 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<