閉包:搞定閉包-閉包體系完整梳理

前言:
問君能有幾多愁,恰似答過閉包后面試官搖搖頭 -- 沃 · 茲?rùn)C(jī)碩德

閉包這個(gè)東西 亡嫌, 面試之中必備的問題之一 嚎于, JavaScript 最關(guān)鍵的底層原理之一 掘而,無(wú)論是從哪個(gè)角度上來(lái)說(shuō),如果想要進(jìn)階為一個(gè)資深jser 于购,那么你都需要完全理解閉包這個(gè)東西∨鬯現(xiàn)在在網(wǎng)上存在非常多的閉包教程,但是我個(gè)人的感覺大多都是些在半路上進(jìn)行講解的教程肋僧,即使背下來(lái)也沒辦法理解斑胜,故而在開發(fā)中或者在面試官連續(xù)的提問之中真的把問題說(shuō)出個(gè)所以然,那么本篇教程的主要目的就是從根源上把閉包的一整套知識(shí)體系梳理給大家嫌吠,所以這篇文章閉包是標(biāo)題止潘,但是我更認(rèn)為這是對(duì)一整套JavaScript程序底層體系的講解。

運(yùn)行一個(gè)函數(shù)

函數(shù)大家肯定熟悉居兆,要是這個(gè)東西你真的不理解的話覆山,請(qǐng)先買本高級(jí)程序看看然后再來(lái)看這篇文章,你以為我要說(shuō)函數(shù) ? 不不不泥栖, 我說(shuō)要說(shuō)的是你知道函數(shù)在被調(diào)用時(shí)發(fā)生了什么不? 這就是一個(gè)函數(shù):

function foo(){
        var hello = "hello world";
        console.log(hello);
}
// 調(diào)用函數(shù) 
foo()

ok , 就這么一段代碼他做了什么簇宽,我不用說(shuō),你也知道吧享,不就是打印了 hello world 的一個(gè)簡(jiǎn)單函數(shù)么魏割,對(duì)但是 too yuang too easy , 你知道咱們?yōu)g覽器的解析器做了些啥不 ? 每段程序的執(zhí)行都是硬件配合軟件最終呈現(xiàn)的結(jié)果 , 這之中有個(gè)非常非常非常重要的東西 內(nèi)存钢颂。

什么是內(nèi)存那 ?

這貨就是內(nèi)存


圖片來(lái)源京東钞它,侵刪

你所有的代碼在執(zhí)行的時(shí)候都會(huì)被塞進(jìn)這里,在本篇文章中你只需要理解到這里就可以了殊鞭,如果需要繼續(xù)理解我會(huì)再單獨(dú)寫一篇關(guān)于內(nèi)存的專題遭垛。

ok 我們接著來(lái)說(shuō),往里面塞數(shù)據(jù)這個(gè)事操灿,究竟怎么塞锯仪, 內(nèi)部的結(jié)構(gòu)是什么樣的?

棧你可以理解為一個(gè)開口向上的容器趾盐,我們將數(shù)據(jù)在開口處放置進(jìn)去庶喜,數(shù)據(jù)則自然下落到結(jié)構(gòu)底部,所以數(shù)據(jù)在棧中的順序是從下至上的救鲤,從底至上的數(shù)據(jù)下標(biāo)分別為 0 久窟, 1 , 2 ... 當(dāng)數(shù)據(jù)已經(jīng)用完了本缠,程序發(fā)出指令需要清空棧內(nèi)存之中的數(shù)據(jù)時(shí)我們刪除的順序是自頂部向下刪除的斥扛,順序?yàn)?... 2 , 1 , 0 。由此我們可以得到規(guī)律棧內(nèi)存數(shù)據(jù)我們遵循的數(shù)據(jù)是先進(jìn)來(lái)的數(shù)據(jù)最后釋放出去丹锹,我們稱此為 FILO (first in last out), 簡(jiǎn)稱先后出稀颁。如果你感覺這個(gè)文字看起來(lái)非常難以理解队他,請(qǐng)看這個(gè)動(dòng)圖,動(dòng)圖中黑色的為棧結(jié)構(gòu)峻村,紅色的表示數(shù)據(jù)麸折,能更直觀的幫你去理解這個(gè)結(jié)構(gòu),當(dāng)然內(nèi)存并不只是有一種結(jié)構(gòu)還有一種樹形結(jié)構(gòu)叫做堆粘昨,我們?cè)诖瞬毁樖銎湓砉柑洌驗(yàn)闀簳r(shí)用不到。

棧模型

@w=200h=200

活動(dòng)對(duì)象-AO(Active Object)

上文說(shuō)到一個(gè)非常重要的概念张肾,就是所有程序在執(zhí)行時(shí)都會(huì)和內(nèi)存產(chǎn)生關(guān)聯(lián)芭析,JavaScript之中函數(shù)執(zhí)行的時(shí)候也會(huì)和內(nèi)存產(chǎn)生很多關(guān)聯(lián), 這個(gè)關(guān)聯(lián)我們現(xiàn)在也只關(guān)注一點(diǎn)吞瞪,就是函數(shù)執(zhí)行時(shí)我們內(nèi)存里面會(huì)儲(chǔ)存些啥馁启。

當(dāng)函數(shù)執(zhí)行的時(shí)候,我們的程序?yàn)榱擞涗浐瘮?shù)內(nèi)部的變量芍秆,所以會(huì)找一塊空間對(duì)這部分?jǐn)?shù)據(jù)進(jìn)行一個(gè)臨時(shí)的存儲(chǔ)惯疙,在使用結(jié)束之后,如果沒用了就刪除掉這部分?jǐn)?shù)據(jù)妖啥。這部分?jǐn)?shù)據(jù)如果我們用JavaScript進(jìn)行表達(dá)的話霉颠,最好的結(jié)構(gòu)就是對(duì)象,我們以對(duì)象的形式對(duì)其進(jìn)行存儲(chǔ)和表示 :

image.png

我們?cè)儆么a去說(shuō)明一下:

function foo(){
        var hello = "hello world";
        console.log(hello);
}
foo()
// 只要是foo() 這段代碼被解析器解析了荆虱,那么調(diào)用內(nèi)存這事就開始了蒿偎。

// 1. 解析器會(huì)在內(nèi)存之中創(chuàng)建一個(gè)臨時(shí)活動(dòng)對(duì)象:

var _temp_Active_Object_foo = {}

// 2. 解析器在解析內(nèi)部代碼 var hello = "hello world"時(shí),會(huì)在這個(gè)對(duì)象上添加一個(gè)屬性怀读,hello  值為 "hello world";

_temp_Active_Object_foo.hello = "hello world";

// 3. 解析器在解析內(nèi)部代碼console.log(hello),檢索到了hello變量的引用诉位,雖然看起來(lái)我們是在使用hello變量可是實(shí)際上我們引用的是活動(dòng)對(duì)象之中的屬性:

console.log(_temp_Active_Object_foo.hello);

//4. 函數(shù)執(zhí)行完畢,在棧內(nèi)存之中釋放掉這個(gè)活動(dòng)對(duì)象 

delete window._temp_Active_Object_foo

好了菜枷,這下我們把這個(gè)內(nèi)容大概說(shuō)清楚了苍糠,如果沒有看明白建議仔細(xì)閱讀流程圖和代碼,直到你把這兩部分的內(nèi)容完全記憶下來(lái)犁跪,這樣你就可以繼續(xù)進(jìn)行下面的學(xué)習(xí)了椿息,你距離學(xué)會(huì)整套閉包的體系還有一步之遙歹袁。

兩個(gè)函數(shù)的嵌套

ok,根據(jù)前面的知識(shí)講解坷衍,我們已經(jīng)明白了一個(gè)函數(shù)執(zhí)行起來(lái)配合內(nèi)存會(huì)做哪些事情,可是總會(huì)感覺學(xué)習(xí)這些東西有啥用条舔,其實(shí)你可以把這些知識(shí)模塊當(dāng)成是一個(gè)又一個(gè)的樂高積木我們正努力把這些東西組裝成我們想要的結(jié)構(gòu)枫耳。

回到主題,我們現(xiàn)在要去研究的就是兩個(gè)函數(shù)的嵌套孟抗,外部函數(shù)我們?nèi)∶?outer , 內(nèi)部函數(shù)我們?nèi)∶鹖nner :

    function outer(){
        function inner(){
        }
    }
    outer()

結(jié)構(gòu)上大體定在這里迁杨,我們根據(jù)上面所學(xué)簡(jiǎn)單發(fā)散一下我們的思維钻心,在外部函數(shù)執(zhí)行的時(shí)候我們做了哪些事情。

    function outer(){
        function inner(){
        }
    }
    outer()
    //1.在內(nèi)存之中創(chuàng)建一個(gè)活動(dòng)對(duì)象 
    var _temp_Active_Object_outer = {};
    //2.在這個(gè)活動(dòng)對(duì)象上去放一個(gè)屬性
    _temp_Active_Object_outer.inner = function(){}

總結(jié)下這段代碼 : 一個(gè)活動(dòng)對(duì)象之中放入了一個(gè)函數(shù)(引用類型)铅协,而不再是具體的值 捷沸, 這又有什么關(guān)系那。你可不能忘了狐史,這個(gè)活動(dòng)對(duì)象是怎么生成的痒给,是由函數(shù)生成的,也就是說(shuō)這個(gè)活動(dòng)對(duì)象之中存在一個(gè)可以創(chuàng)建活動(dòng)對(duì)象的玩意骏全〔园兀可以這么理解,平日里你家人給你發(fā)生活費(fèi)的時(shí)候就一個(gè)紅包姜贡,點(diǎn)一下收一次錢就可以了试吁,這次給你發(fā)的紅包點(diǎn)完開之后不僅顯示收錢了,又給你彈出一個(gè)新的紅包楼咳,上面寫著個(gè)開熄捍,你要不要點(diǎn) ? 點(diǎn)了紅包就打開了潘多拉魔盒,發(fā)現(xiàn)了新大陸母怜,原來(lái)紅包還可以這么玩治唤?

是啊,函數(shù)還可以這么玩糙申。

好的讓我們?cè)龠M(jìn)一步 :

   function outer(){
        //新增一個(gè)外部函數(shù)中的變量
        var freeVar = "something"
        function inner(){
            //在內(nèi)部函數(shù)引用freeVar
            console.log(freeVar);
        }
        // 最后將這個(gè)結(jié)果返回
        return inner
    }
    //在外部接受代碼
   var inner =  outer()

其實(shí)在這個(gè)時(shí)候宾添,我們已經(jīng)使用了閉包,為什么那柜裸?簡(jiǎn)單來(lái)說(shuō)閉包其實(shí)就是:

  1. 在外部函數(shù)聲明的變量在內(nèi)部函數(shù)被引用了
  2. 在外部函數(shù)的時(shí)候缕陕,把內(nèi)部函數(shù)返回出去,在全局接收疙挺。

簡(jiǎn)單的理解先到這里扛邑,下次我會(huì)談一談關(guān)于閉包的實(shí)際應(yīng)用及學(xué)習(xí)內(nèi)存部分知識(shí)的意義。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末铐然,一起剝皮案震驚了整個(gè)濱河市蔬崩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌搀暑,老刑警劉巖沥阳,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異自点,居然都是意外死亡桐罕,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)功炮,“玉大人溅潜,你說(shuō)我怎么就攤上這事⌒椒” “怎么了滚澜?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)嫁怀。 經(jīng)常有香客問我博秫,道長(zhǎng),這世上最難降的妖魔是什么眶掌? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任挡育,我火速辦了婚禮,結(jié)果婚禮上朴爬,老公的妹妹穿的比我還像新娘即寒。我一直安慰自己,他們只是感情好召噩,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布母赵。 她就那樣靜靜地躺著,像睡著了一般具滴。 火紅的嫁衣襯著肌膚如雪凹嘲。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天构韵,我揣著相機(jī)與錄音周蹭,去河邊找鬼。 笑死疲恢,一個(gè)胖子當(dāng)著我的面吹牛凶朗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播显拳,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼棚愤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了杂数?” 一聲冷哼從身側(cè)響起宛畦,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎揍移,沒想到半個(gè)月后次和,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡羊精,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年斯够,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喧锦。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡读规,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出燃少,到底是詐尸還是另有隱情束亏,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布阵具,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏豺旬。R本人自食惡果不足惜咖为,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望帘皿。 院中可真熱鬧东跪,春花似錦、人聲如沸鹰溜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)曹动。三九已至斋日,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間墓陈,已是汗流浹背恶守。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贡必,地道東北人熬的。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像赊级,于是被迫代替她去往敵國(guó)和親押框。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344