JavaScript高級程序設計筆記4

變量可能包含兩種不同數(shù)據(jù)類型的值:基本類型值和引用類型值。

基本類型值:簡單數(shù)據(jù)段

五種基本數(shù)據(jù)類型是按值訪問的,因為可以操作保存在變量值得實際的值。

引用類型值:可能由多個值構成的對象

引用類型的值是保存在內(nèi)存中的對象。與其他語言不同,js不允許直接訪問內(nèi)存中的位置,也就是說不能直接操作對象的內(nèi)存空間。在操作對象時,實際上是在操作對象的引用而不是實際的對象。因此,引用類型的值是按引用訪問的。

1.只能給引用類型值動態(tài)地添加屬性。

2.上面說的是保存的方式不同,在從一個變量向另一個變量復制基本類型值和引用類型值時,也存在不同。

從一個變量向另一個變量復制基本類型值時,會在變量對象上創(chuàng)建一個新值,然后把該值復制到為新變量分配的位置上,這兩個變量可以參與任何操作而不會相互影響。

復制基本類型值

從一個變量向另一個變量復制引用類型的值時,同樣也會將存儲在變量對象中的值復制一份放到位新變量分配的空間中。不同的是,這個值的副本實際上是一個指針,而這個指針指向存儲在堆中的一個對象。復制操作結(jié)束后,兩個變量實際上將引用同一個對象,因此,改變其中一個變量,就會影響另一個變量。


復制引用類型值


示意圖

3.傳遞參數(shù)

所有函數(shù)的參數(shù)都是按值傳遞的。也就是說,把函數(shù)外部的值復制給函數(shù)內(nèi)部的參數(shù),就和把值從一個變量復制到另一個變量一樣?;绢愋椭档膫鬟f如同基本類型變量的復制一樣,引用類型值的傳遞如同引用類型變量的復制一樣。

訪問變量有按值和按引用兩種方式,而參數(shù)只能按值傳遞。

在向參數(shù)傳遞基本類型的值時,被傳遞的值會被復制給另一個局部變量(即命名參數(shù),或者說是arguments對象中的一個元素)。在向參數(shù)傳遞引用類型的值時,會把這個值在內(nèi)存中的地址復制給一個局部變量,因此這個局部變量的變化會反映在函數(shù)的外部。

4.檢測類型

檢測一個變量是不是基本數(shù)據(jù)類型:typeof操作符是最佳的工具

檢測引用類型的值時,instanceof操作符,如果變量時給定引用類型的實例,那么instanceof操作符就會返回true

執(zhí)行環(huán)境及作用域

在web瀏覽器中,全局執(zhí)行環(huán)境被認為是window對象,因此所有全局變量和函數(shù)都是作為window對象的屬性和方法創(chuàng)建的。

某個執(zhí)行環(huán)境的所以代碼執(zhí)行完畢后,該環(huán)境被銷毀,保存在其中的所有變量和函數(shù)定義也隨之銷毀(全局執(zhí)行環(huán)境直到應用程序退出-例如關閉網(wǎng)頁或瀏覽器-時才會被銷毀)

每個函數(shù)都有自己的執(zhí)行環(huán)境。當執(zhí)行流進入一個函數(shù)時,函數(shù)的環(huán)境就會被推入一個環(huán)境棧中,而在函數(shù)執(zhí)行之后,棧將其環(huán)境彈出,把控制權返回給之前的執(zhí)行環(huán)境。

當代碼在一個環(huán)境中執(zhí)行時,會創(chuàng)建變量對象的一個作用域鏈。作用域鏈的用途,是保證對執(zhí)行環(huán)境有權訪問的所有變量和函數(shù)的有序訪問。作用域鏈的前端,始終都是當前執(zhí)行的代碼所在環(huán)境的變量對象。如果這個環(huán)境是函數(shù),則將其活動對象作為變量對象。

作用域鏈中的下一個變量對象來自包含(外部)環(huán)境,而再下一個變量對象則來自下一個包含環(huán)境。這樣,一直延續(xù)到全局執(zhí)行環(huán)境,全局執(zhí)行環(huán)境的變量對象始終都是作用域鏈中的最后一個對象。



執(zhí)行環(huán)境的類型共有兩種:全局和局部,但還是有辦法來延長作用域鏈。

沒有塊級作用域

在c++中,color會在if語句執(zhí)行完畢后被銷毀,在js中,if語句中的變量聲明會將變量添加到當前的執(zhí)行環(huán)境(在這里是全局環(huán)境)中。for語句更要牢記這一點。

1.聲明變量

使用var聲明的變量會自動被添加到最接近的環(huán)境中。在函數(shù)內(nèi)部,最接近的環(huán)境就是函數(shù)的局部環(huán)境;在with語句中,最接近的環(huán)境是函數(shù)環(huán)境。如果初始化變量時沒有使用var聲明,該變量會自動地被添加到全局環(huán)境。

2.查詢標識符

當在某個環(huán)境中為了讀取或?qū)懭攵靡粋€標識符時,必須通過搜索來確定該標識符實際代表什么。搜索過程從作用域鏈的前端開始,向上逐級查詢與給定名字匹配的標識符。如果在局部環(huán)境中找到了該標識符,搜索過程停止,變量就緒,如果在局部環(huán)境中沒有找到該變量名,則繼續(xù)沿作用域鏈向上搜索,搜索過程將一直追溯到全局環(huán)境的變量對象

如果在局部環(huán)境中找到了那個變量名,但是想訪問全局環(huán)境下的此變量,可以使用window.變量名來訪問全局變量。

3.垃圾收集

js具有自動垃圾收集機制,即執(zhí)行環(huán)境會負責管理代碼執(zhí)行過程中使用的內(nèi)存。

而在c和c++之類的語言中,開發(fā)人員的一項基本任務就是手動跟蹤內(nèi)存的使用情況,這是造成許多問題的一個根源。

在編寫js程序時,開發(fā)人員不用再關心內(nèi)存使用問題,所需內(nèi)存的分配以及無用內(nèi)存的回收完全實現(xiàn)了自動管理。

這種垃圾收集機制的原理其實很簡單:找出那些不再繼續(xù)使用的變量,然后釋放其占用的內(nèi)存。為此,垃圾收集器會按照固定的時間間隔(或代碼執(zhí)行中預定的收集時間),周期性地執(zhí)行這一操作。

函數(shù)中局部變量的正常生命周期:

局部變量只在函數(shù)執(zhí)行的過程中存在。而在這個過程中,會為局部變量在棧(或堆)內(nèi)存上分配相應的空間,以便存儲他們的值。然后在函數(shù)中使用這些變量,直至函數(shù)執(zhí)行結(jié)束。此時,局部變量就沒有存在的必要了,因此可以釋放他們的內(nèi)存以供將來使用。在這種情況下,很容易判斷變量是否還有存在的必要;但并非所有情況下都這么容易就能得出結(jié)論。垃圾收集器必須跟蹤哪個變量有用哪個變量沒用,對于不再有用的變量打上標記,以備將來收回其占用的內(nèi)存。用于標識無用變量的策略可能會因?qū)崿F(xiàn)而異,但具體到瀏覽器中的實現(xiàn),則通常有兩個策略。

(1)標記清除,js中最常用的垃圾收集方式。當變量進入環(huán)境時,就將這個變量標記為“進入環(huán)境”。從邏輯上講,永遠不能釋放進入環(huán)境的變量所占用的內(nèi)存,因為只要執(zhí)行流進入相應的環(huán)境,就可能會用到他們。而當變量離開環(huán)境時,則將其標記為“離開環(huán)境”。

(2)引用計數(shù),不太常見的垃圾收集策略。引用計數(shù)的含義是跟蹤記錄每個值被引用的次數(shù)。當聲明了一個變量并將一個引用類型值賦給該變量時,則這個值得引用次數(shù)就是1.如果同一個值又被賦給另一個變量,則該值的引用次數(shù)加1。相反,如果包含對這個值引用的變量又取得了另外一個值,則這個值得引用次數(shù)減1。當這個值得引用次數(shù)變成0時,則說明沒有辦法再訪問這個值了,因而就可以將其占用的內(nèi)存空間回收回來。這樣,當垃圾收集器下次再運行時,它就會釋放那些引用次數(shù)為零的值所占用的內(nèi)存。

(3)性能問題

垃圾收集的時間間隔

(4)管理內(nèi)存

解除引用



?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容