image.png

在JavaScript和TypeScript开发中,对象的深度克隆是一个常见但容易被误解的话题。本文将探讨几种常用的克隆方法,揭示它们的局限性,并介绍真正有效的深度克隆技术。

常见误区:展开运算符和Object.create()

许多开发者习惯使用展开运算符{...}Object.create()来克隆对象,但这些方法实际上只能进行浅拷贝。

展开运算符的局限性:

const original = { name: "John", address: { city: "New York" } };
const clone = { ...original };

clone.address.city = "Los Angeles";
console.log(original.address.city); // 输出: "Los Angeles"

Object.create()的问题:

const original = { name: "John", address: { city: "New York" } };
const clone = Object.create(original);

clone.address.city = "Chicago";
console.log(original.address.city); // 输出: "Chicago"

这两种方法都无法实现真正的深度克隆,因为它们只复制了对象的顶层属性。

JSON.parse(JSON.stringify()):简单而有效

对于简单对象,JSON.parse(JSON.stringify())是一个有效的深度克隆方法:

const original = { name: "John", address: { city: "New York" } };
const clone = JSON.parse(JSON.stringify(original));

clone.address.city = "San Francisco";
console.log(original.address.city); // 输出: "New York"

然而,这种方法也有局限性。它无法处理函数、undefinedInfinityNaN、正则表达式、Map和Set等复杂数据类型。

lodash.deepClone:全面而强大

对于需要处理复杂数据结构的场景,lodash.deepClone是一个更全面的解决方案:

import _ from 'lodash';

const original = {
  name: "John",
  address: { city: "New York" },
  skills: new Set(["JavaScript", "TypeScript"]),
  greet: function() { console.log("Hello!"); }
};

const clone = _.cloneDeep(original);

clone.address.city = "Boston";
clone.skills.add("React");

console.log(original.address.city); // 输出: "New York"
console.log(original.skills.has("React")); // 输出: false

lodash.deepClone能够正确处理嵌套对象、数组、函数,以及特殊的数据结构如Set和Map。

性能考虑

在性能方面,JSON.parse(JSON.stringify())通常对简单对象更快,而lodash.deepClone对复杂结构更可靠但速度较慢。

// 性能测试示例
const simpleObject = { a: 1, b: 2, c: 3 };
const complexObject = { /* 复杂的嵌套结构 */ };

console.time('JSON Simple');
JSON.parse(JSON.stringify(simpleObject));
console.timeEnd('JSON Simple');

console.time('Lodash Simple');
_.cloneDeep(simpleObject);
console.timeEnd('Lodash Simple');

console.time('JSON Complex');
JSON.parse(JSON.stringify(complexObject));
console.timeEnd('JSON Complex');

console.time('Lodash Complex');
_.cloneDeep(complexObject);
console.timeEnd('Lodash Complex');

结论

在JavaScript和TypeScript中实现无突变的深度克隆可能比想象的更复杂。展开运算符和Object.create()虽然常用,但不适合深度克隆。JSON.parse(JSON.stringify())对于简单对象是一个快速有效的解决方案,而lodash.deepClone则是处理复杂数据结构的理想选择。

理解这些方法的优缺点对于选择合适的克隆策略至关重要。在实际开发中,应根据具体需求和数据结构的复杂性来选择适当的深度克隆方法。通过掌握这些技巧,开发者可以更有效地处理对象克隆,提高代码的健壮性和可维护性。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。

王大冶
68k 声望104.9k 粉丝