手写call apply bind

74 阅读1分钟

call

Function.prototype.myCall = function (ctx, ...args) {
  // 普通数据类型和空值,我们可以通过三目去解决
  // 使用globalThis原因是js运行环境有两种
  // 一种是浏览器中,一种是Node环境,所以使用js内置全局属性来判断
  ctx = ctx === null || ctx === undefined ? globalThis : Object(ctx)
  // fn 命名冲突问题,可以借助es6 的 Symbol 解决
  const key = Symbol('fn')
  ctx[key] = this
  const res = ctx[key](...args)
  // 使用完必须删除Symbol,保证对象的干净
  delete ctx[key]
  return res
}

// test
const obj = {
  name: 'zhangsan'
}
test.myCall(null) // this
test.myCall(2) // undefined
test.myCall(obj) // zhangsan

apply

Function.prototype.myApply = function (ctx, args) {
  ctx = ctx === null || ctx === undefined ? globalThis : Object(ctx)
  // 防止args没有或传值不对
  args = Array.isArray(args) ? args : []
  const key = Symbol('fn')
  ctx[key] = this
  const res = ctx[key](...args)
  delete ctx[key]
  return res
}

bind

Function.prototype.myBind = function (ctx, ...args1) {
  ctx = ctx === null || ctx === undefined ? globalThis : Object(ctx)
  const key = Symbol('fn')
  ctx[key] = this
  
  // bind会返回this改变后的函数,并不会立即调用
  return function (...args2) {
    const res = ctx[key](...args1, ...args2)
    delete ctx[key]
    return res
  }
}