前两天作了一份笔试题:按照执行顺序列出下面代码的打印内容浏览器
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 Objectapp
The Window函数
The Objectthis
The Objectspa
OK, 一个一个来分析。code
执行顺序从上往下,这句var func = object.getNameFunc();
会产生第一个输出:The Object
想搞明白为何输出这个,必须先知道,this指向谁?
首先,想知道this指向谁,不能看它在哪里被定义,而要看它在哪里被调用,运行object.getNameFunc()
时,显而易见地,调用这个函数的是object
,当即执行函数里面的this
指向object
,this.name
天然就是object.name
。blog
所以输出The Objectip
那么,接下来,func
被赋了什么值?整个getNameFunc()
函数吗?get
并非的,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
了。
原本写这篇博客以前仍是有点绕的,写完以后脑子就清晰了,相信之后这类题能轻松答上。