第 361 篇 · 第 14 卷 前端,沒有極限 2026 年 6 月 9 日 · 台北
ls -lt ./posts --since=2013 REC · node 361 · uplink

javascript

JavaScript This 系列文:this 與物件的關係

2019 年 03 月 18 日 · 3 分鐘閱讀 · By Wang Casper

本篇是接續先前的:鐵人賽: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 這一個陣列喔!