Урок 03

Область видимости

Область видимости — часть кода, где переменная доступна.

Виды областей

  • Глобальная — весь скрипт
  • Функциональная — внутри функции
  • Блочная — внутри {} (для let и const)

Глобальная область

var globalVar = 1;
let globalLet = 2;

function test() {
    console.log(globalVar); // 1
    console.log(globalLet); // 2
}

Глобальные переменные — плохая практика в больших проектах.

Функциональная

function test() {
    const x = 1;
    console.log(x); // 1
}

console.log(x); // ошибка

var создаёт переменную в функциональной области:

function test() {
    if (true) {
        var x = 1;
    }
    console.log(x); // 1, хотя x в if
}

Блочная

let и const — только внутри блока:

if (true) {
    let x = 1;
    const y = 2;
}

console.log(x); // ошибка

Блок — {} в if, for, while, просто {}.

Вложенные области

Внутренняя видит внешнюю:

const a = 1;

function outer() {
    const b = 2;

    function inner() {
        const c = 3;
        console.log(a, b, c); // 1 2 3
    }

    inner();
    // console.log(c); // ошибка
}

Внешняя не видит внутреннюю.

Цепочка областей

При обращении к переменной JavaScript ищет её:

  1. В текущей области
  2. В родительской
  3. В родительской родительской
  4. В глобальной
  5. Если не находит — ReferenceError

Затенение

Внутренняя переменная скрывает внешнюю:

const name = 'Алиса';

function greet() {
    const name = 'Боб';
    console.log(name); // 'Боб'
}

greet();
console.log(name); // 'Алиса'

Утечка глобальных

Без let, const, var — переменная становится глобальной:

function test() {
    x = 1; // глобальная
}

test();
console.log(x); // 1

В strict mode — ошибка.

Модули

В ES-модулях верхний уровень — не глобальная область. Переменные модуля не попадают в window:

// module.js
const x = 1; // не глобальная

var в цикле

Классическая проблема:

for (var i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 0);
}
// 3, 3, 3 — все видят одну i

С let:

for (let i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 0);
}
// 0, 1, 2 — у каждой итерации своя i

let в for создаёт новую переменную для каждой итерации.

IIFE для изоляции

(function() {
    const secret = 'внутри';
    // secret не видна снаружи
})();

В модулях не нужно.

Замыкания

Внутренняя функция сохраняет доступ к переменным внешней даже после её завершения:

function counter() {
    let count = 0;
    return () => ++count;
}

const next = counter();
next(); // 1
next(); // 2

Подробнее — в следующих уроках.

Итоги

  • Глобальная, функциональная, блочная
  • let и const — блочные
  • var — функциональная
  • Внутренняя видит внешнюю
  • Затенение перекрывает внешнее
  • Без объявления — утечка в глобальную