简体   繁体   English

'Object.assign'在更深层次上改变状态

[英]'Object.assign' mutates state in deeper levels

I have a sample JSBin code at http://jsbin.com/givolafala/edit?html,js,console,output 我在http://jsbin.com/givolafala/edit?html,js,console,output上有一个示例JSBin代码

 var oldObject = { name: 'John', address: { city: 'new york'}}; var newObject = Object.assign({}, oldObject); console.log(oldObject); console.log(newObject); newObject.name = 'Mathew'; newObject.address.city = 'los angeles'; console.log(oldObject); console.log(newObject); 

In this example, I'm changing the name which is at the top level from John to Mathew . 在这个例子中,我正在改变从JohnMathew的顶级名称 The Object.assign returns the new state with the new name Mathew . Object.assign返回新名称Mathew的新状态。 The oldObject keeps its previous value John . oldObject保留其先前值John

If I change any value in any level other than the root, it does not work. 如果我更改除root之外的任何级别中的任何值,则它不起作用。 In the example I change the city to los angeles , and you will notice that the newObject and the oldObject have the same city los angeles . 在示例中,我将城市更改为los angeles ,您会注意到newObjectoldObject具有相同的城市los angeles So the oldObject state is mutated. 因此oldObject状态发生了变异。

Is this a bug? 这是一个错误吗?

This is not a bug, this is called reference. 这不是一个bug,这叫做引用。 There's a difference between how primitive values and objects (references to objectes actually) behaves. 原始值和对象(实际上是对象的引用)的行为方式之间存在差异。

var oldObject = { name: 'John', address: { city: 'new york'}};

oldObject consist of: oldObject包括:

  • name which is a string value (primitive) name是一个字符串 (原始)
  • addres which is an object, so oldObject really has a reference to address object addres这是一个对象,所以oldObject真的有一个引用 address对象

Now: 现在:

var newObject = Object.assign({}, oldObject);

After copying newObject also has name value and address reference 复制newObject还具有name address 引用

newObject.name = 'Mathew';

Here you change a value of newObject 's property. 在这里,您可以更改newObject属性的值。

newObject.address.city = 'los angeles';

But here you change a property of an object that newObject references . 但是在这里你改变了newObject 引用的对象的属性。 But this reference is also in oldObject so this will change oldObject too. 但是这个引用也在oldObject所以这也会改变oldObject

Basically both newObject and oldObject have a reference to same same address object . 基本上newObjectoldObject引用了相同的address对象

What you expected to achieve is called deep copy . 您期望实现的目标称为深层复制

I guess the description of Object.assign() says everything: 我想Object.assign()的描述说明了一切:

The Object.assign() method only copies enumerable and own properties from a source object to a target object. Object.assign()方法仅将可枚举和自己的属性从源对象复制到目标对象。
It uses [[Get]] on the source and [[Set]] on the target, so it will invoke getters and setters . 它在源上使用[[Get]],在目标上使用[[Set]],因此它将调用getter和setter

Therefore it assigns properties versus just copying or defining new properties. 因此,它分配属性而不仅仅是复制或定义新属性。 This may make it unsuitable for merging new properties into a prototype if the merge sources contain getters. 如果合并源包含getter,这可能使它不适合将新属性合并到原型中。 For copying property definitions, including their enumerability, into prototypes Object.getOwnPropertyDescriptor() and Object.defineProperty() should be used instead. 为了将属性定义(包括它们的可枚举性)复制到原型中,应该使用Object.getOwnPropertyDescriptor()Object.defineProperty()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM