目录:
- 深拷贝与浅拷贝的区别
- 实现深拷贝的方式
- 利用JSON.parse(JSON.stringify())实现深拷贝的局限性
- cloneDeep与json的对比
- 手写实现cloneDeep
深拷贝与浅拷贝的区别
深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。
深拷贝和浅拷贝的示意图大致如下:
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
实现深拷贝的方式
1.JSON.parse(JSON.stringify())
原理:
用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。
局限性:
1.这种方法虽然可以实现数组或对象深拷贝,但无法处理函数和 undefined
2.无法处理循环引用
如果原始对象中存在循环引用,即对象的某个属性引用了该对象本身,使用该方法就会抛出 TypeError 异常。
const obj = {
a: 1,
b: {
c: 2
}
};
obj.d = obj;
// 报错:TypeError: Converting circular structure to JSON
JSON.parse(JSON.stringify(obj));
3.无法处理一些特殊对象
JSON.stringify() 方法无法处理某些特殊的 JavaScript 对象,如 RegExp、Error、Date 等,这些对象会被转换成空对象
const obj = {
a: /abc/,
b: new Error('error'),
c: new Date()
};
const newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj); // { a: {}, b: {}, c: '2022-02-22T12:34:56.000Z' }
4.对象的原型链上的属性会丢失
如果原始对象的某个属性是通过原型链继承的,那么使用该方法得到的新对象会丢失该属性。
function Person(name) {
this.name = name;
}
Person.prototype.sayHi = function() {
console.log(`Hi, I'm ${this.name}`);
};
const obj = new Person('Tom');
const newObj = JSON.parse(JSON.stringify(obj));
newObj.sayHi(); // 报错:Uncaught TypeError: newObj.sayHi is not a function
综上,虽然 JSON.parse(JSON.stringify()) 方法是一种简单易用的实现深拷贝的方法,但它并不完美,使用时需要注意其缺陷。对于需要处理函数、循环引用等复杂情况的对象,可以使用其他方法来实现深拷贝
lodash _.cloneDeep
原理: 文档
手写实现记录一下 后期同步git [可参考](http://events.jianshu.io/p/bc75be6218d9)
参考:
https://blog.csdn.net/SSophia/article/details/123964733
https://blog.csdn.net/m0_54566205/article/details/129561012