bind apply call 的区别

71 阅读3分钟

大家好,我们都知道 bind apply call 都是用来改变 this 指向的,那为什么会需要改变 this,其中一个主要原因就是我们拿到的 this 存在偏差;比如下面这个例子,say 方法在定时器中作为回调函数执行,因此在执行栈运行时,是在全局上下文的环境中执行的,所以 this 指向了 window,而我们期待是它们指向 obj,就此我们就需要借助这三个方法来满足我们的需求。

var name = 'boo'

let obj = {
  name: 'aloo',
  say: function() {
    console.log(this.name)
  }
}
obj.say()  // 输出为 aloo,this 指向 obj
setTimeout(obj.say,0) // 输出为 boo,this 指向了 window


// 额外补充:
// obj.say 是函数引用,this 指向 window
setTimeout(obj.say,0) 
// 注意:箭头函数会 obj.say() 返回的是函数值,this 指向 obj
setTimeout(() => {
  obj.say()
},0)

apply

  1. 接收参数:

    • thisArgthis 指向
    • argsArray:函数接收的参数,以数组形式传入
  2. 执行方式:

    • 原函数在变更 this 后会立即执行,但此方法只会临时改变一次 this 指向
var name="boo";
var obj={
  name: "aloo",
  say: function(year,place){
    console.log(this.name+" is "+year+" born from "+place);
  }
};
var say=obj.say;
setTimeout(function(){
  say.apply(obj,["1998", "China"])
},0); // aloo is 1996 born from China,this改变指向了obj
say("1996", "China") // boo is 1996 born from China,this指向window,说明apply只是临时改变一次this指向
  1. 使用场景:
    • 适合参数不固定的动态参数
    • 适合从数组中获取参数,如使用 Math.max() 求出数组最大值,已知 max() 是接收参数列表形式的参数(如:value1, value2, ...)无法直接用数组做参数
var arr=[1,10,5,8,3];
// apply 允许我们在 window 上下文环境中调用 max 函数,arr 作为 apply 的参数会把数组中的每个元素当作参数传给 max()
console.log(Math.max.apply(null, arr)); //10 

call

  1. 接收参数:

    • thisArgthis 指向
    • arg1, ..., argN:函数接收的参数,参数列表的形式传参
  2. 执行方式:

    • 原函数在变更 this 后会立即执行,但此方法只会临时改变一次 this 指向
  3. 使用场景:

    • 适合知道参数列表具体数量
var arr=[1,10,5,8,3];
console.log(Math.max.call(null,arr[0],arr[1],arr[2],arr[3],arr[4])); // 10

bind

  1. 接收参数:

    • thisArgthis 指向
    • arg1, ..., argN:函数接收的参数,参数列表的形式传参,但这个参数列表可以分多次传入,call则必须一次性传入所有参数
  2. 执行方式:

    • 原函数在变更 this 指向后不会立即执行,而是返回一个永久改变 this 指向的新函数。
  3. 使用场景:

    • 需要特定创建一个永久修改 this 指向的实例
var arr=[1,10,5,8,12];
var max=Math.max.bind(null,arr[0],arr[1],arr[2],arr[3])
// 注意:bind方法可以分多次传参,最后函数运行时会把所有参数连接起来一起放入函数运行
console.log(max(arr[4])); //12

总结

applycallbind 三者的区别:

  • 三者都可以改变函数的 this 对象指向
  • 三者第一个参数都是 this 要指向的对象,如果没有这个参数或参数为 undefinednull,则默认指向全局 window
  • 三者都可以传参,但是 apply 是数组,而 call 是参数列表,且 applycall 是一次性传入参数,而 bind 可以分为多次传入。
  • bind 是返回绑定 this 之后的函数,便于稍后调用;applycall 则是立即执行 。