你真的了解數據在堆棧中的存儲方式嗎?
JavaScript數據類型分為:
分類 | 類型 |
---|---|
原始數據類型(7種) | Number、String、Boolean、Null、Undefined、Symbol、BigInt |
引用數據類型 | Object |
先看兩段程式碼
let num = 1;
let data = num;
data = 2;
console.log('num : ' + num);//num : 1
let obj = {
name : 'obj'
}
let data = obj;
data.name = 'data';
console.log('obj.name : ' + obj.name);//obj.name : data
出現這種情況是由於JavaScript中原始數據類型和引用數據類型存儲的方式不同導致
這裡要引入兩個概念:棧和堆
儲存方式 | 優點 | 缺點 |
---|---|---|
棧(stack) | 存儲大小固定,且具有後進先出的線性操作功能,便於對存儲中的數據進行操作 | 存儲容量小 |
堆(heap) | 存儲容量大 | 存儲大小不固定,在不知道記憶體地址時不易操作存儲中的數據 |
註:這裡的優缺點只是相對而言
再看看
分類 | 特點 |
---|---|
原始數據類型 | 需要記憶體大小固定 |
引用數據類型 | 需要記憶體大小不固定 |
所以原始類型是存儲在棧中的
let num = 1;
let data = num;
data = 2;
console.log('num : ' + num);//num : 1
具體流程如下:
1.在棧中開闢一塊記憶體並將值1存儲於其中,聲明變數num,使num指向新開闢的這塊記憶體地址;
2.在棧中再開闢一塊記憶體,將變數num指向的記憶體中的值複製到新開闢的記憶體中,聲明變數data,使data指向新開闢的這塊記憶體地址;
3.將變數data指向的記憶體中的值置換為2;
4.輸出變數num指向的記憶體中存儲的值。
如圖:
引用數據類型的數據存儲在堆中 同時又把存儲在堆中的數據所處的地址值存儲到棧中
let obj = {
name : 'obj'
}
let data = obj;
data.name = 'data';
console.log('obj.name : ' + obj.name);//obj.name : data
具體流程如下:
1.在堆中開闢一塊記憶體,將對象存儲於其中,再在棧中開闢一塊記憶體,將新開闢的記憶體的地址值存儲到棧中,聲明變數obj,使obj指向棧中新開闢的這塊地址值;
2.在棧中再開闢一塊記憶體,將obj指向的記憶體中的值複製到新開闢的記憶體中來,聲明變數data,使data指向新開闢的這塊記憶體地址;
3.通過變數data指向的棧記憶體中存儲的堆記憶體的地址值,修改堆中數據的name屬性為data;
4.輸出變數obj指向的棧記憶體中存儲的堆記憶體的地址值中的數據name屬性的值。
如圖:
還有有個補充的
let obj = {
name : 'obj'
}
let data = obj;
data = {
name : 'data'
}
console.log('obj.name : ' + obj.name);//obj.name : obj
具體流程如下:
1.在堆中開闢一塊記憶體,將對象存儲於其中,再在棧中開闢一塊記憶體,將新開闢的記憶體的地址值存儲到棧中,聲明變數obj,使obj指向棧中新開闢的這塊地址值;
2.在棧中再開闢一塊記憶體,將obj指向的記憶體中的值複製到新開闢的記憶體中來,聲明變數data,使data指向新開闢的這塊記憶體地址;
3.在堆中開闢一塊記憶體,將對象存儲於其中,將新開闢的記憶體的地址值存儲到變數data指向棧中地址值;
4.輸出變數obj指向的棧記憶體中存儲的堆記憶體的地址值中的數據name屬性的值。
如圖: