美文网首页
JavaScript 之实现 call apply

JavaScript 之实现 call apply

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

    [个人博客]:(https://github.com/zenglinan/blog)

    如果对你有帮助,欢迎star。

    实现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类似, 无非是参数形式变了, apply 里要求第二个参数形式是数组

    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
    }
    

    相关文章

      网友评论

          本文标题:JavaScript 之实现 call apply

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