//////////////////////
这道“七连击”的前端面试题来自与Github上的一篇文章,已经火了很久。介于这道题很经典,考点还很多,所以在这里与大家分享。
格式化后的代码,看上去会舒服一些
之前已经在第一部中讲了前面的五道题,所以本篇只讲解第六和第七题,如果您感兴趣、想看前面5道题的讲解,可以通过扫面下面二维码来关注我的公众号,然后回复七连击,来获取全部讲解。
Q
第六问
new Foo().getName();
答案:3
详解:这一题比上一题的唯一区别就是在Foo那里多出了一个括号,这个有括号跟没括号我们在第五问的时候也看出来优先级是有区别的
运算优先级表
结合着上面的《运算优先级表》来看,
那这里又是怎么判断的呢?首先new有参数列表(18)跟点的优先级(18)是同级,同级的话按照从左向右的执行顺序,所以先执行new有参数列表(18)再执行点的优先级(18),最后再函数调用(17)
new有参数列表(18)->.成员访问(18)->()函数调用(17)
这里还有一个小知识点,Foo作为构造函数有返回值,所以这里需要说明下JS中的构造函数返回值问题。
构造函数的返回值
在传统语言中,构造函数不应该有返回值,实际执行的返回值就是此构造函数的实例化对象。 而在JS中构造函数可以有返回值也可以没有。
1.没有返回值则按照其他语言一样返回实例化对象。
2.若有返回值则检查其返回值是否为引用类型。如果是非引用类型,如基本类型(String,Number,Boolean,Null,Undefined)则与无返回值相同,实际返回其实例化对象。
3.若返回值是引用类型,则实际返回值为这个引用类型。
原题中,由于返回的是this,而this在构造函数中本来就代表当前实例化对象,最终Foo函数返回实例化对象。 之后调用实例化对象的getName函数,因为在Foo构造函数中没有为实例化对象添加任何属性,当前对象的原型对象(prototype)中寻找getName函数。 当然这里再拓展个题外话,如果构造函数和原型链都有相同的方法,如下面的代码,那么默认会拿构造函数的公有方法而不是原型链,这个知识点在原题中没有表现出来,后面改进版我已经加上。
//////////////////////
Q
第七问
new new Foo().getName();
答案:3
详解:new new Foo().getName();同样是运算符优先级问题。做到这一题其实我已经觉得答案没那么重要了,关键只是考察面试者是否真的知道面试官在考察我们什么。 最终实际执行为:
new有参数列表(18)->new有参数列表(18)
先初始化Foo的实例化对象,然后将其原型上的getName函数作为构造函数再次new,所以最终结果为3
答案
后续我把这题的难度再稍微加大一点点(附上答案),在Foo函数里面加多一个公有方法getName,对于下面这题如果用在面试题上那通过率可能就更低了,因为难度又大了一点,又多了两个坑,但是明白了这题的原理就等同于明白了上面所有的知识点了