在面试中经常问到深拷贝的实现,但由于在项目中都是用网上现成的或者依赖各种函数库完成。偶尔在回答的时候就脑袋短路了,现在有时间了就简单整理了一下。
先说一下自己用过的一些方法
- 通过 JSON 对象实现深拷贝
//通过js的内置对象JSON来进行数组对象的深拷贝
function deepClone(obj) {
var _obj = JSON.stringify(obj),
objClone = JSON.parse(_obj);
return objClone;
}
缺陷:它会抛弃对象的constructor,深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object;这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,也就是说,只有可以转成JSON格式的对象才可以这样用,像function没办法转成JSON;
- lodash函数库实现深拷贝
lodash是一个很优秀的函数库,提供了 lodash.cloneDeep()实现深拷贝
- Object.assign()拷贝
当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝
上面这几种方法都能简单的实现深拷贝,但是各有各的特点,也有各方面的缺点。所以就有了下面作者自己的实现方式。
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);
}
//函数不需要拷贝
if(typeof value != 'object') return value;
let obj = new value.constructor; //判断是对象还是数组 并且new
if(hash.get(value)){ //如果这个对象拷贝过了 就返回那个拷贝的结果就可以了
return hash.get(value);
}
hash.set(value,obj); //如果这个对象没有拷贝过 就添加到WeakMap里面
for (let key in value) { // in 会遍历当前对象上面的属性和__proto__指代的属性
if (value.hasOwnProperty(key)) {
// 如果值还有可能是对象 就利用递归继续拷贝
obj[key] = deepClone(value[key],hash)
}
}
return obj;
//区分对象和数组 Object.prototype.tostring.call
}
let o = {name: '123'};
console.log(deepClone(o))
网友评论