前端深拷贝的实现方法

在前端开发中,深拷贝(Deep Copy)是指创建一个新对象,并将原对象的所有属性递归地复制到新对象中,使得新对象与原对象完全独立,修改新对象不会影响原对象。实现深拷贝有多种方法,以下是几种常见的实现方式:
1. 使用 JSON.parse
和 JSON.stringify
这是最简单的方法,但有一些局限性(例如不能处理函数、undefined
、Symbol
、循环引用等)。
function deepCopy(obj) {
return JSON.parse(JSON.stringify(obj));
}
const original = { a: 1, b: { c: 2 } };
const copied = deepCopy(original);
console.log(copied); // { a: 1, b: { c: 2 } }
2. 递归实现
通过递归遍历对象的属性,逐一复制到新对象中。
function deepCopy(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (Array.isArray(obj)) {
const arrCopy = [];
for (let i = 0; i < obj.length; i++) {
arrCopy[i] = deepCopy(obj[i]);
}
return arrCopy;
}
const objCopy = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
objCopy[key] = deepCopy(obj[key]);
}
}
return objCopy;
}
const original = { a: 1, b: { c: 2 } };
const copied = deepCopy(original);
console.log(copied); // { a: 1, b: { c: 2 } }
3. 使用 structuredClone
现代浏览器提供了 structuredClone
方法,可以处理大多数数据类型(包括循环引用)。
const original = { a: 1, b: { c: 2 } };
const copied = structuredClone(original);
console.log(copied); // { a: 1, b: { c: 2 } }
4. 使用第三方库(如 Lodash)
Lodash 提供了 _.cloneDeep
方法,可以处理复杂的对象结构。
import _ from 'lodash';
const original = { a: 1, b: { c: 2 } };
const copied = _.cloneDeep(original);
console.log(copied); // { a: 1, b: { c: 2 } }
5. 处理特殊类型(如 Date
、RegExp
等)
如果需要处理特殊类型(如 Date
、RegExp
等),可以在递归实现中增加对这些类型的处理。
function deepCopy(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (obj instanceof Date) {
return new Date(obj);
}
if (obj instanceof RegExp) {
return new RegExp(obj);
}
if (Array.isArray(obj)) {
const arrCopy = [];
for (let i = 0; i < obj.length; i++) {
arrCopy[i] = deepCopy(obj[i]);
}
return arrCopy;
}
const objCopy = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
objCopy[key] = deepCopy(obj[key]);
}
}
return objCopy;
}
const original = { a: 1, b: { c: 2 }, d: new Date() };
const copied = deepCopy(original);
console.log(copied); // { a: 1, b: { c: 2 }, d: Date }
6. 处理循环引用
如果需要处理循环引用,可以使用 WeakMap
来存储已经拷贝过的对象。
function deepCopy(obj, map = new WeakMap()) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (map.has(obj)) {
return map.get(obj);
}
if (obj instanceof Date) {
return new Date(obj);
}
if (obj instanceof RegExp) {
return new RegExp(obj);
}
if (Array.isArray(obj)) {
const arrCopy = [];
map.set(obj, arrCopy);
for (let i = 0; i < obj.length; i++) {
arrCopy[i] = deepCopy(obj[i], map);
}
return arrCopy;
}
const objCopy = {};
map.set(obj, objCopy);
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
objCopy[key] = deepCopy(obj[key], map);
}
}
return objCopy;
}
const original = { a: 1 };
original.self = original;
const copied = deepCopy(original);
console.log(copied); // { a: 1, self: [Circular] }
总结
- 简单场景:可以使用
JSON.parse(JSON.stringify(obj))
。 - 复杂场景:建议使用递归实现或
structuredClone
。 - 特殊类型:需要额外处理
Date
、RegExp
等类型。 - 循环引用:使用
WeakMap
来避免无限递归。
根据具体需求选择合适的方法来实现深拷贝。