Копирование массива объектов в другой массив без ссылки на объект в JavaScript (Deep Copy) - PullRequest
38 голосов
/ 27 марта 2012

У меня есть сценарий, в котором мне нужно скопировать массив объектов (основной массив) в другой массив Temp, который не должен иметь ссылку на объект в основном, если я делаю какие-либо изменения в массиве Main, он не должен отражаться в массиве Temp, так что я сохранит копию независимо.

Я использовал один из фрагментов кода из переполнения стека, этот частично нравится, если я удаляю все объекты из основного массива, временный массив все еще содержит значение, но когда я делаю некоторые изменения в основном массиве и нажимаю кнопку отмены, я удаляю все объекты из основного массива с помощью array.Removeall (); но модификация все еще существует в массиве Temp, что означает, что объект имеет ссылку.

clone: function (existingArray) {
  var newObj = (existingArray instanceof Array) ? [] : {};
  console.debug('newObj value is ' + newObj);
  for (i in existingArray) {
    console.debug('i value is' + i);
    if (i == 'clone') continue;
    console.debug('existingArray[i] value ' + existingArray[i]);
    if (existingArray[i] && typeof existingArray[i] == "object") {

      newObj[i] = this.clone(existingArray[i]);
    } else {
      console.debug('in else part ' + existingArray[i]);
      newObj[i] = existingArray[i];
    }
  }
  return newObj;
}

моя структура объекта похожа на

Я использую нокаут-каркас.

newObjectCreation = function (localIp, RemoteIp, areaId) {
  this.localIP = ko.observable(localIp);
  this.remoteIP = ko.observable(RemoteIp);
  this.areaId = ko.observable(areaId);
};

template.ProtocolArray.push(new newObjectCreation('', '', '')); // to create default row

пожалуйста, помогите мне в этом отношении. Заранее спасибо.

Ответы [ 7 ]

65 голосов
/ 27 марта 2012

Дайте мне понять: вы не хотите просто иметь новый массив, но вы хотите создать новый экземпляр для всех объектов, присутствующих в самом массиве?Так что, если вы измените один из объектов в временном массиве, эти изменения не распространяются на основной массив?

Если это так, это зависит от значений, которые вы храните в основном массиве.Если эти объекты являются простыми объектами и их можно сериализовать в JSON, то самый быстрый способ:

var tempArray = JSON.parse(JSON.stringify(mainArray));

Если у вас есть более сложные объекты (например, экземпляры, созданные некоторыми вашими собственными конструкторами, узлы HTML и т. Д.)) тогда вам нужен подход ad hoc.

Edit:

Если у вас нет методов для newObjectCreation, вы можете использовать JSON, однако конструктор не будетбыть таким же.В противном случае вы должны сделать копию вручную:

var tempArray = [];
for (var i = 0, item; item = mainArray[i++];) {
    tempArray[i] = new newObjectCreation(item.localIP, item.remoteIP, item.areaId);
}
10 голосов
/ 29 мая 2016

Lodash можно использовать для глубокого копирования объектов _. CloneDeep (значение)

var objects = [{ 'a': 1 }, { 'b': 2 }];

var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// → false
5 голосов
/ 11 октября 2018

Для некоторых других людей с таким же вопросом. Вы также можете сделать это таким образом.
Используя новые функции es6 , вы можете создать копию массива (без ссылки) и копию каждого объекта без одного уровня ссылок.

const copy = array.map(object => ({ ...object }))

Это гораздо более функционально и идиоматично ИМХО

Примечание: Синтаксис распространения эффективно переходит на один уровень глубже при копировании массива. Поэтому он может быть неподходящим для копирования многомерных массивов, как показано в следующем примере ( то же самое с Object.assign () и синтаксисом распространения ).
Дополнительная информация: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

Так что, в основном, если у ваших объектов нет объектов в качестве свойств. Этот синтаксис - это все, что вам нужно. К сожалению, в спецификации нет функции глубокого клонирования "из коробки", но вы всегда можете использовать библиотеку, если это то, что вам нужно

Предупреждение о совместимости браузера: Я думаю, что сейчас это часть спецификации Ecma, но некоторые браузеры не имеют полной поддержки расширенной синтаксической струи. Но с помощью одного из популярных транспортеров вы будете в порядке

5 голосов
/ 27 марта 2012

То есть вы хотите глубокое копирование без ссылки на объект? Конечно, используйте .slice().

Пример:

var mainArr = [],
    tmpArr = []

tmpArr = mainArr.slice(0) // Shallow copy, no reference used.

PS: я не думаю, что двойной JSON-анализ - это производительность .

3 голосов
/ 13 ноября 2017

Чтобы скопировать значения массива без копирования ссылки на массив, вы можете просто сделать:

let tempArray = [...mainArray];

Это рекомендуемое решение для Руководства по стилю JS от AirBnb: https://github.com/airbnb/javascript#arrays

Однако это не создаст новые ссылки для объектов внутри массива.Чтобы создать новую ссылку для массива и объектов внутри, вы можете сделать:

JSON.parse(JSON.stringify(mainArray));
3 голосов
/ 29 декабря 2015

Вы можете использовать копию Angular : angular.copy();

0 голосов
/ 01 марта 2018

Используйте angular.copy. Но не для всего массива (потому что он будет передавать элементы массива по ссылке), но итерировать его и использовать angular.copy для его членов.

var newArray = [];
for (var i = 0, item; item = mainArray[i];) {
    newArray[i] = angular.copy(item);
    i++;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...