Область видимости и замыкания

Free Preview
Продолжительность: 12 мин

В прошлых уроках мы объявляли переменные и функции, не задумываясь о том, откуда к ним можно обращаться. На практике это важно: не каждая переменная доступна в каждом месте кода. Эту концепцию называют областью видимости (scope).

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

Область видимости — это часть кода, в которой переменная существует и доступна. Если переменная объявлена в одном месте, это не значит, что к ней можно обратиться откуда угодно.

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

Переменные, объявленные вне каких-либо функций и блоков, попадают в глобальную область видимости. К ним можно обратиться из любого места программы:

const siteName = 'Санкт-Петербург';

function greet() {
  console.log(siteName); // доступно внутри функции
}

greet(); // Санкт-Петербург
js

Область видимости функции

Переменные, объявленные внутри функции, существуют только внутри неё. Снаружи они недоступны:

function calculate() {
  const result = 42;
  console.log(result); // 42
}

calculate();
console.log(result); // Ошибка! result не определён снаружи
js

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

let и const имеют блочную область видимости — они существуют только внутри блока {}, в котором объявлены. Это касается не только функций, но и любых блоков: if, for, while:

if (true) {
  let blockVar = 'я внутри блока';
  console.log(blockVar); // работает
}

console.log(blockVar); // Ошибка! переменная не видна снаружи
js

Именно поэтому var ведёт себя иначе — у него нет блочной области видимости, только функциональная. Это одна из причин, по которым var стараются не использовать:

if (true) {
  var oldWay = 'я var';
}

console.log(oldWay); // 'я var' — var "вытекает" из блока
js

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

Функции могут быть вложены друг в друга. Внутренняя функция видит переменные внешней, но не наоборот:

function outer() {
  const message = 'снаружи';

  function inner() {
    console.log(message); // видит переменную из внешней функции
  }

  inner();
}

outer(); // 'снаружи'
js

Это правило называется лексической областью видимости: функция видит переменные той области, в которой она была объявлена.

Замыкание

Замыкание (closure) — это одна из самых важных концепций в JavaScript. Звучит сложно, но идея простая: функция «запоминает» внешние переменные из своей области видимости, даже когда выполняется за её пределами.

Рассмотрим пример:

function createCounter() {
  let count = 0;

  return function() {
    count = count + 1;
    console.log(count);
  };
}

const counter = createCounter();
counter(); // 1
counter(); // 2
counter(); // 3
js

Что здесь происходит? Функция createCounter создаёт переменную count и возвращает внутреннюю функцию. Когда createCounter завершила работу, переменная count не исчезла — внутренняя функция «захватила» её и продолжает к ней обращаться.

Каждый вызов createCounter() создаёт новое замыкание со своей переменной count:

const counter1 = createCounter();
const counter2 = createCounter();

counter1(); // 1
counter1(); // 2
counter2(); // 1 — у counter2 своё собственное count
js

Замыкания используются повсюду в реальных приложениях — для создания приватных данных, фабрик функций, обработчиков событий. Это тема, к которой стоит вернуться по мере углубления в язык.

В следующем уроке поговорим об одной из самых обсуждаемых концепций JavaScript — ключевом слове this.