04.apply-call-bind的实现(超详细)

106 阅读2分钟

一.call函数的实现

  • 思路

    • 首先要保证能调用那个函数(获取需要被执行的函数)

    • 其次让调用的函数指向thisArg(传过来的参数)

    • 传入的thisArg要用Object()把它变成对象型,且要加判断,如果thisArg为空,那么就是windows

    • 调用需要被执行的函数

  • 剩余运算符(rest parameters)和展开运算符(spread)

    • ...变量名

    • 剩余运算符

      图片.png

    • 展开运算符

      图片.png

  • 代码实现

      ```js
      //call函数的实现
    
      // 给所有函数加一个xsxcall的方法
    
      Function.prototype.xsxcall = function(thisArg,...args){
    
      // console.log('222');
    
          var fn = this
    
          thisArg = thisArg ? Object(thisArg) : window
    
          thisArg.fn = fn
    
          var result = thisArg.fn(...args)
    
          delete thisArg.fn
    
          return result
    
      }
    
    
    
      function foo(){
    
          console.log('foo函数被执行',this);
    
      }
    
      function sum(sum1,sum2){
    
          console.log('sum函数被执行',this);
    
          return sum1 + sum2
    
      }
    
      foo.xsxcall('222')
    
      var result = sum.xsxcall('abc',20,40)
    
      console.log('xsxcall',result);
      ```
    
  • 输出结果

    图片.png

二.apply函数的实现

上一篇文章里面说到apply函数和call函数有个区别就是 call是直接传参(逗号分开),apply是数组传参。所以apply函数的实现和call函数的实现的思路基本一致,关键就是对后面那个参数的处理

  • 注意点
    • 如果在调用apply时,没有传第二个参数,系统会默认传undefined,如果不对这个进行处理的话,...undefined就会报错,所以这里要加一个判断,判断如果没有值,就赋一个空数组
  • 代码实现
    Function.prototype.xsxapply = function(thisArg,argArray){

            var fn = this

            thisArg = (thisArg !== null && thisArg !== undefined ) ? Object(thisArg) : window

            thisArg.fn = fn

            var result

            argArray = argArray || []

            result = thisArg.fn(...argArray)

            delete thisArg.fn

            return result

        }

     function foo(){

            console.log('foo函数被执行',this);

        }

     function sum(sum1,sum2){

            console.log('sum函数被执行',this);

            return sum1 + sum2

        }

    foo.xsxapply('222')

    var result = sum.xsxapply('abc',[20,30])

    console.log('xsxapply',result);
  • 输出结果

    图片.png

三.bind函数的实现

  • 首先我们了解一下bind的传参

    // 方式一
    
    var newSum = sum.bind('aaa',1,2,3,4)
    
    newSum()
    
    //方式二
    
    var newSum = sum.bind('aaa')
    
    newSum(1,2,3,4)
    
    //方式三
    
    var newSum = sum.bind('aaa',1,2)
    
    newSum(3,4)
    
  • 根据bind的传参我们可以发现,传入的两部分参数,都可以达到一样的效果,所以这里我们要写一个数组把这两部分合并,合并数组我们可以用concat (),我们也可以用展开运算符来合并

  • 还有,我们要知道bind和apply,call有个很大的区别点就是,bind是返回一个新的函数,所以这里的话,需要写一个函数代理。

  • 代码实现

    Function.prototype.xsxbind = function(thisArg,...argArray){
    
        //1.获取真实需要调用的函数
    
        var fn = this
    
        thisArg = (thisArg !== null && thisArg !== undefined ) ? Object(thisArg) : window
    
        function proxyFn(...args){
    
            thisArg.fn = fn
    
            //对两个传入的参数进行合并
    
            var finalArgs = [...argArray,...args]
    
            var result = thisArg.fn(...finalArgs)
    
            delete thisArg.fn
    
            return result
    
        }
    
        return proxyFn
    
    }
    
    function foo(){
    
        console.log('foo函数被执行',this);
    
    }
    
    function sum(sum1,sum2,sum3,sum4){
    
        console.log('sum函数被执行',sum1,sum2,sum3,sum4,this);
    
         return sum1 + sum2 + sum3 + sum4
    
    }
    
    var bar = foo.xsxbind('abc')
    
    var result1 = bar()
    
    // console.log(result1);
    
    var newSum = sum.xsxbind('hahaha',1,2,3)
    
    var result2 = newSum(4)
    
    console.log(result2);
    
  • 运行截图

    图片.png