目錄
- 學習來源
- 過去的困惑
- 格式
- 相同之處
- 不同
- 小小知識點
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);