您好,登錄后才能下訂單哦!
本篇內容介紹了“怎么掌握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種基本數據類型:Undefined、Null、Boolean、 Number和String。這5種基本數據類型的值在內存中分別占有固定大小的空間,因此可以把它們的值保存在棧內存。
如果賦給變量的是一個引用類型的值,則必須在堆內存中為這個值分配空間。由于這種值的大小不固定,因此不能把它們保存到棧內存中。但內存地址的 大小 是固定的,因此可以將內存地址保存在棧內存中。這樣,當查詢引用類型的變量時,就可以首先從棧中讀取內存地址,然后再“順藤摸瓜”地找到保存在堆中的值。
保存在棧內存中的每個值,分別占據著固定大小的空間,可以按照順序來訪問它們。如果棧內存中保存的是一塊內存的地址,則這個值就像是一個指向對象在堆內存中位置的指針。保存在堆內存中的數據不是按順序訪問的,因為每個對象所需要的空間并不相等。
當從一個變量向另一個變量復制引用類型的值時,同樣也會將儲存在棧中的值復制一份放到為新變量分配的空間中。不同的是,這個值的副本實際上是一個指針,而這個指針指向存儲在堆中的一個對象。復制操作結束后,兩個變量實際上將引用同一個對象。因此,改變其中一個變量,就會影響到另一個變量。
typeof操作符是確定一個變量是字符串、數值、布爾 值,還是undefined基本數據類型的***工具。檢測引用類型的值時,ECMAScript提供了instanceof操作符。
四、閉包
只要存在調用內部函數的可能,JavaScript就需要保留被引用的函數。而且JavaScript運行時需要跟蹤引用這個內部函數的所有變量,直到***一個變量廢棄,JavaScript的垃圾收集器才能釋放相應的內存空間(紅色部分是理解閉包的關鍵)。
閉包***用處有兩個,一個是可以讀取函數內部的變量,另一個就是讓這些變量的值始終保持在內存中。
使用閉包的注意點
1)由于閉包會使得函數中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存泄露。解決方法是,在退出函數之前,將不使用的局部變量全部刪除。
2)閉包會在父函數外部,改變父函數內部變量的值。所以,如果你把父函數當作對象(object)使用,把閉包當作它的公用方法(Public Method),把內部變量當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數內部變量的值。
閉包一些例子:
“怎么掌握js作用域鏈、內存回收、變量、閉包”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。