iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 22
0
Modern Web

30天入門JavaScript系列 第 22

【Day 22】this(二):bind()、call()、apply(),箭頭函式



昨天講了基本的this規則,今天來介紹函式的內建方法來綁定this,
跟使用this時的注意點



首先是三種函式的內建方法,使用這些方法可以在指定想要的this值

bind()


使用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()


call()方法會傳入想綁定的物件跟參數後呼叫該函式

func.call(ch1, '攻擊', '斬擊'); //角色1行動: 攻擊:斬擊
//第一個引數是你想綁定this的物件  後面是想傳入的參數


apply()


call()有87%像,只差在想傳入的參數是用一個陣列的方式傳入

func.apply(ch2, ['魔法', '雷電術']); //角色2行動: 魔法:雷電術
//把想傳入的參數整合成一個物件



this的優先度


如果一次把所有規則套用在函式上,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()>物件方法呼叫

箭頭函式的this不存在


有時候實作會發生這種事情:

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...


上一篇
【Day 21】this
下一篇
【Day 23】物件(三):prototype跟__proto__
系列文
30天入門JavaScript30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言