现在坐在去北京的高铁上,刚才玩了两把极品飞车,配着列车的座位和颠簸,很带感!眼睛累了,最近确实比较忙,又是拖了好久就想写的博客,在这个特殊的地方,强烈抵制自己的拖延症!
上一篇JS面试题都是基本数据类型,同一个人面试的话不会问太多,而JS中的原型、作用域和闭包是面试官问的最多的,我称之为“吉祥三宝”。
作用域
说白了就是某个函数执行时this
指向谁的问题。
问题1:
1 | var obj = { |
obj.run()
进入函数主体时,因为调用者是obj
,因此run()
内部this
是指向obj
的。但是run()
内部又定义了一个function,直接执行了test()
,因此test()
内部的this
未显式指定,this
默认指向就是window
。
问题2:
1 | var name = 'window'; |
因为直接把obj.child.getName
赋给了getName
变量,因此getName
就是个function,直接调用getName()
时其内部this
指向的是默认值window
,因此alert结果是window
。
而调用obj.child.getName()
时,指定了调用者对象,因此函数内部的this
指向obj.child
对象。由于child
里面的name
给我注释掉了,因此obj.child.getName()
里访问不到this.name
,就alert出undefined
(obj.name
是用来迷惑的)。如果将此注释去掉的话,alert结果就是child
。
问题3:
1 | function a(x, y){ |
这题是在ruanyf老师的微博上看到的,意思是很难的一道面试题,在console里试了下才想通了结果。
执行a()
未传入实际参数,所以a()
刚进入时,x`
y都是
undefined。然后对
y变量赋值成一个函数,函数内部将改变
x的值,这里的
x就是
a函数定义时的形式参数
x`。
函数定义时括号里的叫形式参数,JS中函数调用时传入的实际参数可与形式参数数目不一致。而arguments
指的是实际参数,因此a()
里面this
指向window
,而arguments
就是空数组。
然后执行a()
里面的匿名函数,重新定义了局部变量x = 3
,然后调用匿名函数外部的y()
。而上面已说y
内部改变的是a
函数的形式参数x
的值,因此不会影响匿名函数内部的x
,所以输出结果就是3。这里也可以用闭包来解释,console.log(x)
看到的就是匿名函数内部的变量x
,y
函数内部看不到匿名函数内部的变量。
原型
原型prototype是用来实现JS中的对象继承的,具体可看我以前这篇Javascript模式之五-代码复用模式。
问题1:
1 | var A = function(){ |
Q1:写段代码让B继承A
1 | var F = function(){}; |
我使用了圣杯模式的思想来继承,通过一个中间的空函数,使得B的原型对象实例最小,不会包含A的实例变量name
。
Q2:下面输出结果是多少?
1 | var objB = new B(); |
如果按照我上面那种继承方法的话,由于B的原型对象其实F
的实例(F的原型指向A的原型),F
的实例中并没有name
属性,所以objB.say()
访问不到this.name
,结果就是undefined
啦。
如果上面的继承代码改成B.prototype = new A()
就这一句,那么B的原型对象就是A
的实例,因此B的原型中就有A
的实例属性name
,所以objB.say()
能访问到this.name
。
问题2:
1 | Function.prototype.f = function(){}; |
Q:能调用car.f()
和car.o()
吗?
首先car
是个new出来的对象,而JS中所有对象的原型链追溯到顶层都是Object
,即所有对象都继承自Object,因此car.o()
肯定没问题。
typeof car
是object
,而car.constructor
是Factory
。typeof Factory
是function
,而JS中所有function的constructor默认都是Function
,因此Factory.f()
是能调用到的。即car.constructor.f()
能调用到,而car.f()
是无法调用到的。
闭包
面试中问闭包问的最多的就是循环引用问题,我在使用闭包解决循环引用问题这篇文章中已经列出很多例子了。比如,有一个数组var array = [1, 2, 3, 4]
,请每隔1秒依次输出数组中的元素。这里就不多写了。
总结
JS中的原型、作用域和闭包是非常重要的,这是语言机制,也是这个语言的魅力。有了扎实的基础,再去理解模块化就会容易些,然后再了解一些RequireJS,就能得到面试官的喜欢,至少基础关没太大问题。