js中的棧與堆的講解 基本資料型別與引用型別的講解

2021-08-10 16:59:39 字數 3003 閱讀 3947

1、

棧(stack)

和堆(heap)

stack為自動分配的記憶體空間,它由系統自動釋放;而heap則是動態分配的記憶體,大小不定也不會自動釋放。       

2、基本型別和引用型別

基本型別:存放在棧記憶體中的簡單資料段,資料大小確定,記憶體空間大小可以分配。

5種基本資料型別有undefined、null、boolean、numberstring,它們是直接按值存放的,所以可以直接訪問。

引用型別:存放在堆記憶體中的物件,變數實際儲存的是乙個指標,這個指標指向另乙個位置。每個空間大小不一樣,要根據情況開進行特定的分配。

當我們需要訪問引用型別(如物件,陣列,函式等)的值時,首先從棧中獲得該物件的位址指標,然後再從堆記憶體中取得所需的資料。

3、傳值與傳址

前面之所以要說明什麼是記憶體中的堆、棧以及變數型別,實際上是為下文服務的,就是為了更好的理解什麼是「淺拷貝」和「深拷貝」。

基本型別與引用型別最大的區別實際就是傳值與傳址的區別。測試用例:

1     var a = [1,2,3,4,5];

2 var b =a;//傳址 ,物件中傳給變數的資料是引用型別的,會儲存在堆中; 3 var c = a[0];//傳值,把物件中的屬性/陣列中的陣列項賦值給變數,這時變數c是基本資料型別,儲存在棧記憶體中;改變棧中的資料不會影響堆中的資料 4 alert(b);//1,2,3,4,5 5 alert(c);//1 6 //改變量值 7 b[4] = 6; 8 c = 7; 9 alert(a[4]);//6 10 alert(a[0]);//1

從上面我們可以得知,當我改變b中的資料時,a中資料也發生了變化;但是當我改變c的資料值時,a卻沒有發生改變。

這就是傳值與傳址的區別。因為a是陣列,屬於引用型別,所以它賦予給b的時候傳的是棧中的位址(相當於新建了乙個不同名「指標」),而不是堆記憶體中的物件。而c僅僅是從a堆記憶體中獲取的乙個資料值,並儲存在棧中。所以b修改的時候,會根據位址回到a堆中修改,c則直接在棧中修改,並且不能指向a堆記憶體中。

3、淺拷貝

前面已經提到,在定義乙個物件或陣列時,變數存放的往往只是乙個位址。當我們使用物件拷貝時,如果屬性是物件或陣列時,這時候我們傳遞的也只是乙個位址。因此子物件在訪問該屬性時,會根據位址回溯到父物件指向的堆記憶體中,即父子物件發生了關聯,兩者的屬性值會指向同一記憶體空間。

1   var a = 4 functioncopy(p) ; 6 for (var i inp)  9 returnc; 10 } 11 a.key2 = ['小輝','小輝']; 12 var b =copy(a); 13    b.key3 = '33333'; 14 alert(b.key1); //1111111 15 alert(b.key3); //33333 16 alert(a.key3); //undefined

a物件中key1屬性是字串,key2屬性是陣列。a拷貝到b,12屬性均順利拷貝。給b物件新增乙個字串型別的屬性key3時,b能正常修改,而a中無定義。說明子物件的key3(基本型別)並沒有關聯到父物件中,所以undefined。

1 b.key2.push("大輝");

2 alert(b.key2); //小輝,小輝,大輝

3 alert(a.key2); //小輝,小輝,大輝

但是,若修改的屬性變為物件或陣列時,那麼父子物件之間就會發生關聯。從以上彈出結果可知,我對b物件進行修改,a、b的key2屬性值(陣列)均發生了改變。其在記憶體的狀態,可以用下圖來表示。

原因是key1的值屬於基本型別,所以拷貝的時候傳遞的就是該資料段;但是key2的值是堆記憶體中的物件,所以key2在拷貝的時候傳遞的是指向key2物件的位址,無論複製多少個key2,其值始終是指向父物件的key2物件的記憶體空間。

4、深拷貝

或許以上並不是我們在實際編碼中想要的結果,我們不希望父子物件之間產生關聯,那麼這時候可以用到深拷貝。既然屬性值型別是陣列和或象時只會傳址,那麼我們就用遞迴來解決這個問題,把父物件中所有屬於物件的屬性型別都遍歷賦給子物件即可。測試**如下:

1   functioncopy(p, c) ; 3 for (var i inp) ; 6 copy(p[i], c[i]); 7   } else 10 } 11 returnc; 12 } 13 a.key2 = ['小輝','小輝']; 14 var b={}; 15 b =copy(a,b); 16 b.key2.push("大輝"); 17 alert(b.key2); //小輝,小輝,大輝 18 alert(a.key2); //小輝,小輝

由上可知,修改b的key2陣列時,沒有使a父物件中的key2陣列新增乙個值,即子物件沒有影響到父物件a中的key2。其儲存模式大致如下:

堆與棧的區別(經典講解)

摘要 對於堆和棧,很多朋友都是不怎麼理解的,就算是開發了程式多年的朋友都會容易混淆。其實要區分它們並不難,但是怎樣使自己永久不會忘記哪得有技巧了。我相信,通過下面經典的講解,您一定不會再忘記堆和棧的區別了。對於堆和棧,很多朋友都是不怎麼理解的,就算是開發了程式多年的朋友都會容易混淆。其實要區分它們並...

堆與棧的區別(經典講解)

摘要 對於堆和棧,很多朋友都是不怎麼理解的,就算是開發了程式多年的朋友都會容易混淆。其實要區分它們並不難,但是怎樣使自己永久不會忘記哪得有技巧了。我相信,通過下面經典的講解,您一定不會再忘記堆和棧的區別了。對於堆和棧,很多朋友都是不怎麼理解的,就算是開發了程式多年的朋友都會容易混淆。其實要區分它們並...

js中的堆和棧

今天又去溫故了一下堆和棧,就記錄一下自己的理解吧 說堆和棧之前先說說js的資料型別 基本資料型別 number,string,boolean,null,undefined 復合資料型別 object,array 我們的基本資料型別就是儲存在棧中的 eg var name 張三 var copynam...