昨天講了基本的this規則,今天來介紹函式的內建方法來綁定this,
跟使用this時的注意點
首先是三種函式的內建方法,使用這些方法可以在指定想要的this值
使用bind()
傳入想要綁定的物件後,會回傳綁定this值到傳入物件的新函式
function func(action1, action2) {
console.log(this.name + '行動: ' + action1 + ':' + action2);
}
var ch1 = {
name: '角色1',
};
var ch1Act = func.bind(ch1);//回傳把this綁定ch1的函式
ch1Act('攻擊', '斬擊');//角色1行動: 攻擊:斬擊
//此時就算普通的呼叫this還是指向ch1
另外bind()
方法除了綁this外還能綁定參數,如下
var ch2Magic = func.bind(ch2, '魔法');//綁定this值到ch2 '魔法'到第一個參數
ch2Magic('火球術');//角色2行動: 魔法:火球術
//此時this跟參數1都綁定了 只要傳入參數2
call()
方法會傳入想綁定的物件跟參數後呼叫該函式
func.call(ch1, '攻擊', '斬擊'); //角色1行動: 攻擊:斬擊
//第一個引數是你想綁定this的物件 後面是想傳入的參數
跟call()
有87%像,只差在想傳入的參數是用一個陣列的方式傳入
func.apply(ch2, ['魔法', '雷電術']); //角色2行動: 魔法:雷電術
//把想傳入的參數整合成一個物件
如果一次把所有規則套用在函式上,this值結果會如何?
function func(action1, action2) {
console.log(this.name + '行動: ' + action1 + ':' + action2);
}
var ch1 = {
name: '角色1',
act: func,
};
var ch2 = {
name: '角色2',
act: func,
};
//-----------------------------------------------
new ch1.act.call(ch2, '魔法', '雷電術'); //<-這句
//同時有new關鍵字 call綁定 方法呼叫(話說這是在練蠱?)
//實際上不能這樣寫
但是new關鍵字跟call()方法不能同時使用,只能分開驗證
new ch1.act('魔法', '雷電術'); //undefined行動: 魔法:雷電術
ch1.act.call(ch2, '魔法', '雷電術');//角色2行動: 魔法:雷電術
會發現new跟call()
都比作為物件方法呼叫優先,
優先度是new、call()
(兩者不能同時使用)>物件方法呼叫
不過使用bind()
回傳的函式就能用new呼叫了
可以用以下程式來測試
function func(action1, action2) {
console.log(this.name + '行動: ' + action1 + ':' + action2);
}
var ch1 = {
name: '角色1',
act: func,
};
var funcBind = func.bind(ch1);
var ch2 = {
name: '角色2',
act: funcBind,
};
new funcBind('攻擊', '斬擊'); //undefined行動: 攻擊:斬擊
ch2.act('攻擊', '斬擊');//角色1行動: 攻擊:斬擊
這裡就能知道this的優先度為new>bind()
>物件方法呼叫
有時候實作會發生這種事情:
var This = '全域物件';
var obj = {
This: '物件',
callThis: function () {
function logThis() {
console.log('logThis指向:' + this.This);
}
console.log('callThis指向:' + this.This);
logThis();
},
};
obj.callThis(); //callThis指向:物件 logThis指向:全域物件
當我們想在物件的方法內宣告一個函式並呼叫,但會發現this值又指回全域物件了,
除了使用上面的方法綁定外還有另一種解法:使用箭頭函式
箭頭函式內部沒有this值,當在箭頭函式內部使用this時,會參照外部環境的this(還記得範圍鍊嗎?)
所以可以把上面程式改成這樣:
var This = '全域物件';
var obj = {
This: '物件',
callThis: function () {
var logThis = () => {
console.log('logThis指向:' + this.This);
};
console.log('callThis指向:' + this.This);
logThis();
},
};
obj.callThis(); //callThis指向:物件 logThis指向:物件
另外因為箭頭函式沒有this值,沒辦法使用上面三種方法綁定(畢竟不存在的東西綁不了)
像這樣
var This = '全域物件';
var logThis = () => {
console.log(this.This);
};
var obj = {
This: '物件',
};
logThis.call(obj); //還是全域物件
曾經在不熟this的情況下去學了React,結果教學一下講說要用bind()
,
一下說請用箭頭函式,到最後都不知道發生了什麼事,等鐵人賽結束再回去挑戰React跟Redux...