概念
深拷贝和浅拷贝只针对像 Object, Array 这样的复杂对象。它们最根本的区别在于是否真正获取了一个对象的复制实体,而不是引用。简单来说,假设B复制了A,当修改B时,看A是否会发生变化,如果A变了,说明是浅拷贝;如果A没变,那就是深拷贝
浅拷贝
1. 用 = 号赋值引用地址
let obj = {
name: '李四',
age: 20,
sex: '男',
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
school: {
colleges: "野鸡烧烤工程系"
grade: 2020
name: '野鸡大学'
stuNo: 2020123456
},
say: () => {
console.log('哇塞')
}
};
let obj2 = obj;
obj2.name = 'Rose';
obj2.sex = '女';
obj2.school.name = '野鸡变凤凰';
console.log('obj', obj);
console.log('obj2', obj2);
![](https://i-blog.csdnimg.cn/blog_migrate/e632b137820c281d555a15efde20d0e6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ac8cad41a9b3bb6280429b9e623e9f2a.png)
2. for…in
被循环的对象存在嵌套对象时为浅拷贝
let obj = {
name: '李四',
age: 20,
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
school: {
name: '野鸡大学',
grade: 2020,
stuNo: 2020123456,
colleges: '野鸡烧烤工程系',
},
say: () => {
console.log('哇塞')
}
};
let obj2 = {};
for (let key in obj) {
obj2[key] = obj[key];
}
obj2.name = '小六';
obj2.sex = '男';
obj2.school.name = '野鸡变凤凰';
console.log('obj', obj);
console.log('obj2', obj2);
![](https://i-blog.csdnimg.cn/blog_migrate/ebce82bf9d533762a027d686c9df775f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c42e380b109d9c137c787ed682641c6b.png)
3. Object.assign()
① Object.assign()只有源对象,没有目标对象时为浅拷贝
let obj = {
name: '李四',
age: 20,
sex: null,
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
school: {
name: '野鸡大学',
grade: 2020,
stuNo: 2020123456,
colleges: '野鸡烧烤工程系',
},
say: () => {
console.log('哇塞')
}
};
let obj2 = Object.assign(obj);
obj2.name = 'Rose';
obj2.school.name = '野鸡变凤凰';
console.log('obj', obj);
console.log('obj2', obj2);
![](https://i-blog.csdnimg.cn/blog_migrate/4038d998819d6e3a97e11727d3107f21.png)
![](https://i-blog.csdnimg.cn/blog_migrate/122acf4d25c223a6019a47dcb2a498b5.png)
② Object.assign() 是一种可以对非嵌套对象进行深拷贝的方法,如果对象中出现嵌套情况,那么其对被嵌套对象的行为就成了普通的浅拷贝
let obj = {
name: '李四',
age: 20,
sex: null,
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
school: {
name: '野鸡大学',
grade: 2020,
stuNo: 2020123456,
colleges: '野鸡烧烤工程系',
},
say: () => {
console.log('哇塞')
}
};
let obj2 = {
name: '小二',
school: {
name: '凤凰大学'
}
};
Object.assign(obj2, obj);
obj2.name = '小六';
obj2.school.name = '野鸡变凤凰';
console.log('obj', obj);
console.log('obj2', obj2);
![](https://i-blog.csdnimg.cn/blog_migrate/c30b720eab59fd2d97d3ff74245f5430.png)
![](https://i-blog.csdnimg.cn/blog_migrate/29f2f8ba19bbb5a5735175d97ede6e4b.png)
深拷贝
1. JSON.parse(JSON.stringify())
let obj = {
name: '李四',
age: 20,
sex: null,
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
school: {
name: '野鸡大学',
grade: 2020,
stuNo: 2020123456,
colleges: '野鸡烧烤工程系',
},
say: () => {
console.log('哇塞')
}
};
let obj2 = JSON.parse(JSON.stringify(obj));
obj2.name = '小六';
obj2.school.name = '野鸡变凤凰';
console.log(obj);
console.log(obj2);
![](https://i-blog.csdnimg.cn/blog_migrate/9cdf651aba7c75581065ecae61472b3b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6246302abb61f2eb5750330fd6964691.png)
注意:这种方式无法拷贝 正则表达式,undefine,function
2. for…in
被循环的对象不存在嵌套对象时为深拷贝
let obj = {
name: '李四',
age: 20,
sex: '男',
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
say: () => {
console.log('哇塞')
}
};
let obj2 = {};
for (let key in obj) {
obj2[key] = obj[key];
}
obj2.name = 'Rose';
obj2.sex = '女';
console.log('obj', obj);
console.log('obj2', obj2);
![](https://i-blog.csdnimg.cn/blog_migrate/c53db4f928268d50bdc1efa3e95e9de1.png)
![](https://i-blog.csdnimg.cn/blog_migrate/cc8a3bfcf2a36b17bdeac12ab5ebc8ef.png)
3. Object.assign()
Object.assign() 方法只复制源对象中可枚举的属性和对象自身的属性。如果目标对象中的属性具有相同的键,则属性将被源中的属性覆盖
let obj = {
name: '李四',
age: 20,
sex: null,
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
say: () => {
console.log('哇塞')
}
};
let obj2 = {
name: '小二',
};
Object.assign(obj2, obj);
obj2.name = '小六';
console.log('obj', obj);
console.log('obj2', obj2);
![](https://i-blog.csdnimg.cn/blog_migrate/3689f58bbf1aac9f37db7b66c43e9b87.png)
![](https://i-blog.csdnimg.cn/blog_migrate/699db41d726ab4e3cbc22c0237e7157a.png)
4. 递归
递归拷贝所有层级属性
let obj = {
name: '李四',
age: 20,
sex: null,
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
school: {
name: '野鸡大学',
grade: 2020,
stuNo: 2020123456,
colleges: '野鸡烧烤工程系',
},
say: () => {
console.log('哇塞')
}
}
function deepClone(obj) {
let objClone = Array.isArray(obj) ? [] : {};
if(obj && typeof obj === 'object' ) {
for(key in obj) {
if(obj.hasOwnProperty(key)){
// 判断 obj 子元素是否为对象,如果是则递归复制
if(obj[key] && typeof obj[key] === 'object') {
objClone[key] = deepClone(obj[key]);
} else {
// 如果不是则直接复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
let obj2 = deepClone(obj);
obj2.name = 'Rose';
obj2.school.name = '野鸡变凤凰';
console.log('obj', obj);
console.log('obj2', obj2);
![](https://i-blog.csdnimg.cn/blog_migrate/eb20e3ffa07f6c6af54c56da6d1cf256.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4b4c7a01231e7654e81775629597311a.png)
5. $.extend()
通过 jQuery 的 extend() 方法实现深拷贝,第一个参数 true 为深拷贝,false 为浅拷贝
let obj = {
name: '李四',
age: 20,
sex: null,
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
school: {
name: '野鸡大学',
grade: 2020,
stuNo: 2020123456,
colleges: '野鸡烧烤工程系',
},
say: () => {
console.log('哇塞')
}
}
var obj2 = $.extend(true, {}, obj); // true 为深拷贝,false 为浅拷贝
obj2.name = 'Rose';
obj2.school.name = '野鸡变凤凰';
console.log('obj', obj);
console.log('obj2', obj2);
![](https://i-blog.csdnimg.cn/blog_migrate/9226533365f0ed4965b1fb80baa233cd.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2daf6ab736e52f7cd194e058b6bda040.png)
6. slice()
slice() 对数组进行深拷贝
let arr = [1, 2, 3, 4, 5, 6];
let arr2 = arr.slice(0);
arr2[0] = 'Rose';
arr2[1] = '女';
console.log('arr', arr); // [1, 2, 3, 4, 5, 6]
console.log('arr2', arr2); // ["Rose", "女", 3, 4, 5, 6]
7. concat()
concat() 对数组进行深拷贝
let arr = [1, 2, 3, 4, 5, 6];
let arr2 = arr.concat();
arr2[0] = 'Rose';
arr2[1] = '女';
console.log('arr', arr); // [1, 2, 3, 4, 5, 6]
console.log('arr2', arr2); // ["Rose", "女", 3, 4, 5, 6]