1. 程式人生 > 實用技巧 >實現call,apply和bind方法

實現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