Почти во всех языках программирования объявление переменных – то, с чего вы начинаете изучение ЯП. JavaScript уже здесь может поставить в тупик начинающих разработчиков: у языка есть 2 способа объявления переменных, оператор var и оператор let. Ниже – вкратце о том, чем они отличаются и какой вам стоит использовать.
В первых редакциях языка для объявления переменных использовался var, которому потом дали альтернативу в виде let, поэтому рассматривать объявление будем на примере var – так будет проще понять, что улучшено в let. Итак, объявление переменной выглядит так:
var a;
Да, как видите, в переменной ничего пока не хранится – мы просто объявили имя, которое теперь ассоциируется с каким-то участком оперативной памяти. Теперь мы можем «положить что-то» в эту переменную, первичное присвоение называется инициализацией:
a = 50;
Часто это делают вместе, что и называется объявлением переменной, хотя по факту является объявлением + инициализацией:
var a = 50;
А теперь – немного магии: когда вы пишете «var a;», ваша переменная на самом деле неявно инициализируется значением «undefined», и вы можете обратиться к этому значению (что является очень плохой практикой).
Второй момент объявления связан с областью видимости. Если вы хотите создать глобальную переменную – вы просто пишете ее вне скрипта, и она автоматически становится видна в любой строке файла, это работает одинаково для всех языков программирования. А вот чем объявление переменной через var в JS отличается от остальных ЯП – у него нет понятия видимости блоков, переменная может иметь либо глобальную видимость, либо видимость в пределах функции. Например, вот как это работает в Java:
for (int i = 0; i < 5; i++) {
// Объявление переменной внутри цикла
int insideLoop = i * 2;
System.out.println("insideLoop: " + insideLoop);
}
// System.out.println("insideLoop: " + insideLoop); // Ошибка: cannot find symbol
Здесь мы внутри цикла объявили переменную (на самом деле – 2 переменные, есть еще «i»), и она доступна только в цикле – если мы пытаемся обратиться к ней вне цикла, компилятор выдает ошибку. В JavaScript это работает иначе:
for (var j = 0; j < 3; j++) {
var greeting = 'Hi there!';
console.log(greeting); // 'Hi there!'
}
console.log(j); // 3
console.log(greeting); // 'Hi there!'
Как видите, мы спокойно получаем доступ к переменным, которые были объявлены внутри блока, что – контр-интуитивно и может приводить к неочевидным ошибкам, вроде «i» в цикле, начинающейся не с 0.
Обе особенности, которые мы описали выше, вызваны поднятием переменной (hoisting). Поднятие переменной – это когда переменная, объявленная в любом месте функции, перемещается вверх с присвоением значения undefined. Если мы пишем следующий код:
console.log(myVar); // undefined
var myVar = 5;
console.log(myVar); // 5
, то во время компиляции он превращается в такой:
var myVar = undefined;
console.log(myVar); // undefined
myVar = 5;
console.log(myVar); // 5
Поднятие переменной – спорный механизм, который не нашел большого применения, поэтому разработчики стандарта языка решили кардинально решить проблему – ввели новый оператор let, который работает более предсказуемо.
Let имеет именно такое поведение, которое разработчики ожидают от команды объявления переменной: с областью видимости в рамках блока. Пример:
if (true) {
let message = 'Hello, world!';
console.log(message); // 'Hello, world!'
}
console.log(message); // ReferenceError: message is not defined
Как видите, переменная «message», созданная в блоке «if», теперь доступна только в этом блоке.
С обращением к еще не инициализированной переменной все сложнее – стандарт языка все еще позволяет это, даже если вы используете let. Но многие компиляторы на такое действие выдают предупреждение, поэтому вам стоит привыкать к тому, что пользоваться неинициализированной переменной – нельзя.
Практически во всех случаях лучше использовать let, потому что он ведет себя более предсказуемо. Но если вы попали на старый проект, который использует var – вам тоже придется использовать var.
Ровно так же, как и let, только он не дает переназначить переменную. При этом вы все еще можете изменять свойства объекта, объявленного константным – если константа является объектом с полем name, вы можете изменить этот name.