← Назад к вопросам

В чем разница между блочной и функциональной областями видимости?

1.3 Junior🔥 191 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

В чем разница между блочной и функциональной областями видимости?

Scope (область видимости) определяет, где переменная доступна в коде. JavaScript имеет две основные области видимости: функциональная (Function Scope) и блочная (Block Scope). Понимание различий критично для написания корректного кода.

Функциональная область видимости (Function Scope)

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

function example() {
  var name = 'Иван'; // Функциональная область видимости
  
  if (true) {
    var age = 30;
    console.log(name); // 'Иван' — доступна
  }
  
  console.log(age); // 30 — ДОСТУПНА ВНЕ БЛОКА!
  // Это может привести к ошибкам, переменная "утекла" из блока
}

Проблема: переменная, объявленная внутри блока, доступна во всей функции — это непредсказуемо и часто вызывает ошибки.

Блочная область видимости (Block Scope)

let и const создают переменные с блочной областью видимости. Переменная доступна только внутри блока {}, где она объявлена.

function example() {
  let name = 'Иван'; // Блочная область видимости
  
  if (true) {
    let age = 30; // Блочная область видимости
    console.log(name); // 'Иван' — доступна
  }
  
  console.log(age); // ReferenceError: age is not defined
  // Переменная видна только внутри своего блока
}

Прямое сравнение

for (var i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log('var:', i); // Выведет: 3, 3, 3
  }, 100);
}

for (let j = 0; j < 3; j++) {
  setTimeout(() => {
    console.log('let:', j); // Выведет: 0, 1, 2
  }, 100);
}

// Почему разница?
// var: одна переменная на всю функцию, к моменту вывода i = 3
// let: новая переменная для каждой итерации цикла

Hoisting (Всплывание переменных)

var — всплывает с undefined:

function example() {
  console.log(x); // undefined (не ошибка!)
  var x = 5;
  console.log(x); // 5
}

// JavaScript интерпретирует как:
// function example() {
//   var x; // объявление всплывает
//   console.log(x); // undefined
//   x = 5; // присвоение остаётся на месте
//   console.log(x); // 5
// }

let/const — Temporal Dead Zone (TDZ):

function example() {
  console.log(x); // ReferenceError: Cannot access 'x' before initialization
  let x = 5;
  console.log(x); // 5
}

// let/const тоже всплывают, но в "мёртвой зоне"
// Доступ к ним до объявления — ошибка

Практические проблемы с var

Пример 1: Утечка переменных

function processUsers() {
  if (users.length > 0) {
    var message = 'Есть пользователи';
  }
  
  console.log(message); // 'Есть пользователи'
  // message доступна везде в функции — может быть undefined в других местах!
}

Пример 2: Конфликты в циклах

const buttons = document.querySelectorAll('button');

for (var i = 0; i < buttons.length; i++) {
  buttons[i].addEventListener('click', function() {
    console.log('Нажата кнопка', i); // Все выведут последний i!
  });
}

// Решение: использовать let
for (let i = 0; i < buttons.length; i++) {
  buttons[i].addEventListener('click', function() {
    console.log('Нажата кнопка', i); // Правильный номер для каждой кнопки
  });
}

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

// На глобальном уровне
var globalVar = 'видна везде'; // Создаёт window.globalVar
let globalLet = 'видна везде'; // НЕ добавляется в window
const globalConst = 'видна везде'; // НЕ добавляется в window

console.log(window.globalVar); // 'видна везде'
console.log(window.globalLet); // undefined

Вложенные области видимости (Lexical Scope)

function outer() {
  let name = 'Иван';
  
  function inner() {
    let age = 30;
    console.log(name); // 'Иван' — доступна из родительской области
    console.log(age); // 30
  }
  
  console.log(age); // ReferenceError — недоступна
}

Таблица сравнения var, let, const

Характеристикаvarletconst
Область видимостиФункцияБлокБлок
Hoistingда (undefined)да (TDZ)да (TDZ)
Переприсвоение
Переобъявление
На window объекте

Лучшие практики

  1. Никогда не используй var — это legacy, он содержит слишком много пит-фолов
// ❌ Плохо
var x = 5;

// ✅ Хорошо
let x = 5; // если нужна переприсвоение
const x = 5; // если нужна неизменяемость (preferably)
  1. Используй const по умолчанию — это предотвращает случайное переприсвоение

  2. Используй let, если нужна переприсвоение — например, в циклах

  3. Избегай глобальных переменных — оборачивай в функции или модули

Closure пример (демонстрирует область видимости)

function createCounter() {
  let count = 0; // Блочная область, но сохранится в closure
  
  return {
    increment: () => ++count,
    decrement: () => --count,
    get: () => count
  };
}

const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1
// count остаётся видна только для методов counter — это closure

Итог: блочная область видимости (let/const) безопаснее и предсказуемее, чем функциональная (var). Современный JavaScript использует let/const. Понимание области видимости критично для предотвращения ошибок и написания чистого кода.

В чем разница между блочной и функциональной областями видимости? | PrepBro