几道有意思的js面试题,由于水平所限,欢迎拍砖指正。
控制台输出结果
1 | console.log('x' in window); // true |
分析
in操作符判断属性是否在对象中,并返回一个布尔值。由于变量存在声明提升,因此 var x 会提升到执行环境顶端执行,全局变量会被挂载到 window 对象上,因此 in 操作符返回布尔值true。
分析执行结果
1 | function Foo(){ // A |
分析
Foo.getName()
函数是对象,在B处,将一个getName方法当作静态属性挂载到Foo对象中,因此Foo.getName将直接访问这个静态属性,得2。
getName()
函数声明提升和变量覆盖问题。在这段程序进入执行时,函数声明会率先提升到执行环境的顶端,即E部分首先被执行,getName函数的函数名(一个变量)保存对E函数的引用,随后程序又在 D 处通过函数字面量的方式对getName重新赋予对D函数的引用。因此当程序执行完毕时,getName中保存的是对D函数的引用,因此输出4。
Foo().getName()
变量声明方式和变量覆盖问题。在 A 处Foo()中,未通过var关键字直接声明了一个函数getName,因此这是一个全局的变量,所以Foo()一经执行,其中声明的getName将覆盖原有的getName变量。在全局环境中执行的Foo函数中return的this仍是window对象,window对象此时再调用getName函数时,取到的是已经被Foo函数中声明getName变量覆盖的引用,因此输出1。
new Foo.getName()
按我的理解,这里是把Foo.getName当作构造函数执行了。实例化了一个空对象但是里面什么也没有,Foo.getName()执行得到2。
new Foo().getName()
原型继承。先把Foo函数当作构造函数执行,Foo()中的return this 指向构造出的实例化对象,返回的对象又继承了Foo.prototype中保存的原型方法,因此输出3。
new new Foo().getName
拆成 new(new Foo().getName)这么来看。new Foo().getName和上面一题 new Foo().getName() 的区别是getName没执行,因此这一步里new Foo().getName创建出了一个带有Foo原型的对象并返回了这个对象从Foo继承而来的的getName方法,对这个函数再进行new操作,和之前类似的,这个对象从Foo继承而来的的getName方法执行了一次,创建出一个空的对象。因此输出3。