前言
今天這篇文章,主要希望能讓大家簡單理解JavaScript的this,所以不會有其他太複雜的內容,讓大家快速上手this!
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身上,有兩種方法。
- 使用bind函數。
- 使用箭頭函式寫法。
就讓我們來看看範例:
使用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