скопировать массив объектов - PullRequest
1 голос
/ 08 марта 2019

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

function OBJ1(name, tags) {
    this.myname = name;
    this.mytags = tags;
    this.myvalue = 0;
}

function OBJ2(arg1) {
    this.arg1 = arg1;
    this.myarray = [];
}

var OBJ1_array = [];
var result_array2 = null;
var result;
OBJ1_array = createarray1();
for (i = 0; i < 2; i++) {
    result = createarray2();
}

function createarray1() {
    var myarray = [];
    myarray.push(new OBJ1("NAME", [1, 2, 3]));
    myarray.push(new OBJ1("others", [1, 2, 3]));
    myarray.push(new OBJ1("total", [1, 2, 3]));
    return myarray;
}

function createarray2() {
    var newarray = $.extend(true, [], OBJ1_array); // newarray should refer to a new array, not the same one as OBJ1_array
    OBJ1_array[0].myname = "CHANGED";
    console.log("categories", JSON.parse(JSON.stringify(OBJ1_array)));
    console.log("newarray", JSON.parse(JSON.stringify(newarray)));
}

Вывод:

testscript.js:45 categories (3) [{…}, {…}, {…}]0: {myname: "CHANGED", mytags: Array(3), myvalue: 0}1: {myname: "others", mytags: Array(3), myvalue: 0}2: {myname: "total", mytags: Array(3), myvalue: 0}length: 3__proto__: Array(0)
testscript.js:46 newArray (3) [{…}, {…}, {…}]0: {myname: "CHANGED", mytags: Array(3), myvalue: 0}1: {myname: "others", mytags: Array(3), myvalue: 0}2: {myname: "total", mytags: Array(3), myvalue: 0}length: 3__proto__: Array(0)

Я ожидал, что OBJ1_array[0].myname="CHANGED"; не повлияет на вновь созданный массивnewArray.Вещи, которые я пробовал и не работал:

var newArray = OBJ1_array.map(a => ({...a}));
var newarray=$.extend(true,[],OBJ1_array);

Как я могу решить эту проблему?

Ответы [ 6 ]

4 голосов
/ 08 марта 2019

Документация $.extend гласит следующее:

Не определенные свойства не копируются.Однако свойства, унаследованные от прототипа объекта , будут скопированы . Свойства, которые представляют собой объекты, созданные с помощью new MyCustomObject(args), или встроенные типы JavaScript, такие как Date или RegExp, не восстанавливаются и будут отображаться как простые объекты в результирующем объекте или массиве.

Это означает, что массив со всеми простыми объектами в нем будет глубоко объединен / скопирован.Однако объекты, созданные с ключевым словом new, восстановлены не будут.Это оставляет нам следующий сценарий:

Копирование массива работает очень хорошо, однако, поскольку элементы в массиве создаются с использованием ключевого слова new, они больше не объединяются.При изменении самого массива (push, popping и т. Д.) Вы можете видеть, что массив действительно является копией.

Проблема здесь в том, что вы обращаетесь к одному из элементов в массиве и изменяете объект (созданныйс ключевым словом new).Оба массива по-прежнему указывают на один и тот же объект, поэтому при чтении из другого массива, который содержит ту же ссылку на объект, вы также увидите это изменение.

demonstration image

Чтобы решить эту проблему, вы также должны сделать копию каждого объекта в массиве.В зависимости от вашего варианта использования вы можете использовать Object.assign или Object.create, прежде чем использовать их вслепую, ознакомьтесь с документацией.

I 'Мы также создали минимальный пример проблемы, с которой вы сталкиваетесь, чтобы дать вам лучшее понимание проблемы.

// setup
var array1, array2, array3, array4;
function Dummy(name) { this.name = name }


// test #1 - using plain objects
array1 = [{ name: 'Foo' }];
array2 = $.extend(true, [], array1);

array1[0].name = 'Bar';

console.log(array1[0].name, array2[0].name);


// test #2 - using the `new` keyword
array3 = [new Dummy('Foo')];
array4 = $.extend(true, [], array3);

array3[0].name = 'Bar';

console.log(array3[0].name, array4[0].name);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
1 голос
/ 08 марта 2019

Проблема в вашей петле и функции OBJ1 .в первый раз OBJ1_array в порядке, но когда вы приходите во второй раз, его значение уже изменилось ..

вы можете попробовать этот код

function OBJ1(name, tags) {
   return {myname:name, tags:tags}
    //this.myvalue = 0;
}

function OBJ2(arg1) {
    this.arg1 = arg1;
    this.myarray = [];
}

var OBJ1_array = [];
var result_array2 = null;
var result;
OBJ1_array = createarray1();

for (i = 0; i < 2; i++) {
let tempArr = $.extend(true, [], OBJ1_array);
    result = createarray2();
OBJ1_array = tempArr;
}

function createarray1() {
    let myarray = [];
   myarray.push(new OBJ1("NAME", [1, 2, 3]));
    myarray.push(new OBJ1("others", [1, 2, 3]));
    myarray.push(new OBJ1("total", [1, 2, 3]));
    return myarray;
}

function createarray2() {
    let newarray =$.extend(true, [], OBJ1_array);// newarray should refer to a new array, not the same one as OBJ1_array

    OBJ1_array[0].myname = "CHANGED";
    console.log("categories", JSON.parse(JSON.stringify(OBJ1_array)));
    console.log("newarray", JSON.parse(JSON.stringify(newarray)));
}
0 голосов
/ 08 марта 2019

Я думаю, вам нужно глубокое клонирование вашего объекта. пожалуйста, используйте ниже функцию

function clone(src) {
  var ret=(src instanceof Array ? [] : {});
  for(var key in src)
  {
    if(!src.hasOwnProperty(key)) { continue; }
    var val=src[key];
    if(val && typeof(val)=='object') { val=clone(val);  }
    ret[key]=val;
   }
 return ret;
}

function OBJ1(name, tags) {
    this.myname = name;
    this.mytags = tags;
    this.myvalue = 0;
}

function OBJ2(arg1) {
    this.arg1 = arg1;
    this.myarray = [];
}

var OBJ1_array = [];
var result_array2 = null;
var result;
OBJ1_array = createarray1();
for (i = 0; i < 2; i++) {
    result = createarray2();
}

function createarray1() {
    var myarray = [];
    myarray.push(new OBJ1("NAME", [1, 2, 3]));
    myarray.push(new OBJ1("others", [1, 2, 3]));
    myarray.push(new OBJ1("total", [1, 2, 3]));
    return myarray;
}

function createarray2() {
    var newarray = clone(OBJ1_array) ; // newarray should refer to a new array, not the same one as OBJ1_array
    OBJ1_array[0].myname = "CHANGED";
    console.log("categories", JSON.parse(JSON.stringify(OBJ1_array)));
    console.log("newarray", JSON.parse(JSON.stringify(newarray)));
}

гораздо более простой подход

var cloneOfOBJ1_array = JSON.parse(JSON.stringify(OBJ1_array));
0 голосов
/ 08 марта 2019

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

Используйте Array.map() для перебора массива и копирования каждого элемента.

Используйте Object.create(), чтобы сделать неглубокий клон каждого объекта. Эта функция берет дескриптор прототипа и свойства для создания нового объекта. Вы можете использовать Object.getPrototypeOf() Object.getOwnPropertyDescriptors(), чтобы передать ему дескрипторы прототипа и свойств вашего входного объекта.

function OBJ1(name) {
  this.myname = name;
}

const array1 = [new OBJ1("NAME")];

const array2 = array1.map(obj =>
  Object.create(
    Object.getPrototypeOf(obj),
    Object.getOwnPropertyDescriptors(obj)
  )
);
array2[0].myname = 'Jack';

console.log(array1[0].myname);
console.log(array2[0].myname);
0 голосов
/ 08 марта 2019

Обновлен ответ. Самый простой способ достичь желаемого - использовать JSON.stringify с JSON.parse для создания несвязанной копии массива объектов.

const OBJ1 = (name, tags) => ({
  myname: name,
  mytags: tags,
  myvalue: 0,
})

function createarray1() {
  var myarray=[];
  myarray.push(OBJ1("NAME", [1,2,3]));
  myarray.push(OBJ1("others", [1,2,3]));
  myarray.push(OBJ1("total", [1,2,3]));
  return myarray;
}

const arr = createarray1()
// here you create a copy of array
const newArr = JSON.parse(JSON.stringify(arr))
// apply changes directly to the copy
newArr[0].myname = 'Something else'
console.log(newArr)
console.log(arr)
0 голосов
/ 08 марта 2019

решено клонирование массива объектов с помощью Object.assign

const newArray = myArray.map(a => Object.assign({}, a));

или даже короче с синтаксисом распространения

const newArray = myArray.map(a => ({...a}));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...