您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“怎么掌握js作用域鏈、內(nèi)存回收、變量、閉包”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!
一、作用域鏈:函數(shù)在定義的時候創(chuàng)建的,用于尋找使用到的變量的 值的一個索引,而他內(nèi)部的規(guī)則是,把函數(shù)自身的本地變量放在最前面,把自身的父級函數(shù)中的變量放在其次,把再高一級函數(shù)中的變量放在更后面,以此類推直至 全局對象為止.當函數(shù)中需要查詢一個變量的值的時候,js解釋器會去作用域鏈去查找,從最前面的本地變量中先找,如果沒有找到對應(yīng)的變量,則到下一級的鏈 上找,一旦找到了變量,則不再繼續(xù).如果找到***也沒找到需要的變量,則解釋器返回undefined。
二、內(nèi)存回收機制:一個函數(shù)在執(zhí)行開始的時候,會給其中定義的變 量劃分內(nèi)存空間保存,以備后面的語句所用,等到函數(shù)執(zhí)行完畢返回了,這些變量就被認為是無用的了.對應(yīng)的內(nèi)存空間也就被回收了.下次再執(zhí)行此函數(shù)的時候, 所有的變量又回到最初的狀態(tài),重新賦值使用.但是如果這個函數(shù)內(nèi)部又嵌套了另一個函數(shù),而這個函數(shù)是有可能在外部被調(diào)用到的.并且這個內(nèi)部函數(shù)又使用了外 部函數(shù)的某些變量的話.這種內(nèi)存回收機制就會出現(xiàn)問題.如果在外部函數(shù)返回后,又直接調(diào)用了內(nèi)部函數(shù),那么內(nèi)部函數(shù)就無法讀取到他所需要的外部函數(shù)中變量 的值了.所以js解釋器在遇到函數(shù)定義的時候,會自動把函數(shù)和他可能使用的變量(包括本地變量和父級和祖先級函數(shù)的變量(自由變量))一起保存起來.也就 是構(gòu)建一個閉包,這些變量將不會被內(nèi)存回收器所回收,只有當內(nèi)部的函數(shù)不可能被調(diào)用以后(例如被刪除了,或者沒有了指針),才會銷毀這個閉包,而沒有任何 一個閉包引用的變量才會被下一次內(nèi)存回收啟動時所回收。
三、局部變量&全局變量
1、全局(global)變量的作用域是全局的,在Javascript中處處有定義;而函數(shù)內(nèi)部聲明的變量是局部(local)變量,其作用域是局部性的,只在函數(shù)體內(nèi)部有定義,每次執(zhí)行該函數(shù)時都會創(chuàng)建和破壞該變量。
2、全局變量作用域中使用變量可以不用var語句,但在聲明局部變量是一定要使用var語句,否則會視為對全局變量的引用。
3、
var scope = "local";聲明的變量在整個checkScope函數(shù)作用域內(nèi)都有效,因此***個document.write(scope);執(zhí)行的時scope引用的是局部變量,而此時局部變量scope尚未定義,所以輸出”undefined”。好的編程習慣是將所有的變量聲明集中起來放在函數(shù)的開頭。document.write(window.scope)//輸出global
全局變量總是存在于運行期上下文作用域鏈的最末端,因此在標識符解析的時候,查找全局變量是最慢的。所以,在編寫代碼的時候應(yīng)盡量少使用全局變 量,盡可能使用局部變量。一個好的經(jīng)驗法則是:如果一個跨作用域的對象被引用了一次以上,則先把它存儲到局部變量里再使用(document、 window等)。
在執(zhí)行JavaScript代碼的過程中,當遇到一個標識符,就會根據(jù)標識符的名稱,在執(zhí)行上下文(Execution Context)的作用域鏈中進行搜索。從作用域鏈的***個對象(該函數(shù)的Activation Object對象)開始,如果沒有找到,就搜索作用域鏈中的下一個對象,如此往復(fù),直到找到了標識符的定義。如果在搜索完作用域中的***一個對象,也就是 全局對象(Global Object)以后也沒有找到,則會拋出一個錯誤,提示用戶該變量未定義(undefined)。這是在ECMA-262標準中描述的函數(shù)執(zhí)行模型和標識 符解析(Identifier Resolution)的過程。
由ECMA-262標準第三版定義,該內(nèi)部屬性包含了函數(shù)被創(chuàng)建的作用域中對象的集合,這個集合被稱為函數(shù)的作用域鏈,它決定了哪些數(shù)據(jù)能被函數(shù)訪問。作用域***個對象始終是當前執(zhí)行代碼所在環(huán)境的變量對象
function a(x,y){
var b=x+y;
return b;
}
在函數(shù)a創(chuàng)建的時候它的作用域鏈填入全局對象,全局對象中有所有全局變量
var tatal=a(5,10);
執(zhí)行此函數(shù)時會創(chuàng)建一個稱為“運行期上下文(execution context)”的內(nèi)部對象,運行期上下文定義了函數(shù)執(zhí)行時的環(huán)境。值按照它們出現(xiàn)在函數(shù)中的順序被復(fù)制到運行期上下文的作用域鏈中。它們共同組成了一 個新的對象,叫“活動對象(activation object)”,該對象包含了函數(shù)的所有局部變量、命名參數(shù)、參數(shù)集合以及this,然后此對象會被推入作用域鏈的前端,當運行期上下文被銷毀,活動對 象也隨之銷毀。
ECMAScript變量可能包含兩種不同數(shù)據(jù)類型的值:基本類型值和引用類型值?;绢愋椭抵傅氖悄切┍4嬖跅?nèi)存中的簡單數(shù)據(jù)段,即這種值 完全 保存在內(nèi)存中的一個位置。而引用類型值是指那些保存堆內(nèi)存中的對象,意思是變量中保存的實際上只是一個指針,這個指針指向內(nèi)存中的另一個位置,該位置保存 對象。
5種基本數(shù)據(jù)類型:Undefined、Null、Boolean、 Number和String。這5種基本數(shù)據(jù)類型的值在內(nèi)存中分別占有固定大小的空間,因此可以把它們的值保存在棧內(nèi)存。
如果賦給變量的是一個引用類型的值,則必須在堆內(nèi)存中為這個值分配空間。由于這種值的大小不固定,因此不能把它們保存到棧內(nèi)存中。但內(nèi)存地址的 大小 是固定的,因此可以將內(nèi)存地址保存在棧內(nèi)存中。這樣,當查詢引用類型的變量時,就可以首先從棧中讀取內(nèi)存地址,然后再“順藤摸瓜”地找到保存在堆中的值。
保存在棧內(nèi)存中的每個值,分別占據(jù)著固定大小的空間,可以按照順序來訪問它們。如果棧內(nèi)存中保存的是一塊內(nèi)存的地址,則這個值就像是一個指向?qū)ο笤诙褍?nèi)存中位置的指針。保存在堆內(nèi)存中的數(shù)據(jù)不是按順序訪問的,因為每個對象所需要的空間并不相等。
當從一個變量向另一個變量復(fù)制引用類型的值時,同樣也會將儲存在棧中的值復(fù)制一份放到為新變量分配的空間中。不同的是,這個值的副本實際上是一個指針,而這個指針指向存儲在堆中的一個對象。復(fù)制操作結(jié)束后,兩個變量實際上將引用同一個對象。因此,改變其中一個變量,就會影響到另一個變量。
typeof操作符是確定一個變量是字符串、數(shù)值、布爾 值,還是undefined基本數(shù)據(jù)類型的***工具。檢測引用類型的值時,ECMAScript提供了instanceof操作符。
四、閉包
只要存在調(diào)用內(nèi)部函數(shù)的可能,JavaScript就需要保留被引用的函數(shù)。而且JavaScript運行時需要跟蹤引用這個內(nèi)部函數(shù)的所有變量,直到***一個變量廢棄,JavaScript的垃圾收集器才能釋放相應(yīng)的內(nèi)存空間(紅色部分是理解閉包的關(guān)鍵)。
閉包***用處有兩個,一個是可以讀取函數(shù)內(nèi)部的變量,另一個就是讓這些變量的值始終保持在內(nèi)存中。
使用閉包的注意點
1)由于閉包會使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大,所以不能濫用閉包,否則會造成網(wǎng)頁的性能問題,在IE中可能導(dǎo)致內(nèi)存泄露。解決方法是,在退出函數(shù)之前,將不使用的局部變量全部刪除。
2)閉包會在父函數(shù)外部,改變父函數(shù)內(nèi)部變量的值。所以,如果你把父函數(shù)當作對象(object)使用,把閉包當作它的公用方法(Public Method),把內(nèi)部變量當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數(shù)內(nèi)部變量的值。
閉包一些例子:
“怎么掌握js作用域鏈、內(nèi)存回收、變量、閉包”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。