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

时间:2016-05-25 06:12:50

标签: javascript ecmascript-6 javascript-objects

我在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);

在此示例中,我正在更改位于JohnMathew顶级的名称Object.assign以新名称Mathew返回新状态。 oldObject保留其先前值John

如果我更改除root之外的任何级别中的任何值,则它不起作用。在示例中,我将城市更改为los angeles,您会注意到newObjectoldObject具有相同的城市los angeles。所以oldObject状态发生了变异。

这是一个错误吗?

2 个答案:

答案 0 :(得分:4)

这不是错误,这称为引用。原始值和对象(实际上对象的行为)的行为方式之间存在差异。

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

oldObject包括:

  • name这是一个字符串(原始)
  • addres这是一个对象,因此oldObject确实有一个引用address对象

现在:

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

复制后newObject还有name address 参考

newObject.name = 'Mathew';

您可以在此处更改newObject属性的值。

newObject.address.city = 'los angeles';

但是,您可以在此处更改newObject 引用的对象的属性。但是这个引用也在oldObject中,所以这也会改变oldObject

基本上,newObjectoldObject都有对同一个address对象的引用。

您期望实现的目标称为深层复制

答案 1 :(得分:2)

我想Object.assign()的描述说明了一切:

  

Object.assign()方法仅将源对象的可枚举和自有属性复制到目标对象。
   它在源上使用[[Get]],在目标上使用[[Set]],因此它将调用getter和setter

     

因此,它会分配属性而不仅仅是复制或定义新属性。如果合并源包含getter,这可能会使它不适合将新属性合并到原型中。要将属性定义(包括其可枚举性)复制到原型中,应使用Object.getOwnPropertyDescriptor()Object.defineProperty()