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