js 範圍鏈&記憶體回收&變數&閉包

來源:互聯網
上載者:User

js 範圍鏈&記憶體回收&變數&閉包

閉包主要涉及到js的幾個其他的特性:範圍鏈,垃圾(記憶體)回收機制,函數嵌套,等等

一、範圍鏈:函數在定義的時候建立的,用於尋找使用到的變數的 值的一個索引,而他內部的規則是,把函數自身的本地變數放在最前面,把自身的父級函數中的變數放在其次,把再高一級函數中的變數放在更後面,以此類推直至 全域對象為止.當函數中需要查詢一個變數的值的時候,js解譯器會去範圍鏈去尋找,從最前面的本地變數中先找,如果沒有找到對應的變數,則到下一級的鏈 上找,一旦找到了變數,則不再繼續.如果找到最後也沒找到需要的變數,則解譯器返回undefined。

二、記憶體回收機制:一個函數在執行開始的時候,會給其中定義的變 量劃分記憶體空間儲存,以備後面的語句所用,等到函數執行完畢返回了,這些變數就被認為是無用的了.對應的記憶體空間也就被回收了.下次再執行此函數的時候, 所有的變數又回到最初的狀態,重新賦值使用.但是如果這個函數內部又嵌套了另一個函數,而這個函數是有可能在外部被調用到的.並且這個內建函式又使用了外 部函數的某些變數的話.這種記憶體回收機制就會出現問題.如果在外部函數返回後,又直接調用了內建函式,那麼內建函式就無法讀取到他所需要的外部函數中變數 的值了.所以js解譯器在遇到函數定義的時候,會自動把函數和他可能使用的變數(包括本地變數和父級和祖先級函數的變數(自由變數))一起儲存起來.也就 是構建一個閉包,這些變數將不會被記憶體回收器所回收,只有當內部的函數不可能被調用以後(例如被刪除了,或者沒有了指標),才會銷毀這個閉包,而沒有任何 一個閉包引用的變數才會被下一次記憶體回收啟動時所回收。

三、局部變數&全域變數

1、全域global)變數的範圍是全域的,在Javascript中處處有定義;而函數內部聲明的變數是局部local)變數,其範圍是局部性的,只在函數體內部有定義,每次執行該函數時都會建立和破壞該變數。

2、全域變數範圍中使用變數可以不用var語句,但在聲明局部變數是一定要使用var語句,否則會視為對全域變數的引用。

3、

var scope = "local";聲明的變數在整個checkScope函數範圍內都有效,因此第一個document.write(scope);執行的時scope引用的是局部變數,而此時局部變數scope尚未定義,所以輸出”undefined”。好的編程習慣是將所有的變數聲明集中起來放在函數的開頭。document.write(window.scope)//輸出global

全域變數總是存在於運行期上下文範圍鏈的最末端,因此在標識符解析的時候,尋找全域變數是最慢的。所以,在編寫代碼的時候應盡量少使用全域變 量,儘可能使用局部變數。一個好的經驗法則是:如果一個跨範圍的對象被引用了一次以上,則先把它儲存到局部變數裡再使用(document、 window等)。

在執行JavaScript代碼的過程中,當遇到一個標識符,就會根據標識符的名稱,在執行內容Execution Context)的範圍鏈中進行搜尋。從範圍鏈的第一個對象該函數的Activation Object對象)開始,如果沒有找到,就搜尋範圍鏈中的下一個對象,如此往複,直到找到了標識符的定義。如果在搜尋完範圍中的最後一個對象,也就是 全域對象Global Object)以後也沒有找到,則會拋出一個錯誤,提示使用者該變數未定義undefined)。這是在ECMA-262標準中描述的函數執行模型和標識 符解析Identifier Resolution)的過程。

由ECMA-262標準第三版定義,該內部屬性包含了函數被建立的範圍中對象的集合,這個集合被稱為函數的範圍鏈,它決定了哪些資料能被函數訪問。範圍第一個對象始終是當前執行代碼所在環境的變數對象

function a(x,y){

var b=x+y;

return b;

}

在函數a建立的時候它的範圍鏈填入全域對象,全域對象中有所有全域變數

var tatal=a(5,10);

執行此函數時會建立一個稱為“運行期上下文(execution context)”的內部對象,運行期上下文定義了函數執行時的環境。值按照它們出現在函數中的順序被複製到運行期內容相關的範圍鏈中。它們共同組成了一 個新的對象,叫“使用中的物件(activation object)”,該對象包含了函數的所有局部變數、具名引數、參數集合以及this,然後此對象會被推入範圍鏈的前端,當運行期上下文被銷毀,活動對 象也隨之銷毀。

ECMAScript變數可能包含兩種不同資料類型的值:基本類型值和參考型別值。基本類型值指的是那些儲存在棧記憶體中的簡單資料區段,即這種值 完全 儲存在記憶體中的一個位置。而參考型別值是指那些儲存堆記憶體中的對象,意思是變數中儲存的實際上只是一個指標,這個指標指向記憶體中的另一個位置,該位置儲存 對象。

5種基礎資料型別 (Elementary Data Type):Undefined、Null、Boolean、 Number和String。這5種基礎資料型別 (Elementary Data Type)的值在記憶體中分別佔有固定大小的空間,因此可以把它們的值儲存在棧記憶體。

如果賦給變數的是一個參考型別的值,則必須在堆記憶體中為這個值分配空間。由於這種值的大小不固定,因此不能把它們儲存到棧記憶體中。但記憶體位址的 大小 是固定的,因此可以將記憶體位址儲存在棧記憶體中。這樣,當查詢參考型別的變數時,就可以首先從棧中讀取記憶體位址,然後再“順藤摸瓜”地找到儲存在堆中的值。

儲存在棧記憶體中的每個值,分別佔據著固定大小的空間,可以按照順序來訪問它們。如果棧記憶體中儲存的是一塊記憶體的地址,則這個值就像是一個指向對象在堆記憶體中位置的指標。儲存在堆記憶體中的資料不是按順序訪問的,因為每個對象所需要的空間並不相等。

當從一個變數向另一個變數複製參考型別的值時,同樣也會將儲存在棧中的值複製一份放到為新變數分配的空間中。不同的是,這個值的副本實際上是一個指標,而這個指標指向儲存在堆中的一個對象。複製操作結束後,兩個變數實際上將引用同一個對象。因此,改變其中一個變數,就會影響到另一個變數。

typeof操作符是確定一個變數是字串、數值、布爾 值,還是undefined基礎資料型別 (Elementary Data Type)的最佳工具。檢測參考型別的值時,ECMAScript提供了instanceof操作符。

四、閉包

只要存在調用內建函式的可能,JavaScript就需要保留被引用的函數。而且JavaScript運行時需要跟蹤引用這個內建函式的所有變數,直到最後一個變數廢棄,JavaScript的垃圾收集器才能釋放相應的記憶體空間紅色部分是理解閉包的關鍵)。

閉包最大用處有兩個,一個是可以讀取函數內部的變數,另一個就是讓這些變數的值始終保持在記憶體中。

 

使用閉包的注意點

1)由於閉包會使得函數中的變數都被儲存在記憶體中,記憶體消耗很大,所以不能濫用閉包,否則會造成網頁的效能問題,在IE中可能導致記憶體泄露。解決方案是,在退出函數之前,將不使用的局部變數全部刪除。

2)閉包會在父函數外部,改變父函數內部變數的值。所以,如果你把父函數當作對象object)使用,把閉包當作它的公用方法Public Method),把內部變數當作它的私人屬性private value),這時一定要小心,不要隨便改變父函數內部變數的值。

閉包一些例子:

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.