ES2015 (ES6) принес с собой много новых интересных фич. Теперь на дворе 2020 год, и можно предположить, что многие JavaScript-разработчики уже познакомились с этими фичами и стали их применять.
Хотя такое предположение может оказаться отчасти верным, по-прежнему вероятно, что какие-то из этих фич остаются загадкой для некоторых разработчиков.
Одна из фич, появившихся в E6, — это добавление let
и const
, которые можно использовать, чтобы объявить переменную. Вопрос таков: чем они отличаются от старого-доброго var
, которым мы пользовались до этого? Если вам это до сих пор неясно, тогда эта статья для вас.
В этой статье мы обсудим var
, let
и const
— их области видимости, использование и поднятие. Пока будете читать, обращайте внимание на отличия между ними, на которые я буду указывать.
До пришествия E6 объявления через var
царили безраздельно. Однако существуют проблемы с переменными, объявленными с помощью этого ключевого слова. Вот почему необходимо было появиться новым способам того, как объявлять переменные. Давайте в первую очередь получше разберемся в var
, прежде чем обсуждать упомянутые проблемы.
Область видимости по существу своему указывает на то, где данные переменные доступны для использования. Var
-объявления могут обладать видимостью глобальной или локальной (область видимости в пределах функции).
Переменная var
является глобальной, когда объявлена вне какой-либо функции. Это означает, что любая переменная, объявленная через var
вне блока функции, доступна для использования во всем окне.
Var
является локальной, когда объявлена внутри функции. Это означает, что она доступна и к ней можно обращаться только изнутри этой функции.
Чтобы разобраться получше, давайте рассмотрим пример:
var greeter = "hey hi";
function newFunction() {
var hello = "hello";
}
Здесь переменная greeter
— глобальная, поскольку находится вне какой-либо функции, а hello
— ограничена функцией. Так что мы не можем обратиться к переменной hello
извне данной функции. Поэтому, если попробовать сделать вот так:
var tester = "hey hi";
function newFunction() {
var hello = "hello";
}
console.log(hello); // error: hello is not defined
…на выходе будет ошибка. Это происходит из-за того, что переменная hello
недоступна вне конкретной функции.
Это значит, что мы можем сделать это внутри соответствующей области видимости и не получить ошибку.
var greeter = "hey hi";
var greeter = "say Hello instead";
Или даже так:
var greeter = "hey hi";
greeter = "say Hello instead";
Поднятие — механизм в JavaScript, по которому переменные и объявления функций перемещаются в верхнюю часть своей области видимости, прежде чем начнется выполнение кода. Это означает, что если сделать вот так:
console.log (greeter);
var greeter = "say hello"
…то это будет интерпретировано так:
var greeter;
console.log(greeter); // greeter is undefined
greeter = "say hello"
Таким образом, переменные var
поднимаются в верхнюю часть своей области видимости и инициализируются со значением undefined
.
Есть одна слабость, которая сопутствует var
. Чтобы объяснить ее, я приведу пример ниже:
var greeter = "hey hi";
var times = 4;
if (times > 3) {
var greeter = "say Hello instead";
}
console.log(greeter) // "say Hello instead"
Как видно, поскольку times > 3
возвращает значение true, значение переменной greeter
переопределяется как “say Hello instead”
. Хотя это не проблема, если вы сознательно хотите добиться такого переопределения для greeter
. Проблема возникает тогда, когда вы не осознаёте, что переменная greeter
уже была определена ранее.
Если вы использовали greeter
в других участках вашего кода, вас удивит результат, который получите на выходе. Это наверняка вызовет множество ошибок в вашем коде. Вот почему возникает необходимость в let
и const
.
let
теперь наиболее предпочтительный вариант для объявления переменных. Что неудивительно: let
выступает в качестве улучшения объявления через var
, и к тому же решает проблему с var
, о которой мы только что говорили.
Блок — это фрагмент кода, ограниченный фигурными скобками {}. Всё, что находится внутри фигурных скобок, относится к блоку.
Таким образом, переменная, объявленная в блоке через let, будет доступна только внутри этого блока. Давайте рассмотрим на примере:
let greeting = "say Hi";
let times = 4;
if (times > 3) {
let hello = "say Hello instead";
console.log(hello);// "say Hello instead"
}
console.log(hello) // hello is not defined
Здесь видно, что попытка использовать hello
вне блока (фигурных скобок, в рамках которых переменная была определена) возвращает ошибку. Это происходит потому, что переменные типа let
являются блочными.
Точно так же, как и в случае с var
, переменные, объявленные через let
, можно обновлять внутри их области видимости. Но, в отличие от var
, let
-переменные нельзя повторно объявить внутри области видимости. Так что, хотя такое сработает:
let greeting = "say Hi";
greeting = "say Hello instead";
этот код уже вернет ошибку:
let greeting = "say Hi";
let greeting = "say Hello instead"; // error: Identifier
'greeting' has already been declared
Однако, если переменная с одним и тем же именем определена в разных областях видимости, ошибки не будет:
let greeting = "say Hi";
if (true) {
let greeting = "say Hello instead";
console.log(greeting); // "say Hello instead"
}
console.log(greeting); // "say Hi"
Почему же ошибки нет? Так происходит, потому что оба экземпляра рассматриваются как различные переменные, поскольку у них различаются области видимости.
Это и делает let
лучшей опцией по сравнению с var
. Используя let
, вам не нужно беспокоиться, не было ли у вас уже переменной с таким именем раньше, ведь переменная существует только внутри своей области видимости.
Кроме того, поскольку переменная внутри конкретной области видимости может быть объявлена только единожды, проблема, которую мы обсуждали выше относительно var
, перестает иметь место.
Точно так же, как в случае с var
, объявления через let
перемещаются вверх. Но в отличие от var
-переменных, которые инициализируются как undefined
, ключевое слово для let
не инициализируется. Так что если вы попытаетесь использовать переменную let
до того, как она будет объявлена, то получите ошибку обращения к переменной ReferenceError.
Переменные, объявленные через const
, сохраняют постоянные значения. Объявления через const
имеют некоторое сходство с объявлениями через let
.
Точно как и в случае с let
, переменные, объявленные через const
, могут быть доступны только внутри того блока, где были объявлены.
Это означает, что значение переменной, объявленной через const
, остается неизменным внутри ее области видимости. Нельзя ни обновить его, ни объявить повторно. Так что если мы объявляем переменную const
, то не можем сделать ни такого:
const greeting = "say Hi";
greeting = "say Hello instead";// error: Assignment to constant variable.
…ни вот такого:
const greeting = "say Hi";
const greeting = "say Hello instead";// error: Identifier
'greeting' has already been declared
Таким образом, каждое объявление через const
должно быть инициализировано в момент объявления.
Это поведение несколько отличается, когда речь идет об объектах, объявленных через const
. Пускай const
-объект не может быть обновлен, свойства таких объектов обновлять можно. Поэтому, если объявить const
-объект вот таким образом:
const greeting = {
message: "say Hi",
times: 4
}
…то, пускай, мы не можем сделать такого:
const greeting = {
words: "Hello",
number: "five"
} // error: Assignment to constant variable.
Мы можем сделать другое:
greeting.message = "say Hello instead";
Это позволит обновить значение greeting.message
без того, чтобы получить на выходе ошибку.
Точно так же, как и let
, объявления через const
перемещаются вверх, но не инициализируются.
Так что на случай, если вы упустили суть отличий, то вот они вкратце:
var
, могут быть глобальными или иметь область видимости в рамках функции; let
и const
имеют блочную область видимости.var
-переменные могут быть как обновлены, так и переопределены внутри области видимости; let
-переменные можно обновлять, но не переопределять; const
-переменные нельзя ни обновлять, ни переопределять. var
-переменные при этом инициализируются как undefined
, let
и const
не инициализируются.var
и let
можно объявить, но не инициализировать, const
необходимо инициализировать во время объявления.Перевод статьи Sarah Chima Atuonwu“Var, Let, and Const — What’s the Difference?”
Комментарии