跳到主要内容

对象复制

JavaScript 中复制对象的多种方法。

浅拷贝

扩展运算符

const original = { a: 1, b: { c: 2 } };

// 浅拷贝
const copy = { ...original };

// 修改顶层属性不影响原对象
copy.a = 10;
console.log(original.a); // 1

// 但嵌套对象是引用
copy.b.c = 20;
console.log(original.b.c); // 20 - 原对象被修改

Object.assign()

const original = { a: 1, b: 2, c: 3 };

// 复制到新对象
const copy = Object.assign({}, original);

// 或复制到现有对象
const target = { d: 4 };
Object.assign(target, original);
console.log(target); // { d: 4, a: 1, b: 2, c: 3 }

Object.create()

const original = { a: 1, b: 2 };

// 创建原型为 original 的新对象
const copy = Object.create(original);

// copy 继承 original 的属性
console.log(copy.a); // 1

深拷贝

JSON 方法(简单场景)

const original = { a: 1, b: { c: 2 }, d: 'test' };

// 深拷贝(注意限制)
const copy = JSON.parse(JSON.stringify(original));

// 限制:
// - 不能处理函数
// - 不能处理 undefined
// - 不能处理 Date(会变成字符串)
// - 不能处理循环引用
// - 不能处理 RegExp

const withFunc = { a: 1, fn: () => {} };
JSON.parse(JSON.stringify(withFunc)); // { a: 1 } - 函数丢失

structuredClone()(现代浏览器)

const original = {
a: 1,
b: { c: 2 },
d: new Date(),
e: new RegExp('/test/')
};

// 原生深拷贝 API
const copy = structuredClone(original);

console.log(copy.d instanceof Date); // true
console.log(copy.e instanceof RegExp); // true

递归实现

function deepClone(obj, hash = new WeakMap()) {
// 处理非对象
if (obj === null || typeof obj !== 'object') {
return obj;
}

// 处理 Date
if (obj instanceof Date) {
return new Date(obj);
}

// 处理 RegExp
if (obj instanceof RegExp) {
return new RegExp(obj);
}

// 处理循环引用
if (hash.has(obj)) {
return hash.get(obj);
}

// 创建新对象
const clone = Array.isArray(obj) ? [] : {};
hash.set(obj, clone);

// 递归拷贝属性
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key], hash);
}
}

return clone;
}

const original = { a: 1, b: { c: 2 } };
const copy = deepClone(original);
copy.b.c = 20;
console.log(original.b.c); // 2 - 原对象不受影响

使用 lodash

import _ from 'lodash';

const original = { a: 1, b: { c: 2 } };

// 深拷贝
const copy = _.cloneDeep(original);

选择建议

场景推荐方法
简单对象{ ...obj }
需要深拷贝structuredClone()
兼容旧浏览器JSON 方法或 lodash
处理复杂类型lodash cloneDeep