#移动云AI智启未来#
字数 877,阅读大约需 5 分钟
在JavaScript编程中,我们常常需要复制对象。直接赋值会出现问题。
let obj1 = { name: "小明", age: 18 };
let obj2 = obj1;
obj2.name = "小红";
console.log(obj1.name); // 输出"小红"
看到问题了吗?修改obj2,obj1也跟着变了。这是由于它们指向同一个内存地址。
浅拷贝的局限性
许多人第一想到的是浅拷贝。
// 扩展运算符
let newObj = { ...oldObj };
// Object.assign
let newObj = Object.assign({}, oldObj);
浅拷贝能解决简单问题,但遇到嵌套对象就不行了。
let user = {
name: "小明",
address: {
city: "北京",
street: "朝阳路"
}
};
let userCopy = { ...user };
userCopy.address.city = "上海";
console.log(user.address.city); // 输出"上海"
原始对象的address也被修改了。这不是我们想要的结果。
深拷贝的多种方案
1. JSON方法
let newObj = JSON.parse(JSON.stringify(oldObj));
这个方法很简单,但有明显缺陷:
- • 函数会被忽略
- • undefined会被删除
- • Date对象会变成字符串
- • 循环引用会报错
2. 手动递归实现
function deepClone(obj) {
if (obj === null || typeof obj !== "object") {
return obj;
}
if (obj instanceof Date) {
return new Date(obj.getTime());
}
if (obj instanceof Array) {
return obj.map(item => deepClone(item));
}
let newObj = {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = deepClone(obj[key]);
}
}
return newObj;
}
这个方法很可靠,但代码量很大。
3. 第三方库
Lodash等库提供了深拷贝功能:
let newObj = _.cloneDeep(oldObj);
需要引入额外库,增加了项目体积。
一行代码的终极方案
目前介绍最简单的方法:
const deepClone = obj => structuredClone(obj);
这就是我们今天的主角:structuredClone。
structuredClone详解
基本用法
let original = {
name: "小明",
hobbies: ["篮球", "游泳"],
birthDate: new Date("2000-01-01")
};
let copy = structuredClone(original);
看看以下场景
场景1:状态管理
// 在React中保存状态快照
const saveStateSnapshot = (state) => {
return structuredClone(state);
};
// 恢复到某个状态
const restoreState = (snapshot) => {
setState(structuredClone(snapshot));
};
场景2:数据备份
// 备份表单数据
const backupFormData = (formData) => {
localStorage.setItem('formBackup',
JSON.stringify(structuredClone(formData))
);
};
// 恢复表单数据
const restoreFormData = () => {
const backup = localStorage.getItem('formBackup');
if (backup) {
return structuredClone(JSON.parse(backup));
}
};
场景3:数据比较
// 深比较两个对象是否相等
const isDeepEqual = (obj1, obj2) => {
const clone1 = structuredClone(obj1);
const clone2 = structuredClone(obj2);
return JSON.stringify(clone1) === JSON.stringify(clone2);
};
处理循环引用
循环引用是深拷贝的难点。
let objA = { name: "A" };
let objB = { name: "B" };
objA.ref = objB;
objB.ref = objA;
// 这会报错
// let copy = JSON.parse(JSON.stringify(objA));
// 这会成功
let copy = structuredClone(objA);
structuredClone能够正确处理循环引用,不会进入死循环。
浏览器兼容性
目前主流浏览器都支持structuredClone:
- • Chrome 98+ ✅
- • Firefox 94+ ✅
- • Safari 15.4+ ✅
- • Edge 98+ ✅
对于不支持的环境,可以使用polyfill:
if (typeof structuredClone === "undefined") {
window.structuredClone = function(obj) {
return JSON.parse(JSON.stringify(obj));
};
}
注意事项
重大提醒:
- • 不能复制函数
- • 不能复制DOM元素
- • 在性能敏感的场景要谨慎使用
- • 确保目标环境支持该API
使用提议:
- • 在数据处理、状态管理等场景优先使用
- • 对于简单对象,仍可使用扩展运算符
- • 定期检查浏览器兼容性
使用方法很简单:
const original = { /* 你的对象 */ };
const copy = structuredClone(original);
这一行代码解决了JavaScript开发中的一个大难题。目前你可以专注于业务逻辑,不用再为对象拷贝烦恼了。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
一行代码简洁明了,可大幅减少代码量,提高开发效率