深拷貝 VS 淺拷貝
深拷貝和淺拷貝都是針對的引用類型,JS中的變量類型分爲值類型(基本類型)和引用類型;對值類型進行復制操作會對值進行一份拷貝,而對引用類型賦值,則會進行地址的拷貝,最終兩個變量指向同一份數據。
// 基本類型
var a = 1;
var b = a;
a = 2;
console.log(a, b); // 2, 1 ,a b指向不同的數據
// 引用類型指向同一份數據
var a = {c: 1};
var b = a;
a.c = 2;
console.log(a.c, b.c); // 2, 2 全是2,a b指向同一份數據
對於引用類型,會導致a b指向同一份數據,此時如果對其中一個進行修改,就會影響到另外一個,有時候這可能不是我們想要的結果,如果對這種現象不清楚的話,還可能造成不必要的bug
那麼如何切斷a和b之間的關係呢,可以拷貝一份a的數據,根據拷貝的層級不同可以分爲淺拷貝和深拷貝,淺拷貝就是隻進行一層拷貝,深拷貝就是無限層級拷貝
淺拷貝的實現方式
方法一:通用循環
function shallowCopy(obj) {
if (typeof obj !== 'object') return;
const newObj = obj instanceof Array ? [] : {};
for(let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}
方法二:Object.assign
let a1 = ['hello', '2018']
let b1 = Object.assign([], a1)
// 改變b1中的值
b1[0] = 'hi'
/**
* 輸出結果發現
* 改變b1數據
* a1數組沒有改變,b1數組改變
*/
console.log(a1) // ['hello', '2018']
console.log(b1) // ['hi', '2018']
let a2 = [
{
name: 'java',
count: 12
},
{
name: 'js',
count: 13
}
]
let b2 = Object.assign([], a2)
// 改變b2數組中其中對象的count值
b2[0].count = 111
/**
* 輸出結果發現
* 改變了b2數據
* a1,b1數組都發生了改變
*/
console.log(a2)
console.log(b2)
---輸出結果
方法三:Array.slice
var arr1 = ["前端","安卓","蘋果"];
var arr2 = arr1.slice(0);
arr2[0] = "後端";
console.log("原始值:" + arr1 );//前端,安卓,蘋果
console.log("新值:" + arr2);//後端,安卓,蘋果
通過JS的slice方法,改變拷貝出來的數組的某項值後,對原來數組沒有任何影響。
缺點:適用於對不包含引用對象的一維數組的深拷貝
方法四:Array.concat
var arr1 = ["前端","安卓","蘋果"];
var arr2 = arr1.concat();
arr2[0] = "後端";
console.log("原始值:" + arr1 );//前端,安卓,蘋果
console.log("新值:" + arr2);//後端,安卓,蘋果
concat方法,原數組和新數組修改某值後,不會改變。
缺點:適用於對不包含引用對象的一維數組的深拷貝
方法五:Array.concat
let arr1 = ['ES6', 'let', 'const']
let arr2 = [...arr1]
arr2[0] = 'JavaScript'
console.log(arr1)
console.log(arr2)
深拷貝的實現方式
方法一:JSON.parse(JSON.stringify())
function cloneJSON(source) {
return JSON.parse(JSON.stringify(source));
}
方法二:通用循環遞歸調用
function deepCopy(obj) {
if (typeof obj !== 'object') return;
const newObj = obj instanceof Array ? [] : {};
for(let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj;
}