在JavaScript中克隆对象的3种方法

因为#JavaScript中的对象是引用值,所以不能简单地使用 =。但不用担心,这里有三种方法可以克隆一个对象?

const food = { beef: '?', bacon: '?' }   // "Spread" { ...food }   // "Object.assign" Object.assign({}, food)   // "JSON" JSON.parse(JSON.stringify(food))  // RESULT: // { beef: '?', bacon: '?' } 

对象是引用类型

你的第一个问题可能是,我不能使用乳清 =。让我们看看如果我们这样做会发生什么:

const obj = {one: 1, two: 2};  const obj2 = obj;  console.log(   obj,  // {one: 1, two: 2};   obj2  // {one: 1, two: 2}; ) 

到目前为止,这两个对象似乎输出相同的东西。没问题,对吧。但是让我们看看如果我们编辑第二个对象会发生什么:

const obj2.three = 3;  console.log(obj2); // {one: 1, two: 2, three: 3}; <-- ✅  console.log(obj); // {one: 1, two: 2, three: 3}; <-- ? 

WTH?我变了 obj2 但为什么呢 obj 也受到影响。那是因为对象是引用类型。所以当你使用 =,它将指针复制到它占用的内存空间。引用类型不包含值,它们是指向内存中值的指针。

如果您想了解更多相关信息,请查看Gordon的Zhu Watch and Code价格。可以免费注册并观看视频“与对象比较”。他给出了一个超级棒的解释。

使用Spread

使用spread会克隆你的对象。请注意,这将是一个浅表副本。截至本文,用于克隆对象的扩展运算符位于第4阶段。因此,它尚未正式出现在规范中。因此,如果您要使用它,则需要使用Babel(或类似的东西)进行编译。

const food = { beef: '?', bacon: '?' };  const cloneFood = { ...food };  console.log(cloneFood);  // { beef: '?', bacon: '?' } 

使用Object.assign

或者, Object.assign 是在官方发布并且还创建了对象的浅表副本。

const food = { beef: '?', bacon: '?' };  const cloneFood = Object.assign({}, food);  console.log(cloneFood); // { beef: '?', bacon: '?' } 

使用JSON

这最后的方式会给你一个深刻的副本。现在我要提一下,这是一种深度克隆对象的快速而肮脏的方法。对于更强大的解决方案,我建议使用像lodash这样的东西

const food = { beef: '?', bacon: '?' };  const cloneFood = JSON.parse(JSON.stringify(food))  console.log(cloneFood);  // { beef: '?', bacon: '?' } 

Lodash DeepClone vs JSON

以下是社区的评测。是的,这是我以前的帖子,如何深度克隆数组。但这个想法仍然适用于对象。

Alfredo Salzillo:我想请你注意一下deepClone和JSON.stringify / parse之间存在一些差异。

  • JSON.stringify / parse仅适用于Number和String以及Object literal而不使用函数或Symbol属性。
  • deepClone使用所有类型,函数和符号通过引用复制。

这是一个例子:

const lodashClonedeep = require("lodash.clonedeep");  const arrOfFunction = (() => 2, {     test: () => 3, }, Symbol('4'));  // deepClone copy by refence function and Symbol console.log(lodashClonedeep(arrOfFunction)); // JSON replace function with null and function in object with undefined console.log(JSON.parse(JSON.stringify(arrOfFunction)));  // function and symbol are copied by reference in deepClone console.log(lodashClonedeep(arrOfFunction)(0) === lodashClonedeep(arrOfFunction)(0)); console.log(lodashClonedeep(arrOfFunction)(2) === lodashClonedeep(arrOfFunction)(2)); 

@OlegVaraksin:JSON方法存在循环依赖性问题。此外,克隆对象中的属性顺序可能不同。

浅克隆与深克隆

当我使用spread …复制一个对象时,我只创建一个浅拷贝。如果数组是嵌套的或多维的,它将无法工作。让我们来看看:

const nestedObject = {   country: '??',   {     city: 'vancouver'   } };  const shallowClone = { ...nestedObject };  // Changed our cloned object clonedNestedObject.country = '??' clonedNestedObject.country.city = 'taipei'; 

所以我们通过改变城市改变了克隆对象。我们来看看输出。

console.log(shallowClone); // {country: '??', {city: 'taipei'}} <-- ✅  console.log(nestedObject); // {country: '??', {city: 'taipei'}} <-- ? 

浅拷贝意味着复制第一级,引用更深级别。

深拷贝

我们采用相同的示例,但使用“JSON”应用深层副本

const deepClone = JSON.parse(JSON.stringify(nestedObject));  console.log(deepClone); // {country: '??', {city: 'taipei'}} <-- ✅  console.log(nestedObject); // {country: '??', {city: 'vancouver'}} <-- ✅ 

如您所见,深层副本是嵌套对象的真实副本。通常时间浅的副本足够好,你真的不需要深层复制。它就像钉枪和锤子。大多数时候,锤子非常精细。使用钉枪进行一些小型的艺术和工艺往往是一种矫枉过正,锤子就好了。这就是为正确的工作使用正确的工具?

性能

不幸的是,我不能为传播做一个测试,因为它尚未正式出现在规范中。不过,我将它包含在测试中,以便您将来可以运行它。但结果显示 Object.assign 要快得多 JSON

性能测试

资源

  • MDN Web Docs:Object.assign
  • Stack Overflow:在JavaScript中深度克隆对象的最有效方法是什么?
  • 2ality:休息/传播属性
  • Stack Overflow:对象传播与Object.assign

感谢您阅读❤
问好 Instagram | Twitter | Facebook |博客| SamanthaMing.com

资讯来源:由0x资讯编译自DEV,原文:https://dev.to/samanthaming/3-ways-to-clone-objects-in-javascript-2oie ,版权归作者所有,未经许可,不得转载
你可能还喜欢