this 是一個根據使用位置有不同值的關鍵字。不了解 JavaScript 中這個微小的細節可能會帶來很多困擾,所以花五分鐘的時間來學習所有的技巧是值得的。

this 在嚴格模式下

在任何物件之外,在嚴格模式下,this 的值總是 undefined

請注意,我提到了嚴格模式。如果未啟用嚴格模式(如果你的文件頂部沒有明確添加 'use strict'),你將處於所謂的松散模式,而 this - 除非下面特殊情況中提到的 - 將具有全局物件的值。

這意味著在瀏覽器上下文中是 window

方法中的 this

方法是附加到物件的函式。

你可以以各種形式看到它。

以下是其中一種:

const car = {
 maker: 'Ford',
 model: 'Fiesta',

 drive() {
 console.log(`Driving a ${this.maker} ${this.model} car!`)
 }
}

car.drive()
//Driving a Ford Fiesta car!

在這種情況下,使用一般函式,this 會自動綁定到物件。

注意:上述的方法宣告與 drive: function() {… 是相同的,只是比較簡短:

const car = {
 maker: 'Ford',
 model: 'Fiesta',

 drive: function() {
 console.log(`Driving a ${this.maker} ${this.model} car!`)
 }
}

在這個例子中也是一樣的:

const car = {
 maker: 'Ford',
 model: 'Fiesta'
}

car.drive = function() {
 console.log(`Driving a ${this.maker} ${this.model} car!`)
}

car.drive()
//Driving a Ford Fiesta car!

箭頭函式不以相同的方式工作,因為它們是以語法為基礎的:

const car = {
 maker: 'Ford',
 model: 'Fiesta',

 drive: () => {
 console.log(`Driving a ${this.maker} ${this.model} car!`)
 }
}

car.drive()
//Driving a undefined undefined car!

綁定箭頭函式

你無法像普通函式一樣綁定值到箭頭函式。

這是因為它們的工作方式不同。this以語法為基礎綁定的,這意味著它們的值是從它們被定義的上下文中衍生出來的。

明確地將一個物件傳遞給 this 以用作綁定

JavaScript 提供了幾種方式來將 this 映射到你想要的任何物件上。

函式聲明步驟中使用 bind()

const car = {
 maker: 'Ford',
 model: 'Fiesta'
}

const drive = function() {
 console.log(`Driving a ${this.maker} ${this.model} car!`)
}.bind(car)

drive()
//Driving a Ford Fiesta car!

你也可以綁定一個現有物件的方法以重新映射它的 this 值:

const car = {
 maker: 'Ford',
 model: 'Fiesta',

 drive() {
 console.log(`Driving a ${this.maker} ${this.model} car!`)
 }
}

const anotherCar = {
 maker: 'Audi',
 model: 'A4'
}

car.drive.bind(anotherCar)()
//Driving a Audi A4 car!

函式調用步驟中使用 call()apply()

const car = {
 maker: 'Ford',
 model: 'Fiesta'
}

const drive = function(kmh) {
 console.log(`Driving a ${this.maker} ${this.model} car at ${kmh} km/h!`)
}

drive.call(car, 100)
//Driving a Ford Fiesta car at 100 km/h!

drive.apply(car, [100])
//Driving a Ford Fiesta car at 100 km/h!

你傳遞給 call()apply() 的第一個參數始終會綁定到 thiscall()apply() 之間的區別只是第二個期望參數列表是一個陣列,而第一個接受可變數量的參數,作為函式引數傳遞。

瀏覽器事件處理程序的特殊情況

在事件處理程序回調中,this 參考到接收到事件的 HTML 元素:

document.querySelector('#button').addEventListener('click', function(e) {
 console.log(this) //HTMLElement
}

你可以使用以下方式綁定它:

document.querySelector('#button').addEventListener(
 'click',
 function(e) {
 console.log(this) //Window(如果全局),或你的上下文
 }.bind(this)
)