В недалеком прошлом был только один способ определить переменную в JavaScript - var. Однако с появлением ES6 были добавлены два дополнительных способа: let и const. Подождите ... зачем нам три разных способа сделать одно и то же? Есть ли случаи, когда одно следует использовать вместо другого? Что ж, это некоторые из вопросов, на которые я собираюсь ответить вам в этой статье. Но сначала нам нужно немного обсудить концепцию под названием область действия.

Область действия функции против области действия блока

JavaScript имеет две разные области видимости. Первый - это область действия, иногда называемый глобальной областью, а второй - область действия блока. Давайте рассмотрим несколько примеров, чтобы лучше понять разницу между областью действия функции и областью блока.

Объем функции

В приведенном выше примере значение foo возвращается в строке 4 внутри функции, но вызывает ошибку, когда мы пытаемся получить доступ к foo вне функции в строке 7. Это связано с тем, что переменные, определенные с помощью var, являются функциональная. Доступ к ним можно получить только в той функции, в которой они определены. Так что насчет блочной области видимости?

Блок-область

Давайте добавим еще несколько переменных с использованием let и const, а также оператор if в нашу предыдущую функцию и посмотрим, как различаются области видимости этих переменных.

Как вы можете видеть в строках 7–9, все операторы console.log() в операторе if возвращают ожидаемые значения переменных. Однако при просмотре строк 12–14 мы начинаем видеть некоторые различия. В строке 12 значение для foo отображается в консоли, но строки 13 и 14 возвращают ReferenceError для bar и baz. Это потому, что let и const являются блочными!

JavaScript определяет блок кода как код между фигурными скобками {}.

Поскольку let и const имеют блочную область видимости, они доступны только с фигурными скобками, окружающими оператор if, в котором они были определены. Поскольку var имеет функциональную область видимости, а строка 12 все еще находится в фигурных скобках someFunction, определенных в строке 1 и заканчивающихся на строке 15, у нас есть доступ к значению foo в строке 12 за пределами if блокировать. Наконец, поскольку строка 17 находится за пределами someFunction, мы больше не можем получить доступ к foo в строке 17.

В этом примере показана разница в области видимости между введенным в ES6 let и const и более старым объявлением переменной var. Область видимости - наиболее очевидное различие между этими декларациями, однако у каждого из них есть свои дополнительные нюансы.

Вар

Сначала давайте взглянем на устаревшую декларативную версию var.

Использование var в цикле for

Скажем, у нас есть следующий цикл for:

Как вы думаете, что этот код выведет на консоль?

Серьезно ... дайте предположение, прежде чем прокручивать дальше!

Вывод приведенного выше кода:

0
1
2
3
4
5 // wait...why is this here?!?

Мы ожидаем, что наш код выведет числа 0–4, но мы также получаем число 5 из журнала консоли в строке 5. Причина в том, что мы определили переменную i с помощью var. Поскольку var имеет функциональную область видимости, он по-прежнему доступен за пределами нашего цикла for. Сам цикл for завершается, когда i увеличивается до 5. Однако i сохраняет значение 5, и это то, что возвращается в строке 5.

Переопределение var

Переменная, которая изначально определена с помощью var, может быть переопределена с помощью var позже.

Позволять

Объявление let очень похоже на var и во многом похоже на обновление ES6 до var, которое исправляет некоторые странности. Давайте посмотрим, как let работает в тех же двух примерах, перечисленных выше.

Использование let в цикле for

Давайте рассмотрим тот же цикл for, который мы использовали выше, но с использованием let вместо var.

Так какой же результат на этот раз?

0
1
2
3
4
//ReferenceError: i is not defined

Как видите, значения 1–4 выводятся на консоль, но i недоступен за пределами цикла for из-за того, что let имеет блочную область видимости. Из-за этого мы получаем ReferenceError в строке 5 вместо вывода значения 5 на консоль. В подавляющем большинстве случаев нам действительно не следует обращаться к i за пределами цикла for, в котором он объявлен. Использование let гарантирует, что мы не сможем этого сделать.

Новое определение let

Подобно var, мы можем переопределить переменные, которые были объявлены с помощью let. Тем не менее, синтаксис, который нам разрешено использовать, является более строгим.

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

Const

Ключевое слово const - это сокращение от слова константа. Как и let, const блочная область видимости. В отличие от let и var, которые можно объявить без инициализации, const должен быть инициализирован при объявлении. Основное различие между ними заключается в том, что, когда переменная объявляется с использованием const, ее нельзя переназначить. Это имеет смысл, поскольку цель состоит в том, чтобы переменная оставалась постоянной. Это означает, что использование его в цикле for было бы бессмысленным, поскольку его нельзя было увеличивать.

Как я упоминал ранее, переменную, определенную с помощью const, нельзя переназначить, но можно изменить. Рассмотрим следующий пример.

Как видите, строка 8 выдаст ошибку, потому что она пытается переназначить постоянную переменную cars. Однако можно изменить значение cars, поместив значение «porsche» в конец массива. Результатом вышеупомянутой функции является:

[ 'acura', 'audi', 'bmw', 'porsche' ]

Кроме того, поскольку const имеет блочную область видимости, функция возвращает ошибку ReferenceError в строке 19 из-за того, что console.log(cars) находится за пределами оператора if, в котором определена переменная cars.

Подъем

Тема этой статьи - не подъем, поэтому я не буду вдаваться в подробности того, что такое подъем. Достаточно сказать, что на этапе компиляции JavaScript сохраняет объявления переменных и функций в памяти. Аналогия состоит в том, чтобы представить, что JavaScript берет все ваши переменные и объявления функций и перемещает их в верхнюю часть области видимости перед выполнением кода. Это не то, что происходит, но это нормальный способ думать о подъеме. Возвращаясь к сути этой статьи, есть различия в способах подъема var, let и const. Вот краткий пример:

Есть очень важное отличие в способе подъема var по сравнению с let или const. Разница связана с инициализацией. Когда var поднимается, независимо от присвоенного ему значения, он инициализируется значением undefined. Для сравнения, когда поднимаются let или const, они вообще не инициализируются.

Резюме

  • var - область видимости функции, а let и const - область видимости блока.
  • var и let можно переназначить, а const - нельзя.
  • Когда var поднят, он инициализируется значением undefined. Когда let и const подняты, они вообще не инициализируются.
  • var и let можно объявить без инициализации. Однако при объявлении const необходимо инициализировать.

Итак, что следует использовать, когда? Как правило, лучше избегать использования var, поскольку он обычно указывает на нетронутый унаследованный код, написанный до выпуска ES6. За областью действия var также может быть сложнее следить, чем за областью блока let и const. Более строгие требования к синтаксису let и const также способствуют лучшему кодированию.

В большинстве случаев при создании переменной используется значение по умолчанию const. Если вы подозреваете, что вам потребуется переназначить его в будущем (циклы for, операторы переключения, замена алгоритмов и т. Д.), Используйте let.

Вопросы? Дополнительные мысли? Не стесняйтесь кидать их в комментарии! Надеюсь, вы нашли это полезным.