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

資訊專欄INFORMATION COLUMN

簡單而清楚地理解閉包

SimonMa / 2930人閱讀

摘要:大多數(shù)非閉包的情況下,函數(shù)的外部函數(shù)即全局變量函數(shù)被調(diào)用時(shí),也會創(chuàng)建一條作用域鏈下稱鏈,并將鏈的內(nèi)容包含到鏈中,然后將當(dāng)前函數(shù)的活動對象可以簡單理解為所有的內(nèi)部變量添加到鏈條的頂端。

什么是閉包?
“閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù)?!?--《JavaScript高級程序設(shè)計(jì)》
通常來說,當(dāng)一個函數(shù)可以訪問另一個函數(shù)內(nèi)部定義的變量(包括屬性和方法)時(shí),這個函數(shù)可以稱之為閉包:

function fnA(){
    var a = "this is fnA.a";
    return function fnB(){
        alert(a);
    }
}

var x = fnA();
x(); // "this is fnA.a"

例子中,我們可以通過x(即fnB)去訪問fnA中的內(nèi)部變量(a),此時(shí)我們可以稱fnB為閉包。

閉包是如何產(chǎn)生的?
為了更清楚的解釋閉包的發(fā)生,我們需要先明白“函數(shù)的創(chuàng)建”到“函數(shù)的調(diào)用”到底發(fā)生了什么事情。

1、函數(shù)被創(chuàng)建時(shí),會創(chuàng)建一條作用域鏈(下稱A鏈)。然后根據(jù)跟創(chuàng)建時(shí)的環(huán)境,依照“外部函數(shù)”、“‘外部函數(shù)’的外部函數(shù)”、“‘外部函數(shù)的外部函數(shù)’的外部函數(shù)”....“全局函數(shù)”順序,將所有函數(shù)的活動對象(可以簡單理解為所有的內(nèi)部變量)添加到這條作用域鏈上。(大多數(shù)非閉包的情況下,函數(shù)的外部函數(shù)即全局變量)
2、函數(shù)被調(diào)用時(shí),也會創(chuàng)建一條作用域鏈(下稱B鏈),并將A鏈的內(nèi)容包含到B鏈中,然后將當(dāng)前函數(shù)的活動對象(可以簡單理解為所有的內(nèi)部變量)添加到B鏈條的頂端。
3、當(dāng)訪問函數(shù)內(nèi)部變量時(shí),會按照B鏈中的變量保存的順序依次訪問。即內(nèi)部變量,(創(chuàng)建時(shí)的)外部函數(shù)的變量,(創(chuàng)建時(shí)的)外部函數(shù)的外部函數(shù)的變量...全局變量。

下面是一道經(jīng)典的閉包題:

function fun(n,o) {
    console.log(o)
    return {
    fun:function(m){
        return fun(m,n);
        }
    };
}

var a = fun(0); // undefined。由于會“o”未賦值,所以會顯示:undefined。同時(shí)返回一個字面量對象,對象內(nèi)創(chuàng)建一個名為“fun”的函數(shù),并將對象返回賦值給全局變量a。此時(shí)a內(nèi)部的函數(shù)fun已經(jīng)被創(chuàng)建好了,它的作用域鏈上包含了外部函數(shù)(外層的fun函數(shù))的所有變量,其中包含了n(值為0),o(值為undefined);以及全局函數(shù)的變量fun(值得注意的是,這個fun屬于全局函數(shù)的變量)。
a.fun(1); // 0。上面提到。在創(chuàng)建a的內(nèi)部fun時(shí),它包含的作用域鏈中包含了n(值為0),o(值為undefined);以及全局函數(shù)的變量fun。因此,我們調(diào)用(訪問)的“fun”是作用域鏈中給全局函數(shù)的函數(shù)fun。m=1,n=0,將其賦值給全局函數(shù)的函數(shù)fun,即:n=(m=)1,o=(n=)0,打印0,值為“0”。
a.fun(2); // 0
a.fun(3); // 0。這里有個“坑”需要注意。在上個步驟“a.fun(1);”中,最后會創(chuàng)建一個對象(fun函數(shù)作用域鏈中的n值為1,o值為0)并返回。但是并沒有變量來接收這個對象,更不會影響到a內(nèi)部作用域鏈。因此“a.fun(2);”、“a.fun(3);”中,作用域鏈上的值與“a.fun(1);”中完全一樣。


var b = fun(0).fun(1).fun(2).fun(3); // undefined,0,1,2
//這是一條鏈?zhǔn)秸{(diào)用。為了便于理解,我們將鏈?zhǔn)秸{(diào)用拆分以下等價(jià)的方案:
var b1 = fun(0); // undefined。這個和“ var a = fun(0);”,不重復(fù)解釋。
var b2 = b1.fun(1); // 0。這里和“a.fun(1);”一樣,不重復(fù)解釋。但是要注意的是,此時(shí)有個變量b2接收了b1.fun返回的變量。此時(shí),b2中的函數(shù)fun的作用域鏈的(部分)內(nèi)容情況:n=1,o=0。
var b3 = b2.fun(2); // 1。“var b2 = b1.fun(1);”中,b2中函數(shù)fun的作用域鏈中的n為1,o為0。調(diào)用全局函數(shù)的fun時(shí),n=(m=)2,o=(n=)1。因此打印內(nèi)容為“1”。
var b4 = b3.fun(3); // 2。理由同上。


var c = fun(0).fun(1); // undefined,0
c.fun(2);// 1
c.fun(3);// 1

//為了便于理解,我們將鏈?zhǔn)秸{(diào)用拆分以下等價(jià)的方案進(jìn)行解釋:
var c1 = fun(0); // undefined。這個和“ var a = fun(0);”,不重復(fù)解釋。
var c = c1.fun(1); // 0。要注意的是,“ c1.fun(1); ”返回的對象由變量c接收,即c中的函數(shù)fun作用域鏈中的變量:n=1,o=0。
c.fun(2);// 1。
c.fun(3);// 1?!?c.fun(2);”中返回的對象不會影響到c。因此此處和執(zhí)行“c.fun(2);”時(shí)一樣,c中的函數(shù)fun作用域鏈并未被改變。

我們可以簡單理解為:函數(shù)創(chuàng)建時(shí),就已經(jīng)根據(jù)上下文環(huán)境保存一套所有外部函數(shù)(不包含自身內(nèi)部)的變量。當(dāng)我們在調(diào)用閉包函數(shù)時(shí),閉包函數(shù)自身不存在的變量,將會在這套變量中查找。

值得一提
1、“變量聲明提升”對于閉包的實(shí)現(xiàn)是非常重要的。如果變量聲明沒有被提升,那么我們將無法保存那些在閉包函數(shù)創(chuàng)建以后才聲明的變量。
2、閉包的機(jī)制,作用域鏈會一直引用自身以外的函數(shù)的全部變量,內(nèi)存回收機(jī)制不能及時(shí)回收這些變量,從而增大內(nèi)存開銷。

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

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

相關(guān)文章

  • js閉包的底層實(shí)現(xiàn)和開發(fā)技巧

    摘要:沒有清空的原因是,內(nèi)部函數(shù)返回的匿名函數(shù)的作用域鏈仍然保有對外部函數(shù)的變量的引用。在作用域鏈中,外部函數(shù)的活動對象始終處于第二位,外部函數(shù)的外部函數(shù)的活動對象處于第三位,直至作為作用域鏈終點(diǎn)的全局執(zhí)行環(huán)境。 前言 閉包這個概念幾乎成了JavaScript面試者必問的話題之一,可以毫不客氣地說對閉包的理解和運(yùn)用體現(xiàn)了一名js工程師的功底。那么閉包到底是什么,它又能帶來什么特別的作用?網(wǎng)上...

    Caizhenhao 評論0 收藏0
  • 前端基礎(chǔ)

    摘要:談起閉包,它可是兩個核心技術(shù)之一異步基于打造前端持續(xù)集成開發(fā)環(huán)境本文將以一個標(biāo)準(zhǔn)的項(xiàng)目為例,完全拋棄傳統(tǒng)的前端項(xiàng)目開發(fā)部署方式,基于容器技術(shù)打造一個精簡的前端持續(xù)集成的開發(fā)環(huán)境。 這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機(jī)制,如果讀完本文還不懂,可以揍我。 不論你是javascript新手還是老鳥,不論是面試求職,還是日...

    graf 評論0 收藏0
  • 理解 JavaScript this

    摘要:回調(diào)函數(shù)在回調(diào)函數(shù)中的指向也會發(fā)生變化。在閉包回調(diào)函數(shù)賦值等場景下我們都可以利用來改變的指向,以達(dá)到我們的預(yù)期。文章參考系列文章理解閉包理解執(zhí)行棧理解作用域理解數(shù)據(jù)類型與變量原文發(fā)布在我的公眾號,點(diǎn)擊查看。 這是本系列的第 5 篇文章。 還記得上一篇文章中的閉包嗎?點(diǎn)擊查看文章 理解 JavaScript 閉包 。 在聊 this 之前,先來復(fù)習(xí)一下閉包: var name = Nei...

    zombieda 評論0 收藏0
  • JavaScript閉包,只學(xué)這篇就夠了

    摘要:當(dāng)在中調(diào)用匿名函數(shù)時(shí),它們用的都是同一個閉包,而且在這個閉包中使用了和的當(dāng)前值的值為因?yàn)檠h(huán)已經(jīng)結(jié)束,的值為。最好將閉包當(dāng)作是一個函數(shù)的入口創(chuàng)建的,而局部變量是被添加進(jìn)這個閉包的。 閉包不是魔法 這篇文章使用一些簡單的代碼例子來解釋JavaScript閉包的概念,即使新手也可以輕松參透閉包的含義。 其實(shí)只要理解了核心概念,閉包并不是那么的難于理解。但是,網(wǎng)上充斥了太多學(xué)術(shù)性的文章,對于...

    CoderBear 評論0 收藏0
  • 十分鐘快速了解《你不知道的 JavaScript》(上卷)

    摘要:最近剛剛看完了你不知道的上卷,對有了更進(jìn)一步的了解。你不知道的上卷由兩部分組成,第一部分是作用域和閉包,第二部分是和對象原型。附錄詞法這一章并沒有說明機(jī)制,只是介紹了中的箭頭函數(shù)引入的行為詞法。第章混合對象類類理論類的機(jī)制類的繼承混入。 最近剛剛看完了《你不知道的 JavaScript》上卷,對 JavaScript 有了更進(jìn)一步的了解。 《你不知道的 JavaScript》上卷由兩部...

    趙春朋 評論0 收藏0

發(fā)表評論

0條評論

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