被我誤會(huì)多年的 JS 特性:不是高級(jí)、卻最愛咬人——this
JS 有成百上千個(gè)“怪脾氣”,但最陰魂不散的,偏偏是最常見、所以你以為早就懂的那個(gè)。 我也是——直到某天它又給我來(lái)了一嘴:不是它壞了,是我以為自己懂。
兇手是誰(shuí)?
this。 對(duì),就是人人自信寫下 this.value、轉(zhuǎn)頭又拿到 undefined 的那位老朋友。
不是 this 有病,是 調(diào)用方式 和 上下文 跟你腦海里“我以為”的不一樣。
我到底誤會(huì)了什么
我一直以為:this 指向包著這個(gè)函數(shù)的對(duì)象。比如:
const person = {
name: 'Alex',
sayHi() {
console.log(`Hi, I'm ${this.name}`);
}
};這段當(dāng)然能跑。 可你一把方法丟出去:
setTimeout(person.sayHi, 1000); // undefined嘭!this 直接換了人。 為什么?因?yàn)?nbsp;決定 this 的不是“函數(shù)在哪定義”,而是“函數(shù)怎么被調(diào)用”。
this 的真規(guī)則(人話版)
- 全局函數(shù)(非嚴(yán)格模式):this → 全局對(duì)象(瀏覽器里是 window)
- 嚴(yán)格模式函數(shù):this → undefined
- 對(duì)象方法調(diào)用:this → 點(diǎn)號(hào)左邊那個(gè)對(duì)象
- 箭頭函數(shù):不綁定自己的 this,繼承外層
- DOM 事件處理:this → 觸發(fā)事件的元素(多數(shù)情況下)
- **setTimeout / setInterval**:this → 全局(除非你手動(dòng) bind)
我怎么把認(rèn)知修正了
1) 有意識(shí)地用箭頭函數(shù)
箭頭函數(shù)不創(chuàng)建自己的 this,它捕獲外層。
class Timer {
constructor() {
this.seconds = 0;
}
start() {
setInterval(() => {
this.seconds++;
console.log(this.seconds);
}, 1000);
}
}這能穩(wěn)定自增。若把箭頭換成普通函數(shù),this 多半跑偏。
2) 認(rèn)真學(xué)會(huì) .bind() 是干嘛的
const boundFn = person.sayHi.bind(person);
setTimeout(boundFn, 1000); // Hibind = 把**調(diào)用時(shí)的 this**釘死在你想要的對(duì)象上。
3) 到處 console.log(this),比看書快十倍
在這些地方打點(diǎn)最長(zhǎng)見識(shí):
- 箭頭 vs 普通函數(shù)
- 事件處理函數(shù)
- setTimeout 回調(diào)
- Promise 鏈
- class 方法
你會(huì)被“真實(shí)世界里的 this”教育。
為什么你必須搞清楚
對(duì) this 的誤解會(huì)帶來(lái):
- 靜默的 bug(最難捉)
- 詭異的副作用
- 函數(shù)丟失上下文
- 一整天的抓狂調(diào)試
但當(dāng)你真正“點(diǎn)透”的那一刻:代碼更可讀、更抗 bug,你還能把這套知識(shí)講給新人聽。
實(shí)操心法(拿走就用)
- 方法要外傳?傳已綁定的:obj.method.bind(obj)
- class 回調(diào)??jī)A向箭頭函數(shù):onClick = () => { … }
- 庫(kù)回調(diào)(如事件/定時(shí)器)?確認(rèn)它怎么調(diào)用你,再?zèng)Q定 bind / 箭頭
- 工具函數(shù)?寫成純函數(shù)(別依賴 this),用參數(shù)顯式傳遞
- lint 規(guī)則:開啟 no-invalid-this(配合 TS/ESLint 更香)
最后一句
如果你還對(duì) this 心里沒底:你不是一個(gè)人。 這是那種看著簡(jiǎn)單、下嘴就咬的語(yǔ)法點(diǎn)。 一旦“啪”地悟到,你的 JS 代碼會(huì)少坑、少猜、少崩。




























