幾條規則確定函數里的 this 是什么。
想確定 this 是什么其實非常簡單。總體的規則是,通過檢查它的調用位置,在函數被調用的的時候確定 this。它遵循下面這些規則,接下來以優先級順序說明。
規則
1、如果在調用函數時使用 new 關鍵字,那么函數里的 this 就是一個全新的對象。
function ConstructorExample() { console.log(this); this.value = 10; console.log(this);}new ConstructorExample();// -> {}// -> { value: 10 }2、如果使用 apply、call 或者 bind 調用函數,那么函數里的 this 就是作為參數傳進去的對象。
function fn() { console.log(this);}var obj = { value: 5};var boundFn = fn.bind(obj);boundFn(); // -> { value: 5 }fn.call(obj); // -> { value: 5 }fn.apply(obj); // -> { value: 5 }3、如果函數作為一個方法調用,就是說如果使用點符號調用函數,那么 this 就是擁有這個函數作為屬性的對象。換句話說,當一個點在函數調用的左側時,this 就是這個點左側的那個對象。
var obj = { value: 5, printThis: function() { console.log(this); }};obj.printThis(); // -> { value: 5, printThis: ƒ }4、如果函數作為一個純粹的函數調用,也就是說,它在沒有上述任何條件的情況下被調用,那么 this 就是全局對象。在瀏覽器里,就是 window 對象。
function fn() { console.log(this);}// 如果在瀏覽器里調用:fn(); // -> Window {stop: ƒ, open: ƒ, alert: ƒ, ...}注意這個規則其實和第三個規則是一樣的,區別在于沒有聲明為方法的函數會自動成為全局對象 window 的屬性。因此,這其實是一個隱式的方法調用。當我們調用 fn(),其實就會被瀏覽器理解為 window.fn(),所以 this 就是 window。
console.log(fn === window.fn); // -> true
5、如果上述規則有多個適用,那么優先級更高的就會設置 this 值。
6、如果是 ES2015 里的箭頭函數,那么它將忽略上述所有規則,并在創建的時候接收包含它的作用域作為 this 的值。想確定 this 具體是什么的話,只需從創建箭頭函數那里往上一行,看看那兒的 this 是什么,箭頭函數里的 this 值和它一樣。
const obj = { value: 'abc', createArrowFn: function() { return () => console.log(this); }};const arrowFn = obj.createArrowFn();arrowFn(); // -> { value: 'abc', createArrowFn: ƒ }看回第三個規則,當我們調用 obj.createArrowFn() 的時候,createArrowFn 里的 this 是 obj,因為這是方法調用。因此,obj 會在 arrowFn 里綁定到 this 上。如果我們在全局作用域創建一個箭頭函數,那么 this 值就會是 window。
新聞熱點
疑難解答
圖片精選