一、复制
浅拷贝
浅拷贝的意思就是只复制引用,而未复制真正的值。
// 数组
const originArr = [1, 2, 3]
const cloneArr = originArr
cloneArr[0] = 'a'
console.log(cloneArr) // [a, 2, 3]
// 原先的数组也改变了
console.log(originArr)// [a, 2, 3,]
// 指向的内存是一样的,所以返回true
console.log(cloneArr === originArr) // true
// 对象
const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneObj = originObj;
cloneObj.a = {aa:'aa'};
console.log(cloneObj); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}
console.log(originObj); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}
console.log(cloneObj === originObj) // true
上面的代码是最简单的利用 = 赋值操作符实现了一个浅拷贝,可以很清楚的看到,随着 cloneArray 和 cloneObj 改变,originArray 和 originObj 也随着发生了变化。
深拷贝
深拷贝就是对目标的完全拷贝,不像浅拷贝那样只是复制了一层引用,就连值也都复制了。
只要进行了深拷贝,它们老死不相往来,谁也不会影响谁。
目前实现深拷贝的方法不多,主要是两种方法:
1.JSON.stringify/parse的方法
利用 JSON 对象中的 parse 和 stringify
适用的情况,代码示例如下:
const originArr = [1, 2, 3]
const cloneArr = JSON.parse(JSON.stringify(originArr));
cloneArr[0] = 'a'
console.log(cloneArr) // [a, 2, 3]
// 原先的数组没有改变
console.log(originArr)// [1, 2, 3,]
// 指向的内存改变了,所以返回false
console.log(cloneArr === originArr) // false
不适用的情况,代码示例如下:
// 数组
const originArr = [1, 2, undefined]
const cloneArr = JSON.parse(JSON.stringify(originArr));
cloneArr[0] = 'a'
console.log(originArr)// [1, 2, undefined]
// 复制的数组属性丢失,为null
console.log(cloneArr) // [a, 2, null]
// 对象
const originObj = {
name:'axuebin',
sayHello:function(){
console.log('Hello World');
}
}
console.log(originObj); // {name: "axuebin", sayHello: ƒ}
const cloneObj = JSON.parse(JSON.stringify(originObj));
// 复制的对象属性丢失
console.log(cloneObj); // {name: "axuebin"}
以上代码显示,如果属性里面有undefined、function、symbol就不适用了;
MDN给出的原因解释:
undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时
2.递归的方法
递归的思想就很简单了,就是对每一层的数据都实现一次 创建对象->对象赋值 的操作,简单粗暴上代码:
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;
}
// ES6深度复制的递归方法
const deepClone = obj => {
let clone = Object.assign({}, obj);
Object.keys(clone).forEach(
key => (clone[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key])
);
return clone;
};
一般的:
const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneObj = deepClone(originObj);
console.log(cloneObj === originObj); // false
cloneObj.a = 'aa';
cloneObj.c = [1,1,1];
cloneObj.d.dd = 'doubled';
console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'doubled'}};
console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
带有函数的:
const originObj = {
name:'axuebin',
sayHello:function(){
console.log('Hello World');
}
}
console.log(originObj); // {name: "axuebin", sayHello: ƒ}
const cloneObj = deepClone(originObj);
console.log(cloneObj); // {name: "axuebin", sayHello: ƒ}
也可以。搞定。
是不是以为这样就完了?? 当然不是。请看下篇深浅拷贝拓展
网友评论