Skip to content

怎么手写 bind? ​

bind 返回一个新函数,把 this 和一部分参数固定下来。新函数被 new 调用时,this 改指向实例,预先传入的参数仍然有效。

原理 ​

js
Function.prototype.myBind = function (context, ...preset) {
  if (typeof this !== "function") {
    throw new TypeError("myBind must be called on a function")
  }
  const fn = this
  function bound(...args) {
    return fn.apply(new.target ? this : context, preset.concat(args))
  }
  if (fn.prototype) {
    bound.prototype = Object.create(fn.prototype)
  }
  return bound
}

普通调用走 fn.apply(context, ...)。new bound() 时 new.target 有值,此时用构造出来的 this,忽略绑定时的 context。

bound.prototype 接到原函数的原型上,new bound() 的实例才能通过 instanceof 原构造函数。这里用 Object.create,避免 bound.prototype = fn.prototype 让两边共享同一个对象、后来的修改互相影响。

箭头函数没有自己的 this,也没有 prototype。对它调用 bind 可以固定参数,但不能给它装上一个调用时的 this。

追问 ​

和 call / apply 的差别?

call 和 apply 立刻调用。bind 返回函数,适合交给事件或定时器稍后再调。call 逐个收参数,apply 收数组。

绑定之后再绑定?

原生 bind 的 this 只认第一次。上面的实现如果对 bound 再 myBind,外层是新的函数,行为要单独说明。面试里先把一次绑定和 new 讲对。

易错点 ​

  • 忘记处理 new,会导致 new bound() 的实例属性写到了当初绑定的那个对象上。
  • fn.prototype 可能不存在(箭头函数)。直接 Object.create(fn.prototype) 会抛错。
  • 严格模式下独立调用时 this 可能是 undefined。判断是不是 new,用 new.target,不要写 this instanceof bound。

相关 ​