摘要:第二段代碼由于匿名函數(shù)并沒有被外的其他地方所引用,所以在函數(shù)執(zhí)行完畢后,其活動(dòng)對象也跟隨的執(zhí)行環(huán)境的銷毀而銷毀。
話不多說先來看兩段代碼
function a(){ var num=10; return function(){ console.log(num++) } } var b=a(); b(); //10 b(); //11 b(); //12 b=null; //手動(dòng)釋放內(nèi)存,消除對匿名函數(shù)的引用
function a(){ var num=10; return function(){ console.log(num++) } } a()(); //10 a()(); //10 a()(); //10
下面開始講解代碼:
在講解之前,首先請了解一下關(guān)于函數(shù)作用域方面的知識,可以參考本人之前寫的一片短文https://segmentfault.com/a/11...
//當(dāng)函數(shù)a定義時(shí) 會創(chuàng)建一個(gè)[[scope]]屬性,僅供javascript引擎內(nèi)部使用 //偽代碼 a.[[scope]]={ GO:{ //全局對象globel object this:window, window:{...}, document:{...}, a:(function) ... } }
當(dāng)函數(shù)a調(diào)用的時(shí)候,會創(chuàng)建一個(gè)a的執(zhí)行環(huán)境,每個(gè)執(zhí)行環(huán)境對應(yīng)一個(gè)變量對象。首先會創(chuàng)一個(gè)它自己的活動(dòng)對象【Activation Object】(這個(gè)對象中包含了this、參數(shù)(arguments)、局部變量(包括命名的參數(shù))的定義,當(dāng)然全局對象是沒有arguments的)和一個(gè)變量對象的作用域鏈[[scope chain]],然后,把這個(gè)執(zhí)行環(huán)境的[[scope]]按順序復(fù)制到[[scope chain]]里,最后把這個(gè)活動(dòng)對象推入到[[scope chain]]的頂部。這樣[[scope chain]]就是一個(gè)有序的棧,這樣保了對執(zhí)行環(huán)境有權(quán)訪問的所有變量和對象的有序訪問。
//函數(shù)調(diào)用時(shí)候 a.ex={ //a的執(zhí)行環(huán)境,包括a的活動(dòng)對象和a的作用域鏈 AO:{ this:window, arguments:[], num:undefined }, [[scope chain]]:{ AO:當(dāng)前函數(shù)活動(dòng)對象, GO:{...} //全局對象,從a.[[scope]]中復(fù)制過來的 } //進(jìn)入a的執(zhí)行環(huán)境時(shí),匿名函數(shù)被定義. 匿名函數(shù).[[scope]]={ AO:{ //函數(shù)a的活動(dòng)對象 this:window, arguments:[], num:undefined }, GO:{...} }
關(guān)鍵點(diǎn)來了
上述兩段代碼中:
第一段代碼在執(zhí)行a()的時(shí)候,將a函數(shù)返回的匿名函數(shù)賦給了變量b,并且連續(xù)調(diào)用三次b
第二段代碼在執(zhí)行a()的時(shí)候,沒有對a函數(shù)返回的匿名函數(shù)進(jìn)行賦值。
在Javascript中,如果一個(gè)對象不再被引用,那么這個(gè)對象就會被GC回收。如果兩個(gè)對象互相引用,而不再被第3者所引用,那么這兩個(gè)互相引用的對象也會被回收。
第一段代碼因?yàn)楹瘮?shù)a的活動(dòng)對象被匿名函數(shù)的[[scope]]引用,匿名函數(shù)又被a外的變量b引用,所以在全局環(huán)境下始終保持對a活動(dòng)對象的引用,所以a的活動(dòng)對象無法被回收。
第二段代碼由于匿名函數(shù)并沒有被a外的其他地方所引用,所以在函數(shù)a執(zhí)行完畢后,其活動(dòng)對象也跟隨a的執(zhí)行環(huán)境的銷毀而銷毀。
用圖表示
值得注意的是,雖然執(zhí)行環(huán)境和函數(shù)scope屬性中都保存這作用域鏈,但這兩個(gè)并不是一個(gè)性質(zhì)的。
明確一點(diǎn)區(qū)別
[[Scope]]屬性是函數(shù)創(chuàng)建時(shí)產(chǎn)生的,會一直存在
而執(zhí)行環(huán)境在函數(shù)執(zhí)行時(shí)產(chǎn)生,函數(shù)執(zhí)行結(jié)束便會銷毀
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/81105.html
摘要:之前一篇文章我們詳細(xì)說明了變量對象,而這里,我們將詳細(xì)說明作用域鏈。而的作用域鏈,則同時(shí)包含了這三個(gè)變量對象,所以的執(zhí)行上下文可如下表示。下圖展示了閉包的作用域鏈。其中為當(dāng)前的函數(shù)調(diào)用棧,為當(dāng)前正在被執(zhí)行的函數(shù)的作用域鏈,為當(dāng)前的局部變量。 showImg(https://segmentfault.com/img/remote/1460000008329355);初學(xué)JavaScrip...
摘要:關(guān)于循環(huán)和閉包當(dāng)循環(huán)和閉包結(jié)合在一起時(shí),經(jīng)常會產(chǎn)生讓初學(xué)者覺得匪夷所思的問題。閉包是一把雙刃劍是比較難以理解和掌握的部分,它十分強(qiáng)大,卻也有很大的缺陷,如何使用它完全取決于你自己。 在談閉包之前,我們首先要了解幾個(gè)概念: 什么是函數(shù)表達(dá)式? 與函數(shù)聲明有何不同? JavaScript查找標(biāo)識符的機(jī)制 JavaScript的作用域是詞法作用域 JavaScript的垃圾回收機(jī)制 先來...
摘要:然而,引擎很可能雖然這要看具體實(shí)現(xiàn)將會仍然將這個(gè)結(jié)構(gòu)保持一段時(shí)間,因?yàn)楹瘮?shù)在整個(gè)作用域上擁有一個(gè)閉包。 內(nèi)容 平時(shí)編寫代碼的時(shí)候很少關(guān)注細(xì)節(jié),對javascript深層也沒具體了解,下面針對平時(shí)寫代碼的形式分析、調(diào)整完善自己的代碼,這里以一個(gè)簡單例子分析js作用域和垃圾回收機(jī)制,通過塊級作用域處理一些細(xì)節(jié),提升自己代碼性能。 普通案例 在日常中最常見的代碼編寫方式: function ...
摘要:因此,所有在方法中定義的變量都是放在棧內(nèi)存中的當(dāng)我們在程序中創(chuàng)建一個(gè)對象時(shí),這個(gè)對象將被保存到運(yùn)行時(shí)數(shù)據(jù)區(qū)中,以便反復(fù)利用因?yàn)閷ο蟮膭?chuàng)建成本通常較大,這個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)就是堆內(nèi)存。 上一篇:《javascript高級程序設(shè)計(jì)》筆記:繼承近幾篇博客都會圍繞著圖中的知識點(diǎn)展開 showImg(https://segmentfault.com/img/bVY0C4?w=1330&h=618);...
閱讀 2778·2021-11-19 11:30
閱讀 3064·2021-11-15 11:39
閱讀 1785·2021-08-03 14:03
閱讀 1992·2019-08-30 14:18
閱讀 2048·2019-08-30 11:16
閱讀 2159·2019-08-29 17:23
閱讀 2603·2019-08-28 18:06
閱讀 2539·2019-08-26 12:22