ES6箭頭函數體中的this指向哪裏?
在回答這個問題以前先來揣揣你對this
關鍵字的瞭解程度:
(讓咱們回到ES6以前)
題:es6
var obj = { a: function() { console.log(this); } } var b = obj.a; b();
問:打印出的this
的值?
再來幾個選項:併發
window
obj
document
obj.a
答案是window
(能夠在控制檯運行一下)函數
什麼!什麼狀況!發生了什麼?
一句話解釋:
通常的,this
指向函數運行(調用)時所在的執行環境【《JavaScript高級程序設計》4.2節執行環境及做用域】的(變量)對象(簡單地,this
指向函數的調用者)測試
分析代碼:this
var b = obj.a; // ==>至關於 var b = function() { console.log(this); }
函數調用時(b();
)其所在的執行環境是全局環境,因此this
指向全局變量對象window
設計
若是你以爲以上這些都知道了(我會!我會!)那麼就繼續吧~~
(來到ES6箭頭函數)code
例1【阮一峯《ECMAScript 6 入門》-7.函數的擴展:箭頭函數】對象
我將阮老師的例子代碼修改了一下:
(普通函數)ip
function foo() { console.log("id1:", this.id); console.log("this1:", this); setTimeout(function() { console.log("id2:", this.id); console.log("this2:", this); }, 0); } var id = 21; foo(); // Chrome // id1: 21 // this1: window // id2: 21 // this2: window foo.call({id: 42}); // Chrome // id1: 42 // this1: {id: 42} // id2: 21 // this2: window
注意:超時調用(setTimeout
回調)的代碼都是在全局做用域環境中執行的,所以(setTimeout
回調)函數中this
的值在非嚴格模式下指向window
對象,在嚴格模式下是undefined
作用域
例如
var obj = { console.log(this); setTimeout(function() { console.log(this); }, 0); } obj.a(); // Chrome // {a: f} // window
回到例1
咱們使用foo
函數的call
方法改變了foo
函數調用時函數體內this
的指向({id: 42}
這個對象),但setTimeout
回調函數中的this依舊指向window
對象(由於在全局環境中運行)。
接下來再將例1改寫一下,將foo
函數中的setTimeout
回調函數改爲箭頭函數的形式:
例2
(箭頭函數)
function foo() { console.log("id1:", this.id); console.log("this1:", this); setTimeout(() => { console.log("id2:", this.id); console.log("this2:", this); }, 0); } var id = 21; foo(); // Chrome // id1: 21 // this1: window // id2: 21 // this2: window foo.call({id: 42}); // Chrome // id1: 42 // this1: {id: 42} // id2: 42 // this2: {id: 42}
foo();
的輸出結果沒有變化,但foo.call({id: 42});
的輸出結果改變了。
到底發生了什麼?
在這裏直接給出結論:
箭頭函數根本沒有本身的this
,致使內部的this
指向了外層代碼的this
,這個指向在定義時就已經肯定而不會在調用時指向其執行環境的(變量)對象。
注意:由於箭頭函數內部的this
是指向外層代碼塊的this
(最近的this
,例2中的foo函數)的,因此咱們能夠經過改變外層代碼塊的this
的指向從而改變箭頭函數中this
的指向(例2中使用了foo
函數的call
方法)。
從新解釋例2
由於箭頭函數(setTimeout
回調)沒有本身的this
,致使其內部的this
引用了外層代碼塊的this
,即foo
函數的this
,
(要注意:在定義階段(調用函數前),foo
函數的this
的值並不肯定【《JavaScript高級程序設計》第三版5.5.4函數內部屬性】,但箭頭函數的this
自定義階段開始就指向foo
函數的this
了)
又由於使用call
方法改變了foo
函數運行(調用)時其函數體內this
的指向(從新指向對象{id: 42}
)從而使箭頭函數中this
的指向發生變化,最後輸出例2所示結果。
到這裏,我想小夥伴們應該是比較清楚了,那麼不妨去看看阮一峯老師的《ECMAScript 6 入門》函數的擴展一節箭頭函數部分的一個問題示例:「請問下面的代碼中有幾個this(滑稽)」
加深印象
例3【阮一峯《ECMAScript 6 入門》-19.Class基本語法:this的指向】
class Logger { constructor() { this.printName = (name = 'there') => { this.print(`Hello ${name}`); }; } // ... }
箭頭函數中的this
指向constructor
構造方法內部的this
,因爲此時constructor
中的this
還沒有得到值,當經過new
命令生成對象實例時,將會自動調用constructor
方法,constructor
的this
才能指向該實例對象,在此過程當中,箭頭函數中的this
一直引用着constructor
中的this
,當constructor
中this
發生變化,箭頭函數的this
也會一併發生變化。
如有錯誤,請指出批評!!