JavaScript 的 this 會隨著調用的方式不同影響其指向的不同(ES6 的箭頭函式定義也會影響指向),網路上已經提供相當多的資源介紹 this
指向的觀念,本篇只著重在最常運用的物件方法調用做介紹,並且透過練習題的方式,帶大家一步一步認識 this 的指向。
關於「物件方法調用」可以查看本文章:https://wcc723.github.io/javascript/2019/03/18/JS-THIS/
當函式是使用傳統的定義方式時(function
而不是 ()=>
),並且只有在物件下調用時,請謹記以下這張圖的概念:如果是在物件下調用方法,this
會指向前一個物件;如果不是,大多情況會指向 window
,指向 window 的 this
實戰中也不太會去用它,所以請避免調用指向 window 的 this
。
一開始,先使用傳統函式定義 getName
的函式,以及定義一個 myName
的全域變數,等等我們會不斷地使用此函式及變數。
等等的題目都會詢問 console.log(this.myName)
的結果為何:
function getName() {
console.log(this.myName);
}
var myName = '全域';
好的,讓我們開始練習吧。
請問,以下的 getName 執行結果為:
'全域'
'小明'
function getName() {
console.log(this.myName);
}
var myName = '全域';
// 主要程式碼
var Ming = {
myName: '小明',
getName: getName
};
Ming.getName();
.
.
.
.
.
.
.
本題答案為 2. '小明'
,請謹記一個概念,傳統函式如何定義不會影響 this 的指向,會影響指向的只有調用方式,在此是在 Ming
下調用 getName
的方法,因此 this 會指向 Ming
。
請問,以下的 getName 執行結果為:
'全域'
'小明'
var Ming = {
myName: '小明',
getName: function() {
console.log(this.myName);
}
};
Ming.getName();
.
.
.
.
.
.
.
這題將 getName
函式直接定義在 Ming
的物件下,概念也與先前相同,不管如何定義,直接看是如何調用,所以本題結果依然是 2. '小明'
。
請問,以下的 getName 執行結果為:
'全域'
'小明'
function getName() {
console.log(this.myName);
}
var myName = '全域';
// 主要程式碼
var Ming = {
myName: '小明',
fn: function() {
getName();
}
};
Ming.fn();
.
.
.
.
.
.
.
這題在外層調用 fn()
方法,內部再 “直接呼叫 getName 函式”,所以 函式的 this
是直接由 getName();
這個調用方式而定(請注意,在此調用的前方沒有任何的物件),這種調用方式會稱為 "simple call"(簡易呼叫),this
的指向為 window,結果會是 1. '全域'
。
請問,以下的 getName 執行結果為:
'全域'
'小明'
'小明家'
function getName() {
console.log(this.myName);
}
var myName = '全域';
// 主要程式碼
var Ming = {
myName: '小明',
family: {
myName: '小明家',
getName: getName
}
};
Ming.family.getName();
.
.
.
.
.
.
.
本題又回到 “物件的方法調用”,只要檢視 getName
調用時前方的物件為何就可確認 this
的指向(family 物件
),因此 this 指向為 family 結果為 3. '小明家'
。
請問,以下的執行結果為:
'全域'
'小明'
var myName = '全域';
// 主要程式碼
var Ming = {
myName: '小明',
fn: function() {
setTimeout(function() {
console.log(this.myName);
}, 0);
}
};
Ming.fn();
.
.
.
.
.
.
.
本題的結果為:1. '全域'
這題算是許多新手會遇到的錯誤,在物件內呼叫時如果出現立即函式、回呼函式(callback function)結果會有什麼變化?絕大數的情況下這類型都會指向 window,所以不建議在此類型下直接調用 this
。
大多情況下 callback function
的 this
都會指向全域,但如果回呼函式的調用是在物件下,也會同樣會改變 this 的指向。不過這種情況相當少見,還是會建議避免在回呼函式中使用 this
。
var myName = '全域';
function fn(cb) {
var obj = {
myName: 'fn 內的物件',
cb
}
obj.cb();
}
fn(function() {
console.log(this.myName);
});
請問,以下的執行結果為:
'全域'
'小明'
'小明家'
var myName = '全域';
// 主要程式碼
var Ming = {
myName: '小明',
family: {
myName: '小明家',
fn: function() {
setTimeout(() => {
console.log(this.myName);
}, 0);
}
}
};
Ming.family.fn();
.
.
.
.
.
.
.
本題結果為:3. '小明家'
當遇到箭頭函式時,我會跟大家記住一句話:「箭頭函式沒有自己的 this
」,因此其指向會是對應外層作用域的 this
。
本題的箭頭函式外層為 fn
函式,該函式的 this
指向 family
,所以箭頭函式的 this
也同樣指向 family
。而接下來我們也會繼續介紹關於「箭頭函式」的 this
喔。