Перейти к содержимому
Теория · Область видимости · урок 1 из 8

Блочная область видимости

Чему вы научитесь

Чему вы научитесь:

  • определять, где в программе видна переменная let, const или var;
  • объяснять, почему var выше своей строки хранит undefined, а let там останавливает программу;
  • замечать затенение и понимать, чьи переменные видит функция;
  • включать строгий режим, чтобы опечатка в имени стала ошибкой.
Комната { } за тонированным стеклом с коробкой let b внутри; из неё виден коридор с var a, а снаружи внутрь не видно

Представьте квартиру, где у каждой комнаты стены из тонированного стекла. Изнутри комнаты видно и её саму, и коридор за стеклом. А из коридора внутрь комнаты заглянуть нельзя.

Вещь, которую оставили в комнате, существует только для тех, кто в этой комнате находится. Переменные в JavaScript устроены похоже: где переменную объявили, там её и видно.

Но у разных слов объявления «комнаты» разного размера. Здесь в одной ветке if объявлены две переменные, а после ветки прочитать можно только одну из них:

JavaScript
function show(n) {
    if (n > 0) {
        var a = n;
        let b = n * 2;
        console.log(a, b); // 5 10
    }
    console.log(a); // 5
}

show(5);

Давайте разберём, что происходит при вызове show(5):

  1. Условие n > 0 истинно, и выполнение входит в ветку if.
  2. var a = n кладёт в a число 5, а let b = n * 2 кладёт в b число 10.
  3. Внутри ветки видны обе переменные, и программа печатает 5 10.
  4. После закрывающей скобки ветки console.log(a) печатает 5: переменная a пережила ветку.

Если поставить console.log(b) на место последней строки функции, программа остановится с ошибкой ReferenceError: b is not defined. Переменная a объявлена словом var, а b — словом let, и правила видимости у них разные.

Блок и область видимости

Область видимости — часть программы, в которой имя переменной можно прочитать. Блок — код в фигурных скобках: ветка if, тело цикла или функции. В нашей картинке блок — это комната со стеклянными стенами.

Фигурные скобки можно написать и отдельно, без if и for. Такая пара тоже считается блоком.

let и const живут в блоке

Переменная, объявленная через let или const, видна от строки объявления до закрывающей скобки своего блока:

  • во вложенных блоках она видна, как коридор из комнаты;
  • снаружи блока её нет;
  • на закрывающей скобке блока она исчезает.

Поэтому в двух соседних блоках могут жить две разные переменные с одним именем:

JavaScript
const limit = 10;

{
    const half = limit / 2;
    if (half > 2) {
        console.log(half); // 5
    }
}

{
    const half = 1;
    console.log(half); // 1
}

Разберём, кто что видит:

  1. Константа limit объявлена вне блоков, поэтому её видно в обоих.
  2. Первая half видна в своём блоке и во вложенном блоке if, и программа печатает 5.
  3. На первой закрывающей скобке первая half исчезает.
  4. Вторая half — уже другая константа, и программа печатает 1.

Здесь картинка с комнатами перестаёт работать. Настоящая комната стоит и тогда, когда в ней никого нет. А блок создаётся заново каждый раз, когда выполнение входит в него, и пропадает вместе со своими переменными на закрывающей скобке.

var живёт в функции

Слово var — старый способ объявлять переменные, и такая переменная не замечает блоков. Её видно во всей функции, где она объявлена, даже после if или цикла. Такую область называют областью видимости функции.

Если функция — квартира, то переменная var стоит не в комнате, а в прихожей: её видно из любой комнаты этой квартиры. Параметры живут по тому же правилу: они видны во всём теле своей функции.

JavaScript
function lastSquare(n) {
    for (var i = 1; i <= n; i++) {
        var square = i * i;
    }
    return i + " " + square;
}

console.log(lastSquare(3)); // 4 9

Давайте посмотрим, откуда берётся 4 9:

  1. Цикл проходит i от 1 до 3, и на последнем шаге square получает 9.
  2. Затем i++ делает i равной 4, условие i <= n становится ложным, и цикл заканчивается.
  3. Обе переменные пережили цикл, поэтому return собирает строку 4 9.

Если заменить оба var на let, строка с return остановит программу с ReferenceError. За пределы функции var не выходит: вне lastSquare имён i и square нет.

Этот вопрос часто задают на собеседовании: «Чем отличаются var, let и const?» Ответ состоит из трёх частей:

  • var виден во всей функции и не замечает блоков;
  • let и const видны только в своём блоке;
  • переменной const нельзя присвоить новое значение.

В новом коде пишут let и const. var встречается в старом коде, и такой код нужно уметь читать.

Частая ошибка

Переменную объявили внутри веток if, а прочитали после них:

JavaScript
function label(n) {
    if (n > 0) {
        let sign = "plus";
    } else {
        let sign = "minus";
    }
    return sign; // ✗
}

console.log(label(5));
TEXT
ReferenceError: sign is not defined

Каждая sign живёт только в своей ветке, и к строке с return обе уже исчезли. Чтобы прочитать переменную после if, объявите её до if строкой let sign;, а в ветках присвойте ей значение: sign = "plus"; и sign = "minus";.

Главное

  • Область видимости — часть программы, где имя переменной можно прочитать.
  • let и const видны от своей строки до закрывающей скобки блока, включая вложенные блоки.
  • var не замечает блоков и виден во всей функции, но не за её пределами.
  • Переменную, нужную после if, объявляют до if, а в ветках только присваивают.

Подпишись, чтобы пройти курс

Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.

Войти другим способом