У меня была возможность пересмотреть свою ментальную модель отношений между переменными и ценностями. Это помогло мне лучше понять такие концепции JavaScript, как мелкое копирование.
Поверхностное копирование происходит, когда вы клонируете переменную, которая имеет значение объекта, присваивая ее другой переменной. Изменение объекта через одну переменную влияет на другую переменную.
Чтобы исследовать это глубже, есть несколько утверждений о JavaScript, которые мы должны иметь в виду:
Чтобы исследовать это глубже, есть несколько утверждений о JavaScript, которые мы должны иметь в виду:
- Все примитивные значения уже существуют, и каждое значение существует один раз.
- Мы можем создавать только непримитивные значения.
- Правая часть присваивания всегда возвращает значение. [например:
let age = 10*3
, значение, на которое указывает age, равно30
, а не10*3
.] - Каждый раз, когда используется литерал объекта
{}
, создается новое значение объекта. [например:Object.is({}, {})
равноfalse
.] - Объект не может иметь два свойства с одинаковыми значениями.
Давайте посмотрим на этот фрагмент кода, используя примитивные типы.
Создание копий с помощью метода, описанного выше, прекрасно работает с примитивными типами значений, такими как Number
и String
. Это связано с первым утверждением «Все примитивные значения уже существуют, и каждое значение существует один раз».
В этой статье я буду использовать эскизы и текст для пошаговых фрагментов кода. Давайте рассмотрим это для приведенного выше фрагмента.
- У нас есть переменная
a
, которая указывает на числовое значение2
. - У нас есть еще одна переменная
b
, которая указывает на значение2
a
. - В этот момент
a
иb
представляют одно и то же значение2
. b
получает новое значение3
и больше не указывает2
.a
иb
указывают на2
и3
соответственно.
Эти представления вызвали у вас какие-то лампочки или это было очевидно?
Теперь давайте рассмотрим другой пример, но на этот раз мы будем рассматривать непримитивные типы, такие как объекты. Можете ли вы угадать, что будет зарегистрировано в консоли?
Это вывод из моей консоли, и вы тоже можете попробовать.
Если вы угадали Ibadan
, результат может вас шокировать. Однако, если вы угадали Lagos
, то вы либо хорошо разбираетесь в значениях и свойствах, либо знаете их как JavaScript.
Может возникнуть соблазн подумать, что line 5
создает новое значение объекта для son.address
, но это не так. Если вы помните, одно из утверждений гласит: «Каждый раз, когда используется литерал объекта {}
, создается новое значение объекта».
Глядя на скетч ниже, мы видим, что были созданы только 3 значения объекта, family.address
и son.address
указывают на один и тот же объект. Каждый раз, когда свойство изменяется в значении Object для address
, family.address
и son.address
изменяются, поскольку они указывают на один и тот же объект.
family
указывает на новое значение объекта, которое содержит только одно свойствоaddress
.- Свойство
address
указывает на новое значение объекта, которое имеет свойствоcity
и указывает на строковое значениеIbadan
. son
указывает на новое значение объекта и имеет свойствоaddress
.address
указывает на то же значение объекта, которое было создано на шаге 2, и на его свойства.son.address.city
обновляется и указывает наLagos
.- Поскольку
son.address
иfamily.address
указывают на одно и то же значение объекта, изменение свойств этого объекта влияет на оба. Вы можете проверить это, проверив выводObject.is(son.address, family.address)
в консоли. - Выход для
family.address.city
теперьLagos
. Вы можете убедиться в этом, следуя стрелкам на скетче для example2.js.
Давайте рассмотрим еще один пример, чтобы закрепить то, что мы обсуждали. Можете ли вы угадать вывод этого фрагмента?
У нас есть предпосылка, аналогичная предыдущему примеру. Помня обо всех утверждениях, приступим к наброску.
- У нас есть переменная
family
, которая указывает на новое значение объекта с двумя свойствами:name
иaddress
. name
указывает на строковое значениеMadueke
, аaddress
указывает на новое значение объекта, которое имеет свойствоcity
и указывает на строковое значениеIbadan
.- Далее у нас есть переменная
son
, которая указывает на другое значение объекта с тремя свойствами:name
,surname
иaddress
. son.name
указывает на строковое значениеAdetola
.son.surname
указывает на то же значение, что иfamily.name
.son.address
указывает на то же значение, что иfamily.address
. ПопробуйтеObject.is(son.address, family.address)
в своей консоли.son.address.city
обновляется,city
теперь указывает наLagos
, а это означает, чтоfamily.address.city
также указывает наLagos
.family.name
теперь указывает на новое значение объекта со свойствомsurname
.- Значение, на которое указывает
son.surname
, не изменяется, поскольку его значение было определено до того, какfamily.name
было переназначено.
Резюме
Присвоение переменных другим переменным или свойствам, которые указывают на объекты, не создает новое значение Object для переменной. Вместо этого переменная указывает на существующее значение объекта, что означает создание поверхностной копии. Если объект мутирует, все переменные, указывающие на значение объекта, также изменятся.
Эта идея также применима к массивам, поскольку массивы являются объектами. Попробуйте typeof []
в консоли.
Упражнение:
Каков результат этого?
PS: Вы можете создать скетч для фрагмента кода, как я сделал выше, а также просмотреть примеры.
Поделитесь своими ответами в комментариях или отправьте ответ мне в Твиттере через эту тему.
В восторге от этого изменения в моем процессе мышления JS и улучшения моих ментальных моделей в JS и программировании в целом. Какие вещи, которые вы узнали о программировании, вы хотели бы знать, когда начинали?