JS: Неожиданное наследование через метод .push () - PullRequest
0 голосов
/ 26 марта 2019

Сейчас я разрабатываю игровой движок, работающий на холсте. У меня есть некоторые базовые, но теперь я хочу добавить родителей и детей ... Все работает нормально, пока я не попытаюсь добавить ссылку на дочерний объект в родительский объект. Вот очень короткая часть моей проблемы:

// 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. Как мне этого избежать?

Заранее спасибо ...

Ответы [ 2 ]

2 голосов
/ 26 марта 2019

После obj1 = Object.assign({}, obj0) и obj0, и obj1 ссылаются на один и тот же массив 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);
1 голос
/ 26 марта 2019

Что касается комментариев, проблема в том, что 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...