在學習JS時最讓我頭疼的就是棧和堆以及一切概念性的問題 也是最近才把想給這個搞通提上了日程
簡單來說 深淺拷貝的區別:
A復制了B 當改變 A 中的一個元素 B 中的這個元素也改變了 這就叫做淺拷貝
反之 改變 A 中的元素 B 中的元素並沒有一起改變 這就叫做 深拷貝 深拷貝都是針對於較為復雜的object類型
這個也就要牽扯到棧和堆 以及 數據類型的概念了
JS幾大基本數據類型: Null Undefined Number Boolean String Object Symbol(唯一值) BigInt(ES10未來 任意精度整數)
引用類型:Object類 --- 常規名值對的無序對象{a: 1} 數組:[1, 2] 函數等
1、基本類型 --- 名值都儲存再棧內存中; let a = 1

當 b = a 復制時; 棧內存會新開辟一個內存

所以當你修改 a = 2 時 b 的值並不會發生改變 但這也算不上深拷貝 因為深拷貝都是針對於較為復雜的object類型
2、引用類型 名存棧內存中 值存堆內存中 但是棧內存會提供一個引用地址指向堆內存中的值

所以當 a = b 進行拷貝的時候 復制的是 a 的引用地址 而非堆里面的值

當我們 a [0] = 7 時 由於 a 和 b 指向的都是同一個堆內存值 所以 a 的修改 影響到了 b 這就是所謂的淺拷貝

所以要實現深拷貝 就是要在堆內存中新建一個 b 的堆內存

實現深拷貝
function deepClone(obj){
let a = JSON.stringify(obj);
b = JSON.parse(a)
return b
}
let a = [0, 1, [3,4], 9]
b = deepClone(a)
a[2][0] = 7
console.log(a, b) //[0,1,[7,4],9] [0, 1, [3,4], 9]
JSON.stringify() 和 JSON.parse() 的區別
JSON.stringify() 將對象轉換為 JSON字符串 而 JSON.parse() 則是將JSON字符串轉換為 對象
但是在使用JSON.parse()時 所轉換的JSON字符串必須要符合JOSN格式 即鍵值都需要 "" 進行包裹
let a = '["1","2"]';
let b = "['1','2']";
console.log(JSON.parse(a));// Array [1,2]
console.log(JSON.parse(b));// 報錯

遞歸方式實現:
function deepClone(obj){
let objClone = Array.isArray(obj)?[]:{};
if(obj && typeof obj==="object"){
for(key in obj){
if(obj.hasOwnProperty(key)){
//判斷ojb子元素是否為對象,如果是,遞歸復制
if(obj[key]&&typeof obj[key] ==="object"){
objClone[key] = deepClone(obj[key]);
}else{
//如果不是,簡單復制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
let a=[1,2,3,4],
b=deepClone(a);
a[0]=2;
console.log(a,b);

數組放 splice concat slice 都不是真正的深拷貝 在一級層級是沒問題的 當有二層層級時 就會被影響
let a=[1,2,3,4],
b=a.slice();
a[0]=2;
console.log(a,b);

let a=[0,1,[2,3],4], b=a.slice();
a[0]=1; a[2][0]=1; console.log(a,b);

