手写实现call、apply、bind,注释非常详细。

假设有如下的 add 方法:

function add(num1, num2) {
  return num1 + num2
}

手写call:

// call 方法调用场景:console.log(add.call(null, 1, 2))
Function.prototype.myCall = function (context) {
  if(typeof this != 'function'){
    throw new TypeError('Not a function')
  }
  // 如果 context 没有传的话,默认指向 window
  context = context || window
  // 将执行 myCall 的函数赋值到 context 对象中,
  // 这样,当通过 context 执行 fn 函数的时候,fn 中的 this 会指向 context
  context.fn = this
  // 获取执行 fn 函数时的参数,从 1 下标开始截取
  let args = Array.from(arguments).slice(1)
  // 执行 fn 函数获取结果
  let result = context.fn(...args)
  // 删除 context 中的 fn,
  // 因为原生的 call 方法并不会向 context 中添加额外的属性,我们需要与其报持一直
  delete context.fn
  // 返回计算的 result
  return result
}

手写apply:

// apply 方法调用场景:console.log(add.apply(null, [1, 2]))
Function.prototype.myApply = function (context) {
  if(typeof this != 'function'){
    throw new TypeError('Not a function')
  }
  // 如果 context 没有传的话,默认指向 window
  context = context || window
  // 将执行 myApply 的函数赋值到 context 对象中,
  // 这样,当通过 context 执行 fn 函数的时候,fn 中的 this 会指向 context
  context.fn = this
  // 执行 fn 函数,apply 的用法是第二个参数为函数参数的数组,用户可能传递了这个参数数组,也有可能没有传递,所以这里用 (arguments[1] || []) 这种兼容写法
  let result = context.fn(...(arguments[1] || []));
  // 删除 context 中的 fn,
  // 因为原生的 apply 方法并不会向 context 中添加额外的属性,我们需要与其报持一直
  delete context.fn
  // 返回计算的 result
  return result
}

手写bind:

// bind 方法调用场景:console.log(add.bind(null, 1, 2)())
Function.prototype.myBind = function (context) {
  // bind 方法的返回值是一个函数,这一点和 call、apply 是不一样的
  if(typeof this != 'function'){
    throw new TypeError('Not a function')
  }
  // 保存执行 myBind 方法的函数
  let _this = this
  // 获取执行 myBind 时传递的参数
  let args = Array.from(arguments).slice(1)
  // 返回一个函数
  return function F() {
    // 返回的函数有两种用法。
    // 第一种用法:new F(xxx)
    // 第二种用法:直接嗲用 let result = F(xxx)
    // 下面使用 instanceof 判断是上面两种用法的哪一种

    // 因为 bind 有这样的特性:Foo.bind(context, 1)(2) 等价于 context.Foo(1, 2)
    // 所以我们需要把这两处参数合在一起
    if(this instanceof F){
      return new _this(...args, ...arguments)
    } else {
      return _this.apply(context, args.concat(...arguments))
    }
  }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值