前两天做了一份笔试题:按照执行顺序列出下面代码的打印内容

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指向objectthis.name自然就是object.name

因此输出The Object

那么,接下来,func被赋了什么值?整个getNameFunc()函数吗?

并不是的,object.getNameFunc()函数运行的时候,闭包那段代码没有被执行,只是作为返回结果赋给了func,因此事实上var func = object.getNameFunc()这句等价于:

var func = function() {
     console.log(this.name)
}

现在funcobject就已经没什么关系了,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()(),事实上会顺序执行输出两个结果:一个是立即执行函数的结果,一个是闭包函数的结果。

clipboard.png

由于object.getNameFunc()赋值给了func,因而使用func()就可以只调用闭包,而不触碰那个立即执行函数。这几句话要小心理解!

通常一个变量未被声明就使用,会指向window.undefined,然而this是不会指向undefined的,像我们平时定义一个普通函数

function app() {}
// 调用
app()
// 实际上是这样调用的
window.app()

所以this会指向windowfunc()自然也等于window.func(),调用方是windowthis.name即是window.name

理解了上面那些,接下来的两句反倒是简单了。

func.call(object);
func.apply(object);

callapplythis指向改变至objectthis.name也就是object.name了。

本来写这篇博客之前还是有点绕的,写完之后脑子就清晰了,相信以后这类题能轻松答上。


夜鹰
742 声望7 粉丝

优秀,是一种习惯……