2、深拷贝与浅拷贝
看这一篇的时候建议先看一下上一篇关于数据类型的文章。
直接赋值
直接赋值:把对象a赋值给对象b,实际上是把对象b的地址指向对象a的对象。a与b的地址指针一样,指向同一个对象,所以修改b时,a也会跟着发生改变。注意,修改b的无论是对象属性(引用数据类型)还是非对象属性(基本数据类型),a都会跟着发生改变。
let a = {
name:'a',
arr:[1,2]
}
let b = a;
b.name = 'b';
console.log(a.name); // b
b.arr = [1,3]
console.log(a.arr); // [1,3]
浅拷贝
浅拷贝:赋值对象的非对象属性,对象a与对象b的地址指针不一样,不会指向同一个对象,对象b是一个新的对象。修改b的非对象属性,a的非对象属性不会跟着变化。但是修改b的对象属性,会影响a的对象属性。这是因为,在浅拷贝时如果是非对象属性(基本数据类型),那么拷贝的是这个非对象属性的值,如果拷贝的是对象属性(引用数据类型),那么拷贝的是地址指针,所以修改b的对象属性,会影响a的对象属性。
let a = {
name:'a',
other:{
arr:[1,2]
}
}
let b = Object.assign({},a);
b.name = 'b';
console.log(a.name); // a
b.other.arr = [1,3]
console.log(a.other.arr); // [1,3]
浅拷贝实现方法
注意如果object只有一层那么就是深拷贝。
1)Object.assign()
Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。例子可以看上面。
2)引用复制
function shallowClone(copyObj){
var obj = {}
for(let i in copyObj){
obj[i] = copy[i]
}
return obj
}
3)Array.prototype.concat()
let a = [1,2,{name:'a'}]
let b = a.concat()
4)Array.prototype.slice()
let a = [1,2,{name:'a'}]
let b = a.slice()
深拷贝
深拷贝:拷贝一个一模一样的对象,对象a与对象b的地址指针不一样,不会指向同一个对象,对象b是一个新的对象,而且对象b与对象a不再共享内存。**无论修改b的非对象属性还是对象属性,a的非对象属性/对象属性都不会跟着变化。**这是因为对象b的对象属性与a对象的对象属性都不再指向同一个对象,即地址指针不一样。
let a = {
name:'a',
other:{
arr:[1,2]
}
}
let b = JSON.parse(JSON.stringify(a));
b.name = 'b';
console.log(a.name); // a
b.other.arr = [1,3]
console.log(a.other.arr); // [1,2]
深拷贝实现方法
1) JSON.parse(JSON.stringify())
用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。
弊端:
1、如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象;
2、如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象;
3、如果obj里有函数,undefined,symbol,则序列化的结果会把函数或 undefined,symbol丢失;
4、如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null;
5、JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor;
6、如果对象中存在循环引用的情况也无法正确实现深拷贝;
详情可见:关于JSON.parse(JSON.stringify(obj))实现深拷贝应该注意的坑
2) 递归拷贝
function deepCopy(obj) {
if (obj=== null) return null;
if (typeof obj!== 'object') return obj;
var result = Array.isArray(obj) ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === 'object' && obj[key]!==null) {
result[key] = deepCopy(obj[key]); //递归拷贝
} else {
result[key] = obj[key];
}
}
}
return result;
}
3)函数库lodash
var lodash = require('lodash');
var obj1 = {
a: 1,
b: { b: { b: 1 } },
c: [1, 2, 3]
};
var obj2 = lodash.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);