欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript中改變this指向的三種方式總結(jié)

 更新時間:2023年12月14日 11:23:55   作者:秋天的一陣風  
this?指向的值是可以通過手動方式去改變的,比如call、bind、apply方法,本文主要為大家介紹了這三種方式的具體實現(xiàn)步驟,需要的可以參考下

前言

在上篇文章 可能是你看過最完整的this指向總結(jié)!中介紹了this指向在不同環(huán)境下的總結(jié)情況,里面提到過:

this 指向的值是可以通過手動方式去改變的,比如call、bind、apply方法。

那么在本篇中我們介紹的是call、bind、apply方法的使用以及如何實現(xiàn)自己的myCall、myBind、myApply方法。

一、call

1. 使用方法

function person(a,b,c){
  console.log(this);
  console.log(this.name,this.age)
}

person();  // 1.直接調(diào)用,this指向window
           // 打印  window
           // 打印  undefined,undefined
           
const obj = {name:"owl",age:18}
person.call(obj)                 // 2.傳入指定的this值
                                 // 打印 {name: 'owl', age: 18}
                                 // owl 18


function person(a,b,c){
  console.log(a,b,c)
  console.log(this);
  console.log(this.name,this.age)
}
person.call(obj,1,2,3)          // 3.給person函數(shù)傳入指定的this值和實參值
                                // 打印 1 2 3
                                // {name: 'owl', age: 18}
                                // owl 18

2. 實現(xiàn)myCall方法

介紹完call()方法以后,我們來嘗試寫一個自己的myCall方法,具體實現(xiàn)代碼和注釋如下:

Function.prototype.myCall = function (obj) {
        if (typeof this !== "function") {
                  throw new Error(
                    "Function.prototype.myCall - what is trying to be bound is not callable"
                  );
                }
        
        const ctx = obj || window; // 1.定義一個ctx變量獲取傳入的對象obj,如果沒有則取window
        ctx.func = this;           // 2.在ctx對象上新增一個屬性func,并且給他賦值為this
                                   // this就是調(diào)用myCall函數(shù)的函數(shù),在本例中就是person()方法
                                   
        const args = Array.from(arguments).slice(1); // 3.處理傳入的參數(shù),第一個參數(shù)為對象obj,
                                                     // 所以從第二個開始參數(shù)截取
        const result = arguments.length > 1 ? ctx.func(...args) : ctx.func(); 
        // 4. 如果傳入?yún)?shù),我們就把實參帶入到func函數(shù)中執(zhí)行,如果沒有,則直接執(zhí)行。
        delete ctx.func;   // 5. 執(zhí)行完函數(shù)以后,記得刪除掉這個“中間變量”屬性 ctx
        return result;     // 6. 返回result
      };

在上面的代碼中,func其實就是person函數(shù),ctx則是我們傳入要指定this指向的對象,也就是 {name: 'owl', age: 18}

那么我們在第四步使用ctx.func()或者ctx.func(...args)調(diào)用func()時是不是就滿足了上篇文章中的調(diào)用對象的函數(shù)方法時,被調(diào)用函數(shù)中的this永遠指向這個對象。

所以自然而然就實現(xiàn)了我們手動改變this指向的目的。

  var obj = {
        name: "owllai",
      };

       function testCall(a, b, c) {
         console.log(this.name, a, b, c);
       }

    testCall.myCall(obj,1,2,3)

apply

  • apply和call的唯一區(qū)別就在于,接收的第二個參數(shù)為類數(shù)組。
  • 除此之外,和call幾乎一模一樣,所以我們在使用和實現(xiàn)自定義apply方法的代碼里只需要修改對應(yīng)的部分就行了。

1.使用方法

function person(a,b,c){
  console.log(this);
  console.log(this.name,this.age)
}

person();  // 1.直接調(diào)用,this指向window
           // 打印  window
           // 打印  undefined,undefined
           
const obj = {name:"owl",age:18}
person.apply(obj)                 // 2.傳入指定的this值
                                 // 打印 {name: 'owl', age: 18}
                                 // owl 18


function person(a,b,c){
  console.log(a,b,c)
  console.log(this);
  console.log(this.name,this.age)
}
person.apply(obj,[1,2,3])       // 3.給person函數(shù)傳入指定的this值和實參值(類數(shù)組對象)
                                // 打印 1 2 3
                                // {name: 'owl', age: 18}
                                // owl 18

2.實現(xiàn)myApply方法

 Function.prototype.myApply = function (obj) {
         if (typeof this !== "function") {
              throw new Error(
                "Function.prototype.myApply - what is trying to be bound is not callable"
                          );
        }
        const ctx = obj || window; // 1.定義一個ctx變量獲取傳入的對象obj,如果沒有則取window
        ctx.func = this;           // 2.在ctx對象上新增一個屬性func,并且給他賦值為this
                                   // this就是調(diào)用myApply函數(shù)的函數(shù),在本例中就是person()方法
                                   
        const args = arguments[1]; // 3.處理傳入的參數(shù),第一個參數(shù)為對象obj,
                                   // 第二個參數(shù)為數(shù)組實參
        const result = arguments[1] ? ctx.func(...arguments[1]) : ctx.func(); 
        //第四步: 調(diào)用方法,獲得結(jié)果。
        delete ctx.func;
        return result;
      };

myApply方法里面,我們只需要更改兩點:

  • 第三步獲取參數(shù)上,直接獲取arguments數(shù)組的第二項
  • 第四步調(diào)用方法上,傳入獲取到的arguments 數(shù)組的第二項

bind

1.使用方法

  • bind接收的參數(shù)形式和call有點相似的:第一個參數(shù)是指定this指向的值,第二個參數(shù)開始則是執(zhí)行函數(shù)需要的形參
  • bind方法在調(diào)用以后不會像call、apply一樣直接執(zhí)行,而是返回一個新函數(shù)。

語法:

bind(thisArg)
bind(thisArg, arg1)
bind(thisArg, arg1, arg2)
bind(thisArg, arg1, arg2, /* …, */ argN)

 function person(a, b, c) {
        console.log(this);  
        console.log(this.name, this.age);
      }

      const obj = { name: "owl", age: 18 };
      let newPerson =  person.bind(obj); 
      console.log(newPerson); // ? person(a, b, c) {
                              //      console.log(this);
                              //      console.log(this.name, this.age);
                              //    }
      newPerson();            // {name: 'owl', age: 18}
                              // owl  18
                              
function person(a, b, c) {
        console.log(a,b,c)
        console.log(this);  
        console.log(this.name, this.age);
      }                              
                              
      let newPersonWithArgs = person.bind(obj,1,2,3) ;
      newPersonWithArgs();    // 1 2 3 
                              // {name: 'owl', age: 18}
                              // owl  18

2.實現(xiàn)myBind方法

簡單版本

      function person(a, b, c) {
        console.log(a, b, c);
        console.log(this);
        console.log(this.name, this.age);
      }
      let obj = {
        name: "owllai",
        age: 18,
      };

      Function.prototype.myBind = function (obj) {
        if (typeof this !== "function") {
          throw new Error(
            "Function.prototype.bind - what is trying to be bound is not callable"
          );
        }

        var self = this; // 1. 這個this代表調(diào)用myBind方法的函數(shù),在本例中也就是person
        var args = Array.prototype.slice.call(arguments, 1); 
        // 2. 獲取傳入的其他參數(shù),從arguments數(shù)組的第二項開始截取
        
        var fn = function () {        // 3.定義一個要返回的函數(shù)   
          //4. 返回的新函數(shù)也是可以接收參數(shù)的,所以我們要一起獲取                         
          var newArgs = Array.prototype.slice.call(arguments);
          //5. 將obj和參數(shù)一起傳入,使用apply來執(zhí)行
          return self.apply(obj, args.concat(newArgs));  
        };
        //6. 最后返回結(jié)果函數(shù)
        return fn;
      };

      let newBind = person.myBind(obj, 1, 2, 3);
      newBind();

myBind的簡單版本已經(jīng)實現(xiàn),但是還有一個問題沒有解決,那就是既然返回的是一個新函數(shù),那除了直接調(diào)用newBind() 方法以外,還可以將newBind當成構(gòu)造函數(shù),使用 new 關(guān)鍵字進行實例化。

比如下面的實例化例子:

let newBind = person.myBind(obj, 1, 2, 3);
let n = new newBind();
  • 我們知道變量n正常來說應(yīng)該是newBind函數(shù)的實例化對象,構(gòu)造函數(shù)的this指向?qū)嵗瘜ο蟆?/li>
  • 而在return self.apply(obj, args.concat(newArgs)); 這一行代碼中,我們是寫死this指向為obj。這樣顯然是不對的。
  • 我們必須考慮到new的情況,所以對簡單版本的myBind代碼進行改造

完整版本

  Function.prototype.myBind = function (obj) {
        if (typeof this !== "function") {
          throw new Error(
            "Function.prototype.bind - what is trying to be bound is not callable"
          );
        }

        var self = this; // 這個this代表調(diào)用myBind方法的函數(shù),在本例中也就是person函數(shù)
        var args = Array.prototype.slice.call(arguments, 1);
        var fn = function () {
          var newArgs = Array.prototype.slice.call(arguments);
          return self.apply(
           //如果沒有進行判斷,永遠寫死obj作為apply的第一個參數(shù),那么如果對fn這個返回函數(shù)進行new時,這個fn函數(shù)的this指向永遠是外部傳過來的obj
           //這樣是不正確的,如果作為new關(guān)鍵字使用這個fn函數(shù),this指向必須是指向new出來的實例對象
           //怎么判斷是不是用new關(guān)鍵字來調(diào)用呢?
           // 我們可以用 instanceof 來判斷返回函數(shù)的原型是否在實例的原型鏈上
           // 如果返回函數(shù)是被new了,那這個返回函數(shù)的實例對象的this就指向了person函數(shù)
           this instanceof fn ? this : obj,
            args.concat(newArgs)
          );
 
        };

        // 創(chuàng)建一個空函數(shù)
        var tmpFn = function () {};

        // 修改返回函數(shù)的 prototype 為綁定函數(shù)的 prototype,實例就可以繼承綁定函數(shù)的原型中的值
        // 可以直接使用  fn.prototype = this.prototype  (this代表fn)
        // fn.prototype = this.prototype;  
        // 也就是讓返回函數(shù)的原型對象和person函數(shù)的原型對象映射
        // 至于為什么使用一個空函數(shù) tmpFn 作為中介,把 fn.prototype 賦值為空對象的實例(原型式繼承),
        // 這是因為直接 fn.prototype = this.prototype 有一個缺點,修改 fn.prototype 的時候,也會直接修改 this.prototype ;
        
        // tmpFn空函數(shù)的原型指向綁定函數(shù)的原型
         tmpFn.prototype = this.prototype; //(this代表person函數(shù))

        // 空對象的實例賦值給 fn.prototype
        fn.prototype = new tmpFn();
        return fn;
      };

到此這篇關(guān)于JavaScript中改變this指向的三種方式總結(jié)的文章就介紹到這了,更多相關(guān)JavaScript改變this指向內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論