this
大部份跟 function
怎麼宣告沒有關聯,跟怎麼調用 function
比較有關。
var someone = '全域';
function callSomeone (){
console.log(this.someone);
};
callSomeone();
// 這邊是用 simple call 的方式調用 function
// 裡面的 this 會指向 window 中的 someone
// 所以這邊會印出 '全域'
const obj = {
someone: '物件',
callSomeone
};
obj.callSomeone();
// 這邊是 物件的方法調用
// 裡面的 this 會指向前面物件 obj 裡的 someone
// 所以這邊會印出 '物件'
const person = 'window';
function callPerson(){
console.log(this.person);
};
callPerson();
// 這邊是用 simple call 的方式調用 function
// 裡面的 this 會指向 window 中的 person
// 但變數 person 宣告時是用 const,const 不會污染全域變數
// 所以 window 裡面沒有變數 person
// 這邊結果會是 undefine
const obj2 = {
person: 'object',
callPerson
};
obj2.callPerson();
// 這邊是 物件的方法調用
// 裡面的 this 會指向前面物件 obj2 裡的 person
// 所以這邊會印出 'object'
setTimeout(callSomeone, 1000);
(callPerson)();
// 這 2 個調用方式也是 simple call
// 所以 this 會指向 window
// 結果會是 undefine
比較好記的方式:看 function 前面的物件是誰,this 就會指向該物件。
function callSomeone (){
console.log(this.someone);
};
const obj = {
someone: '物件',
callSomeone,
innerObj: {
someone: '內層物件',
callSomeone,
innermostObj: {
someone: '深處物件',
callSomeone,
}
}
};
obj.callSomeone();
// 這邊調用 callSomeone() 時前面的物件是 obj
// 所以裡面的 this 會指向前面 obj
// 這邊會印出 '物件'
obj.innerObj.callSomeone();
// 這邊調用 callSomeone() 時前面的物件是 innerObj
// 所以裡面的 this 會指向前面 innerObj
// 這邊會印出 '內層物件'
obj.innerObj.innermostObj.callSomeone();
// 這邊調用 callSomeone() 時前面的物件是 innermostObj
// 所以裡面的 this 會指向前面 innermostObj
// 這邊會印出 '深處物件'
影響 this 的語法
Javascript 有 3 種方法可以強制綁定 this
的指向,分別是:
call()
apply()
bind()
call()
當 call()
傳入參數後會立即執行 function。
var myName = 'window';
const obj1 = {
myName: 'object1'
};
const obj2 = {
myName: 'object2',
fn(){
console.log(this.myName);
}
};
obj2.fn.call(obj1); // 'object1'
另外,call()
除了 this
參數以外也可以代入其他參數。
var myName = 'window';
const obj1 = {
myName: 'object1'
};
const obj2 = {
myName: 'object2',
fn(msg){
console.log(msg + ', ' + this.myName);
}
};
obj2.fn.call(obj1, 'Hi'); // 'Hi, object1'
// 這裡第 1 個參數是要綁定的 this 參數
// 第 2 個參數是 fn() 的參數
apply()
apply()
與 call()
非常相似,不同的是 apply()
除了要綁定的 this
參數之外是代入 array。
fun.apply(thisArg, [argsArray])
var myName = 'window';
const obj1 = {
myName: 'object1'
};
const obj2 = {
myName: 'object2',
fn(msg1, msg2){
console.log(msg1 + ', ' + this.myName + '. ' + msg2);
}
};
obj2.fn.apply(obj1, ['Hi', 'How about you?']);
// 'Hi, object1. How about you?'
bind()
bind()
也和 call()
相似,差別在於 bind()
不會馬上執行函式,而是回傳綁定好 this
的 function。
var myName = 'window';
const obj1 = {
myName: 'object1'
};
const obj2 = {
myName: 'object2',
fn(msg){
console.log(msg + ', ' + this.myName);
}
};
const newFn = obj2.fn.bind(obj1, 'Hi');
newFn();
// 'Hi, object1.
如果作為 this 的參數所傳入的值不是 Object
這時這些值會被轉為相關的建構方法:
function fn() {
console.log(this);
}
fn.call(3); // this = new Number(3)
fn.apply('hi'); // this = new String('hi')
fn.bind(true)(); // this = new Boolean(true)
將 undefined、null 傳入 call()、apply()、bind()
當我們在執行 call()
、apply()
、bind()
時把綁定 this 的參數代入 undefined、null,這時 function 裡的 this
將會重新指向 window
。
var myName = 'window';
const obj = {
myName: 'object',
fn(msg){
console.log(msg + ', ' + this.myName);
}
};
obj.fn.call(undefined, 'Hi'); // 'Hi, window'
obj.fn.apply(undefined, ['Hi']); // 'Hi, window'
const newFn = obj.fn.bind(null, 'Hi');
newFn(); // 'Hi, window'
// 'Hi, object1.
而在嚴謹模式下則會出錯。
'use strict'
var myName = 'window';
const obj = {
myName: 'object',
fn(msg){
console.log(msg + ', ' + this.myName);
}
};
obj.fn.call(undefined, 'Hi');
// Uncaught TypeError:
// Cannot read properties of undefined (reading 'myName')
箭頭函式的 this
箭頭函式本身沒有 this,箭頭函式的 this 會指向外層作用域的 this
var person = 'window';
const callPerson = () => {
console.log(this.person);
};
const obj = {
person: 'object',
callPerson
};
obj.callPerson();
// 箭頭函式的 this 會指向外層作用域的 this
// 這邊外層沒有作用域
// 所以這裡的 this 會指向 window
const obj2 = {
person: 'object2',
fn() {
(() => {
console.log(this.person);
})();
}
};
obj2.fn();
// obj2.fn 內的箭頭函式的 this 會指向 obj2.fn() 的 this
// 所以這邊會印出 'object2'