Рубрики
Без рубрики

Глубокое копирование в JS

### Проблема только вчера, я и мой друг [Utkarsh] (http://github.com/iamutkarshtiwari/) наблюдали, что в коде JavaScript мы работали пару ошибок, которые мы работали. Сом …

Автор оригинала: Avijit Gupta.

Проблема

Просто вчера, я и мой друг Utkarsh Наблюдалось, что в коде JavaScript мы работали пару ошибок, которые мы работали. Некоторое расследование показало, что источник ошибок является копией массива, который содержал такую же ссылку, как оригинальный массив. Таким образом, изменение копии привело к изменению исходного массива. Итак, нам нужно было создать Глубокая копия оригинального массива, чтобы преодолеть эту проблему.

По умолчанию при копировании = JavaScript хранит ссылку на тот же объект (называемая A неглубокая копия ).

var a = [1,2,3];
var b = a;
a[0] = 5;
console.log(b[0]); // 5

Что все мы пробовали

Наша исходная мысль должна была использовать Object.Create Отказ

  • Использование Object.Create :

Object.Create, казалось, решал проблему, когда мы впервые смотрели на это.

var obj = {name: 'a'};
var obj_copy = Object.create(obj);
obj_copy.name = 'c';
console.log(obj.name); // 'a'

Но позже мы поняли, что, поскольку у нас был объект (ы) внутри массива, Object.Create не работал правильно:

var arr = [{name: 'a'}];
var arr_copy = Object.create(arr);
arr_copy[0].name = 'c';
console.log(arr[0].name); // 'c'

Оказывается, даже копии сделано из Object.Create Не существенно не ссылаются в этом случае:

var arr = [{name: 'a'}];
var arr_copy_1 = Object.create(arr);
var arr_copy_2 = Object.create(arr);

// Now, arr_copy_1 and arr_copy_2 still point to the same reference.

arr_copy_1[0].name = 'c';
console.log(arr_copy_2[0].name); // 'c'
  • Использование Object.Create с массивами:

При подаче заявления Object.Create В массиве результат не был настоящим массивом (это был A Array PSEDUO )!

var a = [1,2,3];
var b = Object.create(a);
console.log(b); // Object { }
  • Использование Object.Create с Array.rom :

Чтобы преобразовать ранее полученный массив PSEDUO в реальный массив, мы попробовали использовать Array.rom :

var a = [1,2,3];
var b = Array.from(Object.create(a));
var c = Array.from(Object.create(a));
b[0] = 8;
console.log(c[0]); // 1

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

var a = [{name: 1},{name: 2},{name: 3}];
var b = Array.from(Object.create(a));
var c = Array.from(Object.create(a));
b[0].name = 8;
console.log(c[0].name); // 8

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

  • Использование Json.stringify и Json.parse :

Продолжая дальше, мы пробовали использовать другой метод в целом. Но это снова не сработало с тех пор, как наш массив содержал объекты, которые имели Функция S внутри них. На Json.stringify Объект, все это несериализуемые свойства теряются:

var a = {name: 'a', exec: function() {return true;}};
var b = JSON.parse(JSON.stringify(a));
console.log(b); // {name: 'a'}

Решение

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

function copy(o) {
   var output, v, key;
   output = Array.isArray(o) ? [] : {};
   for (key in o) {
       v = o[key];
       output[key] = (typeof v === "object") ? copy(v) : v;
   }
   return output;
}

Так что теперь следующие работы:

var a = [{name: 1},{name: 2},{name: 3}];

var b = copy(a);
var c = copy(a);
b[0].name = 8;
console.log(c[0].name); // 1

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

ОБНОВИТЬ:

Объект.assign к {} кажется, делает трюк.

var a = [{name: 1},{name: 2},{name: 3}];

var b = Object.assign({}, a);
var c = Object.assign({}, a);
b[0].name = 8;
console.log(c[0].name); // 1

Первоначально опубликовано на мой блог