javascript, почему 2 разных объекта ссылаются на / используя один и тот же массив? - PullRequest
0 голосов
/ 27 апреля 2018

У меня есть определение объекта, в котором есть массив. Когда я создаю 2 объекта и получаю доступ к его членам, оба объекта записывают в один и тот же массив. Я ожидал, что для каждого объекта будет свой массив, а не один и тот же. Он отлично работает для других членов объекта. Почему это так и как правильно это сделать? Ниже приведен пример кода

//define simple object
var OBJ = {
  id: 0,
  arr: [0,0]
};

//instantiate objects
let obj1 = Object.create(OBJ);
let obj2 = Object.create(OBJ);

//change members value
obj1.id = 1;
obj1.arr[0]=1111;

obj2.id=2;
obj2.arr[1]=2222;

//verify changes
console.log(obj1.id);   //id = 1 as expected
console.log(obj1.arr);  //<--- expected [1111, 0000] NOT [1111, 2222]
console.log(obj2.id);   //id = 2 as expected
console.log(obj2.arr);  //<--- expected [0000, 2222] NOT [1111, 2222]

Ответы [ 3 ]

0 голосов
/ 27 апреля 2018

Задача

Когда вы используете Object.create() для создания нового объекта из OBJ, OBJ становится прототипом нового объекта. Все методы и свойства взяты из цепочки прототипов , если только объект не переопределяет их, имея свои собственные свойства с тем же именем. Поскольку arr является свойством OBJ, все объекты обновляются и отображают один и тот же массив.

Предлагаемое решение

Вы можете преобразовать arr в getter , который проверит, является ли arr свойством текущего объекта, используя Object.hasOwnProperty(), и, если нет, клонирует прототипы. массив, а затем вернуть его.

//define simple object
var OBJ = {
  id: 0,
  _arr: [0, 0],
  get arr() {
    if(!this.hasOwnProperty('_arr')) this._arr = [...this._arr];
    
    return this._arr;
  }
};

//instantiate objects
let obj1 = Object.create(OBJ);
let obj2 = Object.create(OBJ);

//change members value
obj1.id = 1;
obj1.arr[0] = 1111;

obj2.id = 2;
obj2.arr[1] = 2222;

//verify changes
console.log(obj1.id); //id = 1 as expected
console.log(obj1.arr); //<--- expected [1111, 0000]

console.log(obj2.id); //id = 2 as expected
console.log(obj2.arr); //<--- expected [0000, 2222]
0 голосов
/ 27 апреля 2018

То, что вы пытаетесь достичь, возможно:

function OBJ() {
    this.id = 0;
    this.arr = [0,0];
}

let obj1 = new OBJ();    
let obj2 = new OBJ(); 

потому что он создает отдельный экземпляр для каждого нового созданного объекта, т. Е. Каждый новый созданный объект имеет свою собственную копию id и arr.


Ваш подход будет хорошо работать для примитивных типов данных, но не для непримитивных типов данных, таких как Array. Вы создаете экземпляр массива в прототипе, не понимая, что изменение этого массива изменит его для всех экземпляров.

obj1 и obj2 изначально имеют ссылку на тот же id и arr прототипа OBJ.

obj1 / obj2 имеет свою собственную новую копию id только при изменении obj1.id / obj2.id , в противном случае они ссылаются на одно и то же id из Прототип OBJ .

Теперь, это поведение только для примитивных типов. С не примитивными типами, т.е. массивом, и obj1 и obj2 всегда ссылаются на один и тот же arr прототипа OBJ.

0 голосов
/ 27 апреля 2018

https://lodash.com/docs/4.17.5#cloneDeep

должно быть тем, что вы хотите, оно будет копировать все рекурсивно

...