Let, Var и Const: определение переменных в JavaScript

Окончательная доработка ES6 в 2015 году принесла новые способы определения переменных JavaScript. Ключевое слово let
создает блочную переменную, а const
задает неизменяемое значение. Вот краткое изложение того, чем эти современные типы переменных отличаются от классического var
.
Вар
До ES6 единственным вариантом при определении переменной был var
. Вы можете свободно изменять значения переменных, созданных с помощью var
. Вы также можете повторно объявить саму переменную.
class="kw1">var demo class="sy0">= class="st0">"first value"class="sy0">;
class="kw1">var demo class="sy0">= class="st0">"second value"class="sy0">;
demo class="sy0">= class="st0">"third value"class="sy0">;
example class="sy0">= class="st0">"this throws an error - variable not declared"class="sy0">;
Использование var
создает переменную, область действия которой ограничена текущей функцией. Если вы используете его вне функции, результирующая переменная будет иметь глобальную область видимости.
«Область действия» переменной описывает, где ее можно использовать. К переменной области действия функции можно получить доступ из кода в функции, которая ее определяет. Глобальная переменная доступна во всем коде.
class="kw1">var myGlobal class="sy0">= class="st0">"global"class="sy0">;
class="kw1">function testAclass="br0">(class="br0">) class="br0">{
class="kw1">var myFunctionScope class="sy0">= class="st0">"testA"class="sy0">;
console.class="me1">logclass="br0">(myFunctionScopeclass="br0">)class="sy0">;
console.class="me1">logclass="br0">(myGlobalclass="br0">)class="sy0">;
class="br0">}
class="kw1">function testBclass="br0">(class="br0">) class="br0">{
myGlobal class="sy0">= class="st0">"overwritten!"class="sy0">;
console.class="me1">logclass="br0">(myGlobalclass="br0">)class="sy0">;
class="co1">// console.log(myFunctionScope); // ERROR
class="br0">}
testAclass="br0">(class="br0">)class="sy0">;
testBclass="br0">(class="br0">)class="sy0">;
testAclass="br0">(class="br0">)class="sy0">;
В этом примере показана разница между глобальными и функциональными переменными. myGlobal
может быть прочитан (и записан) как testA
, так и testB
. myFunctionScope
определен только в testA
, поэтому testB
выдает ошибку при попытке доступа к нему. Вот что выведет этот пример:
testA
global
overwritten!
testA
overwritten!
Значение myFunctionScope
поддерживается отдельно в каждой функции. Значение myGlobal
обновляется в обеих функциях, когда testB
перезаписывает его.
Позволять
Более новое ключевое слово let
является современной альтернативой var
. Вы часто можете использовать let
во всех местах, где раньше писали var
. Однако следует отметить важные различия.
Наиболее важной функцией let
является его область действия. Переменные ограничиваются отдельными блоками кода, а не целыми функциями. В JavaScript блок — это часть кода, заключенная в фигурные скобки. Каждая переменная let
доступна только для кода внутри ее блока.
class="kw1">function letTestclass="br0">(xclass="br0">) class="br0">{
let demo class="sy0">= class="st0">"hello world"class="sy0">;
class="kw1">if class="br0">(x class="sy0">> class="nu0">10class="br0">) class="br0">{
let y class="sy0">= class="nu0">9000class="sy0">;
demo class="sy0">= class="st0">"foobar"class="sy0">;
class="br0">}
console.class="me1">logclass="br0">(democlass="br0">)class="sy0">; class="co1">// "foobar"
console.class="me1">logclass="br0">(yclass="br0">)class="sy0">; class="co1">// ERROR
class="br0">}
В этом примере оператор if
создает новый блок кода. Блоки наследуют область действия своего родительского блока, поэтому переменная demo
остается доступной. Область действия переменной y
ограничена оператором if
. Попытка доступа к y
вне блока if
приводит к ошибке неопределенной переменной.
Как и var
, переменные, созданные с помощью let
, могут изменять свои значения в любое время. Однако их нельзя повторно объявить — использование let
дважды с одним и тем же именем в одном блоке вызовет ошибку.
let demo class="sy0">= class="st0">"test"class="sy0">;
demo class="sy0">= class="st0">"example"class="sy0">;
let demo class="sy0">= class="st0">"test"class="sy0">; class="co1">// ERROR
Исключением является повторное объявление переменной во вложенной области. Правила области видимости на уровне блоков означают, что это разрешено — в итоге вы получите две отдельные переменные, которые имеют один и тот же идентификатор.
let foo class="sy0">= class="st0">"bar"class="sy0">;
class="kw1">if class="br0">(class="kw2">trueclass="br0">) class="br0">{
let foo class="sy0">= class="st0">"foobar"class="sy0">;
console.class="me1">logclass="br0">(fooclass="br0">)class="sy0">;
class="br0">}
console.class="me1">logclass="br0">(fooclass="br0">)class="sy0">;
В приведенном выше примере выдается foobar bar
. Переменная foo
повторно объявляется в блоке if
, не затрагивая переменную foo
внешней области. Вы теряете возможность ссылаться на внешнюю переменную из внутреннего блока.
Постоянная
Ключевое слово const
было еще одним дополнением ES6. Он имеет блочную область действия, как let
. const
— это сокращение от «константа» и используется для неизменяемых значений, которые никогда не изменятся. Попытка обновить значение переменной const
всегда приводит к ошибке.
class="kw1">const foo class="sy0">= class="st0">"bar"class="sy0">;
class="kw1">const foo class="sy0">= class="st0">"foobar"class="sy0">; class="co1">// ERROR
Как следствие, вы всегда должны инициализировать переменные const
со значением. Недопустимо определять const
и устанавливать его значение позже.
let demoLetclass="sy0">; class="co1">// OK
class="kw1">var demoVarclass="sy0">; class="co1">// OK
class="kw1">const demoConstclass="sy0">; class="co1">// ERROR
class="kw1">const demoConst class="sy0">= class="st0">"value"class="sy0">; class="co1">// OK
Технически const
не определяет постоянное значение. На самом деле он создает постоянную ссылку на значение. В результате вы по-прежнему можете обновлять свойства объектов, назначенных const
. Ошибки возникают только в том случае, если вы используете сам const
в левой части присваивания.
Какой тип переменной следует использовать?
Вы должны принять let
для большинства переменных общего назначения в вашем коде JavaScript. Область действия на уровне блоков и запрещенное повторное объявление помогают обнаруживать ошибки и избегать непреднамеренных перезаписей.
Использование let
останавливает «утечку» переменных, когда к переменным можно получить доступ в областях, для которых они не предназначены. Классический пример — итераторы в циклах:
class="kw1">for class="br0">(class="kw1">var i class="sy0">= class="nu0">0class="sy0">; i class="sy0"><= class="nu0">10class="sy0">; iclass="sy0">++class="br0">) class="br0">{
class="co1">// do something
class="br0">}
console.class="me1">logclass="br0">(iclass="br0">)class="sy0">;
Это приведет к тому, что 10
будет выведено на консоль. Использование вместо этого let
вызовет undefined
, поскольку переменная i
будет недоступна вне if
. объем. Обычно это желаемый результат в такого рода сценариях.
Циклы также демонстрируют опасность переназначения var
:
class="kw1">for class="br0">(class="kw1">var i class="sy0">= class="nu0">0class="sy0">; i class="sy0"><= class="nu0">10class="sy0">; iclass="sy0">++class="br0">) class="br0">{
setTimeoutclass="br0">(class="br0">(class="br0">) class="sy0">=> console.class="me1">logclass="br0">(iclass="br0">)class="sy0">, class="nu0">1000class="br0">)class="sy0">;
class="br0">}
На первый взгляд, этот код выглядит так, будто он должен выдавать числа от 1 до 10. Вместо этого 10
будет записано десять раз. setTimeout()
является асинхронным, а i
в обратном вызове лексически привязан к области. Поскольку в цикле используется var i
, переменная i
получает новое значение на каждой итерации. Когда запускается обратный вызов таймера, все десять итераций уже завершены, и i
всегда будет разрешаться в окончательное значение — в данном случае 10
.
Использование вместо этого let i
приведет к объявлению новой переменной с именем i
для каждой итерации цикла. Каждая переменная сохранит свое значение после завершения итерации, что приведет к ожидаемому выводу журнала.
Когда не использовать Let
Есть сценарии, в которых не следует использовать let
. Вы должны использовать const
, когда создаете переменную, которая, как вы знаете, никогда не изменится. Тогда упаковщики и инструменты статического анализа смогут предупредить вас, если вы невольно попытаетесь переназначить его значение.
Обычно хорошей идеей является сохранение переменных неизменными везде, где это возможно. Это помогает устранить ошибки, вызванные непреднамеренной перезаписью. Использование const
также помогает указать ваше намерение в кодовой базе, явно указав, что значение не изменится.
Такие функции ES6, как let
и const
, теперь повсеместно поддерживаются современными браузерами. Некоторые старые браузеры без полной поддержки ES6, особенно Internet Explorer 11, также предлагают их. Вам не нужно беспокоиться о том, будут ли они доступны, если только вы не ориентируетесь на сильно устаревшую платформу. Используйте let
и const
, чтобы сделать ваш код чище и снизить риск скрытых ошибок.
Статьи по данной тематике:
- Исправить ошибку «dpkg: ошибка: синтаксический анализ файла '/var/lib/dpkg/updates/0014'» в Ubuntu
- Исправить ошибку «E: не удалось получить блокировку /var/lib/dpkg/lock» в Ubuntu
- Как исправить — Не удалось получить ошибку блокировки /var/lib/dpkg/lock в Ubuntu
- Исправление ошибки «не удалось получить блокировку /var/lib/dpkg/lock» раз и навсегда (Ubuntu)
- Как переместить /var в другой каталог на полном разделе
- SELECT * WHERE var == [одна из многих альтернатив] в MySQL?
- Как исправить ошибку «Не удалось получить блокировку /var/lib/dpkg/lock» в Ubuntu?
- Как исправить «Невозможно подключиться к локальному серверу MySQL через сокет var/run/mysqld/mysqld.sock»?
- Как решить ошибку «Не удалось открыть файл блокировки /var/lib/dpkg/lock-frontend»
- Что такое сообщения журнала var (/var/log/messages)
- Не удалось получить блокировку var lib dpkg — Ubuntu/Debian
- Измените корневой каталог Docker /var/lib/docker в другое место.
- Исправить «Невозможно заблокировать каталог администрирования (/var/lib/dpkg/)» в Ubuntu.
- Установка Debian 8 (Jessie) с зашифрованными LUKS разделами /home и /var
- Тип переменной Python для печати – как получить тип Var