代碼執行流程
- 步驟1: 執行
obj.cool(),調用cool方法 - 步驟2: 在
cool方法內部,this指向obj對象,通過var self = this;保存這個引用 - 步驟3: 條件判斷
self.count < 1 為true(初始值為0) - 步驟4: 設置
setTimeout定時器,延遲100ms執行 - 步驟5:
cool方法執行完畢 - 步驟6: 100ms后定時器觸發,執行回調函數
- 步驟7:
self.count++ 將count變為1,輸出"awesome?"
var self = this 的工作原理
1. 調用時的this指向
當執行 obj.cool() 時,根據隱式綁定規則,函數內的this指向obj對象本身。
obj.cool(); // 此時cool函數內的this指向obj
2. 保存this引用
這行代碼的作用:
- 將當前
this(指向obj)的引用保存到局部變量self中 self變量存儲的是對obj對象的引用- 通過閉包機制,這個引用在定時器回調函數中仍然可訪問
3. 解決this丟失問題
如果沒有保存this引用:
代碼高亮:
// ? 錯誤示例 - this指向丟失
setTimeout(function timer() {
this.count++; // this指向全局對象或undefined,不是obj
}, 100);
// ? 正確示例 - 使用self
setTimeout(function timer() {
self.count++; // self仍指向obj
}, 100);
閉包的作用
timer回調函數形成了閉包:
function coolFn() {
var self = this; // 外層函數作用域
return function timer() {
// 內層函數可以訪問外層函數的self變量
self.count++;
};
}
閉包特性:
- 即使
coolFn函數執行完畢,self變量仍然存在于內存中 timer函數引用著self變量,所以不會被垃圾回收定時器觸發時,仍然可以訪問到保存的self引用
三種解決this綁定問題的方法
方法1:使用箭頭函數(推薦)
var obj = {
count: 0,
cool: function coolFn() {
if (this.count < 1) {
setTimeout(() => {
// 箭頭函數不改變this指向,this仍然指向obj
this.count++;
console.log('awesome?');
}, 100);
}
}
}
obj.cool();
特點:
- 箭頭函數沒有自己的
this,繼承外層作用域的this - 代碼簡潔優雅
- ES6語法,現代瀏覽器和Node.js都支持
方法2:使用bind綁定
var obj = {
count: 0,
cool: function coolFn() {
if (this.count < 1) {
setTimeout(function timer() {
this.count++;
console.log('awesome?');
}.bind(this), 100); // 使用bind將this綁定到當前函數的this
}
}
}
obj.cool();
特點:
- 使用
Function.prototype.bind方法顯式綁定this - 代碼稍長,但意圖明確
- 兼容性較好(ES5)
方法3:使用var self = this(經典方案)
代碼高亮:
var obj = {
count: 0,
cool: function coolFn() {
var self = this; // 保存this引用
if (this.count < 1) {
setTimeout(function timer() {
self.count++; // 使用保存的引用
console.log('awesome?');
}, 100);
}
}
}
obj.cool();
特點:
- 經典解決方案,兼容性最好
- 適合需要支持舊版瀏覽器的場景
需要額外的變量聲明
三種方法對比

在項目中的應用建議
推薦使用箭頭函數方案,因為:
- 代碼更簡潔優雅
- 符合現代JavaScript開發習慣
- TypeScript對箭頭函數有良好支持
- 提高代碼可讀性和維護性
補充:this指向規則總結
- 默認綁定: 嚴格模式下指向
undefined,非嚴格模式指向全局對象 - 隱式綁定: 調用時使用對象,
this指向該對象 - 顯式綁定: 使用
call、apply、bind顯式指定this new綁定: 使用new調用構造函數,this指向新創建的對象
- 箭頭函數: 繼承外層作用域的
this,不能被改變
參考文章:
原文鏈接?