JavaScript中call、apply、bind简单实现原理

142 阅读2分钟

在真正实现这个三个函数的方式其实是用c++来实现的,这边我们只是用js来简单模拟实现一下其中的思路,(还要一些边界情况需要判断)想要弄明白这个三个方法的实现需要先明白几点

  • 构造函数的原型,如何往原型上添加方法(面试中常见的面试题:原型、原型链、构造函数实现继承与哪些方法)
  • 在我们JavaScript中this的理解(难点)
  • ES6中剩余参数

1. call的实现:

Function.prototype.FqCall = function(thisArg, ...argArray) {
  // 获取到当前函数
  var fn = this
  // 这里是处理传递过来需要绑定的this如果是undefined和null的时候需要绑定到window上,但是还有一种传了0的时候不应该绑定到window上
  thisArg = (thisArg !== undefined && thisArg !== null ) ? Object(thisArg) : window
  // 将这个函数添加到传入需要绑定的参数中
  thisArg.fn = fn
  // 利用隐式绑定调用这个函数,将this绑定到传入的参数中
  const result = thisArg.fn(...argArray)
  delete thisArg.fn
  // 将最终的结果进行返回
  return result
}

function foo(num1, num2, num3) {
  console.log('foo被调用了', this, num1, num2)
  return num1 + num2
}

const result = foo.FqCall({name: 'fang'}, 10, 20)
console.log(result) // 30

2.apply的实现:

其实逻辑跟call差不多,只是处理参数有一点区别而已

Function.prototype.FqApply = function(thisArg, argArray) {
  // 1. 获取到需要执行的函数
  const fn = this
  // 处理需要绑定的this
  thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
  thisArg.fn = fn
  //这里是为了处理如果没有传递参数的情况,因为不传的情况argArray的值就是undefined,不能将undefined进行展开运算符
  const arr = argArray || []
  const result = thisArg.fn(...arr)
  delete thisArg.fn
  return result
}

function sum(num1, num2) {
  console.log('sum函数被调用了', this, num1, num2)
  return num1 + num2
}


const result = sum.FqApply({name: 'fang'}, [10, 20])
console.log(result)

function bar() {
  console.log('bar被执行了')
}
bar.FqApply({name: 'fang'})

3.bind的实现:

Function.prototype.FqBind = function(thisArg, ...argArray) {
  const fn = this
  thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
  return function proxyFn(...arrList) {
    thisArg.fn = fn
    // 参数合并,因为我们在调用系统的bind的时候参数其实是可以分开传递的
    const arr = [...argArray, ...arrList]
    const result = thisArg.fn(...arr)
    delete thisArg.fn
    return result
  }
}

function sum(num1, num2, num3, num4){
  console.log('sum函数被调用了:' , this, num1, num2, num3, num4)
  return num1 + num2 + num3 + num4
}

const result = sum.FqBind({name: 'sum'}, 10, 20)
console.log(result(30, 40))