深拷贝和浅拷贝是针对复杂数据类型来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝。
深拷贝
深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象。
浅拷贝
浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。
浅拷贝
可以使用 forin
、 Object.assign
、 扩展运算符...
、 Array.prototype.slice()
、 Array.prototype.concat()
等实现浅拷贝。
下面代码使用 Object.assign 实现浅拷贝:
- 只能保证第一层属性为基本类型
String|Number|Boolean|null|undefined|Symbol
时,新对象和原来对象互不影响(如:在给 res.name 赋值为'res1'后,test.name 没有改变); - 如果第一层的属性是引用数据类型
Object|Array|Function|Date|RegExp
时,新对象和原对象的属性值指针指向的是同一块内存地址(如:res.arr[0]设置为'res1'后,test.arr[0]也变成'res1')。
const test = {
name: 'test',
arr: [1, 2, 3]
};
const res = Object.assign({}, test); // {...test} 相同效果
res.name = 'res1';
res.arr[0] = 'res1';
console.log(test.name);// test
console.log(test.arr);// ["res1", 2, 3]
深拷贝
- 1.深拷贝最简单的实现是:
JSON.parse(JSON.stringify(obj))
JSON.parse(JSON.stringify(obj))
是最简单的实现方式,但是有一些缺陷:
- 对象的属性值是函数时,无法拷贝。
- 不能正确的处理 Date 类型的数据
- 不能处理 RegExp
- 会忽略 symbol
- 会忽略 undefined
- 原型链上的属性无法拷贝()
function HH () {
this.hhname = '123';
}
HH.prototype.dd = '123';
var test = {
name: 'haha',
date: new Date(),
height: null,
width: undefined,
arr: [1, 3, 4],
func: function () { console.log('test.func');
},
proto: new HH(),
mysymbol: Symbol(),
reg: new RegExp('abc')
};
var res1 = JSON.parse(JSON.stringify(test));
console.log(test);
console.log(res1);
效果如下
![64463bbc17109f733628c298c61ae3bb.png](https://i-blog.csdnimg.cn/blog_migrate/fd50f40ba748d698627a1e7ca948236a.jpeg)
实现一个 deepClone 函数
var deepClone = (function f (obj) {
// Date && RegExp && undefined&&Symbol&&Function&&原型链
// 判断是否存在
if (!obj) {
return obj;
}
// 判断是不是Date类型
if (obj instanceof Date) {
return new Date(obj);
}
// 判断是不是RegExp
if (obj instanceof RegExp) {
return new RegExp(obj);
}
// 判断是不是null
if (obj === null) {
return obj;
}
// 判断是不是非对象
if (typeof obj !== 'object') {
return obj;
}
// 判断是数组还是对象
var result = obj instanceof Array ? [] : {};
// 循环
for (var key in obj) {
// 判断是不是自身的属性
if (obj.hasOwnProperty(key)) {
// 判断是不是对象,因为对象是引用类型,所以需要对引用类型(除了null 这个空对象,null属于基本类型,但是也是对象)再次使用该方法做递归处理
result[key] = typeof obj[key] === 'object' ? f(obj[key]) : obj[key];
}
}
return result;
});
var res2 = deepClone(test);