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

資訊專欄INFORMATION COLUMN

圖解JS閉包形成的原因

wind3110991 / 2704人閱讀

摘要:閉包的出現(xiàn)正好結(jié)合了全局變量和局部變量的優(yōu)點(diǎn)。這就是閉包的一個(gè)使用場(chǎng)景保存現(xiàn)場(chǎng)。

前言

什么是閉包,其實(shí)閉包是可以重用一個(gè)對(duì)象,又保護(hù)對(duì)象不被篡改的一種機(jī)制。什么是重用一個(gè)對(duì)象又保護(hù)其不被篡改呢?請(qǐng)看下面的詳解。

作用域和作用域鏈

注意
理解作用域和作用域鏈對(duì)理解閉包有非常大的幫助,所以我們先說(shuō)一下作用域和作用域鏈

什么是作用域
作用域表示的是一個(gè)變量的可用范圍、其實(shí)它是一個(gè)保存變量的對(duì)象
為什么要使用作用域
避免不同范圍的變量互相干擾

作用域包含了哪兩種
1、全局作用域
在JavaScript中的全局作用域其實(shí)就是windows
優(yōu)點(diǎn):可重復(fù)使用,隨處可用
缺點(diǎn):會(huì)造成全局污染

2、函數(shù)作用域
臨時(shí)創(chuàng)建的活動(dòng)對(duì)象AO(Activation Object)、該對(duì)象包含了函數(shù)的所有局部變量、命名參數(shù)、參數(shù)集合以及this,當(dāng)運(yùn)行時(shí)上下文被銷毀、活動(dòng)也會(huì)被銷毀(閉包形成的原因其實(shí)因?yàn)榫褪且驗(yàn)榛顒?dòng)對(duì)象被引用著無(wú)法被銷毀而導(dǎo)致的,詳細(xì)的請(qǐng)繼續(xù)往下看)
優(yōu)點(diǎn):不污染全局
缺點(diǎn):不可重復(fù)使用、僅在函數(shù)內(nèi)可以使用

程序執(zhí)行的四個(gè)階段
我以下面一段代碼解釋一下程序執(zhí)行的幾個(gè)階段

    var age = "21";
    function myAge(){
        var age = 0;
        age++;
        console.log(age);
    }
    myAge();
    console.log(age);

第一階段:在內(nèi)存中創(chuàng)建執(zhí)行執(zhí)行環(huán)境棧、把全局對(duì)象window壓入棧底、在window中聲明變量

第二階段:函數(shù)調(diào)用時(shí)
在執(zhí)行環(huán)境中添加當(dāng)前函數(shù)調(diào)用、為本次函數(shù)調(diào)用創(chuàng)建活動(dòng)對(duì)象AO、根據(jù)scope指定運(yùn)行期活動(dòng)對(duì)象AO的上下文內(nèi)部對(duì)象

第三階段:函數(shù)調(diào)用后
函數(shù)調(diào)用從執(zhí)行環(huán)境棧中出棧、函數(shù)作用域AO釋放、函數(shù)作用域AO中的局部變量也一同被釋放

由上面可以看出當(dāng)一個(gè)函數(shù)調(diào)用完畢它的局部變量就會(huì)被釋放,下次再次調(diào)用時(shí)會(huì)創(chuàng)建新的局部變量。這就是函數(shù)中的局部變量不可重用的原因。

為什么要使用閉包

先介紹一下全局變量和局部變量的優(yōu)缺點(diǎn)
全局變量:可以重用、但是會(huì)造成全局污染而且容易被篡改
局部變量:僅函數(shù)內(nèi)使用不會(huì)造成全局污染也不會(huì)被篡改、不可以重用
從上面可以看出全局變量和局部變量的優(yōu)缺點(diǎn)剛好是相對(duì)的。閉包的出現(xiàn)正好結(jié)合了全局變量和局部變量的優(yōu)點(diǎn)。

何時(shí)使用閉包
希望重用一個(gè)對(duì)象,又保護(hù)對(duì)象不被污染篡改時(shí)

閉包的實(shí)現(xiàn)原理

弄清楚了作用域和作用域鏈、閉包實(shí)現(xiàn)的原理也就很容易弄懂了。
下面請(qǐng)看一段代碼和幾張圖^_^
這是一段閉包的代碼,我們又這段代碼講講閉包的原理

    function addAge(){
        var age = 21;
        return function(){
            age++;
            console.log(age);
        }
    }
    var clourse = addAge();
    clourse();
    clourse();
    clourse();

第一階段:在內(nèi)存中創(chuàng)建執(zhí)行執(zhí)行環(huán)境棧、把全局對(duì)象window壓入棧底、在window中聲明變量(和前面是相似的)

第二階段:
1、在棧中添加addAge的函數(shù)調(diào)用
2、為addAge函數(shù)創(chuàng)建活動(dòng)對(duì)象AO、根據(jù)addAge函數(shù)的scope可以知道其活動(dòng)對(duì)象指向window
3、window對(duì)象中的clourse變量記錄著addAge()返回的匿名函數(shù)的地址[現(xiàn)在addAge()和clourse變量都可以找到匿名函數(shù)和addAge()產(chǎn)生的AO]

第三階段:
addAge()調(diào)用完畢出棧、其對(duì)活動(dòng)對(duì)象AO的引用也隨之消失。
在作用域和作用域鏈中舉的例子中,活動(dòng)對(duì)象AO會(huì)被JS中的垃圾回收機(jī)制回收大家還記得嘛^_^,
但是這里和前面是不一樣的哦!注意了:匿名函數(shù)中的scope引用著活動(dòng)對(duì)象AO、匿名函數(shù)的地址也被clourse變量記錄著。因此,addAge()雖然出棧了,對(duì)它的活動(dòng)對(duì)象的引用也消失了,但是其活動(dòng)對(duì)象被匿名函數(shù)的scope拽著、所以無(wú)法釋放不會(huì)被回收。
大家觀看藍(lán)色的箭頭,其實(shí)可以發(fā)現(xiàn)、藍(lán)色的箭頭已經(jīng)形成了一個(gè)閉環(huán)了。
此時(shí),由圖也可以看出,活動(dòng)對(duì)象AO只能通過(guò)clourse變量來(lái)找到。這里形成了一個(gè)閉包。保存了addAge()函數(shù)中的局部變量,使其可以重復(fù)使用,但是又不會(huì)造成全局污染。這就是閉包的一個(gè)使用場(chǎng)景:保存現(xiàn)場(chǎng)。
至于怎么調(diào)用重復(fù)使用局部變量,具體過(guò)程請(qǐng)看下面兩幅圖。

第四階段:
clourse()進(jìn)棧,產(chǎn)生clouse()的活動(dòng)對(duì)象AO,根據(jù)它的scope可以知道它的__parent__指向addAge()產(chǎn)生的活動(dòng)對(duì)象AO。
clouse()執(zhí)行age++,由于在它自己的作用域里面沒(méi)有age、于是它會(huì)到上一級(jí)作用域查找age,它在它的上一級(jí)作用域中找到了age,于是對(duì)其進(jìn)行了age++,age從21變成了22。執(zhí)行console.log(age)輸出22。

第五階段:
clourse()出棧,因?yàn)閏lourse產(chǎn)生的AO沒(méi)有scope拽著它,因此clourse的AO是可以正常釋放的。函數(shù)出棧,其AO被JS的垃圾回收機(jī)制回收。
clourse變量中的匿名函數(shù)中的scope依舊拽著addAge()產(chǎn)生的活動(dòng)對(duì)象AO,于是這個(gè)活動(dòng)對(duì)象依舊無(wú)法被釋放[而且這個(gè)AO現(xiàn)在只能被clourse找到、clourse可以重復(fù)使用這個(gè)AO里面的局部變量age、又不會(huì)造成全局污染]

剩下階段:
代碼中還有兩個(gè)函數(shù)還有執(zhí)行

clourse()
clourse()

它的執(zhí)行和第四階段和第五階段的原理是一樣的。所以在這里我就不重復(fù)畫圖了。
執(zhí)行clourse():看第四階段的圖,age從22變成了23,執(zhí)行console.log(age)輸出23、看第五階段的圖
執(zhí)行clourse(): 看第四階段的圖,age從23變成了24,執(zhí)行console.log(age)輸出24、看第五階段的圖

總結(jié)

以上就是對(duì)閉包形成過(guò)程的圖解。也說(shuō)明了閉包保存現(xiàn)場(chǎng)的作用場(chǎng)景。閉包結(jié)合了局部變量和全局變量的優(yōu)點(diǎn)。可以使變量不污染全局,但是又能對(duì)變量進(jìn)行重用。但是,其實(shí)閉包也有有缺點(diǎn)的,它比起普通函數(shù)會(huì)占用更多的內(nèi)存。
總的來(lái)說(shuō),以上就是我對(duì)閉包的理解。如果大家發(fā)現(xiàn)了什么錯(cuò)誤歡迎評(píng)論指出,一起交流一起學(xué)習(xí)一起進(jìn)步!^_^

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

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

相關(guān)文章

  • 結(jié)合作用域,執(zhí)行上下文圖解閉包

    摘要:作用域鏈所謂作用域鏈,是由當(dāng)前環(huán)境與上層環(huán)境的一系列變量對(duì)象組成,它保證當(dāng)前執(zhí)行環(huán)境對(duì)符合訪問(wèn)權(quán)限的變量和函數(shù)的有序訪問(wèn)。當(dāng)我們?cè)趫?zhí)行函數(shù)的時(shí)候,需要的變量,在自己的作用域內(nèi)找不到,便會(huì)順著作用域鏈往上找,直到找到全局作用域。 一 作用域相關(guān)? ? ? 作用域是一套規(guī)則,用來(lái)管理引擎如何查找變量。在es5之前,js只有全局作用域及函數(shù)作用域。es6引入了塊級(jí)作用域。但是這個(gè)塊級(jí)別作用域...

    msup 評(píng)論0 收藏0
  • 圖解作用域及閉包

    摘要:那其實(shí)閉包的原因就是外層函數(shù)的作用域?qū)ο鬅o(wú)法釋放其實(shí)就是一個(gè)函數(shù)調(diào)用會(huì)生成的臨時(shí)作用域圖中可看出其實(shí)就是在中的匿名函數(shù),所以他的就指向留下的作用域。 引言 網(wǎng)絡(luò)上關(guān)于作用域及閉包的文章很多,自己對(duì)于純理論知識(shí)并不能很快的理解,但自己對(duì)于圖畫有很強(qiáng)的記憶和理解能力,因此決定將此知識(shí)點(diǎn)以圖畫的知識(shí)表現(xiàn)出來(lái),加深自身理解的同時(shí)如果能幫到正在學(xué)習(xí)的童鞋就再好不過(guò)了 下面我以函數(shù)的整個(gè)生命周期來(lái)...

    shiyang6017 評(píng)論0 收藏0
  • 理解閉包

    摘要:我的理解就是還處于被引用狀態(tài)。內(nèi)存機(jī)制的內(nèi)存空間分為棧堆其中棧存放變量,堆存放復(fù)雜對(duì)象。對(duì)堆內(nèi)數(shù)據(jù)進(jìn)行復(fù)制修改時(shí)理解閉包有了前面的鋪墊,我們?cè)賮?lái)看看閉包是怎么回事。這種反常的現(xiàn)象我們就叫它,中文名閉包。這就是閉包形成的原因了。 知識(shí)小儲(chǔ)備 ECMAScript 的數(shù)據(jù)有兩種類型:基本類型值和引用類型值,基本類型指的是簡(jiǎn)單的數(shù)據(jù)段,引用類型指的是可能由多個(gè)值構(gòu)成的對(duì)象。Undefined...

    fox_soyoung 評(píng)論0 收藏0
  • javascript系列--javascript深入淺出圖解作用域鏈和閉包

    摘要:變量對(duì)象也是有父作用域的。作用域鏈的頂端是全局對(duì)象。當(dāng)函數(shù)被調(diào)用的時(shí)候,作用域鏈就會(huì)包含多個(gè)作用域?qū)ο?。?dāng)函數(shù)要訪問(wèn)時(shí),沒(méi)有找到,于是沿著作用域鏈向上查找,在的作用域找到了對(duì)應(yīng)的標(biāo)示符,就會(huì)修改的值。 一、概要 對(duì)于閉包的定義(紅寶書P178):閉包就是指有權(quán)訪問(wèn)另外一個(gè)函數(shù)的作用域中的變量的函數(shù)。 關(guān)鍵點(diǎn): 1、閉包是一個(gè)函數(shù) 2、能夠訪問(wèn)另外一個(gè)函數(shù)作用域中的變量 二、閉包特性 對(duì)...

    Jensen 評(píng)論0 收藏0
  • 《javascript高級(jí)程序設(shè)計(jì)》筆記:內(nèi)存與執(zhí)行環(huán)境

    摘要:因此,所有在方法中定義的變量都是放在棧內(nèi)存中的當(dāng)我們?cè)诔绦蛑袆?chuàng)建一個(gè)對(duì)象時(shí),這個(gè)對(duì)象將被保存到運(yùn)行時(shí)數(shù)據(jù)區(qū)中,以便反復(fù)利用因?yàn)閷?duì)象的創(chuàng)建成本通常較大,這個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)就是堆內(nèi)存。 上一篇:《javascript高級(jí)程序設(shè)計(jì)》筆記:繼承近幾篇博客都會(huì)圍繞著圖中的知識(shí)點(diǎn)展開(kāi) showImg(https://segmentfault.com/img/bVY0C4?w=1330&h=618);...

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

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

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<