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

  • У вас есть массив объектов
  • Вы не хотите его клонировать и расширять
  • Вы не хотите изменять оригинал

Звучит довольно прямолинейно, верно? Правильно. Давайте к этому:

Просто так, не так ли? Мы не хотим изменять исходный массив, поэтому просто создаем новый массив и распространяем в него содержимое оригинала. Да будет благословен синтаксис распространения!

Теперь давайте изменим value для одного из объектов внутри нашего клона:

clone[2].value = 'c'

Великолепный. Третий объект внутри нашего скопированного массива теперь должен иметь значение c. При этом мы ожидаем, что исходный объект останется нетронутым. Давайте сравним оба, чтобы увидеть, правы ли мы:

original[2] == clone[2] // true

Чего ждать? Они не должны быть равными! Мы никогда не меняли значение original[2], не так ли? Да, мы сделали.

Проблема:

Как мы знаем, в JavaScript все является объектом. Это означает, что как массив, так и его содержимое рассматриваются как таковые. Кроме того, во время выполнения каждый объект имеет свою собственную ссылку.

Создав новый массив для нашего клона, мы также создали новую ссылку. Однако: распространение оригинала на его содержимое не создаст для них новую ссылку. Вместо этого эти объекты по-прежнему будут указывать на оригинал. Это означает, что изменение clone[2].value фактически будет ссылаться на исходный объект и, таким образом, изменить его в обоих массивах.

Решение:

Хорошо, JavaScript: если вы хотите новый объект, мы дадим вам новый объект! К счастью, наш друг Object.assign здесь, чтобы помочь:

clone[2] = Object.assign({}, { id: original[2].id, value: 'c' })

Или даже лучше: мы можем просто снова использовать оператор распространения, чтобы распространить фактический объект.

clone[2] = {...original[2], value: 'c'}

Поскольку синтаксис расширения будет клонировать только первый уровень массива, этот подход не работал с клонированием нашего массива original. Однако: расширение одномерного объекта в основном будет делать то же самое, что и Object.assign .

Теперь, когда мы фактически назначили совершенно новый объект, мы также создали совершенно новую ссылку.

Начнем с самого начала, давайте посмотрим, получится ли это:

Здорово! Теперь оригинал остается нетронутым, в то время как нашему новому объекту присваивается новое значение.

«Но подождите!», — слышу я ваш вопрос. «Вы использовали original[2] для присвоения id нашему новому объекту. Разве это не означает, что он также изменится, если мы попытаемся изменить его?»

Мы будем, я рад, что вы спросили. Почему бы просто не пойти и не попробовать?

clone[2].id = 4
clone[2].id // 4
original[2].id // 3

Как видите: несмотря на то, что мы ссылались на оригинал, чтобы назначить id для нашего клона, его изменение не повлияет на оригинал. Это потому, что Object.assign создаст совершенно новую ссылку не только для самого объекта, но и для его содержимого.

Я надеюсь, что этот небольшой экскурс поможет вам понять, как JavaScript лучше обрабатывает объекты и ссылки. Не забудьте поставить лайк, если статья была вам полезна!