淺複製
學深複製之前我們先了解一下淺複製
可以看到使用擴充套件運算子進行複製obj之後生成objCopy,改變objCopy的值obj的值並沒有跟著變化。這麼看是沒有任何問題,那麼我們再來嘗試下將obj.a變成一個陣列呢。
上面可以看到兩個物件變成了一樣的,由此可以得出淺複製只能複製一層。
深複製
1 JSON.parse(JSON.stringify())
這種深複製方式會有幾個問題,讓我們來看一下。
- 1 時間和正則的問題
使用這個方法執行後時間格式會變成字串格式(正則同理)
- 2 丟失和型別
使用序列化之後會導致函式丟失,obj裡有NaN、Infinity和-Infinity,則序列化的結果會變成null
自己實現一個深複製
/*
* 資料型別:基本資料型別,引用資料型別;
* 基本資料型別:String,null,undefined,Number,Boolean
* 引用資料型別:RegExp,Date,Array,object,Function
* */
function deepClone(value) {
//判斷是否為null/undefined,因為在不是===的情況下 null=undefined if (value == undefined) return;
//判斷是否是正則
if (value instanceof RegExp) return new RegExp(value);
//判斷是否是時間格式
if (value instanceof Date) return new Date(value);
//判斷是否是String,Number,Boolean,Function(因為函式不會進行複製,直接執行)
if (typeof value != 'object') return value;
// 能走到這裡的只有陣列和物件了
//value.constructor指向建構函式本身 Array/Object. new Array/new Object生成的就是[]/{}
let container = new value.constructor;
for (let key in value) {
container[key] = deepClone(value[key])
}
return container
}
let obj = {
a: [1, 2],
b: 500
};
let objCopy = deepClone(obj);
obj.a[0]=100;
console.log('我是obj', obj);
console.log('我是objCopy', objCopy);
上面基本實現了一個深複製,但是在這個方法中還存在些問題。如果我傳入這樣一個物件那麼就會出現爆棧的現象。
let b={};
let a = {b:b};
b.a=a;
let copy = deepClone(a);
console.log(copy);
瀏覽器報錯:
這個方法顯然不是很友好,那麼我們使用Map和Set函式來最佳化一下,如果在Map中能找到直接使用Map中的即可;
完整程式碼:
/*
* 資料型別:基本資料型別,引用資料型別;
* 基本資料型別:String,null,undefined,Number,Boolean
* 引用資料型別:RegExp,Date,Array,object,Function
* */
//傳入map
function deepClone(value, hash = new Map()) {
//判斷是否為null/undefined,因為在不是===的情況下 null=undefined if (value == undefined) return;
//判斷是否是正則
if (value instanceof RegExp) return new RegExp(value);
//判斷是否是時間格式
if (value instanceof Date) return new Date(value);
//判斷是否是String,Number,Boolean,Function(因為函式不會進行複製,直接執行)
if (typeof value != 'object') return value;
//進來先判斷是不是在map中,如果存在直接獲取,就不需要再執行下面的deepClone函式進行遞迴為瀏覽器開闢無數個新的記憶體了。
if (hash.get(value)) {
return value;
}
// 能走到這裡的只有陣列和物件了
//value.constructor指向建構函式本身 Array/Object. new Array/new Object生成的就是[]/{}
let container = new value.constructor;
//每次進來向map函式中存值
hash.set(value, container)
for (let key in value) {
container[key] = deepClone(value[key], hash)
}
return container
}
let b = {};
let a = {b: b};
b.a = a;
let copy = deepClone(a);
console.log(copy);
輸出結果