Создать копию многомерного массива, а не ссылки - JavaScript

Возможный дубликат:
Каков наиболее эффективный способ клонирования объекта JavaScript?

Это также называют "глубоким копированием", на котором я нашел некоторые статьи. Ближе всего выглядит этот, но для jQuery - я пытаюсь сделать это без библиотеки.

Я также видел в двух местах, что можно сделать что-то вроде:

arr2 = JSON.decode(JSON.encode(arr1));

Но это, по-видимому, неэффективно. Также возможно циклическое и копирование каждого значения по отдельности и повторение всех массивов. Это кажется утомительным и неэффективным.

Итак, какой самый эффективный, небиблиотечный способ копирования многомерного массива JavaScript [[a],[b],[c]]? При необходимости я полностью доволен методом "не IE".

Спасибо!

Ответ 1

Так как это похоже на то, что вы имеете дело с массивом массивов на неизвестном уровне глубины, но вам нужно только иметь дело с ними на одном уровне глубоко в любой момент времени, тогда он будет простым и быстрым в использовании .slice().

var newArray = [];

for (var i = 0; i < currentArray.length; i++)
    newArray[i] = currentArray[i].slice();

Или используя .map() вместо цикла for:

var newArray = currentArray.map(function(arr) {
    return arr.slice();
});

Итак, это итерация текущего массива и построение нового массива мелких копий вложенных массивов. Затем, когда вы переходите на следующий уровень глубины, вы сделали бы то же самое.

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

Ответ 2

Я не уверен, насколько лучше JSON.stringy и JSON.parse, чем encode и decode, но вы можете попробовать:

JSON.parse(JSON.stringify(array));

Что-то еще я нашел (хотя я бы немного его изменил):

http://www.xenoveritas.org/blog/xeno/the-correct-way-to-clone-javascript-arrays

function deepCopy(obj) {
  if (typeof obj == 'object') {
    if (isArray(obj)) {
      var l = obj.length;
      var r = new Array(l);
      for (var i = 0; i < l; i++) {
        r[i] = deepCopy(obj[i]);
      }
      return r;
    } else {
      var r = {};
      r.prototype = obj.prototype;
      for (var k in obj) {
        r[k] = deepCopy(obj[k]);
      }
      return r;
    }
  }
  return obj;
}

Ответ 3

Как вы просили повысить производительность, я думаю, вы также поделитесь с не общим решением. Чтобы скопировать многомерный массив с известным количеством уровней, вы должны пойти с самым простым решением, некоторые вложенные для-петли. Для вашего двухмерного массива это будет выглядеть примерно так:

var len = arr.length,
    copy = new Array(len); // boost in Safari
for (var i=0; i<len; ++i)
    copy[i] = arr[i].slice(0);

Нативный метод slice более эффективен, чем пользовательский для цикла, но он не создает глубокие копии, поэтому мы можем используйте его только на самом низком уровне.

Ответ 4

Любой рекурсивный алгоритм, который не посещает один и тот же node дважды, будет примерно таким же эффективным, как и с javascript (по крайней мере в браузере) - в некоторых ситуациях на других языках вы можете уйти с копированием патронов памяти, но javascript явно не обладает этой способностью.

Я предлагаю найти кого-то, кто уже сделал это, и используя их реализацию, чтобы убедиться, что вы правильно поняли - это нужно только определить один раз.