- 浅拷贝:只复制对象的第一层属性,嵌套的对象仍然引用原始对象中的数据。
- 深拷贝:不仅复制对象的所有属性,还包括所有嵌套对象的值,使得新对象与原始对象完全独立。
深拷贝
- 深拷贝和浅拷贝是针对复杂数据类型(对象及数组)来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝。
- 深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。 深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象。
- 深拷贝会开辟新的栈,两个对象对应两个不同的地址,修改对象A的属性,并不会影响到对象。
实现深拷贝的4种方式
-
递归方式(推荐,项目中最安全最常用)
//使用递归的方式实现数组、对象的深拷贝
export function deepClone (obj) {let objClone = Array.isArray(obj) ? [] : {};if (obj && typeof obj === "object") {for (var key in obj) {if (obj.hasOwnProperty(key)) {//判断ojb子元素是否为对象,如果是,递归复制if (obj[key] && typeof obj[key] === "object") {objClone[key] = deepClone(obj[key]);} else {//如果不是,简单复制objClone[key] = obj[key];}}}}return objClone;
};
2.JSON.stringify() (不推荐)
其实就是将一个 JavaScript 对象或值转换为 JSON 字符串,最后再用 JSON.parse()
的方法将JSON 字符串生成一个新的对象,
普通的对象也可以进行深拷贝,但是
- 取不到值为 undefined 的 key;
- 如果对象里有函数,函数无法被拷贝下来;
- 无法拷贝 copyObj 对象原型链上的属性和方法;
- 对象转变为 date 字符串;
- NaN 转变为 null。
浅拷贝
浅拷贝创建一个新对象,这个对象的第一层属性值与原对象相同,但如果这些属性值是引用类型(如数组或对象),不在堆内存中重新开辟空间,只复制栈内存中的引用地址。
方法:
Object.assign(): 用于对象的浅拷贝。
扩展运算符(Spread Operator)...: 对于对象和数组都可以使用。
Array.prototype.slice(): 对于数组的浅拷贝。
Array.from(): 也可以用于数组的浅拷贝。
- 浅拷贝只复制对象的基本属性,而不复制引用类型的属性指向的对象,即只复制引用而不复制引用指向的对象。
- 在浅拷贝中,新对象与原始对象共享引用类型的属性指向的对象,即它们指向同一个对象。
- 修改新对象或原始对象的共享引用类型属性指向的对象的属性值,会影响到另一个对象。
类型 | 第一级为基础数据类型 | 原数据中包含子对象 |
---|---|---|
浅拷贝 | 改变不会使原始数据改变 | 改变会使原始数据改变 |
深拷贝 | 改变不会使原始数据改变 | 改变不会使原始数据改变 |
选择浅拷贝还是深拷贝取决于你的需求。如果只需要复制顶层属性,并且不关心修改拷贝对象是否影响原始对象,则可以使用浅拷贝。 如果需要完全独立的副本,则必须使用深拷贝,并且推荐使用像 Lodash 这样的第三方库来确保可靠性。 避免使用 JSON.parse(JSON.stringify(...))
除非你确认你的数据结构非常简单且只包含可序列化的数据类型。
推荐链接:面试题:深拷贝和浅拷贝(超级详细,有内存图)_深copy和浅copy面试-CSDN博客