以简单话语总结call()、apply()、bind()

347 阅读2分钟

这三个 Function.prototype 中的函数,老熟人了,可以说是经常看见;但把它们弄明白,的确需要花点功夫。

以简单话语总结

这三个函数都可以修改函数执行时的上下文,也就是修改 this 的指向。

  • call( thisArg, arg1, ..., argN )
  • apply( thisArg, [argArray]
  • bind( thisArg, arg1, ... , argN )

上面可以看见,call 第二个参数是参数列表apply 第二个参数是数组。并且callapply 都是立即执行的。

bind 第二个参数也是参数列表,但是这个是返回一个函数,还需要调用一下才会执行,也就是被动的。

call() 和 apply()

这两个功能都是一样的,就是写法不同。call的是参数列表,apply的可以是数组或类数组 (比如arguments)。

举个例子:

function func(avg1, avg2) {
  console.log(avg1, avg2);
}

function apply_func() {
  return func.apply(this, arguments);
}
apply_func(1, 2); // 1 2

function call_func() {
  return func.call(this, ...arguments);
}
call_func(3, 4); // 3 4

你可以用这两个来实现继承或者另外一些其他技巧,看自己习惯就行,举个继承的例子:

function Parent (name) {
    this.name = name;
}

function Child (name) {
    Parent.call(this, name);
}

bind()

相比前面两个,这个bind()就使用的多了,挺多实现都有bind的身影。

区别前面也说了,使用bind后还需要自己调用一次,也就是被动的,没有立即执行的。

举个比较常见的例子:

class Person {
  constructor(name) {
    this.name = name;
  }
  sayName() {
    console.log('sayName', this.name);
  }
  sayNameDelay() {
    setTimeout(function () {
      console.log('sayNameDelay', this.name)
    }, 1000);
  }
}
let p = new Person('Zeekg');
p.sayName(); // sayName Zeekg
p.sayNameDelay(); // sayNameDelay

可以看见setTimeout里面的name输出的undefined。这里使用bind()

class Person {
  constructor(name) {
    this.name = name;
  }
  sayName() {
    console.log('sayName', this.name);
  }
  sayNameDelay() {
    setTimeout(function () {
      console.log('sayNameDelay', this.name)
    }.bind(this), 1000); // 这里添加了代码
  }
}
let p = new Person('Zeekg');
p.sayName(); // sayName, Zeekg
p.sayNameDelay(); // sayNameDelay Zeekg

但其实直接使用setTimeout(()=> {},1000}箭头函数一样也可以解决。

写在最后

这篇主要是总结,并没有过多解释怎么使用这些函数。

虽然不难,但完全弄明白还是需要花点时间的。

链接:

如有不正确之处,欢迎在评论区中指出