【问题标题】:'Object.assign' mutates state in deeper levels'Object.assign' 在更深层次上改变状态
【发布时间】:2016-09-22 13:59:52
【问题描述】:

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

在本例中,我将顶层的 nameJohn 更改为 MathewObject.assign 返回具有新名称 Mathew 的新状态。 oldObject 保持其先前的值 John

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

这是一个错误吗?

【问题讨论】:

  • 如果你想要一个递归 Object.assign 看看deep-assign

标签: javascript ecmascript-6 javascript-objects


【解决方案1】:

这不是错误,这称为参考。原始值和对象(实际上是对对象的引用)的行为方式有所不同。

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

oldObject 包括:

  • name 这是一个字符串 value(原始)
  • addres 是一个对象,所以 oldObject 确实有一个 referenceaddress 对象

现在:

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

复制newObject后还有nameaddress参考

newObject.name = 'Mathew';

在这里更改newObject 的属性值。

newObject.address.city = 'los angeles';

但是在这里你改变了newObject引用的对象的属性。但是这个引用也在oldObject,所以这也会改变oldObject

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

您期望达到的目标称为深拷贝

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2014-09-20
      • 2016-06-11
      • 1970-01-01
      • 2020-01-14
      • 1970-01-01
      • 2016-06-27
      • 2018-03-16
      • 1970-01-01
      • 2015-07-03
      相关资源
      最近更新 更多