你不懂JS:作用域與閉包 附錄C:詞法this

官方中文版原文鏈接

感謝社區中各位的大力支持,譯者再次奉上一點點福利:阿里云產品券,享受所有官網優惠,并抽取幸運大獎:點擊這里領取

這本書通篇沒有講解this機制的任何細節,有一個ES6的話題以一種重要的方式將this與詞法作用域聯系了起來,我們將快速檢視它一下。

ES6為函數聲明增加了一種特殊的語法形式,稱為“箭頭函數”。它看起來像這樣:

var foo = a => {
    console.log( a );
};

foo( 2 ); // 2

這個所謂的“大箭頭”經常被稱為是 乏味煩冗的(諷刺)function關鍵字的縮寫。

但是在箭頭函數上發生的一些事情要重要得多,而且這與在你的聲明中少敲幾下鍵盤無關。

簡單地說,這段代碼有一個問題:


var obj = {
    id: "awesome",
    cool: function coolFn() {
        console.log( this.id );
    }
};

var id = "not awesome";

obj.cool(); // awesome

setTimeout( obj.cool, 100 ); // not awesome

這個問題就是在cool()函數上丟失了this綁定。有各種方法可以解決這個問題,但一個經常被重復的解決方案是var self = this;。

它可能看起來像:

var obj = {
    count: 0,
    cool: function coolFn() {
        var self = this;

        if (self.count < 1) {
            setTimeout( function timer(){
                self.count++;
                console.log( "awesome?" );
            }, 100 );
        }
    }
};

obj.cool(); // awesome?

用不過于深入細節的方式講,var self = this的“解決方案”免除了理解和正確使用this綁定的整個問題,而是退回到我們也許感到更舒服的東西上面:詞法作用域。self變成了一個可以通過詞法作用域和閉包解析的標識符,而且一直不關心this綁定發生了什么。

人們不喜歡寫繁冗的東西,特別是當他們一次又一次重復它的時候。于是,ES6的一個動機是幫助緩和這些場景,將常見的慣用法問題 固定 下來,就像這一個。

ES6的解決方案,箭頭函數,引入了一種稱為“詞法this”的行為。

var obj = {
    count: 0,
    cool: function coolFn() {
        if (this.count < 1) {
            setTimeout( () => { // 箭頭函數能好用?
                this.count++;
                console.log( "awesome?" );
            }, 100 );
        }
    }
};

obj.cool(); // awesome?

簡單的解釋是,當箭頭函數遇到它們的this綁定時,它們的行為與一般的函數根本不同。它們摒棄了this綁定的所有一般規則,而是將它們的立即外圍詞法作用域作為this的值,無論它是什么。

于是,在這個代碼段中,箭頭函數不會以不可預知的方式丟掉this綁定,它只是“繼承”cool()函數的this綁定。

雖然這使代碼更短,但在我看來,箭頭函數只不過是將一個開發者們常犯的錯誤固化成了語言的語法,這混淆了“this綁定”規則與“詞法作用域”規則。

換一種說法:為什么要使用this風格的編碼形式來招惹麻煩和繁冗?只要通過將它與詞法作用域混合把它剔除掉就好。對于給定的一段代碼只采納一種方式或另一種看起來才是自然的,而不是在同一段代碼中將它們混在一起。

注意: 源自箭頭函數的另一個非議是,它們是匿名的,不是命名的。參見第三章來了解為什么匿名函數不如命名函數理想的原因。

在我看來,這個“問題”的更恰當的解決方式是,正確地使用并接受this機制。

var obj = {
    count: 0,
    cool: function coolFn() {
        if (this.count < 1) {
            setTimeout( function timer(){
                this.count++; // `this` 因為 `bind(..)` 所以安全
                console.log( "more awesome" );
            }.bind( this ), 100 ); // 看,`bind()`!
        }
    }
};

obj.cool(); // more awesome

不管你是偏好箭頭函數的新的詞法this行為,還是偏好經得起考驗的bind(),重要的是要注意箭頭函數 僅僅是關于可以少打一些“function”。

它們擁有一種我們應當學習并理解的,有意的行為上的不同,而且如果我們這樣選擇,就可以利用它們。

現在我們完全理解了詞法作用域(和閉包?。?,理解詞法this應該是小菜一碟!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容