bind、apply、call解析

目錄
  1. 學習來源
  2. 過去的困惑
  3. 格式
  4. 相同之處
  5. 不同
  6. 小小知識點

1. 學習來源

推薦一篇教程,用例豐富、描述準確、總結(jié)到位:
深入淺出妙用 Javascript 中 apply、call、bind

上文作者的總結(jié)

  • apply 、 call 、bind 三者都是用來改變函數(shù)的this對象的指向的;
  • apply 、 call 、bind 三者第一個參數(shù)都是this要指向的對象,也就是想指定的上下文;
  • apply 、 call 、bind 三者都可以利用后續(xù)參數(shù)傳參;
  • bind 是返回對應(yīng)函數(shù),便于稍后調(diào)用;apply 、call 則是立即調(diào)用 。

2. 過去的困惑

過去對于js的學習就停留于“傳參直接調(diào)用方法”,認為Array.prototype.push.apply這樣的語句有點抽象,無法理解。

// 用例目的:把 array2 追加到 array1 的尾部
var array1 = [1,2,3,4,5]; 
var array2 = [7,7,7,7,7]; 

Array.prototype.push.apply(array1, array2);            /* array1 值為  [1,2,3,4,5,7,7,7,7,7] */
// 實際就是以array1這一數(shù)組變量調(diào)用了Array對象的push方法
// 并且將array2中的每一個元素拆解為一個push方法的參數(shù)

具體擴展后:

Array.prototype.push.apply(array1,  array2);

等同于如下寫法:

array1.push(array2[0],  array2[1],  array2[2],  array2[3],  array2[4]);

es6優(yōu)化后:

// 使用es6的"...擴展運算符"取代apply方法
array1.push(...array2) ;

追加一個小栗子:

// ES5 的寫法
Math.max.apply(null, [14, 3, 77])

// ES6 的寫法
Math.max(...[14, 3, 77])

// 等同于
Math.max(14, 3, 77);

3. 格式

var func = function (arg1, arg2) {};

func.apply(this, [arg1, arg2]);       // 調(diào)用func函數(shù),并且指定this為當前作用域,并且把兩個參數(shù)以數(shù)組的形式傳入

func.call(this, arg1, arg2);            // 調(diào)用func函數(shù),并且指定this為當前作用域,順序傳入?yún)?shù) 

func.bind(this);                            // 為func函數(shù)綁定作用域為“當前的this”,留作后續(xù)調(diào)用

4. 相同之處

bing、apply、call三者都:

  • 用于改變函數(shù)指向的this對象,即函數(shù)作用域;
  • 傳入的第一個參數(shù)即為this指向的新對象,即“想要指定的上下文”
  • 都可以傳入?yún)?shù)(bind的傳參類似于傳入默認值)

5. 不同

bind: 創(chuàng)建并返回一個新函數(shù),并綁定每一次的this,但并不調(diào)用;
apply:指定此次的this,并且立即調(diào)用;(以數(shù)組形式傳參)
call:指定此次的this,并且立即調(diào)用;(多參數(shù)逐個傳參)

6. 小小知識點

6.1 多次調(diào)用bind是無效的

var bar = function(){
    console.log(this.x);
}
var foo = {
    x:3
}
var sed = {
    x:4
}
var func = bar.bind(foo).bind(sed);
func();          // 輸出3,綁定的上下文是foo
 
var fiv = {
    x:5
}
var func = bar.bind(foo).bind(sed).bind(fiv);
func();         // 輸出3,綁定的上下文依然是foo

文首作者解釋的無效原因

bind() 的實現(xiàn),相當于使用函數(shù)在內(nèi)部包了一個 call / apply ,第二次 bind() 相當于再包住第一次 bind() ,故第二次以后的 bind 是無法生效的。

對于這段話,我的理解是:
對于bind調(diào)用鏈來說,執(zhí)行順序是從后往前的。
var func = bar.bind(foo).bind(sed).bind(fiv);
這一句的實際調(diào)用順序是bind(fiv) ==> bind(sed) ==> bind(foo);
也可以看做 ( ( (bar.bind(fiv)) ).bind(sed) ).bind(foo);

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容