【五分鐘讀前端】快速上手JavaScript的this

布魯斯前端
7 min readMar 20, 2021

--

快速上手JavaScript的this

前言

今天這篇文章,主要希望能讓大家簡單理解JavaScript的this,所以不會有其他太複雜的內容,讓大家快速上手this!

來快速上手囉Yeah!

this到底是誰?

對JavaScript的初學者來說,一開始都會搞不清楚this到底是什麼,為什麼會一直亂跑?

簡單說,在JavaScript裡面:

誰調用了包含「this」的function,誰就是this。

只要能把這個概念記住,this其實一點都不難。

JavaScript的this

this顧名思義就是「這個東西」的意思,但比起其他語言,this並不會因為我宣告在「誰」的底下就一直代表它。

this在JavaScript裡是代表「當下執行的物件」,讓我們來看看下面的例子。

function hello() {
console.log("我的名字是", this.name)
}
const a = { name: "Bruce" }
const b = { name: "Mike" }
a.hello = hello
b.hello = hello
//輸出:我的名字是Bruce
a.hello()
//輸出:我的名字是Mike
b.hello()

從上面的例子可以看見,this的「代表」,就是當下「誰」去執行那個hello function。

就如一開始我提到的:

「誰調用了包含「this」的function,誰就是this。」

這就是對this的基本認識,其實並不難,再來讓我們看看用class寫的例子。

class Car {  constructor() {
this.name = "我的車子"
}
start() {
console.log("啟動:", this.name)
}
}const myBus = { name: "我的公車" }
const myCar = new Car()
// this代表為myCar,輸出「啟動:我的車子」
myCar.start()
// 重點!!!把myCar的start交給myBus
myBus.start = myCar.start
// this代表為myBus,輸出「啟動:我的公車」
myBus.start()

這其實跟上面差不多,重點就是把start function給了myBus,所以執行start時this就變成myBus。

如果我想「特別指定」誰為this,可以嗎?

答案是可以!JavaScript提供了三種方法讓你「指定」誰成為this。

這三種方法分別為:call、apply、bind

call跟apply沒啥太大的區別,只是傳遞參數要求不同,call是一個一個傳,apply是叫你包成array傳。

bind是返回了一個新的function,幫你把「this」綁定在你想綁的物件上。

讓我們來看看一些例子:

call的部分:

function hello(years, address) {
console.log(this.name)
console.log(years, "歲")
console.log("住址:", address)
}
const a = { name: "bruce" }
const b = { name: "mike" }
// bruce
// 100歲
hello.call(a, 100, "高雄市XXX")
// mike
// 100歲
hello.call(b, 100, "台北市XXX")

apply的部分:

function hello(years, address) {
console.log(this.name)
console.log(years, "歲")
console.log("住址:", address)
}
const a = { name: "bruce" }
const b = { name: "mike" }
// bruce
// 100歲
//
只是把參數改成用array收集
hello.apply(a, [100, "高雄市XXX"])
// mike
// 100歲
hello.apply(b, [100, "台北市XXX"])

bind的部分:

function hello(years, address) {
console.log(this.name)
console.log(years, "歲")
console.log("住址:", address)
}
const a = { name: "bruce" }
const b = { name: "mike" }
// 返回了新函數~~~
const newHelloA = hello.bind(a, 100, "高雄市XXX")
const newHelloB = hello.bind(b, 100, "台北市XXX")
// bruce
// 100歲
newHelloA()
// mike
// 100歲
newHelloB()

class綁定this

有時候,我們不希望this亂跑,所以想把this綁定在class身上,有兩種方法。

  1. 使用bind函數。
  2. 使用箭頭函式寫法。

就讓我們來看看範例:

使用bind函數:

class Car {  constructor() {
this.name = "我的車子"
// 綁定start的this在Car身上
this.start = this.start.bind(this)
}
start() {
console.log("啟動:", this.name)
}
}const myBus = { name: "我的公車" }
const myCar = new Car()
// 輸出「啟動:我的車子」
myCar.start()
// 重點!!!把myCar的start交給myBus
myBus.start = myCar.start
// 依然輸出「啟動:我的車子」!
myBus.start()

使用箭頭函式寫法:

class Car {  constructor() {
this.name = "我的車子"
}
// 箭頭函式的宣告方式,自動綁定this為Car
start = () => {
console.log("啟動:", this.name)
}
}const myBus = { name: "我的公車" }
const myCar = new Car()
// 輸出「啟動:我的車子」
myCar.start()
// 重點!!!把myCar的start交給myBus
myBus.start = myCar.start
// 依然輸出「啟動:我的車子」!
myBus.start()

有個需要注意的小細節

注意!!!

這裡有個小細節需要注意:

使用箭頭函式時,start function並不像第一種寫法是賦予在prototype上

讓我們來理解這是什麼意思,先來看看程式碼先。

...class Car {
// 賦予在Car的prototype上
start() { ... }
}
class Car {
// 沒有賦予在Car的prototype上
start = () => { ... }
}
...

上面兩種在class裡宣告start的方式,主要的差別為:

  • 假設我今天new了100次。
const car1 = new Car().....
....
..
const car100 = new Car()

用箭頭函式宣告,沒有賦予在Car的prototype上:
每個物件(car1….car100)裡都會有一個start function,所以等於佔了100個start function在記憶體空間裡。

用一般宣告方式,賦予在Car的prototype上:
因為start是依附在Car的prototype上,這100個物件全部共用同一個start function。

結尾

以上就是對this的基本教學,雖然沒有涵蓋到更多複雜的東西,但相信足以應付大部分的開發情況。

讓我們再來複習一次~

誰調用了包含「this」的function,誰就是this。

希望這篇文章能讓大家快速上手this!

想持續關注我的話

  • 去Medium追蹤給他按下去~!
  • Facebook粉專按按讚~!
  • Youtube頻道訂閱,每週三都直播聊聊大家想問的問題~!
  • 加入我創的Line社群,群組目前有1200多人,可以一起進來交流分享經驗跟技術。
  • Line社群點我加入:https://reurl.cc/V3WjGZ

--

--