bind 函数实现

第一版: 借助 call/apply

Function.prototype.bind1 = function (context) {
  const self = this
  return function () {
    return self.call(context)
  }
}

// 测试:
const obj = {
  value: 'muyy',
}
function testBind() {
  console.log(this.value)
}
const resultBind = testBind.bind1(obj)
resultBind() // muyy

第二版: 借助 arguments

Function.prototype.bind2 = function (context) {
  const arr = Array.prototype.slice.call(arguments, 1)
  const self = this
  return function () {
    const restArr = Array.prototype.slice.call(arguments)
    return self.apply(context, arr.concat(restArr))
  }
}

这种方式的实现其实是函数柯里化的变版

比如在监听事件时可以这样子用:

dom.addEventListener('click', fn.bind(this))

进行如下测试:

const obj2 = {
  value: 'muyy',
}
function testBind2(age, gender) {
  console.log(this.value) // muyy
  console.log(age)        // 23
  console.log(gender)     // male
}
const resultBind2 = testBind2.bind2(obj2, 23)
resultBind2('male')

第三版: 区分环境, 是普通调用还是 new 调用

Function.prototype.bind3 = function (context) {
  const arr = Array.prototype.slice.call(arguments, 1)
  const self = this
  return function () {
    const restArr = Array.prototype.slice.call(arguments)
    return self.apply(this !== windows ? this : context, arr.concat(restArr))
  }
}

// 测试: 使用 new 以后 this 会指向 newObj
const obj3 = {
  value: 'muyy',
}
function testBind3(age, gender) {
  console.log(this.value)
  console.log(age)
  console.log(gender)
}
const resultBind3 = testBind3.bind3(obj3, 23, 'male')
const newObj = new resultBind3()