【2022年最佳的手写代码系列之二】new, call, apply, bind

211 阅读1分钟
// @ts-ignore
const _new = function (Fn, ...args) {
  if (typeof Fn !== 'function') {
    throw new TypeError('_new function TypeError: the first param must be a function')
  }
  const obj = Object.create(Fn.prototype)
  const res = Fn.apply(obj, args)
  if ((typeof res === 'object' && res !== null) || typeof res === 'function') {
    return res
  }
  return obj
}
// @ts-ignore
Function.prototype._call = function (context = window, ...args) {
  const fn = Symbol() // Symbol是唯一的,防止重名key
  context[fn] = this
  const result = context[fn](...args)
  delete context[fn] // 用完要删除
  return result
}
// @ts-ignore
Function.prototype._apply = function (context = window, args) {
  const fn = Symbol() // Symbol是唯一的,防止重名key
  context[fn] = this
  const result = context[fn](...args)
  delete context[fn] // 用完要删除
  return result
}
// @ts-ignore
Function.prototype._bind = function (context = window, ...args) {
  if (typeof this !== 'function') {
    throw new Error('Function.prototype.bind - what is trying to be bound is not callable')
  }
  const self = this
  const fbound = function (...innerArgs) {
    // 当作为构造函数时,this 指向实例,self 指向绑定函数,因为下面一句 `fbound.prototype = this.prototype;`,已经修改了 fbound.prototype 为 绑定函数的 prototype,此时结果为 true,当结果为 true 的时候,this 指向实例。
    // 当作为普通函数时,this 指向 window,self 指向绑定函数,此时结果为 false,当结果为 false 的时候,this 指向绑定的 context。
    self.apply(this instanceof self ? this : context, args.concat(innerArgs))
  }
  // 修改返回函数的 prototype 为绑定函数的 prototype,实例就可以继承函数的原型中的值
  fbound.prototype = this.prototype
  return fbound
}