硬拷贝 vs 浅拷贝 JavaScript

17

这可能是一个老问题,但我真的很好奇javascript中通过引用复制对象作为赋值的本质。

也就是说,如果

var a = {}; 
var b = a;
a.name = "Renato";
console.log(b); 
Object {name: "renato"}

我对 JavaScript 还比较陌生,但这个默认使用浅拷贝来赋值对象引起了我的注意。我搜索了一下,发现如果要创建深拷贝,必须创建一个 mixin。我想知道为什么选择这个作为默认值,因为它的转换似乎非常隐晦。谢谢!


1
想知道为什么这被选为默认选项吗?因为在大多数情况下,它是最佳选择。Javascript 是一种垃圾回收环境,其优势之一是能够传递对象而不必担心内存泄漏。另一个优点是速度。 - Keith
此外,深拷贝的成本更高。默认进行浅拷贝可以让程序员自由地选择他们想要执行哪种拷贝。 - Alex
1个回答

29

对象和数组被视为对同一对象的引用。如果想要克隆该对象,有几种方法可以做到。

在较新的浏览器中,您可以使用以下方法:

var b = Object.assign({}, a);

如果你想使用库,lodash 提供了 _.clone(以及_.cloneDeep):

var b = _.clone(a);

如果你不想使用上述两种方法,你可以遍历每个键和值,并将它们分配给一个新对象。

在多个函数中传递时,通常将它们视为引用是有价值的。但是对于像数字和字符串这样的基本数据类型来说,大多数情况下这并不可行,因为那样会感觉相当反直觉。


3
你还可以使用老旧的JSON.parse/stringify方法。 var b = JSON.parse(JSON.stringify(a)) - Keith
1
@Keith 还有另一个想法,但对于具有函数值的对象不起作用。 - Josh Beam
1
如果我们有 { a: 'b', c: function(){} },将其转换为字符串将会得到 "'{'a':'b'}'" - Josh Beam
2
确实,我应该提到数据是否可序列化。这只是另一个选项,如果在旧浏览器上运行,无需加载lodash / underscore等库也可以执行此操作。 - Keith
2
如果你正在使用ES6编写代码,你也可以使用对象展开运算符:let b = {...a};。看起来这在许多浏览器中还不被支持,所以只有在使用转译器(如babel)并且目标是ES5或更早版本时才应该这样做。 - AJ Richardson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接