Оператор распространения, также известный как три последовательные точки «…», невероятно удобен, когда мы пишем Javascript, особенно при копировании итерируемого объекта, такого как массив. Например, мы можем использовать оператор распространения для создания копии существующего массива без изменения исходного массива:
const originalArray = [1, 2, 3]; const newArray = [...originalArray]; newArray[0] = 10; console.log(originalArray); // Output: [1, 2, 3] console.log(newArray); // Output: [10, 2, 3]
Однако одно важное предостережение при копировании массивов или объектов с использованием оператора расширения заключается в том, что процесс по-прежнему создает поверхностную копию оригинала, а не глубокую копию.
Поверхностная копия объекта — это копия, которая копирует только свойства объекта верхнего уровня. Это означает, что любые вложенные объекты или массивы будут по-прежнему ссылаться на исходные объекты и массивы.
Давайте пересмотрим приведенный выше пример массива и изменим его на сценарий вложенного массива:
const originalArray = [[1], [2], [3]]; const newArray = [...originalArray]; //changing the top level does not affect the original array newArray[0] = 10; console.log(originalArray); // Output: [[1], [2], [3]] console.log(newArray); // Output: [10, [2], [3]] //but changing the nested level does!!! newArray[1][0] = 20; console.log(originalArray); // Output: [[1], [20], [3]] console.log(newArray); // Output: [10, [20], [3]]
Как видите, когда мы изменяем первый элемент массива, который является верхним уровнем, это не влияет на исходный массив, как ожидалось. Но когда мы изменим элемент во вложенном массиве на 20, исходный массив также изменится. Чтобы полностью «отключить» новый массив newArray от оригинала, вместо этого мы должны сделать глубокуюкопию.
Глубокаякопия, как следует из названия, называется глубокой. Он не просто создает новую копию на верхнем уровне, вместо этого копируются все уровни объекта. Настоящая, реальная, абсолютная глубокая копия означает, что любые изменения, внесенные в копию или любой из ее вложенных объектов, не повлияют на исходный объект.
Не все копии одинаковы!
Итак, как мы можем сделать глубокую копию?
Вы можете подумать про себя, хорошо, а что, если я использую оператор распространения для этих вложенных элементов? Конечно, вы можете вручную перебирать массив, чтобы использовать оператор распространения, как показано ниже:
const originalArray = [[1], [2], [3]]; const newArray = originalArray.map(innerArray => [...innerArray]); newArray[0][0] = 10; console.log(originalArray); // Output: [[1], [2], [3]] console.log(newArray); // Output: [[10], [2], [3]]
Но если бы у нас было больше вложенных структур, это может быть невероятно утомительным процессом!
Чтобы создать настоящую глубокую копию массива, содержащего вложенные массивы или объекты, можно использовать комбинацию методов JSON.stringify()
и JSON.parse()
.
const originalArray = [[1], [2], [3]]; const deepCopyArray = JSON.parse(JSON.stringify(originalArray)); deepCopyArray[0][0] = 10; console.log(originalArray); // Output: [[1], [2], [3]] console.log(deepCopyArray); // Output: [[10], [2], [3]]
Таким образом, мы используем метод JSON.stringify()
для преобразования исходного массива в строку, а затем используем JSON.parse()
для анализа строки в новый массив.
Это не означает, что вы должны делать глубокие копии все время! В большинстве случаев оператор распространения является отличным методом для создания копий массивов и объектов. По одной очевидной причине поверхностное копирование выполняется намного быстрее. Но если ваши объекты и массивы глубокие (вложенные!), ваш метод копирования тоже должен быть глубоким!