成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

this全面解析(二)

iflove / 1807人閱讀

摘要:在傳統(tǒng)的面向類的語言中,構(gòu)造函數(shù)是類中的一些特殊方法,使用初始化類是會調(diào)用類中的構(gòu)造函數(shù)。

在上一節(jié)中我們詳細(xì)介紹了this的兩種綁定方式,默認(rèn)綁定隱式綁定,在這一節(jié)我們繼續(xù)介紹this的另外兩種綁定方式顯示綁定new綁定。那么,我們要解決的問題當(dāng)然就是上一節(jié)中我們提到的:this丟失!

顯式綁定

在隱式綁定中,我們必須在一個對象的內(nèi)部包含一個指向函數(shù)的屬性,并通過這個屬性間接引用函數(shù),從而把this間接綁定到這個對象上。那么如果我們不想在每個對象內(nèi)部包含函數(shù)引用,而想在每個對象上強制調(diào)用函數(shù),該怎么做呢?
這時就需要 call(綁定this, 其他參數(shù)...)apply(綁定this, 其他參數(shù)...)方法出場了,這兩個方法的第一個參數(shù)都是給this準(zhǔn)備的,不同之處在于其他參數(shù)的形式上,他們兩的其他參數(shù)對比如下:

call(綁定this, "參數(shù)1","參數(shù)2","參數(shù)3","參數(shù)4");
apply(綁定this, ["參數(shù)1","參數(shù)2","參數(shù)3","參數(shù)4"]);

apply的其他參數(shù)是以數(shù)組序列形式存在的,它會在執(zhí)行時將其解析成單個的參數(shù)再依次的傳遞到調(diào)用的函數(shù)中,這有什么用處呢?加入我們有一個數(shù)組:

var arr = [1,2,3,4,5,6];

現(xiàn)在我要找到其中的最大值,當(dāng)然這里有很多方法了。既然這里講到apply那么我們就用apply方法來解決這個問題。如果想要找到一組數(shù)中最大的一個,有一個簡單的方法,使用Math.max(...)。但是,該方法并不能找出一個數(shù)組中的最大值,也就是說:

Math.max(1,2,3,4,5); // 可以找到最大值5
Math.max([1,2,3,4,5]); // 這就不行了,因為不接受以數(shù)組作為參數(shù)

我們的做法就是通過:

Math.max.apply(null, [1,2,3,4,5]); //得到數(shù)組中的最大值5

還有很多其他方面的用處,比如push等等,似乎有點跑題了?。?!
不過我想說的就是通過call()和apply()這兩種方法我們可以顯式的綁定this到指定的對象!

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

但是,顯式綁定仍舊無法解決this丟失綁定的問題。

硬綁定

顯式綁定的一個變種可以解決這個問題。

    function foo(){
        console.log(this.a);
    }
    var obj = {
            a: 2
         }
    var bar = function(){
        foo.call(obj);
    }
    bar();// 2
    setTimeout(bar, 100); // 2
    bar.call(window); // 2

看看它是如何工作的:我們創(chuàng)建了一個函數(shù)bar(),并在他的內(nèi)部手動調(diào)用foo.call(obj)。因此,強制把foo的this綁定到了obj,無論之后如何調(diào)用函數(shù)bar,它總會手動在obj上調(diào)用foo。這樣的形式我們稱之為硬綁定。
硬綁定的典型應(yīng)用場景就是創(chuàng)建一個包裹函數(shù),負(fù)責(zé)接收參數(shù)并返回值:

    function foo(something){
        console,log(this.a, something);
        return this.a + something;
    }
    var obj = {
        a: 2
    }
    var bar = function(){
        return foo.apply(obj, arguments);
    }
    var b = bar(3); //2, 3
    console.log(b); //5

另一個常用的方法是創(chuàng)建一個可以重復(fù)使用的輔助函數(shù):

    function foo(something){
        console,log(this.a, something);
        return this.a + something;
    }
    //簡單的輔助函數(shù)
    function bind(fn, obj){
        return function(){
            return fn.apply(obj, arguments);
        }
    }
    var obj = {
        a:2
    }
    
    var bar = bind(foo, obj);

    var b = bar(); //2, 3
    console.log(b); //5

硬綁定是一種非常常用的模式,所以ES5提供了內(nèi)置的方法Function.prototype.bind,它的用法如下:

    function foo(something){
        console,log(this.a, something);
            return this.a + something;
    }
    var obj = {
        a:2
    }
    var bar = foo.bind(obj);
    var b = bar(3); //2, 3
    console.log(b); //5

bind(...)會返回一個硬編碼的心函數(shù),它會把指定的參數(shù)設(shè)置為this的上下文并調(diào)用原始函數(shù)。

new 綁定

第四條規(guī)則,也是最后一條規(guī)則,在講解他之前我們首先要澄清一個非常常見的關(guān)于javascript中函數(shù)和對象的誤解。
在傳統(tǒng)的面向類的語言中,“構(gòu)造函數(shù)”是類中的一些特殊方法,使用new初始化類是會調(diào)用類中的構(gòu)造函數(shù)。通常的形式是這樣:

someThinges = new MyClass(...)

javascript中也有個new操作符,但javascript中的new操作符的機制與面向類的語言完全不同。首先我們重新定義一下JavaScrit中的“構(gòu)造函數(shù)”。在Javascript中,構(gòu)造函數(shù)只是一些使用new操作符時被調(diào)用的函數(shù)。它并不會屬于某個類,也不會實例化一個類。實際上它甚至都不能說是一種特殊的函數(shù)類型,它們只是被new操作符調(diào)用的普通函數(shù)而已。
舉例來說,思考一下Number()作為構(gòu)造函數(shù)時的行為,ES5.1中這樣描述它:

Number構(gòu)造函數(shù)
當(dāng)Number在new表達(dá)式中被調(diào)用時,它是一個構(gòu)造函數(shù):它會初始化新建的對象。

所以,包括內(nèi)置對象函數(shù)在內(nèi)的所有函數(shù)都可以用new來調(diào)用,這種函數(shù)被稱為構(gòu)造函數(shù)調(diào)用,這有個非常細(xì)微的區(qū)別:實際上并不存在所位的“構(gòu)造函數(shù)”,只有對于函數(shù)的“構(gòu)造調(diào)用”。
使用new來調(diào)用函數(shù),會自動執(zhí)行下面的操作:

創(chuàng)建一個全新的對象

這個新對象會被執(zhí)行[[prototype]]連接(之后會細(xì)說)

這個新對象會綁定到函數(shù)調(diào)用的this

如果函數(shù)沒有返回其他對象,那么new表達(dá)式中的函數(shù)會自動返回這個對象。

    function foo(a){
        this.a = a
    }

    var bar = new foo(2);
    console.log(bar) // foo {a: 2}
    console.log(bar.a); //2

使用new 來調(diào)用foo(...)時,我們會構(gòu)造一個新的對象,并把它綁定到foo(...)調(diào)用中的this上。new是最后一種可以影響函數(shù)調(diào)用時this綁定行為的方法。我們稱之為new綁定。

箭頭函數(shù)

我們之前介紹的四條規(guī)則已經(jīng)可以包含所有正常是有的函數(shù)。但是在ES6中介紹了一種無法使用這些規(guī)則的特殊函數(shù)類型:箭頭函數(shù)
箭頭函數(shù)不是使用function關(guān)鍵字定義的,而是使用“ => ”定義。箭頭函數(shù)不使用this的四種標(biāo)準(zhǔn)規(guī)則,而是根據(jù)外層作用域(函數(shù)或全局)來決定this。

    function foo(){
        //返回一個箭頭函數(shù)
        return (a) =>{
            //this繼承自foo()
            console.log(this.a);
        }
    }
    var obj1 = {
        a: 2
    }
    var obj2 = {
        a: 3
    }
    var bar = foo.call(obj1);
    bar.call(obj2); //2  不是3

foo()內(nèi)部創(chuàng)建的箭頭函數(shù)會捕獲調(diào)用時foo()的this,由于foo()的this綁定到obj1,bar的this也會綁定到obj1上,而且箭頭函數(shù)的綁定無法被修改!
箭頭函數(shù)最常用與回調(diào)函數(shù)中,例如事件處理器或者定時器:

    function foo(){
        setTimeot(()=>{
            //這里的this在詞法上繼承自foo(),也就是說只要foo()綁定到了obj1上,箭頭函數(shù)的this也就綁定到了obj1上
            console.log(this.a)
        },100)
    }
    var obj1 = {
            a: 2
        }
    foo.call(obj1); //2

箭頭函數(shù)可以像bind(..)一樣確保函數(shù)的this被綁定到指定的對象,此外,其重要性還體現(xiàn)在他用更常見的詞法作用域取代了傳統(tǒng)的this機制。實際上在,ES6之前我們就已經(jīng)使了用一種幾乎和箭頭函數(shù)完全一樣的模式。

    function foo(){
        console.log(this); //Object {a: 2}
        
        var self = this; //詞法作用域捕獲this
        
        setTimeout(function(){
        console.log(this); // Window {external: Object, chrome: Object, document: document, obj1: Object, obj2: Object…}
       
       console.log(self.a);
        }, 100);
    }
    var obj1 = {
                a: 2
            }
    foo.call(obj1); //2

我分別在這段代碼中foo()的內(nèi)部,和setTimeout()的內(nèi)部加了兩行代碼console.log(this),當(dāng)調(diào)用foo()函數(shù)并將其this綁定到obj1上時(即執(zhí)行foo.call(obj1)),foo()內(nèi)的this此時是Object {a: 2},說明foo()函數(shù)中的this已經(jīng)綁定到了obj1上,setTimeout()內(nèi)的結(jié)果是Window...,如果你看了上一節(jié)《this全面解析(一)》的內(nèi)容應(yīng)該會很好理解,因為在setTimeout()方法中,函數(shù)傳參相當(dāng)于隱式賦值,調(diào)用方式自然運用默認(rèn)規(guī)則setTimeout()方法中函數(shù)的this指向window。為了讓我們得到預(yù)期的結(jié)果,我們將foo()中的this保存下來(即var self = this),然后通過詞法作用域的在setTimeout()方法中的函數(shù)中引用self變量。讀者可以自行測試,如果不這樣做得出的結(jié)果會是什么(undifined嗎?自行驗證一下吧?。?br>好吧!一不小心又啰嗦的講了這么多。雖然,self = this和箭頭函數(shù)看起來都可以取代bind(),但本質(zhì)上來說,他們想取代的是this機制。

小結(jié)

如果要判斷一個運行中函數(shù)的this綁定,就需要找到這個函數(shù)的直接調(diào)用位置。找到后就可以順序應(yīng)用下面這四條規(guī)則來判斷this的綁定對象

是否由new調(diào)用?綁定到新創(chuàng)建的對象

是否由call()或apply()調(diào)用?綁定到指定的對象

是否由上下文對象調(diào)用?綁定到那個上下文對象

默認(rèn):嚴(yán)格模式undifined,非嚴(yán)格綁定到全局對象

ES6中的箭頭函數(shù)不會使用四條標(biāo)準(zhǔn)的綁定規(guī)則,而是根據(jù)詞法作用域來決定this,具體來說,箭頭函數(shù)會繼承外層函數(shù)調(diào)用的this綁定(無論this綁定到了什么),這其實和ES6之前代碼中的self = this 機制一樣。

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/79002.html

相關(guān)文章

  • 全面解析JS中的this

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

    calx 評論0 收藏0
  • 關(guān)于this全面解析(下)

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

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

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

    caige 評論0 收藏0
  • 【進階3-2期】JavaScript深入之重新認(rèn)識箭頭函數(shù)的this

    摘要:箭頭函數(shù)的尋值行為與普通變量相同,在作用域中逐級尋找。題目這次通過構(gòu)造函數(shù)來創(chuàng)建一個對象,并執(zhí)行相同的個方法。 我們知道this綁定規(guī)則一共有5種情況: 1、默認(rèn)綁定(嚴(yán)格/非嚴(yán)格模式) 2、隱式綁定 3、顯式綁定 4、new綁定 5、箭頭函數(shù)綁定 其實大部分情況下可以用一句話來概括,this總是指向調(diào)用該函數(shù)的對象。 但是對于箭頭函數(shù)并不是這樣,是根據(jù)外層(函數(shù)或者全局)作用域(...

    Rainie 評論0 收藏0
  • Java雜記17—String全面解析

    摘要:所以也就是說在沒有的基礎(chǔ)上,執(zhí)行代碼會在串池中創(chuàng)建一個,也會在堆內(nèi)存中再出來一個。不可變性的優(yōu)點安全性字符串不可變安全性的考慮處于兩個方面,數(shù)據(jù)安全和線程安全。 摘要: String基本特性,String源碼,為什么String不可變? 前言 基于字符串String在java中的地位,關(guān)于String的常識性知識就不多做介紹了,我們先來看一段代碼 public class Test {...

    jeffrey_up 評論0 收藏0

發(fā)表評論

0條評論

iflove

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<