本篇是接續先前的:鐵人賽:JavaScript 的 this 到底是誰?,會更深入的探討 JavaScript This 的運作及觀念,這一系列的文章順序上不會從基礎開始介紹,會建議先從先前文章開始閱讀。
物件的方法調用 (As an object method)
「物件的方法調用」是最常見改變 this 的方法,只要搞懂這一部份就能了解決大部分的 this 運作,大部分的文件介紹此部分說明為:在函式內的 this
值取決於該函式如何被呼叫。而如何被呼叫實在難以被定義,如:callback、閉包、函式內的函式等等其實都與 this 沒有關聯性。
提供另一個比較易懂的中文說明:this 大部分取決於 它在哪個物件下被呼叫,也就是本段落主要介紹的「物件的方法調用」這個觀念佔了 絕大部分 的 JavaScript 實作時的 this 運作(接下來幾篇會陸續介紹其它幾種),版頭圖則是說明這一類型的 This 運作模式,只要找到上層物件就搞定了整個觀念,下述文中產生了一個函式,透過兩個不同的方式取用則有不同的結果:
function callName() {
console.log(this.name);
}
var name = '全域阿婆';
var auntie = {
name: '漂亮阿姨',
callName: callName
// 這裡的 function 指向全域的 callName function
}
callName() // '全域阿婆'
auntie.callName() // '漂亮阿姨',呼叫是在物件下調用,那麼 this 則是該物件
前者是稱為「純粹的呼叫」,此種情況相對單純下個段落會有完整介紹,而另一個物件呼叫 auntie.callName()
則會將 this 指向 “漂亮阿姨”,這個部分相信大家就能有基本的體會,物件下呼叫會影響 this 的指向。
概念如同下圖,在物件下的函式 this 為前者物件。
而 this 這個詞就可以思考成 這一個「物件」,它會隨著在哪一個物件下被調用而影響結果,在此情境下如果有更深層的 this 依然是當下這一個物件。
function callName() {
console.log(this.name);
}
var auntie = {
name: '漂亮阿姨',
callName: callName,
watch: {
name: 'Magic Watch',
callName: callName
}
}
auntie.callName() // '漂亮阿姨'
auntie.watch.callName() // 'Magic Watch'
在這個概念下,每一層的函式的 this 都是上一層物件,很簡單吧,所以漂亮阿姨下的每一層物件函式 this,都是指向該上層物件。
Vue.js 下的概念
使用 Vue.js 時運作的原理就與上述的接近,我們可以看到以下的程式碼運作時,物件第一層的內容均是指向 myCar 這一個物件。
var myCar = {
name: '長大以後要當保時捷',
go: function() {
console.log(this);
},
init: function(){
this.go()
}
}
myCar.init()
接下來看一下 Vue.js 的程式碼,你可能會思考這樣的結構比上述的多了一層,理論上 Vue 的 this 的運作會不太一樣才是。
var app = new Vue({
data: {
text: '這是一段話'
},
methods: {
go() {
console.log(this.text) // 這是一段話
}
},
created() {
console.log(this)
}
})
不過當 Vue 實際運作時,元件內的物件、函式等等均會被向上拉,methods, computed 等等均不會存在,所以並非以原始碼而是以實際運行的狀態為主,如下圖,methods 內的 go()
及 data 內的 text 均在元件物件頂層。
接下來運行的概念如下,元件下的函式的 this 就會直接指向該元件,所以 go()
這個函式的 this 自然就能夠使用元件內的 text 資料囉。
延伸閱讀:陣列內插入函式
在 JS 型別中,陣列也是屬於物件的一種,因此將函式插入陣列之中運行,this 的指向會如何呢?
一般來說不會有人這樣寫,但我們可以從中獲得相同的結果:
function callSomeone() {
console.log('this is', this);
}
var MingFamily = ['小明', '爸', '媽', callSomeone]
MingFamily[3]()
同上所述,callSomeone 這一個函式的運作也是接在 MingFamily 陣列後方,所以 this 將會指向 MingFamily 這一個陣列喔!