最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

前言

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

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

那么在本篇中我們介紹的是call、bind、apply方法的使用以及如何實(shí)現(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值和實(shí)參值
                                // 打印 1 2 3
                                // {name: 'owl', age: 18}
                                // owl 18

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

介紹完call()方法以后,我們來嘗試寫一個自己的myCall方法,具體實(shí)現(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ù),我們就把實(shí)參帶入到func函數(shù)中執(zhí)行,如果沒有,則直接執(zhí)行。
        delete ctx.func;   // 5. 執(zhí)行完函數(shù)以后,記得刪除掉這個“中間變量”屬性 ctx
        return result;     // 6. 返回result
      };

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

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

所以自然而然就實(shí)現(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幾乎一模一樣,所以我們在使用和實(shí)現(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í)參值(類數(shù)組對象)
                                // 打印 1 2 3
                                // {name: 'owl', age: 18}
                                // owl 18

2.實(shí)現(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ù)組實(shí)參
        const result = arguments[1] ? ctx.func(...arguments[1]) : ctx.func(); 
        //第四步: 調(diào)用方法,獲得結(jié)果。
        delete ctx.func;
        return result;
      };

myApply方法里面,我們只需要更改兩點(diǎn):

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

bind

1.使用方法

  • bind接收的參數(shù)形式和call有點(diǎn)相似的:第一個參數(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.實(shí)現(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ù)組的第二項(xiàng)開始截取
        
        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)實(shí)現(xiàn),但是還有一個問題沒有解決,那就是既然返回的是一個新函數(shù),那除了直接調(diào)用newBind() 方法以外,還可以將newBind當(dāng)成構(gòu)造函數(shù),使用 new 關(guān)鍵字進(jìn)行實(shí)例化。

比如下面的實(shí)例化例子:

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

完整版本

  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(
           //如果沒有進(jìn)行判斷,永遠(yuǎn)寫死obj作為apply的第一個參數(shù),那么如果對fn這個返回函數(shù)進(jìn)行new時,這個fn函數(shù)的this指向永遠(yuǎn)是外部傳過來的obj
           //這樣是不正確的,如果作為new關(guān)鍵字使用這個fn函數(shù),this指向必須是指向new出來的實(shí)例對象
           //怎么判斷是不是用new關(guān)鍵字來調(diào)用呢?
           // 我們可以用 instanceof 來判斷返回函數(shù)的原型是否在實(shí)例的原型鏈上
           // 如果返回函數(shù)是被new了,那這個返回函數(shù)的實(shí)例對象的this就指向了person函數(shù)
           this instanceof fn ? this : obj,
            args.concat(newArgs)
          );
 
        };

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

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

        // 空對象的實(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)文章

  • js實(shí)現(xiàn)頁面a向頁面b傳參的方法

    js實(shí)現(xiàn)頁面a向頁面b傳參的方法

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)頁面a向頁面b傳參的方法,感興趣的小伙伴們可以參考一下
    2016-05-05
  • JS中數(shù)組重排序方法

    JS中數(shù)組重排序方法

    在數(shù)組中有兩個可以用來直接排序的方法,分別是reverse()和sort()。下面通過本文給大家詳細(xì)介紹,對js 數(shù)組重排序相關(guān)知識感興趣的朋友一起看看吧
    2016-11-11
  • 詳解JavaScript樹結(jié)構(gòu)

    詳解JavaScript樹結(jié)構(gòu)

    對于數(shù)據(jù)結(jié)構(gòu)“樹”,想必大家都熟悉,本文,我們就再來回顧一下數(shù)據(jù)結(jié)構(gòu)中的二叉樹與樹,并用JavaScript實(shí)現(xiàn)它們。下面就跟著小編一起來看下吧
    2017-01-01
  • Electron無邊框自定義窗口拖動的問題小結(jié)

    Electron無邊框自定義窗口拖動的問題小結(jié)

    最近使用了electron框架,發(fā)現(xiàn)如果自定義拖動是比較實(shí)用的;特別是定制化比較高的項(xiàng)目,如果單純的使用-webkit-app-region:?drag;會讓鼠標(biāo)事件無法觸發(fā),這篇文章主要介紹了Electron無邊框自定義窗口拖動的問題小結(jié),需要的朋友可以參考下
    2024-04-04
  • JavaScript實(shí)現(xiàn)自動生成網(wǎng)頁元素功能(按鈕、文本等)

    JavaScript實(shí)現(xiàn)自動生成網(wǎng)頁元素功能(按鈕、文本等)

    這篇文章主要介紹了JavaScript實(shí)現(xiàn)自動生成網(wǎng)頁元素功能,文章列出了三種可以進(jìn)行增刪改克隆按鈕、文本等元素的方法,感興趣的小伙伴們可以參考一下
    2015-11-11
  • JS實(shí)現(xiàn)隨機(jī)抽獎小功能

    JS實(shí)現(xiàn)隨機(jī)抽獎小功能

    這篇文章主要為大家詳細(xì)介紹了JS實(shí)現(xiàn)隨機(jī)抽獎小功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 取得元素的左和上偏移量的方法

    取得元素的左和上偏移量的方法

    利用offsetParent屬性在Dom層次中逐級向上回溯,將每個層次偏移量合計(jì),需要的朋友可以參考下
    2014-09-09
  • js 分欄效果實(shí)現(xiàn)代碼

    js 分欄效果實(shí)現(xiàn)代碼

    原創(chuàng)JS分欄效果,面向?qū)ο螅?使用簡單。
    2009-08-08
  • Bootstrap的基本應(yīng)用要點(diǎn)淺析

    Bootstrap的基本應(yīng)用要點(diǎn)淺析

    BootStrap是基于HTML、CSS和JavaScript的框架,使你只需要寫簡單的代碼就可以很快的搭建一個還不錯的前端框架,他是后端程序員的福音,使他們只需要專注業(yè)務(wù)邏輯,而無須浪費(fèi)太多的精力在界面設(shè)計(jì)上
    2016-12-12
  • 小程序采集錄音并上傳到后臺

    小程序采集錄音并上傳到后臺

    這篇文章主要為大家詳細(xì)介紹了小程序采集錄音并上傳到后臺,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-11-11

最新評論

高陵县| 彰化县| 罗山县| 井研县| 鹰潭市| 岱山县| 隆德县| 长汀县| 仁布县| 阿坝县| 南木林县| 五河县| 沧源| 汉寿县| 文水县| 庐江县| 田阳县| 双桥区| 吴江市| 双辽市| 和龙市| 福清市| 禹州市| 仲巴县| 嘉定区| 黄山市| 曲沃县| 呈贡县| 新丰县| 新蔡县| 武乡县| 永川市| 富蕴县| 怀宁县| 江油市| 江源县| 长垣县| 闽清县| 吴川市| 兴业县| 松原市|