一個簡單的 JavaScript 類示例
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
speak() {
console.log(this)
}
}
const p = new Person('Callback', 27)
p.speak();
執行上面的示例可以看到控制台輸出如下圖

接下來做一個操作:
const f = p.speak
f() // 輸出 undefined
這里將常量 f 指向 speak() 方法,注意這里是「指向」,並不是「調用」。之后調用 f() 可以觀察到控制台輸出為 undefined。那么問題來了,為什么這么賦值之后,函數內部的 this 不再是 Person 的實例 p 而變成了 undefined ?
實際上,方法內部的 this 永遠指向的是調用這個方法的對象,通過 Person 的實例 p 調用 speak() 方法,那么 this 就指向 p。后面將 speak 賦值給常量 f 后, f() 表示的就是通過全局的 window 對象來調用 f() 方法。按理說,f() 方法被調用時應該輸出 window 對象的信息,但這里輸出的卻是 undefined。這是因為根據 JavaScript 的語法規則,所有在類中定義的方法都默認開啟局部嚴格模式。在嚴格模式下,所有指向 window 對象的 this,都全部變更為 undefined。看下面的示例:
function demo() {
console.log(this)
}
function demo2() {
'use strict'
console.log(this)
}
demo() // 輸出 window 對象信息
demo2() // 輸出 undefined
回到最初的問題,之所以調用 f() 方法后輸出 undefined,是因為 f 指向的方法 speak() 是在 Person 類中定義的,其默認開啟了局部嚴格模式。當 f() 被調用時,調用方為 window 對象,這樣 this 就變成了 undefined。
其實這一點和 Java 中對方法的處理是類似的。每一個實例對象都持有對方法的引用而不是保存一份方法,方法會自動在參數列表的最前面添加一個 this 參數,這就是我們之所以能夠在 Java 方法里使用 this 關鍵字的原因,而這個 this 指向的就是當前在調用這個方法的對象。區別在於,Java 里所有的方法都不能脫離定義它的類,不可以像 JavaScript 里面把類的某個方法賦值給一個全局變量或常量。
