lxinr/interview-question

2021/01/30 - 模拟实现bind函数

lxinr opened this issue · 1 comments

lxinr commented

bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数

function.bind(thisArg[, arg1[, arg2[, ...]]])
  • thisArg: 用绑定函数时作为this参数传递给目标函数的值。 如果使用new运算符构造绑定函数,则忽略该值。当使用 bindsetTimeout 中创建一个函数(作为回调提供)时,作为 thisArg 传递的任何原始值都将转换为 object。如果 bind 函数的参数列表为空,或者thisArgnullundefined,执行作用域的 this 将被视为新函数的 thisArg
  • arg1, arg2, ...: 当目标函数被调用时,被预置入绑定函数的参数列表中的参数

实现:

Function.prototype.myBind = function(context) {

  if (typeof this !== 'function') {
    throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
  }

  var self = this
  var args = Array.prototype.slice.call(arguments, 1) // 从第二个参数起作为入参
  // 通过一个空函数来进行中转
  var fNOP = function() {}
  var fBound = function() {
    var arrs = Array.prototype.slice.call(arguments) // 如果还有传参,则也加入入参
    // 当作为构造函数时,this 指向实例,此时结果为 true,将绑定函数的 this 指向该实例,可以让实例获得来自绑定函数的值
    // 当作为普通函数时,this 指向 window,此时结果为 false,将绑定函数的 this 指向 context
    return self.apply(this instanceof fNOP ? this : context, args.concat(arrs))
  }
  // 下述代码其实就类似于fBound.prototype = Object.create(this.prototype)
  // 为了让 fBound 构造的实例能够继承绑定函数的原型中的值,这是原生bind所具有的能力
  fNOP.prototype = this.prototype
  fBound.prototype = new fNOP()

  return fBound
}

相关链接:
Function.prototype.bind()
JavaScript深入之bind的模拟实现

@lxinr 。当使用 bind 在 setTimeout 中创建一个函数(作为回调提供)时,作为 thisArg 传递的任何原始值都将转换为 object.这句话怎么理解?