this是js裡面一個特別的關鍵字,有關this的第一件事就是,它是一個動態的值,依照各種函式呼叫的情境不同而指向不同的東西。
呼叫obj裡的方法,this指向呼叫method的物件
下面例子當中的this就是指向物件john
const john = {
firstName: "John",
greet: function () {
console.log(this);
console.log(`Hi, I'm ${this.firstName}.`);
},
};
john.greet();
執行結果:
需要注意的是,上面例子的定義method和呼叫method都是同一物件,容易造成誤會this是指當初定義method的物件,但其實不是。
下面的例子從借用第一個物件的方法,新增到第二個物件裡,但在使用第二個物件呼叫method時,this是第二的物件
const emma = {
firstName: "Emma",
};
emma.greet = john.greet; //借用john物件裡的method, 新增到emma物件裡當method
console.log(emma.greet); //內容與john物件裡的相同
emma.greet();
執行結果:
當呼叫一般函式時,函式裡的this有兩種可能性:
"use strict";
const john = {
firstName: "John",
greet: function () {
console.log(this);
console.log(`Hi, I'm ${this.firstName}.`);
},
};
const simpleFunc = john.greet;
simpleFunc();
在一般模式下,this=window物件
下面的例子跟上面很像,就取消了嚴格模式,並新增了一個var宣告,卻有完全不一樣的結果
var firstName = "OMG!😱";
const john = {
firstName: "John",
greet: function () {
console.log(this);
console.log(`Hi, I'm ${this.firstName}.`);
},
};
const simpleFunc = john.greet;
simpleFunc();
執行結果:
再來一個把var改成const會變這樣:
const firstName = "OMG!😱";
const john = {
firstName: "John",
greet: function () {
console.log(this);
console.log(`Hi, I'm ${this.firstName}.`);
},
};
const simpleFunc = john.greet;
simpleFunc();
執行結果:
有感覺到頭暈了嗎?但其實只要知道下面兩件事,說穿了根本也沒什麼大不了,一個就是在一般模式之下,simple function call的this指向window物件,再來就是var宣告會再window物件新增一個以變數為名的屬性(而const和let並不會),把window物件點開往下滑,仔細找找會看到下圖,所以this.firstName會抓到window物件的屬性
,
arrow function沒有自己的this,當在arrow function裡使用this時,會指向它父層的this。
回到一開始的例子,但把method改成arrow function宣告,神奇的事又發生了...因為arrow function會抓父層的this,這邊的父層是全域,也就是抓到的是window物件,而其中並沒有firstName這個屬性。
const john = {
firstName: "John",
greet: () => {
console.log(this);
console.log(`Hi, I'm ${this.firstName}.`);
},
};
john.greet();
那如果剛好在全域有一個用var宣告的firstName,那就會出現難以發覺的bug,而原因就像之前的例子說過的,var會在window物件新增屬性。所以如果避免用arrow function宣告methhod,就可以避免這件事。
var firstName = "OMG!😱";
const john = {
firstName: "John",
greet: () => {
console.log(this);
console.log(`Hi, I'm ${this.firstName}.`);
},
};
john.greet();
而event listener裡的callback function若有使用this關鍵字,它所指的則是被監聽的那個物件。
下面我們把最一開始的例子,加上一個按鈕並設定若它被點擊會跳出一個alert視窗,視窗中的字串我們用了this。其中this指向button element而this.firstName則為undefined。
const john = {
firstName: "John",
greet: function () {
const btnEl = document.querySelector("button");
btnEl.addEventListener("click", function () {
console.log(this);
alert(`Hi, I'm ${this.firstName}.`);
});
},
};
執行結果:
各種this | 指向什麼 |
---|---|
method裡的this | 呼叫method的物件 |
regular function裡的this | 嚴格模式下=>undefined; 一般模式下=>window物件 |
arrow function裡的this | 父層的this |
event listener裡的this | 監聽的元素 |
從上面的表格能發現,一般函式的this指向undefined或window物件,似乎會造成一些困擾。下篇會整理一些例子與應用上的注意事項,see you then.
ref
關於 JavaScript 的 this 各種用法與探討