搭建Manven環境教程在idea 2021.1版本下
1、js棧記憶體和堆記憶體的區別?
首先JavaScript中的變數分為基本型別和引用型別。基本型別就是儲存在棧記憶體中的簡單資料段,而引用型別指的是那些儲存在堆記憶體中的物件。
(1)基本型別
基本型別有Undefined、Null、Boolean、Number 和String。這些型別在記憶體中分別佔有固定大小的空間,他們的值儲存在棧空間,我們通過按值來訪問的。
(2)引用型別
引用型別,值大小不固定,棧記憶體中存放地址指向堆記憶體中的物件。是按引用訪問的。如下圖所示:棧記憶體中存放的只是該物件的訪問地址,在堆記憶體中為這個值分配空間。由於這種值的大小不固定,因此不能把它們儲存到棧記憶體中。但記憶體地址大小的固定的,因此可以將記憶體地址儲存在棧記憶體中。 這樣,當查詢引用型別的變數時, 先從棧中讀取記憶體地址, 然後再通過地址找到堆中的值。對於這種,我們把它叫做按引用訪問當我們看到一個變數型別是已知的,就分配在棧裡面,比如INT,Double等。其他未知的型別,比如自定義的型別,因為系統不知道需要多大,所以程式自己申請,這樣就分配在堆裡面。基本型別大小固定,引用型別大小不固定,分開存放使得程式執行佔用記憶體最小。
(3)棧記憶體:存放基本型別。 堆記憶體:存放引用型別(在棧記憶體中存一個基本型別值儲存物件在堆記憶體中的地址,用於引用這個物件。)
(4)基本型別在當前執行環境結束時銷燬,而引用型別不會隨執行環境結束而銷燬,只有當所有引用它的變數不存在時這個物件才被垃圾回收機制回收。
基本資料型別
var a = 3;
var b = a;
b = 5;
console.log(a); // 3
console.log(b); // 5
可以看到的是對於基本型別來說,我們將一個基本型別的值賦予 a 變數,接著將 a 的值賦予變數 b ;然後我們修改 b ;可以看到 b 被修改了,而 a 的值沒有被修改,兩個變數都使用的是獨立的資料;
資料引用型別
var obj1 = { a: 1, b: 2, c: 3 } var obj2 = obj1; obj2.a = 5; console.log(obj1.a); // 5 console.log(obj2.a); // 5
可以看到的是,兩個物件的值全部被修改了
物件是引用型別的值,對於引用型別來說,我們將 obj1 賦予 obj2 的時候,我們其實僅僅只是將 obj1 儲存在棧堆中的的引用賦予了 obj2 ,而兩個物件此時指向的是在堆記憶體中的同一個資料,所以當我們修改任意一個值的時候,修改的都是堆記憶體中的資料,而不是引用,所以只要修改了,同樣引用的物件的值也自然而然的發生了改變
我們想要改變新的陣列(物件)的時候,不改變原陣列(物件),就需要用到深拷貝。
arr=[100, [{a : 'hello'}, {b : "world"}], { c: "123456789" }]; //判斷修改的是不是'object'或者null,如果不是 object 或者 null 那麼直接返回 function deepClone(obj = {}) { if (typeof obj !== 'object' || obj == null) { return obj; } let result; //判斷上面下來的obj是不是陣列 用instanceof來檢測 因為是陣列應用型別 obj instanceof Array?result=[]:result={} for (var item in obj) { //查詢一個物件是否有某個屬性 if (obj.hasOwnProperty(item)) { // 遞迴呼叫 result[item] = deepClone(obj[item]) } } return result; } let arr1=deepClone(arr); arr1[1][0].a='vue' arr1[0]=99 console.log('原陣列',arr) console.log('新陣列',arr1)
深拷貝作用在引用型別上!例如:Object,Array
深拷貝不會拷貝引用型別的引用,而是將引用型別的值全部拷貝一份,形成一個新的引用型別,這樣就不會發生引用錯亂的問題,使得我們可以多次使用同樣的資料,而不用擔心資料之間會起衝突。