call、apply、bind的区别

/ Javascript前端 / 没有评论 / 500浏览

call,apply和bind都是Function原型中的方法,而所有的函数都是Function的实例。

相同点:

在功能上是没有区别的,都用于改变this的指向。

不同点:

不同的地方在于,方法的实现形式上和参数的传递上的不同。

call 和 apply 方法都是在调用之后立即生效的。而bind 调用之后是返回原函数,需要再调用一次才行。

call 和 bind 传参数都是直接传入的,而apply 方法需要以数组的形式传入。

常见的相关问题:

使用场景

手写bind方法

bind方法创建一个新的函数,当这个新函数被调用时,将其this置为提供的值,其参数列表前几项置为创建时指定的参数列表。

bind() 函数会创建一个新的绑定函数,绑定函数与被调用函数具有相同的函数体(ES5)。调用绑定函数通常会导致执行包装函数。绑定函数通常也可以使用new操作符创建对象,这种行为就像把原函数当成构造器。提供的this值将被忽略,而前置参数将提供给模拟函数。

总体来说,bind函数有如下三个功能点:

Function.prototype.myBind = function(thisArg) {
  if (typeof this !== 'function') {
      return;
  }
  const self = this;
  // 获取要绑定的参数, 从第二个参数截取
  const args = [].slice.call(arguments, 1); 
  const fnNop = function() {} // 定义一个空函数
  var fnBound = function() {
      // 检测new
      // 如果当前函数的this指向的是构造函数中的this则判定为new
      const _this = this instanceof self ? this : thisArg;
      return self.apply(_this, args.concat([].slice.call(arguments))); // 注意参数的处理
  }
  // 维护原型关系
  if (this.prototype) {
    fnNop.prototype = this.prototype;      
  }
  fnBound.prototype = new fnNop();
  return fnBound;
}

创建一个空函数来做中间人,实现继承原型链又不改变原函数的原型链。