js中的深拷贝
普通的数组,slice,concat或者es6的扩展运算符都可以实现深拷贝,但是如果是数组对象却不可以
例如:
[
{name: 'A', count: 1},
{name: 'B', count: 2},
{name: 'C', count: 3},
{name: 'D', count: 4},
{name: 'E', count: 5},
]
有以下3种方式可以快速的实现
let start = [
{name: 'A', count: 1},
{name: 'B', count: 2},
{name: 'C', count: 3},
{name: 'D', count: 4},
{name: 'E', count: 5},
]
let end = start.map(o => Object.assign({}, o));
let end = start.map(o => ({...o}));
let end=JSON.parse(JSON.stringify(start)) //此方法不推荐,因为:
//undefined,Function,Symbol 时,它被忽略掉
Infinity,NaN 会被变成 null
Date 对象会被转化为 String (默认调用date.toISOString())
但是呢,经过事实的检验我们发现,concat和slice只是对数组的第一层进行深拷贝,如果是[1,[1,2,3],{a:1}] 这种数组,就不行嘞。
同样的 … 实现的是对象第一层的深拷贝。后面的只是拷贝的引用值
而Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。也就是说,如果对象的属性值为简单类型(如string, number),通过Object.assign({},srcObj);得到的新对象为深拷贝;如果属性值为对象或其它引用类型,那对于这个对象而言其实是浅拷贝的。
哎 弄了半天都不行呗,总结: 并没有简单快速又无敌的深拷贝!!
怎么办呢 只有递归喽
递归的思想就很简单了,就是对每一层的数据都实现一次 创建对象->对象赋值 的操作,简单粗暴上代码:
function deepClone(source){
const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
for(let keys in source){ // 遍历目标
if(source.hasOwnProperty(keys)){
if(source[keys] && typeof source[keys] === 'object'){ // 如果值是对象,就递归一下
targetObj[keys] = source[keys].constructor === Array ? [] : {};
targetObj[keys] = deepClone(source[keys]);
}else{ // 如果不是,就直接赋值
targetObj[keys] = source[keys];
}
}
}
return targetObj;
}