浅拷贝
浅拷贝是指创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。换句话说,拷贝过程中,只复制了对象的第一层属性,而不是递归复制整个对象及其嵌套对象。
Object.assign()
javascript
let original = { a: 1, b: { c: 2 } };
let copy = Object.assign({}, original);
在浅拷贝中,当属性值是对象时(比如 b
是一个对象 { c: 2 }
),**拷贝后的对象中的这些属性仍然引用原始对象中相同的对象实例,而不是复制其内容。**因此,如果你修改了拷贝后对象中的这些属性,实际上也会影响到原始对象中对应的属性,因为它们引用的是同一个对象实例。(即b拷贝时是地址而不是值,引用数据类型拷贝的是地址)
Spread 操作符 (...)
javascript
let original = { a: 1, b: { c: 2 } };
let copy = { ...original };
Array.slice()(仅适用于数组)
javascript
let originalArray = [1, 2, { a: 3 }];
let copyArray = originalArray.slice();
扩展运算符 (...)(仅适用于数组)
javascript
let originalArray = [1, 2, { a: 3 }];
let copyArray = [...originalArray];
注意事项:
嵌套对象的引用:浅拷贝只复制了第一层属性,如果原始对象的属性值是对象,那么拷贝后的对象仍然引用同一个嵌套对象。
原始对象引用问题:浅拷贝只会复制对象本身的属性,并不会复制它们背后的对象的实例。因此,对拷贝后的对象进行修改可能会影响到原始对象。
不适用于复杂对象:如果原始对象中有函数、RegExp 对象、Date 对象等特殊类型的属性,浅拷贝可能无法正确复制它们。
深拷贝
深拷贝与浅拷贝不同,它会递归地复制所有层级的对象及其属性,确保拷贝后的对象与原始对象完全独立,互不影响。
递归实现 这是一种基础的方法,通过递归遍历对象的所有属性,对每个属性进行复制,以确保深度复制整个对象及其嵌套对象。
javascript
let obj = {
name: 'John',
age: 30,
address: {
city: 'New York',
postalCode: '10001'
}
};
let copy = {};
function deepCopy(value) {
// 简单示例的深度复制函数
if (typeof value === 'object' && value !== null) {
return JSON.parse(JSON.stringify(value)); // 简单的方式,不适用于包含函数、循环引用等情况
} else {
return value; // 基本类型直接返回
}
}
// 遍历 obj 的所有属性,进行深度复制
for (let key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
copy[key] = deepCopy(obj[key]);
}
}
console.log(copy);
使用 JSON 序列化与反序列化 利用 JSON.stringify()
和 JSON.parse()
可以实现简单的深拷贝,但要注意它有一些限制**,比如不能复制函数、正则表达式对象等特殊类型的属性。**
JSON.stringify() 方法将 JavaScript 对象转换为字符串
JSON.parse() 方法将数据转换为 JavaScript 对象
javascript
let deepCopy = JSON.parse(JSON.stringify(obj));
第三方库 如果需要处理更复杂的对象或者避免自己实现深拷贝的逻辑,可以使用第三方库,例如 Lodash 的 _.cloneDeep()
方法:
lodash.cloneDeep | Lodash中文文档 | Lodash中文网 (lodashjs.com)
javascript
const _ = require('lodash');
let deepCopy = _.cloneDeep(obj);
注意事项:
性能问题**:深拷贝可能会比浅拷贝消耗更多的时间和内存,特别是对于大型对象或对象层级很深的情况。**
特殊类型的处理**:一些特殊类型的属性(如函数、RegExp 等)可能需要额外的处理,以确保正确复制或避免因序列化而丢失信息。**
循环引用**:在处理可能存在循环引用的对象时,需要小心处理,以避免无限递归或栈溢出的问题。**