До вчерашнего дня я думал, что правильный способ скопировать объект в JavaScript - это использовать Object.assign ().

let obj = {a: 1, b: 2, c: 3};
let newObj = Object.assign({}, obj);
// assign new value to a in newObj
newObj.a = 4;
// old obj should be unaffected, no reference error
obj
// returns original obj {a: 1, b: 2, c: 3}

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

У вас есть справочные проблемы с любыми глубоко вложенными свойствами.

let obj = {a: 1, b: 2, c: {d: 4} };
let newObj = Object.assign({}, obj);
// reassign new value to c.d
newObj.c.d = 5;
// obd obj has been changed with newObj
obj
// returns {a: 1, b: 2, c: {d: 5} }
// what I had expected {a: 1, b: 2, c: {d: 4} }

Вот и все, ссылки на ошибки при копировании любого объекта с глубоко вложенными свойствами.

Вчера гнался за странной ошибкой в ​​приложении response-redux. Что-то меняло мой магазин redux, хотя этот конкретный редуктор так и не был вызван. Произошло то, что когда я установил состояние в другом редукторе, я использовал Object.assign ({}, obj), чтобы (как мне казалось) скопировать объект из другого хранилища. На самом деле, когда я изменил массив, вложенный в скопированный объект, исходный объект также был затронут.

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

Я не могу поверить в (почти) 2018 год, со всеми улучшениями, сделанными, чтобы сделать программирование более чистым, что лучший способ скопировать объект JavaScript таков:

let obj = {a: 1, b: 2, c: {d: 4}};
let newObj = JSON.parse(JSON.stringify(obj));
newObj.c.d = 100
// original object c.d is unaffected
obj
// returns {a: 1, b: 2, c: {d: 4}}
newObj
// returns {a: 1, b: 2, c: {d: 100}}

Но именно так Mozilla рекомендует глубокое клонирование объекта. У них даже есть раздел с предупреждением об этом недостатке в Object.assign () в документации mdn.

Я надеюсь, что этот пост поможет кому-то другому не тратить впустую часы, как я.