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

Внутри чего видна var

2.0 Middle🔥 162 комментариев
#JavaScript Core

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

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

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

Внутри чего видна var (область видимости переменных)

var — это ключевое слово для объявления переменных в JavaScript. Область видимости var существенно отличается от let и const. Это один из основных источников багов в старом коде JavaScript.

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

var видна внутри:

  1. Функции (Function Scope)
  2. Глобального скоупа (Global Scope)

var НЕ видна внутри:

  • Блоков кода (if, for, while, {}) — это функция var работает не как хотелось бы

Function Scope

var видна в ЛЮБОМ месте функции, где она объявлена, независимо от блока кода.

function example() {
  var x = 10;
  
  if (true) {
    var x = 20;  // Переопределяет внешнюю x!
    console.log(x);  // 20
  }
  
  console.log(x);  // 20 (!!! не 10, как можно было ожидать)
  // Потому что var НЕ имеет блочной области видимости
}

example();

Проблема:

function processData(items) {
  for (var i = 0; i < items.length; i++) {
    var item = items[i];  // var видна во ВСЕЙ функции
  }
  
  // После цикла i и item всё ещё видны и имеют значение!
  console.log(i);     // 3 (последнее значение)
  console.log(item);  // последний элемент массива
  
  // Это может привести к ошибкам
}

Почему это плохо:

function buggyCounter() {
  if (condition) {
    var count = 0;
  }
  
  // Разработчик ожидает ReferenceError здесь
  console.log(count);  // 0 или undefined, но НЕ ошибка!
  count++;  // Работает! Но count может быть undefined
}

Global Scope

var на глобальном уровне видна везде в коде.

// Глобальная область видимости
var globalVar = 'я видна везде';

function myFunction() {
  console.log(globalVar);  // 'я видна везде'
}

myFunction();
console.log(globalVar);  // 'я видна везде'

if (true) {
  console.log(globalVar);  // 'я видна везде'
}

Hoisting (поднятие переменных)

var подвергается hoisting — объявление поднимается в начало области видимости, но инициализация нет.

// Ты пишешь:
function example() {
  console.log(x);  // Что будет?
  var x = 10;
}

// JavaScript интерпретирует как:
function example() {
  var x;  // Объявление поднято
  console.log(x);  // undefined (не ошибка!)
  x = 10;  // Инициализация остаётся на месте
}

example();  // undefined

Более сложный пример:

var x = 'глобальная';

function example() {
  console.log(x);  // undefined, НЕ 'глобальная'!
  var x = 'локальная';
  console.log(x);  // 'локальная'
}

example();

// Почему первый console.log показал undefined?
// Потому что var x объявлена в функции,
// значит локальная x затеняет глобальную,
// но инициализация = 'локальная' ещё не произошла

Сравнение var, let, const

// 1. FUNCTION SCOPE vs BLOCK SCOPE

function test() {
  var varVariable = 'var';
  let letVariable = 'let';
  const constVariable = 'const';
}

console.log(varVariable);      // ReferenceError: не видна за пределами функции
console.log(letVariable);      // ReferenceError
console.log(constVariable);    // ReferenceError

// Но внутри блоков:
if (true) {
  var varVariable = 'var';
  let letVariable = 'let';
  const constVariable = 'const';
}

console.log(varVariable);      // 'var' — видна!
console.log(letVariable);      // ReferenceError — НЕ видна
console.log(constVariable);    // ReferenceError — НЕ видна

2. HOISTING:

// var — hoisted как undefined
console.log(varVar);   // undefined
var varVar = 10;

// let/const — Temporal Dead Zone (TDZ)
console.log(letVar);   // ReferenceError: Cannot access before initialization
let letVar = 10;

console.log(constVar); // ReferenceError
const constVar = 10;

3. ПЕРЕОПРЕДЕЛЕНИЕ:

// var можно переопределить
var x = 1;
var x = 2;  // OK

// let/const нельзя переопределить в одной области видимости
let y = 1;
let y = 2;  // SyntaxError: Identifier 'y' has already been declared

const z = 1;
const z = 2;  // SyntaxError

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

Проблема 1: Цикл с setTimeout

// С var
for (var i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i);  // 3, 3, 3 (не 0, 1, 2!)
  }, 100);
}

// С let
for (let i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i);  // 0, 1, 2 (правильно)
  }, 100);
}

// let создаёт отдельную переменную i для каждой итерации
// var переопределяет одну и ту же i для всех итераций

Проблема 2: Условное объявление

// Опасное с var
if (someCondition) {
  var message = 'Ошибка';
}

console.log(message);  // 'Ошибка' или undefined, но не ReferenceError
// Разработчик может случайно использовать message везде

// Безопасное с let
if (someCondition) {
  let message = 'Ошибка';
}

console.log(message);  // ReferenceError (сразу ловим ошибку)

Проблема 3: Случайная переопределение

var name = 'Alice';

// Несколько функций в одном файле
function processUser() {
  var name = 'Bob';  // Локальная переменная в функции
  console.log(name);
}

function getGlobal() {
  var name = 'Charlie';  // Ещё одна локальная
  return name;
}

// Случайно создали глобальную переменную
for (var i = 0; i < 10; i++) {
  var name = 'Dave';  // Переопределяет глобальную!
}

console.log(name);  // 'Dave' — всё испорчено

Таблица сравнения

Свойствоvarletconst
Область видимостиFunctionBlockBlock
HoistingДа (undefined)Да (TDZ)Да (TDZ)
ПереопределениеРазрешеноЗапрещеноЗапрещено
ПереприсваиваниеРазрешеноРазрешеноЗапрещено
РекомендацияИзбегатьИспользоватьИспользовать по умолчанию

Современный подход

// НИКОГДА не используй var
// Используй let и const

// 1. const по умолчанию
const user = { name: 'Alice' };
user.name = 'Bob';  // OK — изменение свойства
user = {};  // Error — переприсваивание запрещено

// 2. let если нужно переприсвоить
let count = 0;
count++;  // OK
count = 10;  // OK

// 3. var никогда
var x = 1;  // Избегать в новом коде

Резюме

var видна внутри функции, в которой объявлена, и глобально. Это Function Scope, не Block Scope. var подвергается hoisting (объявление поднимается, инициализация нет), что приводит к неожиданному поведению. Из-за этого в современном JavaScript var считается устаревшей и не рекомендуется. Вместо var используй let (для переменных, которые меняются) и const (для константы по умолчанию), которые имеют Block Scope и безопаснее для разработки.