美文网首页
自己实现call apply

自己实现call apply

作者: 临安linan | 来源:发表于2019-08-13 13:33 被阅读0次

实现call

call可以指定函数调用的this, 并传入多个参数执行

举个例子:

var a = {
  val: 1
}
var b = {
  fn: function(){
    console.log(this.val)
  }
}

b.fn.call(a)

观察一下call的调用形式, 只需将call指定的this提前到b前面, 即: a.fn()

但是a中并没有fn这个属性, 所以还需将fn属性添加到a中

总结一下: 只需要在a中添加fn, 然后执行a.fn, 然后删除这个属性(ÒωÓױ!必须要删除啊, 不然a会凭空多了个属性)

实现过程:

Function.prototype.call = function(target){
  target.fn = this  // 这里fn随便取名字
  target.fn()
  delete target.fn
}

基础版完成! 但还需支持传参, 原版的call除了传this还可以传函数的参数

但是这里不知道函数的参数有多少个, 这里可以借助arguments来取出参数

Function.prototype.call = function(target){
  const arg = []
  for(let i = 1; i < arguments.length; i ++){
    arg.push(arguments[i])
  }
  target.fn = this
  target.fn(...arg)  // 因为不知道有几个参数, 这里用...arg取出所有参数, 当然也可以用eval(还是算了 = =)
  delete target.fn
}

这里就实现了传参了, 但还差点意思, 当call传的是null或者undefined的时候应该返回window

Function.prototype.call = function(target){
  target = target || window  // 判断target为null或undefined时设为window
  const arg = []
  for(let i = 1; i < arguments.length; i ++){
    arg.push(arguments[i])
  }
  target.fn = this
  target.fn(...arg)
  delete target.fn
}

最后差一步, 原生的call是有返回值的, 这里我们给call设一下返回值

Function.prototype.call = function(target){
  target = target || window
  const arg = []
  let result
  for(let i = 1; i < arguments.length; i ++){
    arg.push(arguments[i])
  }
  target.fn = this
  result = target.fn(...arg)
  delete target.fn
  return result
}

基本完成(), 但是以上方法还存在的不足是: 当传入基础类型时, 原生的call对基础类型进行了类包装

比如将字符串包装成new String("xxx")的包装类对象

实现apply

跟call类似, 无非是参数形式变了

Function.prototype.apply = function(target, arr){
  target = target || window
  let result
  target.fn = this
  if(!arr){
    result = target.fn() 
  }else{
    const arg = []
    for(let i = 0; i < arr.length; i ++){
      arg.push(arr[i])
    }
    result = target.fn(...arg)
  }
    delete target.fn
    return result
}

参考: https://github.com/mqyqingfeng/Blog/issues/11

相关文章

网友评论

      本文标题:自己实现call apply

      本文链接:https://www.haomeiwen.com/subject/hfivjctx.html