前两天做了一份笔试题:按照执行顺序列出下面代码的打印内容
var name = "The Window";
var object = {
name : "The Object",
getNameFunc : function(){
(() => {
console.log(this.name)
})()
return function(){
console.log(this.name)
};
}
};
var func = object.getNameFunc();
func();
func.call(object);
func.apply(object);
可能有些小朋友会被里面那个立即执行函数吓傻。没关系,先看答案,整段代码输入浏览器,输出如下:
The Object
The Window
The Object
The Object
OK, 一个一个来分析。
执行顺序从上往下,这句var func = object.getNameFunc();
会产生第一个输出:The Object
想搞明白为什么输出这个,必须先知道,this指向谁?
首先,想知道this指向谁,不能看它在哪里被定义,而要看它在哪里被调用,运行object.getNameFunc()
时,显而易见地,调用这个函数的是object
,立即执行函数里面的this
指向object
,this.name
自然就是object.name
。
因此输出The Object
那么,接下来,func
被赋了什么值?整个getNameFunc()
函数吗?
并不是的,object.getNameFunc()
函数运行的时候,闭包那段代码没有被执行,只是作为返回结果赋给了func
,因此事实上var func = object.getNameFunc()
这句等价于:
var func = function() {
console.log(this.name)
}
现在func
跟object
就已经没什么关系了,func
里面的this
自然指向window
。
因此第二句执行语句func()
相似于(注意用词,我这里用的是相似,不是相等):
object.getNameFunc()() //是的,我没打错,两个括号
嘻嘻,是不是有点蒙圈?
上面说了,由于object.getNameFunc()
执行后,会对外暴露出一个匿名函数,即return返回的那个匿名函数
function () {
console.log(this.name)
}
所以object.getNameFunc()()
会调起立即执行函数
(function () {
console.log(this.name)
})()
注意 —— object.getNameFunc()()
这个写法只是为了能调用闭包函数,如果在真的在浏览器跑object.getNameFunc()()
,事实上会顺序执行输出两个结果:一个是立即执行函数的结果,一个是闭包函数的结果。
由于object.getNameFunc()
赋值给了func
,因而使用func()
就可以只调用闭包,而不触碰那个立即执行函数。这几句话要小心理解!
通常一个变量未被声明就使用,会指向window.undefined
,然而this
是不会指向undefined
的,像我们平时定义一个普通函数
function app() {}
// 调用
app()
// 实际上是这样调用的
window.app()
所以this
会指向window
,func()
自然也等于window.func()
,调用方是window
,this.name
即是window.name
。
理解了上面那些,接下来的两句反倒是简单了。
func.call(object);
func.apply(object);
call
和apply
将this
指向改变至object
,this.name
也就是object.name
了。
本来写这篇博客之前还是有点绕的,写完之后脑子就清晰了,相信以后这类题能轻松答上。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。