Сравнение области видимости переменных var и let
Когда вы объявляете переменную с ключевым словом var
, она объявляется глобально, если не внутри функции, и локально, если объявляется внутри функции.
Ключевое слово let
ведет себя аналогично, но с некоторыми дополнениями. Когда вы объявляете переменную с ключевым словом let
внутри блока, оператора или выражения, его область действия ограничена этим блоком, оператором или выражением. Например:
var numArray = [];
for (var i = 0; i < 3; i++) {
numArray.push(i);
}
console.log(numArray); // [0, 1, 2]
console.log(i); // 3
С ключевым словом var
переменная i
объявляется глобально. Поэтому, когда i++
выполняется, он обновляет глобальную переменную.
На самом деле можно чуть-чуть переписать этот код и получить следующее:
// Объявляем массив
var numArray = [];
// Объявляем глобальную переменную i, пока еще без значения
var i;
// Пишем цикл for, задав переменной i начальное значение 0
for (i = 0; i < 3; i++) {
numArray.push(i);
}
console.log(numArray); // [0, 1, 2]
console.log(i); // 3
Такое поведение вызовет проблемы, если вы должны были создать функцию и сохранить ее для последующего использования внутри цикла for, который использует переменную i
. Это связано с тем, что хранимая функция всегда будет ссылаться на значение обновленной глобальной переменной i
.
var printNumTwo;
for (var i = 0; i < 3; i++) {
if (i===2) {
/*
Если i равно 2, переменной printNumTwo
задаем в качестве значения новую фукнцию,
которая при выполнении должна вернуть
значение переменной i
*/
printNumTwo=function() {
/*
Здесь предполагается, что будет возвращено 2,
ведь i равнялась 2,
когда мы создавали функцию
*/
return i;
};
}
}
console.log(printNumTwo());
Как вы можете видеть, printNumTwo()
печатает 3, а не 2 (как изначально предполагалось). Это связано с тем, что значение, присвоенное переменной i
было обновлено далее в цикле, и printNumTwo()
возвращает актуальное значение глобальной переменной i
, а не значение, которое i
имела при создании функции в цикле for.
Ключевое слово let
ведет себя по-другому:
let printNumTwo;
for (let i = 0; i < 3; i++) {
if (i===2) {
printNumTwo=function() {
return i;
};
}
}
console.log(printNumTwo()); // 2
console.log(i); // Uncaught ReferenceError: i is not defined
Здесь в вызове console.log(i)
мы получаем ошибку, что переменная i
не объявлена. Это правильно, так как здесь она объявляется только в инструкции цикла for и не видна за его пределами. printNumTwo()
вернула правильное значение, потому что при каждой итерации цикла for
создавалась новая переменная i
с ключевым словом let
и с уникальным значением (0, 1 и 2 соответственно в каждой итерации). Такое поведение называется Замыканием.Исправьте код, чтобы в выражении if создавалась отдельная переменная i
, которая не будет пересекаться с переменной i
, объявленной в первой строке функции.
Ключевое слово var
не должно использоваться.
Это упражнение предназначено для иллюстрации разницы между тем, как ключевые слова var
и let
назначают область видимости для объявленных переменных. При программировании функции, аналогичной той, которая используется в этом упражнении, часто лучше использовать разные имена переменных, чтобы избежать путаницы.