成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

this全面解析(一)

darry / 1074人閱讀

摘要:調(diào)用棧就是為了到達(dá)當(dāng)前執(zhí)行位置所調(diào)用的所有函數(shù)。由于無(wú)法控制回調(diào)函數(shù)的執(zhí)行方式,因此就沒(méi)有辦法控制調(diào)用位置得到期望的綁定,下一節(jié)我們會(huì)介紹如何通過(guò)固定來(lái)修復(fù)這個(gè)問(wèn)題。

在《你不知道的this》中我們排除了對(duì)于this的錯(cuò)誤理解,并且明白了每個(gè)函數(shù)的this是在調(diào)用時(shí)綁定的,完全取決于函數(shù)的調(diào)用位置。在本節(jié)中我們主要介紹一下幾個(gè)主要內(nèi)容:

什么是調(diào)用位置

綁定規(guī)則

this詞法

調(diào)用位置

調(diào)用位置:就是函數(shù)在代碼中被調(diào)用的位置(而不是聲明位置)。要想回答this到底引用的是什么?只有仔細(xì)分析調(diào)用位置才能回答這個(gè)問(wèn)題。
而分析調(diào)用位置最重要的就是分析調(diào)用棧。下面是調(diào)用棧的定義。
調(diào)用棧:就是為了到達(dá)當(dāng)前執(zhí)行位置所調(diào)用的所有函數(shù)。

    function baz(){
         //當(dāng)前調(diào)用棧是:baz
         //因此,當(dāng)前調(diào)用位置是全局作用域
         console.log("baz");
         bar(); //bar的調(diào)用位置
    }
    function bar(){
         //當(dāng)前調(diào)用棧是:baz -> bar
         //因此,當(dāng)前調(diào)用位置是在baz中
         console.log("bar");
         foo(); //foo的調(diào)用位置
    }
    function foo(){
         //當(dāng)前調(diào)用棧是:baz -> bar -> foo
         //因此,當(dāng)前調(diào)用位置是在baz中
         console.log("foo");
    }
    baz(); // baz的調(diào)用位置
綁定規(guī)則

我們的思路是,通過(guò)找到函數(shù)的調(diào)用位置,然后判斷需要應(yīng)用規(guī)則中的哪一條。便可決定this的綁定對(duì)象。關(guān)于this的綁定規(guī)則主要是以下四種:

默認(rèn)綁定

隱式綁定

顯式綁定

new綁定

1.默認(rèn)綁定

默認(rèn)綁定的典型類(lèi)型是:獨(dú)立函數(shù)調(diào)用。 思考如下代碼:

    function foo(){
             console.log(this.a);
    }
    var a = 2;
    foo(); // 2

調(diào)用foo()時(shí),函數(shù)應(yīng)用了默認(rèn)綁定,this只想全局對(duì)象window(這是在非嚴(yán)格模式下,若是在嚴(yán)格模式下會(huì)報(bào)錯(cuò)),所以this.a被解析成了全局變量a。所以,在不使用任何修飾的函數(shù)引用進(jìn)行調(diào)用,只能使用默認(rèn)綁定,無(wú)法應(yīng)用其他規(guī)則。

2.隱式綁定

隱式綁定的常見(jiàn)形式是在調(diào)用位置具有上下文對(duì)象,或者說(shuō)被某個(gè)對(duì)象擁有或者包含??慈缦麓a:

     function foo(){
        console.log(this.a);
     }
     var obj = {
          a: 2,
          foo: foo
     };
     obj.foo(); // 2

這里函數(shù)foo()是預(yù)先定義好的,然后再將其添加為obj對(duì)象的引用屬性。調(diào)用位置使用obj上下文來(lái)引用函數(shù),因此可以說(shuō)函數(shù)被調(diào)用時(shí)obj對(duì)象“擁有”或者“包含”它。
無(wú)論你如何稱(chēng)呼這個(gè)模式,當(dāng)foo()被調(diào)用時(shí),它的前面確實(shí)是加上了obj的引用。當(dāng)函數(shù)引用上下文對(duì)象時(shí),隱式綁定規(guī)則就會(huì)把函數(shù)調(diào)用中的this綁定到這個(gè)上下文對(duì)象。所以,this.a和obj.a是一樣的。

另一個(gè)需要注意的點(diǎn)是:對(duì)象屬性引用鏈中只有最后一層在調(diào)用位置起作用

    function foo(){
         console.log(this.a);
    }
    var obj2 = {
         a: 100,
         foo: foo
    };
    var obj1 = {
         a: 1,
         obj2: obj2
    }
    obj1.obj2.foo(); // 100
隱式綁定一個(gè)最常見(jiàn)的問(wèn)題

一個(gè)最常見(jiàn)的問(wèn)題就是:隱式綁定的函數(shù)會(huì)丟失綁定對(duì)象。也就是是說(shuō)它會(huì)應(yīng)用默認(rèn)綁定,而把this綁定到全局對(duì)象或者undifined上,取決于是否是嚴(yán)格模式。

    function foo(){
        console.log(this.a);
    }
    var obj ={
        a: 2,
        foo: foo
    }
    var bar = obj.foo; //函數(shù)別名
    var a = "global";
    bar(); // "global"

雖然bar是obj.foo的一個(gè)引用,但實(shí)際上,他引用的是foo函數(shù)本身, 因此, 此時(shí)的bar()其實(shí)是一個(gè)不帶任何修飾的函數(shù)調(diào)用,因此,它應(yīng)用了默認(rèn)綁定
一種更微妙,更常見(jiàn)的并且更出乎意料的情況發(fā)生在傳入回調(diào)函數(shù)時(shí):

    function foo(){
        console.log(this.a);
    }
    function callBack(fn){
        fn();
    }

    var obj = {
        a: 2,
        foo: foo
    }
    var a = "global";
    callBack(obj.foo); // "global"

參數(shù)傳遞其實(shí)就是一種隱式賦值,這句話(huà)我們可以用下面的兩段代碼來(lái)詳細(xì)的講解:

    var a = 1;
    function fn(){
        alert(a); //1
        a = 2;
    }
    fn();
    alert(a); // 2

_ _ _

    var a = 1;
    function fn(a){
          alert(a); //undifined
          a = 2;
    }
    fn();
    alert(a); // 1

思考一下結(jié)果是否與你想象的一致呢?
在第一段代碼中:
首先,在全局作用域中,先通過(guò)變量提升,找到了標(biāo)識(shí)符a和函數(shù)fn,a此時(shí)有個(gè)默認(rèn)值為undifined。然后,在執(zhí)行階段我們先將變量a賦值為1,緊跟著函數(shù)fn()執(zhí)行。此時(shí),在函數(shù)域中,依舊應(yīng)用變量提升的規(guī)則,但是什么都沒(méi)找到,接著執(zhí)行函數(shù)內(nèi)的代碼:alert(a),因?yàn)樵诤瘮?shù)中并沒(méi)有找到變量a。所以,通過(guò)作用域鏈向上層的父級(jí)作用域中查找,我們找到了a,并且此時(shí)a的值已經(jīng)被賦值為1,所以,alert(a)這句的結(jié)果就是1。下一句代碼:a = 2,注意a的前面沒(méi)有關(guān)鍵字var, 即這里的a是全局的,也就是說(shuō)在執(zhí)行這句代碼時(shí),他修改了全局作用域中a的值,即a現(xiàn)在為2。最后在執(zhí)行alert(a)時(shí),自然而然a的值便是2了。

在第二段代碼中:
同樣,通過(guò)變量提升,我們找到了標(biāo)識(shí)符a和函數(shù)fn,a此時(shí)的默認(rèn)值也為undifined。開(kāi)始執(zhí)行,a首先被賦值為1。然后,函數(shù)執(zhí)行,這里與第一段代碼的不同之處在于,在函數(shù)fn中傳入了參數(shù)a,那么這么做的結(jié)果就是:在函數(shù)域先運(yùn)用變量提升的規(guī)則,不會(huì)像第一段代碼中那樣什么都找不到,而是相當(dāng)于定義了一個(gè)值為undifined(調(diào)用的時(shí)候沒(méi)有傳入?yún)?shù))的變量a,所以當(dāng)執(zhí)行函數(shù)域中的alert(a)時(shí),結(jié)果就為undifined,而不會(huì)通過(guò)作用域鏈向上去查找,因?yàn)楸竞瘮?shù)中已經(jīng)找到了,只不過(guò)是以參數(shù)的形式傳入的。同理代碼(a = 2)會(huì)修改a的值,即在函數(shù)域中,a的值現(xiàn)在為2(讀者可以去嘗試在函數(shù)中最后面alert一下a的值)。而在函數(shù)外執(zhí)行alert(a),我們得到的結(jié)果便是1,因?yàn)樵摼浯a是在全局中執(zhí)行的,即會(huì)在全局中去查找變量a,而不會(huì)去訪(fǎng)問(wèn)函數(shù)域中的a。這也是因?yàn)?,在JavaSceipt中子作用域可以訪(fǎng)問(wèn)父作用域而反過(guò)來(lái)卻不行的規(guī)則。

回到我們this綁定丟失的話(huà)題上,說(shuō)了這么多,我其實(shí)就是想說(shuō):參數(shù)傳遞其實(shí)就是一種隱式賦值,參數(shù)傳遞其實(shí)就是一種隱式賦值,參數(shù)傳遞其實(shí)就是一種隱式賦值,重要的事說(shuō)三遍!
我們按照上面的方式來(lái)解析代碼:在執(zhí)行callBack(obj.foo)時(shí),在函數(shù)作用域通過(guò)變量提升找到了參數(shù)fn,它的默認(rèn)值為undifined,然后我們將參數(shù)傳入,其實(shí)相當(dāng)于(var fn = obj.foo),這就與前面的將其直接賦值給一個(gè)變量對(duì)等上了,然后再執(zhí)行fn(),應(yīng)用默認(rèn)綁定,此時(shí)的this已經(jīng)不指向obj了,而是指向window(嚴(yán)格模式)。

如果把函數(shù)傳入內(nèi)置的函數(shù)而不是傳入你自己聲明的函數(shù),會(huì)發(fā)生什么呢?結(jié)果是一樣的,沒(méi)有區(qū)別:

    function foo(){
        console.log(this.a)
    }
    var obj = {
        a: 2,
        foo: foo
    }
    var a = "global";
    setTimeout(obj.foo, 1000); //"global"

JavaSceipt環(huán)境中內(nèi)置的setTimeout()函數(shù)實(shí)現(xiàn)和下面的偽代碼類(lèi)似:

    function setTimeout(fn, delay){
        //等待delay秒
        fn(); //調(diào)用位置
    }

就向你們看到的那樣,回調(diào)函數(shù)丟失this綁定的情況是非常常見(jiàn)的,并且還有一種情況this的行為會(huì)出乎我們意料:調(diào)用回調(diào)函數(shù)的函數(shù)可能會(huì)修改this。由于無(wú)法控制回調(diào)函數(shù)的執(zhí)行方式,因此就沒(méi)有辦法控制調(diào)用位置得到期望的綁定,下一節(jié)我們會(huì)介紹如何通過(guò)固定this來(lái)“修復(fù)“這個(gè)問(wèn)題。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/78968.html

相關(guān)文章

  • 全面解析JS中的this

    摘要:當(dāng)我們不想再對(duì)象內(nèi)部間接包含引用函數(shù),而像在某個(gè)對(duì)象上強(qiáng)制調(diào)用函數(shù)。我們可以用中內(nèi)置的和的方法來(lái)實(shí)現(xiàn),這兩個(gè)方法的第一個(gè)參數(shù)是一個(gè)對(duì)象,是給準(zhǔn)備的,接著再調(diào)用函數(shù)時(shí)將其綁定到。 this是什么 在javascript中,每個(gè)執(zhí)行上下文可以抽象成一組對(duì)象showImg(https://segmentfault.com/img/bVuKR7); 而this是與執(zhí)行上下文相關(guān)的特殊對(duì)象,任何...

    calx 評(píng)論0 收藏0
  • this全面解析(二)

    摘要:在傳統(tǒng)的面向類(lèi)的語(yǔ)言中,構(gòu)造函數(shù)是類(lèi)中的一些特殊方法,使用初始化類(lèi)是會(huì)調(diào)用類(lèi)中的構(gòu)造函數(shù)。 在上一節(jié)中我們?cè)敿?xì)介紹了this的兩種綁定方式,默認(rèn)綁定和隱式綁定,在這一節(jié)我們繼續(xù)介紹this的另外兩種綁定方式顯示綁定和new綁定。那么,我們要解決的問(wèn)題當(dāng)然就是上一節(jié)中我們提到的:this丟失! 顯式綁定 在隱式綁定中,我們必須在一個(gè)對(duì)象的內(nèi)部包含一個(gè)指向函數(shù)的屬性,并通過(guò)這個(gè)屬性間接引用...

    iflove 評(píng)論0 收藏0
  • 關(guān)于this全面解析(下)

    摘要:關(guān)于的全棉解析上的文章地址判斷函數(shù)是否在中調(diào)用綁定如果是的話(huà)綁定的是新創(chuàng)建的對(duì)象。顯而易見(jiàn),這種方式可能會(huì)導(dǎo)致許多難以分析和追蹤的。默認(rèn)在嚴(yán)格模式下綁定到,否則綁定到全局對(duì)象。 關(guān)于this的全棉解析(上)的文章地址 判斷this 函數(shù)是否在new中調(diào)用(new綁定)?如果是的話(huà)this綁定的是新創(chuàng)建的對(duì)象。 bar = new foo() 函數(shù)是否通過(guò)call、apply(顯式綁定...

    philadelphia 評(píng)論0 收藏0
  • 關(guān)于this全面解析(上)

    摘要:關(guān)于的全面解析下頁(yè)面鏈接的調(diào)用位置調(diào)用位置就是函數(shù)在代碼中被調(diào)用的位置而不是聲明的位置,尋找調(diào)用位置就是尋找函數(shù)被調(diào)用的位置,最重要的是分析調(diào)用棧就是為了到達(dá)當(dāng)前執(zhí)行位置所調(diào)用的所有函數(shù)。因此,調(diào)用函數(shù)時(shí)被綁定到這個(gè)對(duì)象上,所以和是一樣的。 關(guān)于this的全面解析(下)頁(yè)面鏈接 this的調(diào)用位置 調(diào)用位置就是函數(shù)在代碼中被調(diào)用的位置(而不是聲明的位置),尋找調(diào)用位置就是尋找函數(shù)被調(diào)用...

    caige 評(píng)論0 收藏0
  • 全面解析this

    摘要:在嚴(yán)格模式下,對(duì)象的函數(shù)中的指向調(diào)用函數(shù)的對(duì)象實(shí)例顯式綁定,,通過(guò)可以把的綁定到上。間接引用最容易在賦值時(shí)發(fā)生返回目標(biāo)函數(shù)的引用詞法之前介紹的種綁定規(guī)則可以包含所有正常的函數(shù),但是中介紹了一種無(wú)法使用這些規(guī)則的特殊函數(shù)類(lèi)型箭頭函數(shù)。 this到底指向什么? this關(guān)鍵詞是javaScript中最復(fù)雜的機(jī)制之一,一般有兩個(gè)誤區(qū):1.this指向函數(shù)自身;2.this指向函數(shù)的作用域; ...

    Y3G 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<