一道筆試題引起的思考

前兩天作了一份筆試題:按照執行順序列出下面代碼的打印內容瀏覽器

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

所以輸出The Objectip

那麼,接下來,func被賦了什麼值?整個getNameFunc()函數嗎?get

並非的,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了。

原本寫這篇博客以前仍是有點繞的,寫完以後腦子就清晰了,相信之後這類題能輕鬆答上。

相關文章
相關標籤/搜索