Довольно сложно решить проблему копирования или клонирования в программировании.

Во-первых, вам нужно понять, что понятия "значение" и "память" разделены. Языки программирования имеют свою собственную систему типов данных, которую можно разделить на две части. «Типы значений» и «Ссылочные типы». Данные с введенным значением всегда сохраняются в новой памяти при копировании. Когда данные ссылочного типа копируются, копируется только адрес памяти, так что и исходная переменная, и новая переменная имеют одинаковое значение в одной и той же памяти. Это называется «поверхностное копирование». Или вы можете вручную скопировать значение данных и сохранить его в новую память, используя «глубокую копию».

Во-вторых, вам нужно выбрать способ копирования объекта. поверхностная копия против глубокой копии. Это означает, что вам нужно подумать о неизменности свойств исходного объекта. Вы хотите, чтобы свойства глубоко внутри исходного объекта были изменены свойствами скопированного объекта?

Наконец вам нужно решить, какой метод использовать. Если вы хотите сделать поверхностную копию, вы можете просто создать новую переменную и присвоить исходный объект или массив новой переменной с помощью оператора «=».

Для создания глубокой копии вы можете использовать Array.prototype.slice() для массива и синтаксис распространения для объекта. Кроме того, существует множество методов массива, которые не влияют на элементы исходного массива после изменения скопированного.

Но когда вы хотите сделать глубокую копию, это немного сложно.

Глубокая копия объекта с несколькими глубинами

При попытке использовать методы массива или синтаксис распространения для глубокого копирования объекта с несколькими глубинами возникает проблема. Более глубокие свойства указывают на те же данные в той же памяти, что и исходный объект. Таким образом, кажется, что единственный настоящий метод глубокого копирования может быть достигнут только с помощью пользовательской рекурсивной функции. (Или есть библиотека Lodash, поддерживающая метод cloneDeep, что очень полезно)

Но недавно я узнал о structuredClone API из спецификации HTML 5. Вы можете сериализовать данные и сделать глубокую копию массива или объекта независимо от того, сколько у него глубины.

По данным caniuse.com, большинство современных веб-браузеров поддерживают этот API. Так что кажется, что нет большой проблемы в использовании этого замечательного API. Вам не нужно создавать свою собственную рекурсивную функцию, чтобы каждый раз делать глубокую копию. Как чудесно!

Дело в том, что есть проблема, когда ваш объект имеет свойство, которое является функцией, включающей все три типа функций JS. («Функциональный объект [Function]», «обычная функция [function(){}]», «стрелочная функция [()=>{}]»)

Это потому, что функция JS не сериализуема.

В javascript функция состоит из двух частей. Тело функции (исходный код) и лексическое окружение. Каждая функция имеет внутренний слот, в который записывается лексическое окружение. Лексическое окружение — это внешняя область действия функции, в которой эта функция была определена. Так что в основном функции знают, где они были сделаны.

Из-за этого лексического окружения мы можем использовать замыкания. Закрытие — это внутренние функции вложенных функций, которые могут использовать данные внешней функции после завершения жизненного цикла внешней функции. В javascript каждая функция может быть замыканием, поскольку лексическое окружение записывается в ее внутренний слот. (Но мы вызываем замыкание функции только тогда, когда оно напрямую ссылается на данные внешней функции)

Поскольку доступ к внутреннему слоту невозможен, состояние лексического окружения не сериализуемо. В соответствии со спецификацией HTML5 только сериализуемые значения могут быть клонированы с использованием API-интерфейсаstructuredClone.

Ссылки