JS面试题----手写call, apply, bind

首先我们要知道call、apply、bind的作用都是用来改变this的指向的,可以从以下几点来考虑如何实现这几个函数:

  • 不传入第一个参数,那么上下文默认是window
  • 改变了this指向,让新的对象可以执行该函数

实现call

// 通过配置默认参数的方式,第一个参数如果不传,默认为window
Function.prototype.myCall = function (context = window) {
  // 上下文校验
  if (typeof this !== 'function') {
    throw new TypeError('Errors')
  }
  // 改变this指向
  context.fn = this
  // 截取参数
  const args = [...arguments].slice(1)
  // 通过新的上下文调用函数并得到结果
  const result = context.fn(...args)
  // 删除临时绑定在context上的方法
  delete context.fn
  return result
}

function foo(x, y) {
  console.log(this, this.a * x * y)
}

obj = {
  a: 1,
  b: 2
}

foo.myCall(obj, 2, 3)

以下是对实现的分析:

  • 首先context为可选参数,如果不传,默认上下文为window
  • 接下来给context创建一个fn属性,并将值设置为需要调用的函数
  • 因为call可以传入多个参数作为调用函数的参数,所以需要将参数剥离出来
  • 然后调用函数并将对象上的函数删除

以上就是call的实现思路了

apply

apply的实现和call类似,区别在于对参数的处理,call是可以接受多个参数,而apply是接受一个数组作为第二个参数,将数组中的项作为函数的参数。

Function.prototype.myApply = function(context) {
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  context = context || window
  context.fn = this
  let result
  // 处理参数和 call 有区别
  if (arguments[1]) {
    result = context.fn(...arguments[1])
  } else {
    result = context.fn()
  }
  delete context.fn
  return result
}

bind

Function.prototype.myBind = function (context = window) {
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  const _this = this

  /* if (arguments[1]) {
    args = arguments[1]
  } else {
    args = []
  } */
  const args = [...arguments].slice(1)
  return function F () {
    // 因为返回了一个函数,所以可能存在用new调用的情况,所以需要判断
    if (this instanceof F) {
      return new _this(...args, ...arguments)
    }

    return _this.apply(context, arsg.concat(...arguments))
  }
}

以下是对实现的分析:

  • bind返回了一个函数,对于函数来说又两种方式调用,一种是直接调用,一种是通过new的方式
  • 对于直接调用来说,这里选择了apply的方式实现,但是对于参数需要注意以下情况:因为bind可以实现类似这样的代码f.bind(obj, 1)(2), 所以我们需要将两边的参数拼接起来,于是就有了这样的实现args.concat(...arguments)
  • 对于通过new的方式,因为new调用函数是不会被任何方式改变this的,所以要忽略传入的this, 用最外层保存的_this

猜你喜欢

转载自www.cnblogs.com/jett-woo/p/12564066.html
今日推荐