Область видимости (scope) определяет, где в коде доступны переменные и функции. Понимание scope помогает избегать ошибок вроде “переменная не определена” и случайного перезаписывания значений.
Виды области видимости
В JavaScript чаще всего встречаются:
- глобальная область видимости - доступна “сверху вниз” по всему файлу (и иногда шире)
- функциональная область видимости - переменные видны внутри функции
- блочная область видимости - переменные видны внутри блока
{ ... }(if, for, while и т.п.)
Глобальная область видимости
Переменные, объявленные на верхнем уровне файла, находятся в глобальной области видимости этого файла/модуля.
const appName = "Demo";
function show() {
console.log(appName);
}
show(); // "Demo"
Глобальные переменные удобны для констант, но их обычно стараются ограничивать: слишком много глобальных значений усложняют поддержку и повышают риск конфликтов.
Функциональная область видимости
Все, что объявлено внутри функции, доступно только внутри этой функции.
function demo() {
const value = 123;
console.log(value);
}
demo();
console.log(value); // ReferenceError
Параметры функции - это тоже переменные внутри функции:
function sum(a, b) {
return a + b;
}
console.log(sum(2, 3)); // 5
Блочная область видимости: let и const
let и const имеют блочную область видимости, то есть видны только внутри ближайших { ... }.
if (true) {
const status = "ok";
let count = 1;
console.log(status, count);
}
console.log(status); // ReferenceError
console.log(count); // ReferenceError
То же работает в for:
for (let i = 0; i < 2; i += 1) {
console.log(i);
}
console.log(i); // ReferenceError
var и функциональная область видимости
var не имеет блочной области видимости - только функциональную. Это часто приводит к неожиданностям, поэтому var обычно избегают.
if (true) {
var x = 10;
}
console.log(x); // 10
Еще один типичный пример - for с var:
for (var i = 0; i < 3; i += 1) {}
console.log(i); // 3 (переменная "утекла" наружу)
С let такого не происходит.
Lexical scope: переменные берутся из внешних областей
JavaScript использует лексическую (статическую) область видимости: функция “видит” переменные из тех областей, где она была объявлена.
const base = 10;
function addToBase(n) {
return base + n;
}
console.log(addToBase(5)); // 15
addToBase использует base из внешней области.
Вложенные функции
Внутренняя функция видит переменные внешней:
function outer() {
const prefix = "id-";
function inner(n) {
return prefix + n;
}
return inner(7);
}
console.log(outer()); // "id-7"
Это подводит к теме замыканий (closures), которая будет дальше.
Shadowing: переменная перекрывает переменную из внешней области
Если во внутреннем scope объявить переменную с тем же именем, она “перекроет” внешнюю. Это называется shadowing.
const value = "outer";
function demo() {
const value = "inner";
console.log(value); // "inner"
}
demo();
console.log(value); // "outer"
Shadowing иногда полезен, но чаще делает код менее очевидным. Обычно лучше избегать одинаковых имен в разных уровнях, если это не оправдано.
Частые ошибки
1) Использование переменной вне области видимости
function demo() {
const x = 1;
}
demo();
console.log(x); // ReferenceError
2) Случайная “утечка” через var
if (true) {
var temp = "data";
}
console.log(temp); // "data"
3) Путаница с одинаковыми именами
let count = 0;
function inc() {
let count = 10;
count += 1;
return count;
}
console.log(inc()); // 11
console.log(count); // 0
Здесь count внутри функции не меняет внешний count, потому что это другая переменная.
Что стоит запомнить
- Scope определяет, где доступна переменная.
letиconst- блочный scope,var- функциональный scope.- Функции видят переменные из внешних областей (lexical scope).
- Одинаковые имена во вложенных областях создают shadowing и могут запутывать.