bind

  const args = [].slice.call(arguments)
  const boundThis = args.shift()
  const targetFn = this

  function boundFn() {
    const boundFnArgs = [].slice.call(arguments)
    // 当 boundFn 通过 new 执行时,绑定当前实例
    targetFn.apply(
      this instanceof boundFn ? this : boundThis,
      args.concat(boundFnArgs)
    )
  }

  // 继承原型方法
  function o() {}
  // 当 Function.prototype.myBind() 时,targetFn.prototype === undefined
  if (targetFn.prototype) {
    o.prototype = targetFn.prototype
  }
  // 避免 boundFn.prototype 与 targetFn.prototype 指向同一引用
  // 此时 boundFn 的实例 obj 原型链为:obj.__proto__.__proto__ === targetFn.prototype
  boundFn.prototype = new (o as any)()

  return boundFn
}

// @ts-ignore
Function.prototype.myCall = function (context) {
  // 当 call 第一个参数为 undefined 或者 null 时,this 默认指向 window
  context = context ? Object(context) : window

  const n = arguments.length
  const args = []
  // 排除 context
  for (let i = 1; i < n; i++) {
    args.push('arguments[' + i + ']')
  }
  // 利用 this 指向调用者
  context._fn = this
  // context._fn(arguments[1], arguments[2], arguments[1])
  const result = eval('context._fn(' + args + ')')
  delete context._fn

  return result
}

// @ts-ignore
Function.prototype.myApply = function (context, args: unknown[]) {
  context = context ? Object(context) : window
  context._fn = this

  let result
  if (!args) {
    result = context._fn()
  } else {
    const n = args.length
    const arr: unknown[] = []
    for (let i = 0; i < n; i++) {
      arr.push('args[' + i + ']')
    }
    result = eval('context._fn(' + arr + ')')
  }

  delete context._fn

  return result
}

export function newFactory(Constructor: Function, ...args: unknown[]): object {
  // obj.__proto__ = Constructor.prototype
  const obj = Object.create(Constructor.prototype)
  const result = Constructor.apply(obj, args)
  return typeof result === 'object' && result !== null ? result : obj
}

export function _instanceof(left: object, right: Function) {
  const proto = right.prototype
  // @ts-ignore
  left = left.__proto__
  while (true) {
    // 查询到原型链末端
    if (left === null) return false
    if (left === proto) return true
    // @ts-ignore
    left = left.__proto__
  }
}