JavaScript 核心觀念(40)-函式以及 This 的運作-最常見的 this:物件的方法調用

前言

接下來就會開始講一推讓許多 JavaScript 開發者煩惱的東西,也就是 this

最常見的 this:物件的方法調用

首先 this 基本上在 JavaScript 非常的常見,而且是不需要使用這設置就會存在的東西,這是什麼意思呢?

這邊先打開瀏覽器的控制台,並按下 source 中的暫停按鈕,接下來輸入以下程式碼

1
2
3
4
5
function fn () {

}

fn();

就會看到以下畫面

source

然後按下 「Step info next function call」就會進入該函式的執行堆疊,這時候就會看到 Scope 裡面會有一個 this

Scope

因此 this 只要在執行環境成立時,就會自動生成,因此並不需要我們特別去設定,除此之外在此我們也可以看到目前 this 是指向到 window,因此若此時我們有一個 Global 變數,那麼我們就可以直接使用 this 取得

1
2
3
4
5
6
7
var myName = 'Ray';

function fn () {
console.log(this.myName); // Ray
}

fn();

this

這邊再強調一次 this 並不需要我們特別去設定或是宣告,它本身在存活在每一個執行環境下,其中包含函式的執行環境以及全域執行環境,因此基本上 this 也有一些基本觀念要注意

this 基本觀念

第一個是我們剛剛一直在強調的,每一個執行環境都有屬於自己的關鍵字 this,第二個觀念若能熟悉的話,基本上大多 this 的指向都可以了解,最後一個則是嚴格模式。

而這邊課程也有列出常見的 this 調用方式

this 調用方式

那麼這邊回歸 this 有什麼用呢?

基本上 this 它的指向與我們怎麼定義它並沒有太大的什麼關係,因此它是可以略過函式的定義方式來呼叫並取的特定的物件屬性

this 的用途

而在此 this 在物件的方法中調用是非常的常見

this:物件的方法調用

因此我們舉例一段程式碼

1
2
3
4
5
6
7
8
var data = {
name: 'Ray',
callName() {
console.log(this.name);
},
}

data.callName();

在此我們可以看到 callName 是基於 data 這個物件底下呼叫的,因此 this 就會指向到 data,所以 console.log(this.name) 就會出現 Ray

除此之外範例程式碼改成以下,結果也會是相同的

1
2
3
4
5
6
7
8
9
function fn () {
console.log(this.name);
}
var data = {
name: 'Ray',
callName: fn,
}

data.callName();

因此我們就可以得知,只要它在哪一個物件下呼叫那麼它就會指向到哪一個物件。

接下來這一段在額外調整一個範例程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function fn () {
console.log(this.name);
}
var data = {
name: 'Ray',
callName: fn,
ming: {
name: 'Ray2',
callName: fn,
}
}

data.callName();
data.ming.callName();

基本上 this 的重點觀念在於是在哪一個物件下呼叫的,那麼它會指向哪一個屬性,所以 data.callName(); 是基於在 data 底下呼叫 callName,因此就會是出現 Ray,這邊前面觀念是完全一樣,而第二個 data.ming.callName();callName 是基於在 ming 呼叫,因此 callName 就會指向到 ming 而出現 Ray2

接下來再來額外看一些不同的範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function fn () {
console.log(this.myName);
}
var data = {
myName: 'Ray',
callName: fn,
ming: {
myName: 'Ray2',
callName: fn,
}
}

var a = data.callName;
a();

在此我們會發現 callName 出來的結果會是 undefined

為什麼呢?剛剛有講到 this 的指向最主要與它怎麼呼叫有關係,因此我們將 data.callName 直接賦予到變數 a 中(注意這邊並沒有執行 callName),因此 a 變數在呼叫時,是在 window 下呼叫,而此時的 window 並沒有 myName 這個屬性,因此就會是一個 undefined

這時候若調整成這樣就可以看到囉~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var myName = 'JavaScript'
function fn () {
console.log(this.myName);
}
var data = {
myName: 'Ray',
callName: fn,
ming: {
myName: 'Ray2',
callName: fn,
}
}

var a = data.callName;
a(); // JavaScript

透過該章節我們可以了解到,不管你怎麼定義函式 this 的指向終究只會與它的呼叫有關係而與它的定義方式沒有太大關聯。

最後再寫一個範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var myName = 'JavaScript'
function fn () {
setTimeout(function() {
console.log(this.myName);
}, 1000);
}
var data = {
myName: 'Ray',
callName: fn,
ming: {
myName: 'Ray2',
callName: fn,
}
}

data.callName();

上面這一段程式碼,基本上在你輸入之後過一秒會發現 this 竟然會是出現 JavaScript 而不是 Ray,而這邊最主要原因是出在與 this 的簡易呼叫有關係而導致 this 指向跑掉。

參考文獻

Liker 讚賞 (拍手)

如果這一篇筆記文章對你有幫助,希望可以求點支持或 牡蠣 鼓勵 (ノД`)・゜・。

Liker 是一個按讚(拍手)的讚賞機制,每一篇文章最多可以按五下拍手,過程你只需要登入,如果你願意按個讚,對於創作者來講是一個莫大的鼓勵與支持。

Google AD

撰寫一篇文章其實真的很花時間,如果你願意「關閉 Adblock (廣告阻擋器)」來支持我的話,我會非常感謝你 ヽ(・∀・)ノ