深拷贝和浅拷贝
变量存储类型
在理解拷贝之前我们要先熟悉变量存储类型 变量的数据类型分为 基本数据类型 (值类型)和 复杂数据类型(引用数据类型) 基本数据类型的值是直接存放在栈内存的 而复杂数据类型的栈内存保存的是内存地址 值都是保存在堆内存中
浅拷贝
概念
我们可以理解为 浅拷贝就是创建一个新对象 这个对象有着被拷贝对象的对象属性值
如果是基本数据类型 拷贝的就是这个基本数据类型的值 改变新对象不会导致原来的数据发生改变
如果属性是复杂数据类型 拷贝的就是复杂数据类型的内存地址
所以如果其中一个对象改变了这个地址 就会影响到另外一个对象 就会导致原数据发生改变
这里借用GitHub中ConardLi大佬的图片来方便我们理解
浅拷贝使用实现:
方法一 Object.assign()
语法 Object.assign(target, … sources) 第一个参数是目标对象 第二分参数是原对象(也就是被拷贝的对象) 这是es6提供给我们的新方法 我们使用的时候需要注意兼容性的问题 还有个需要注意的是 这个方法一般用来浅拷贝对象 用来处理数组的时候 会把数组视为对象
const obj = {
name:'xiaoming',
age:18,
hobby:['football','music']
}
const obj2 = Object.assign({}, obj)
obj2.hobby.push('swim');
console.log(obj);
console.log(obj2);
方法2 利用展开运算符进行浅拷贝
const obj = {
name:'xiaoming',
age:18,
hobby:['football','music']
}
const obj2 = {...obj};
obj2.hobby.push('swim');
console.log(obj);
console.log(obj2);
方法3 forin循环
const obj = {
name:'xiaoming',
age:18,
hobby:['football','music']
}
const obj2 = {};
for(const key in obj){
obj2[key] = obj[key]
}
obj2.hobby.push('swim');
console.log(obj);
console.log(obj2);

深拷贝
概念
深拷贝指的是 将被拷贝的对象从内存中完全拷贝一份出来 在堆内存中开辟一个新的区域来存放新对象 并且修改新对象不会影响原来对象
我们在借用一次 GitHub中ConardLi大佬的图片来方便我们理解
方法一:递归
const obj = {
name:'xiaoming',
age:18,
hobby:['football','music']
}
function deepClone(data){
if(!data ){
return data;
}
const target = Array.isArray(data)? [] :{};
for(const key in data){
const item = data[key];
if(typeof item === 'function'){
target[key] = new Function(`return ${item.toString()}`)();
}else if(typeof item === 'object'){
target[key] = deepClone(item);
}else{
target[key] = item
}
}
return target;
}
const obj2 = deepClone(obj);
obj2.hobby.push('swim');
console.log('obj',obj);
console.log('obj2',obj2);
方法二 JSON.parse(JSON.stringify())
乍看 JSON.parse(JSON.stringify()) 不太明白 我们来解释一下 JSON.parse() 是一个生成新对象的方法 JSON.stringify() 是把原对象序列化为一个JSON字符串 简单的说 就是先把源对象序列化为一个JSON字符串 然后利用JSON.parse()方法转变为一个新对象 这也是我们最常用的方法 我们来使用看看结果如何:
const obj = {
name:'xiaoming',
age:18,
hobby:['football','music']
};
const objString = JSON.stringify(obj);
const obj2 = JSON.parse(objString);
obj2.hobby.push('swim');
console.log(obj);
console.log(obj2);
有以下几种情况时,不能正确的进行深拷贝: 1.obj里面有new Date(),深拷贝后,时间会变成字符串的形式。而不是时间对象;
let a = {
name: 'a',
date: [new Date(1536627600000), new Date(1540047600000)],
};
let b = JSON.parse(JSON.stringify(a))
console.log(a,b);
2.obj里有RegExp、Error对象,则序列化的结果会变成空对象{};
const a = {
name: 'a',
date: new RegExp('\\w+'),
};
const b = JSON.parse(JSON.stringify(a));
a.name = 'test'
console.log( a, b)
3.obj里有function,undefined,则序列化的结果会把function或 undefined丢失
const a = {
name: 'a',
date: function hehe() {
console.log('fff')
},
};
const b = JSON.parse(JSON.stringify(a));
a.name = 'test'
console.log(a, b)
4.obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null;
const a = {
name: 'a',
date: NaN,
};
const b = JSON.parse(JSON.stringify(a));
a.name = 'test'
console.log(a, b)