深拷贝——忘记JSON.parse 和 JSON.stringify,拥抱structuredClone
-
structuredClone()是什么?structuredClone()是在2022年引入的一个全局函数,它能够深度克隆JavaScript对象。与传统的方法JSON.stringify()和JSON.parse()不同。之前的方法在处理复杂结构和循环引用时存在一定的问题,而structuredClone()则能够轻松应对这些挑战。
-
为什么它是一个游戏规则改变者?
- 它是一个强大的工具,用于实现真正的深度克隆,保留嵌套对象和循环引用的完整性,无需额外的逻辑或hack方法。此外,它在现代浏览器中可用,这其中也包括Web Workers。
1. 简单对象克隆:基础
- 使用
{...obj}(浅拷贝)
const original = { name: "Alice", details: { age: 25 } };
const shallowCopy = { ...original };
shallowCopy.details.age = 30;
console.log(original.details.age); // 30
console.log(shallowCopy.details.age); // 30
-
发生了什么?
- 展开运算符
{...obj}只创建浅拷贝。details对象没有被深度克隆,因此对shallowCopy.details的更改也会影响原始的details。 - 使用
JSON.stringify()+JSON.parse()(深度拷贝)
- 展开运算符
const original = { name: "Alice", details: { age: 25 } };
const deepCopy = JSON.parse(JSON.stringify(original));
deepCopy.details.age = 30;
console.log(original.details.age); // 25
console.log(deepCopy.details.age); // 30
-
发生了什么?
- 这种方法创建了一个深度拷贝,但它有局限性:它无法处理
Function、undefined或循环引用。 - 使用
structuredClone()(深度拷贝)
- 这种方法创建了一个深度拷贝,但它有局限性:它无法处理
const original = { name: "Alice", details: { age: 25 } };
const clone = structuredClone(original);
clone.details.age = 30;
console.log(original.details.age); // 25
console.log(clone.details.age); // 30
- 发生了什么?
structuredClone()创建了一个深度克隆,保留了结构,没有任何JSON.stringify()的限制,并能够处理复杂的数据类型,如循环引用和undefined。
2. 处理循环引用:一个挑战
- 使用
{...obj}的循环引用
const original = { name: "Alice" };
original.self = original;
// 这将导致一个错误:
const shallowCopy = { ...original }; // TypeError: Converting circular structure to JSON
-
发生了什么?
{...obj}无法处理循环引用,导致错误。- 使用
JSON.stringify()的循环引用
const original = { name: "Alice" };
original.self = original;
// 这将导致一个错误:
const jsonCopy = JSON.parse(JSON.stringify(original)); // TypeError: Converting circular structure to JSON
-
发生了什么?
JSON.stringify()也处理不了循环引用,抛出错误。- 使用
structuredClone()的循环引用
const original = { name: "Alice" };
original.self = original;
const clone = structuredClone(original);
console.log(clone !== original); // true
console.log(clone.self === clone); // true
- 发生了什么?
structuredClone()能够无缝处理循环引用,创建一个正确的深度克隆,没有错误。
3. 克隆包含函数和undefined:另一个测试* 使用 {...obj}
const original = { name: "Alice", greet: () => "Hello!", value: undefined };
const shallowCopy = { ...original };
console.log(shallowCopy.greet()); // "Hello!"
console.log(shallowCopy.value); // undefined
-
发生了什么?
{...obj}按预期复制函数和undefined,但只是浅拷贝。- 使用
JSON.stringify()
const original = { name: "Alice", greet: () => "Hello!", value: undefined };
const jsonCopy = JSON.parse(JSON.stringify(original));
console.log(jsonCopy.greet); // undefined
console.log(jsonCopy.value); // undefined
-
发生了什么?
JSON.stringify()无法序列化函数或undefined,导致在克隆对象中丢失它们。- 使用
structuredClone()
const original = { name: "Alice", greet: () => "Hello!", value: undefined };
const clone = structuredClone(original);
console.log(clone.greet); // undefined
console.log(clone.value); // undefined
- 发生了什么?
structuredClone()也不克隆函数,但保留undefined值,使其比JSON.stringify()更可靠,适用于复杂对象。
4. 速度和效率:性能提示
- 处理大数据的效率
const largeArray = new Array(1e6).fill({ key: "value" });
console.time("structuredClone");
const clone = structuredClone(largeArray);
console.timeEnd("structuredClone");
console.time("JSON.stringify + JSON.parse");
const jsonCopy = JSON.parse(JSON.stringify(largeArray));
console.timeEnd("JSON.stringify + JSON.parse");
- 发生了什么?
structuredClone()通常比JSON.stringify()+JSON.parse()更快,适用于大型复杂数据,避免了序列化和反序列化的陷阱。
5. 结论:为什么 structuredClone() 是未来
- 可靠性:更可预测地处理循环引用、函数和
undefined值。 - 效率:对于大型数据集执行深度克隆更快,不需要变通方法。
- 简洁性:一种方法统治所有——不再需要在
{...obj},JSON.stringify()或自定义深度克隆函数之间选择。