js 对象深拷贝、浅拷贝有哪些方法/设拷贝循环引用报错
浅拷贝
1. 扩展运算符 ...const obj = { a: 1, b: { c: 2 } };
const shallowCopy = { ...obj };obj.b.c = 3;
console.log(shallowCopy.b.c); // 3(被修改)
2.Object.assign()
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, obj);obj.b.c = 3;
console.log(shallowCopy.b.c); // 3(被修改)
3. 数组的浅拷贝方法
const arr = [1, 2, { a: 3 }];
const shallowCopy1 = arr.slice();
const shallowCopy2 = [...arr];
const shallowCopy3 = Array.from(arr);arr[2].a = 4;
console.log(shallowCopy1[2].a); // 4(全部被修改)
深拷贝(Deep Copy)
-
- JSON.parse(JSON.stringify())(最简单但有局限)
const obj = { a: 1, b: { c: 2 },d: new Date(),e: function() {},f: undefined,g: /regex/,h: Symbol('sym')
};const deepCopy = JSON.parse(JSON.stringify(obj));console.log(deepCopy);
// 输出: { a: 1, b: { c: 2 }, d: "2023-05-15T12:00:00.000Z", g: {} }
// 丢失了: e(函数)、f(undefined)、h(Symbol)
// 注意: 日期变成了字符串,正则表达式变成了空对象
- 不能处理函数、undefined、Symbol
- 会丢失对象的构造函数信息
- 遇到循环引用会报错
- . 递归实现深拷贝
function deepClone(source, hash = new WeakMap()) {if (source === null || typeof source !== 'object') {return source;}// 处理循环引用if (hash.has(source)) {return hash.get(source);}const target = Array.isArray(source) ? [] : {};hash.set(source, target);for (let key in source) {if (source.hasOwnProperty(key)) {target[key] = deepClone(source[key], hash);}}return target;
}const obj = { a: 1, b: { c: 2 } };
const deepCopy = deepClone(obj);obj.b.c = 3;
console.log(deepCopy.b.c); // 2(未被修改)
- 使用第三方库
lodash 的 _.cloneDeep()import _ from 'lodash';const obj = { a: 1, b: { c: 2 } };
const deepCopy = _.cloneDeep(obj);
- HTML5 的 structuredClone()(较新API)
const obj = { a: 1, b: { c: 2 },d: new Date(),e: [1, 2, 3]
};try {const deepCopy = structuredClone(obj);console.log(deepCopy);
} catch (err) {console.error('不支持 structuredClone 或对象包含不可克隆属性');
}
- 支持的数据类型:
-
原始值
-
Boolean、Number、String 对象
-
Date、RegExp、Blob、File、ImageData
-
Array、Object、Map、Set
-
ArrayBuffer、DataView
-
不支持:
-
Function、DOM节点
-
对象的原型链
-
某些特定属性(如Error的stack)