【问题标题】:JS: Unexpected inheritance throught .push() methodJS:通过 .push() 方法意外继承
【发布时间】:2019-03-26 19:31:30
【问题描述】:

我现在正在开发一些在画布上运行的游戏引擎。我有一些基本的,但现在我想添加父母和孩子......一切运行正常,直到我尝试将对子对象的引用添加到父对象。我的问题有很短的部分:

// Object that will be parent of obj1
var obj0 = {
  childs: [],
  someValue: 10,
  parent: null
}

// obj1 is defined from obj0 throught Object.assign(), so any change in
// obj1 will NOT reflect to obj0 (I added console.log() to show it)
var obj1 = Object.assign({}, obj0);
console.log("Expected result: false; Result: " + (obj0 == obj1));
obj1.someValue = 5;
console.log("Expected result: false; Result: " + (obj0.someValue == obj1.someValue));

// Now add obj0 as parent to obj1...
obj1.parent = obj0;

// ... and add obj1 as child to obj0 - I need to do this throught .parent
// (I can't directly do some change in obj1)
obj1.parent.childs.push(obj1);

// Everything seems be alright, but... If I look into obj1.childs...
console.log(obj1.childs)
// I see, that .push applied to all objects that are...

如你所见,.push() 方法应用于所有对象(在本例中为两个对象)。

所以我的问题:
1. 为什么?
2. 如何避免?

提前谢谢你...

【问题讨论】:

  • Object.assign() 调用导致两个对象具有相同childs 数组的副本。这是一个“浅”的副本。
  • @Pointy 你是对的,谢谢.. 但是,你知道如何避免这种情况吗?
  • 那么您必须编写自己的代码才能将您的一个对象复制到另一个对象。根据我的经验,想要进行“深拷贝”表明存在架构问题,而在一般情况下,深对象拷贝并不总是可能的。
  • @Pointy 是的...我知道完全复制一个对象非常困难,但是如果我只有空数组(每次创建新数组时它都会是空的)对象),每当我创建一个新对象时,我可以做一些obj1.childs = [] 的事情吗?不会有参考的吧?
  • Object.assign 与继承无关。你的意思是Object.create

标签: javascript object inheritance


【解决方案1】:

obj1 = Object.assign({}, obj0) 之后,obj0obj1 都引用相同的childs 数组。因此,无论您为该数组带来什么突变(例如,push),都将通过两个对象可见。

消除这种不良影响的一种方法是创建一个构造函数(JavaScript 的一个特殊功能),甚至可以使用class 表示法:

class MyClass {
    constructor(value) {
        this.childs = [];
        this.someValue = value;
        this.parent = null;
    }
}

// Object that will be parent of obj1
var obj0 = new MyClass(10);

var obj1 = new MyClass(5);
console.log("Expected result: false; Result: " + (obj0 == obj1));
console.log("Expected result: false; Result: " + (obj0.someValue == obj1.someValue));

// Now add obj0 as parent to obj1...
obj1.parent = obj0;
obj1.parent.childs.push(obj1);

// Everything is alright.
console.log(obj0.childs);
//  Nothing changed here:
console.log(obj1.childs);

【讨论】:

    【解决方案2】:

    根据 cmets,问题在于 Object.assign 是一个浅拷贝,最终两个对象的 childs 属性是同一个数组,因此当您将 push 转换为一个 childs 数组时,另一个也更新了(childs 数组是一个并且相同)。

    也许您想使用一个类来定义您的对象:

    // Object that will be parent of obj1
    class MyObj {
      constructor() {
        this.childs = [];
        this.someValue = 10;
        this.parent = null;
      }
    }
    
    var obj0 = new MyObj();
    var obj1 = new MyObj();
    console.log("Expected result: false; Result: " + (obj0 == obj1));
    obj1.someValue = 5;
    console.log("Expected result: false; Result: " + (obj0.someValue == obj1.someValue));
    
    // Now add obj0 as parent to obj1...
    obj1.parent = obj0;
    
    // ... and add obj1 as child to obj0 - I need to do this throught .parent
    // (I can't directly do some change in obj1)
    obj1.parent.childs.push(obj1);
    
    console.log("obj0's children:")
    console.log(obj0.childs)
    console.log("obj1's children:")
    console.log(obj1.childs)

    【讨论】:

      猜你喜欢
      • 2021-10-16
      • 1970-01-01
      • 1970-01-01
      • 2014-01-01
      • 1970-01-01
      • 2018-05-10
      • 2018-09-15
      • 2023-03-27
      • 2019-04-11
      相关资源
      最近更新 更多