实现call,apply和bind方法

实现call 和bind 

  • 改变this指向
  • 传入参数
  • 返回结果
  •  <script>
        /* 
          实现call()
          思路: 改变this指向:可以将目标函数作为这个对象的属性
                利用arguments类数组对象实现参数不定长
                不能增加对象的属性,所以在结尾需要delete
         */
        Function.prototype.mycall = function (obj) {
          obj = obj || window;
          var args = [];
          //  参数是从1开始的
          for (var i = 1; i < arguments.length; i++) {
            args.push('arguments[' + i + ']');
            //args => [arguments[1], arguments[2], arguments[3], ...]
          }
          obj.fn = this;//此时的this就是函数fn
          let result = eval('obj.fn(' + args + ')');//执行fn
          delete obj.fn;//删除fn
          return result;
        }
        //  利用ES6实现call()
        Function.prototype.mycall2 = function (obj) {
          obj = obj || window;
          obj.fn = this;//绑定this
          // 利用拓展运算符直接将arguments转换为数组
          let args = [...arguments].slice(1);
          let result = obj.fn(...args);//执行fn
          delete obj.fn;
          return result;
        }
        /* 
        实现apply()
        思路: 改变this指向:可以将目标函数作为这个对象的属性
              利用arr传入参数
              不能增加对象的属性,所以在结尾需要delete
       */
        Function.prototype.myapply = function (obj, arr) {
          obj = obj ? Object(obj) : window;
          obj.fn = this;//此时的this就是函数fn
          var result;
          if (!arr) {
            result = obj.fn();//执行fn
          } else {
            var args = [];
            for (var i = 0; i < arr.length; i++) {
              args.push('arr[' + i + ']');
            }
            result = eval('obj.fn(' + args + ')');//执行fn
          }
          delete obj.fn;//删除fn
          return result;
        }
    
        // es6实现apply()
        Function.prototype.myapply2 = function (obj, arr) {
          obj = obj ? Object(obj) : window;
          obj.fn = this;
          var result;
          if (!arr) {
            result = obj.fn();//执行fn
          } else {
            result = obj.fn(...arr);////执行fn
          }
          delete obj.fn;
          return result;
        }
    
        //实例  
        var obj = {
          name: 'zpl',
          fn: function () {
            console.log("我的名字是" + this.name);
          }
        };
        //全局
        var name = 'zs';
        obj.fn();//我的名字是zpl
        // fn();// fn is not defined
    
        var fun = obj.fn;
        fun();//我的名字是zs
        obj.fn.mycall({ name: "wcy" });//我的名字是wcy
        obj.fn.mycall2({ name: "YY" });//我的名字是YY
        obj.fn.myapply({ name: "影子" });//我的名字是影子
        obj.fn.myapply({ name: "CC" });//我的名字是CC
      </script>

     

实现bind() 方法

  • 改变this
  • 传入参数
  • 返回函数
  • <script>
        /* 
        实现bind()
          bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,
          而其余参数将作为新函数的参数,供调用时使用。
    
          说的通俗一点,bind与apply/call一样都能改变函数this指向,
          但bind并不会立即执行函数,而是返回一个绑定了this的新函数,
          你需要再次调用此函数才能达到最终执行。
    
          实现思路:
            1. 因为bind方法不是立即执行函数,需要返回一个待执行的函数,所以使用闭包
            2. 作用域绑定: 可以使用apply或call方法来实现
            3. 参数传递: 由于参数的不确定性,需要使用apply传递数组
         */
         
        //  实现简单的bind方法
         Function.prototype.mybind2 = function(obj) {
           var fn = this;
           var agrs = Array.prototype.slice.call(arguments,1);
           return function() {
            //  将回调函数的参数arguments数组化,然后与绑定时传入的参数args合并
             var newArgs = Array.prototype.slice.call(arguments);
             return fn.apply(obj, args.concat(newArgs));
           }
         }
    
        // 完整实现bind()
         Function.prototype.mybind2 = function(obj) {
           if(typeof this !== 'function') {
              throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
           };
           var args = Array.prototype.slice.call(arguments,1);
           var fn = this;
          // 创建中介函数
          var fn_ = function(){};
          var bound = function() {
            var params = Arrayx.prototype.slice.call(arguments);
            // 通过constructor判断调用方法,为true ,this指向实例,否则为obj
            fn.apply(this.constructor === fn ? this : obj, args.concat(params));
            console.log(this);
          };
          fn_.prototype = fn.prototype;
          bound.prototype = new fn_();
          return bound;
         }
    
        // 实例
        var obj = {
          name: "zpl",
          fn: function() {
            console.log("我的名字是" + this.name);
          }
        }
        var name = "zs";
        obj.fn();//我的名字是zpl
        obj.fn.bind({name: "yz"})();//我的名字是yz
        var bound = obj.fn.bind({name: "ying"});
        var b = new bound();//我的名字是undefined
      </script>

     

参考:

https://www.cnblogs.com/echolun/p/12178655.html

https://blog.csdn.net/qq_36367995/article/details/81319852

posted @ 2020-10-25 17:26  CHUNYIN  阅读(548)  评论(0)    收藏  举报