在 JavaScript 中,匿名函式作為物件方法的回傳值時,其 this 的指向取決於「函式是如何被呼叫的」,而非定義位置。
- 非嚴格模式(Non-strict mode):以普通函式(參考範例一的 t_run())呼叫時, this 指向全域物件(瀏覽器中為 window )。
- 嚴格模式(Strict mode):this 會是 undefined。
## 範例一:觀察 this 的遺失
當我們將回傳的函式賦值給變數並執行時,它會變成一個「普通函式呼叫」。
<script type="text/javascript">
var name = "Tom"; // 全域變數
var objectA = {
name: "John" ,
test_1: function() {
return function() {
this.name = "Mary"; // 此時的 this 可能不如預期
};
}
};
console.log(window.name); // Tom
console.log(objectA.name); // John
var t_run = objectA.test_1();
t_run(); // 關鍵點:這是一個獨立函式呼叫,this 指向 window
console.log(window.name); // Mary (全域變數被修改了)
console.log(objectA.name); // John(物件屬性未變)
</script>
## 解決方案
1. 使用 .bind(this) 鎖定指向
.bind(this) 會建立一個新的函式,並將其 this 永久綁定到指定物件。
<script type="text/javascript">
test_1: function() {
// 此處的 this 是 objectA,我們將它綁定給回傳的匿名函式
return function() {
this.name = "Mary";
}.bind(this);
}
</script>
2. 使用 ES6 箭頭函式(推薦做法)
箭頭函式沒有自己的 this,它會捕捉定義時所在環境的 this (稱為 lexical this)。
<script type="text/javascript">
test_1: function() {
return () => {
this.name = "Mary"; // 自動繼承 test_1 執行時的 this(即 objectA)
};
}
</script>
3. 使用變數暫存
在 ES6 普及前,開發者常用變數(如 self 或 that)來捕捉當前的 this。
<script type="text/javascript">
test_1: function() {
var self = this; // 鎖住當前的 objectA
return function() {
self.name = "Mary";
};
}
</script>
## 關鍵觀念:為什麼會這樣?
請記住這句話:this 的指向取決於呼叫方式,而不是函式定義的位置。
- 程式碼 A(物件呼叫 vs 賦值後呼叫)
<script type="text/javascript">
var obj = {
name: "john",
fn: function() {
console.log(this);
}
};
// 物件呼叫
obj.fn(); // this -> obj
// 賦值後呼叫
var f = obj.fn;
f(); // this -> window(或 'use strict' -> undefined)
</script>
- 程式碼 B(連續呼叫)
<script type="text/javascript">
var objectA = {
name: "John" ,
test_1: function(){
return function(){
console.log(this);
};
}
};
objectA.test_1()();
// 第一個 () 回傳匿名函式
// 第二個 () 是在全域執行該回傳函式 -> this 指向 window
</script>
結論:嚴格模式的行為
若開啟 'use strict';,範例一執行 trun() 時,this 會是 undefined。此時嘗試執行 this.name = "Mary" 會噴出 TypeError。這雖然會讓程式中斷,但能強迫開發者修正錯誤的 this 引用,是更安全的做法。
沒有留言:
張貼留言
請注意 : 您的留言發佈成功 , 需經審核後 , 才能決定是否回覆 . 謝謝 !!