在面試中經(jīng)常問到深拷貝的實(shí)現(xiàn),但由于在項(xiàng)目中都是用網(wǎng)上現(xiàn)成的或者依賴各種函數(shù)庫完成。偶爾在回答的時(shí)候就腦袋短路了,現(xiàn)在有時(shí)間了就簡(jiǎn)單整理了一下。
先說一下自己用過的一些方法
- 通過 JSON 對(duì)象實(shí)現(xiàn)深拷貝
//通過js的內(nèi)置對(duì)象JSON來進(jìn)行數(shù)組對(duì)象的深拷貝
function deepClone(obj) {
var _obj = JSON.stringify(obj),
objClone = JSON.parse(_obj);
return objClone;
}
缺陷:它會(huì)拋棄對(duì)象的constructor,深拷貝之后,不管這個(gè)對(duì)象原來的構(gòu)造函數(shù)是什么,在深拷貝之后都會(huì)變成Object;這種方法能正確處理的對(duì)象只有 Number, String, Boolean, Array, 扁平對(duì)象,也就是說,只有可以轉(zhuǎn)成JSON格式的對(duì)象才可以這樣用,像function沒辦法轉(zhuǎn)成JSON;
- lodash函數(shù)庫實(shí)現(xiàn)深拷貝
lodash是一個(gè)很優(yōu)秀的函數(shù)庫,提供了 lodash.cloneDeep()實(shí)現(xiàn)深拷貝
- Object.assign()拷貝
當(dāng)對(duì)象中只有一級(jí)屬性,沒有二級(jí)屬性的時(shí)候,此方法為深拷貝,但是對(duì)象中有對(duì)象的時(shí)候,此方法,在二級(jí)屬性以后就是淺拷貝
上面這幾種方法都能簡(jiǎn)單的實(shí)現(xiàn)深拷貝,但是各有各的特點(diǎn),也有各方面的缺點(diǎn)。所以就有了下面作者自己的實(shí)現(xiàn)方式。
function deepClone(value,hash = new WeakMap){ // WeakMap弱引用,不要用map
if(value == null){
return null;
}
if(value instanceof RegExp){
return new RegExp(value);
}
if(value instanceof Date){
return new Date(value);
}
//函數(shù)不需要拷貝
if(typeof value != 'object') return value;
let obj = new value.constructor; //判斷是對(duì)象還是數(shù)組 并且new
if(hash.get(value)){ //如果這個(gè)對(duì)象拷貝過了 就返回那個(gè)拷貝的結(jié)果就可以了
return hash.get(value);
}
hash.set(value,obj); //如果這個(gè)對(duì)象沒有拷貝過 就添加到WeakMap里面
for (let key in value) { // in 會(huì)遍歷當(dāng)前對(duì)象上面的屬性和__proto__指代的屬性
if (value.hasOwnProperty(key)) {
// 如果值還有可能是對(duì)象 就利用遞歸繼續(xù)拷貝
obj[key] = deepClone(value[key],hash)
}
}
return obj;
//區(qū)分對(duì)象和數(shù)組 Object.prototype.tostring.call
}
let o = {name: '123'};
console.log(deepClone(o))