zl程序教程

您现在的位置是:首页 >  其它

当前栏目

bind、apply、call解析

解析 call bind apply
2023-09-27 14:29:03 时间
目录
  1. 学习来源
  2. 过去的困惑
  3. 格式
  4. 相同之处
  5. 不同
  6. 小小知识点

1. 学习来源

推荐一篇教程,用例丰富、描述准确、总结到位:
深入浅出妙用 Javascript 中 apply、call、bind

上文作者的总结

  • apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
  • apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
  • apply 、 call 、bind 三者都可以利用后续参数传参;
  • bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。

2. 过去的困惑

过去对于js的学习就停留于“传参直接调用方法”,认为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这一数组变量调用了Array对象的push方法
// 并且将array2中的每一个元素拆解为一个push方法的参数

具体扩展后:

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

等同于如下写法:

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

es6优化后:

// 使用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]);       // 调用func函数,并且指定this为当前作用域,并且把两个参数以数组的形式传入

func.call(this, arg1, arg2);            // 调用func函数,并且指定this为当前作用域,顺序传入参数 

func.bind(this);                            // 为func函数绑定作用域为“当前的this”,留作后续调用

4. 相同之处

bing、apply、call三者都:

  • 用于改变函数指向的this对象,即函数作用域;
  • 传入的第一个参数即为this指向的新对象,即“想要指定的上下文”
  • 都可以传入参数(bind的传参类似于传入默认值)

5. 不同

bind: 创建并返回一个新函数,并绑定每一次的this,但并不调用
apply:指定此次的this,并且立即调用;(以数组形式传参)
call:指定此次的this,并且立即调用;(多参数逐个传参)

6. 小小知识点

6.1 多次调用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() 的实现,相当于使用函数在内部包了一个 call / apply ,第二次 bind() 相当于再包住第一次 bind() ,故第二次以后的 bind 是无法生效的。

对于这段话,我的理解是:
对于bind调用链来说,执行顺序是从后往前的。
var func = bar.bind(foo).bind(sed).bind(fiv);
这一句的实际调用顺序是bind(fiv) ==> bind(sed) ==> bind(foo);
也可以看做 ( ( (bar.bind(fiv)) ).bind(sed) ).bind(foo);



作者:daisimin7
链接:http://www.jianshu.com/p/797218ea32e2
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。