Эта статья посвящена привязке переменных к областям действия. Итак, я предполагаю, что у вас есть базовое понимание программирования на любом языке. В противном случае это может показаться трудным для понимания. Потому что я собираюсь обсуждать немного туманные вещи. Начнем с определения привязки.
Что такое привязка?
Переменная более официально известна как привязка. Когда мы объявляем и / или инициализируем переменную, мы фактически привязываем значение к имени внутри области. Область действия обычно относится к определенной части программы.
Таким образом, привязка возникает всякий раз, когда мы объявляем и / или инициализируем переменную с использованием одного из этих ключевых слов: var, let и const в JavaScript. Например:
ES6 предлагает несколько лучших подходов для привязки блоков с использованием var, let и const. Но есть некоторые нечеткие вещи, которые движок JavaScript делает за кулисами. Сначала я бы использовал привязку var:
Привязка VAR: путаница
Здесь я трижды записываю переменную name в консоль в блоках if, else, и включающие. Разобьем блоки:
если заблокировать
Блокировать еще
заключающий блок
Теперь вы можете представить, что произойдет, если мы передадим в функцию логическое значение? Что ж, здесь происходит путаница. Если вы передадите true, функция получит результат из блоков if и включающих, в противном случае - из else и включающие блоки. Но помните, что name объявляется и инициализируется только в блоке if.
Как имя доступно в блоках else и включающие? Ответ - из-за подъема.
Подъем?
ES6 предлагает новую функцию под названием подъем. В общем, подъем - это механизм, который обрабатывает контексты выполнения в JavaScript. Это означает, что объявления переменных и функций (не инициализации) помещаются в память на этапах компиляции перед тем, как перейти к выполнению.
Объявления var обрабатываются так, как если бы они поднимались в верхнюю часть функции (включающий блок) или в глобальную область видимости, если они объявлены вне функции. Таким образом, движок JavaScript внутренне обрабатывает предыдущую функцию следующим образом:
Обратите внимание, что объявление поднято вверх, но инициализация остается именно там, где мы вводим переменную name. Это означает, что мы можем получить доступ к переменной name из любого места в охватывающем блоке в случае привязки var.
Чтобы решить эту проблему с помощью var, ES6 вводит объявления на уровне блоков с использованием let и const.
Объявления уровня блока
Если вы объявляете переменную в области видимости на уровне блока, используя любую из let и const, вы не сможете получить доступ к объявлению вне этой области видимости блока. Области блока могут быть созданы в следующих местах:
- Внутри функции (функциональный блок)
- Внутри блока (в двух фигурных скобках {})
Мы уже видели эти области видимости на уровне блока в приведенном выше примере. Теперь мы снова воспользуемся предыдущей функцией, но на этот раз с использованием let или const. В порядке. Я собираюсь использовать let. Рассмотрим следующий пример:
Обратите внимание на привязку let. На этот раз name существует только внутри блока if. Он недоступен за пределами блока if. Поскольку механизм JavaScript не поддерживает объявления let и const. Таким образом, имя недоступно в блоках else и включающих .
CONST Binding: недоразумение
Как правило, привязка const является константой. Это означает, что вам не разрешается изменять или модифицировать однажды установленное значение. Это означает, что вы должны объявлять и инициализировать значение одновременно. Это не позволит вам объявить идентификатор без инициализации, как это делается с объявлением let.
Привязка const не позволяет вам изменять привязку, но не значение. Непонимание происходит, когда вы привязываете объект к идентификатору с помощью привязки const. Рассмотрим следующее:
Сначала мы привязываем литерал объекта к идентификатору person с типом привязки const. Это все еще верно. Но привязка const запрещает повторные объявления с теми же идентификаторами в той же области.
О, нет! Кажется, выше есть еще три идентификатора человека. Как?
Хорошо! Обратите внимание, что мы дважды привязываем новые имена к свойству name объекта person. Таким образом, это меняет то, что содержится в человеке, но не меняет того, к чему привязан этот человек. person содержит ссылку на литерал объекта. Таким образом, человек привязан к ссылке на этот объектный литерал. Таким образом, мы не меняем привязку идентификатора person, мы меняем значение свойства person.name.
Так что же происходит с последним фрагментом кода? Обратите внимание, что мы не только меняем здесь значение свойства name, но и снова назначаем новый литерал объекта идентификатору person, что неверно. Ранее это уже было объявлено и инициализировано с помощью привязки const. Это фактически нарушает правило привязки const и вызывает ошибку.
TDZ: временная мертвая зона
Временная мертвая зона или TDZ не упоминается в спецификации ECMAScript 6. Но обычно это используется, чтобы объяснить, почему привязки let и const недоступны до их объявления. Рассмотрим следующий пример:
Здесь оператор console.log (name) вызывает ошибку ссылки. Потому что мы обращаемся к переменной name перед ее объявлением. Место, где мы пытаемся получить доступ к переменной name, называется временной мертвой зоной. Это напоминает нам, что мы не можем получить доступ к переменным до их объявления для привязок let и const.
«Когда механизм JavaScript просматривает предстоящий блок и находит объявление переменной, он либо поднимает объявление в верхнюю часть функции или в глобальную область (для var), либо помещает объявление в TDZ (для let и const) ». - Николас Закас
Приведенный выше пример может выглядеть как следующий фрагмент кода, если вы сосредоточитесь на движке JavaScript.
Таким образом, любая попытка доступа к переменной в TDZ приводит к ошибке выполнения. Эта переменная удаляется из TDZ, когда выполнение переходит к объявлению переменной. То же самое происходит с привязкой const.
Почему именно ТДЗ?
Как и привязка блоков, TDZ предлагает поведение, которое с меньшей вероятностью приведет к непреднамеренным ошибкам. Переменные следует объявлять именно там, где они нужны. Вот почему ES6 порождает привязки let и const. Вам не разрешен доступ к их привязкам до их объявления.
Поступая таким образом, JavaScript устраняет проблему, вызывающую ошибку. Потому что вы можете непреднамеренно это сделать.
Еще один ТДЗ!
До сих пор мы видели TDZ с использованием let и const. Но значение параметра по умолчанию в функции также имеет TDZ. Каждый параметр создает новую привязку, аналогичную объявлению let. И вы не можете ссылаться на эту привязку перед инициализацией. Инициализация параметра происходит, когда функция вызывается либо путем передачи для нее значения, либо с использованием значения по умолчанию. Посмотрите следующий код:
Когда мы вызываем функцию add, движок JavaScript присваивает параметрам следующие значения:
Здесь мы видим, что вызов add (undefined, 1) вызывает ошибку ссылки, сообщающую нам, что y не определен. Уведомление y было присвоено x перед его инициализацией. Но y в этот момент находится в TDZ. Следовательно, ссылки на y запрещены. Вот почему мы получаем ошибку.
Вот и все!
Вывод
Здесь я пытаюсь выделить три вещи. Один устанавливает привязку var, другой - объекты с помощью const, а третий - TDZ. Если вы хотите написать лучший код JavaScript, вы должны четко понимать эти, казалось бы, неясные три вещи.
На данный момент я надеюсь, что вы теперь очень хорошо разбираетесь в этих вещах. Я собираюсь разместить несколько ссылок ниже. Так что вы, возможно, захотите узнать о них больше. И я также надеюсь, что вам понравится читать это письмо.
Если вы считаете, что это полезно, пожалуйста, поделитесь им. Пожалуйста, не стесняйтесь предлагать мне что-нибудь помимо комментариев. Большое Вам спасибо.
Ссылки:
- "Переполнение стека"
- Изучение ES6
- Mozilla MDN
- Понимание ECMAScript 6