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

Как понимаешь к каким переменным можно обращаться?

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

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

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

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

Scope и доступность переменных

Отличное понимание scope - это фундамент программирования на JavaScript. Давайте разберемся, как JavaScript определяет, к каким переменным можно обращаться.

1. Лексическая область видимости (Lexical Scope)

JavaScript использует лексическую область видимости. Переменная доступна, если она объявлена в текущей области или в какой-то из родительских областей:

const globalVar = 'global';

function outerFunction() {
  const outerVar = 'outer';
  
  function innerFunction() {
    const innerVar = 'inner';
    
    // Можно обращаться к:
    console.log(innerVar);    // 'inner' - переменная текущей области
    console.log(outerVar);    // 'outer' - родительская область
    console.log(globalVar);   // 'global' - глобальная область
  }
  
  innerFunction();
  
  // Нельзя обращаться к innerVar
  console.log(innerVar); // ReferenceError: innerVar is not defined
}

outerFunction();

2. Цепь области видимости (Scope Chain)

Когда вы ссылаетесь на переменную, JavaScript ищет её в цепи областей снизу вверх:

let x = 1;

function first() {
  let x = 2;
  
  function second() {
    let x = 3;
    
    function third() {
      console.log(x); // 3 - найдена в области third
    }
    third();
  }
  
  second();
}

first();

// Алгоритм поиска:
// 1. Поискать в области third - найдено x = 3
// 2. (Если бы не было) посмотреть в области second
// 3. (Если бы не было) посмотреть в области first - найдено x = 2
// 4. (Если бы не было) посмотреть в глобальной области - найдено x = 1

3. Функциональная область видимости

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

var globalVar = 'global';

function myFunction() {
  var localVar = 'local';
  let blockVar = 'block';
  
  console.log(globalVar); // 'global' - доступна
  console.log(localVar);  // 'local' - доступна
}

myFunction();

console.log(globalVar); // 'global' - доступна
console.log(localVar);  // ReferenceError - не доступна

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

let и const создают блочную область видимости (область блока, обычно в фигурных скобках):

if (true) {
  let blockVar = 'block';
  var functionVar = 'function';
  const blockConst = 'const';
}

console.log(functionVar); // 'function' - var видна за пределами блока
console.log(blockVar);    // ReferenceError - let видна только в блоке
console.log(blockConst);  // ReferenceError - const видна только в блоке

// Это особенно важно в циклах
for (let i = 0; i < 3; i++) {
  // i доступна только внутри блока цикла
}
console.log(i); // ReferenceError

for (var j = 0; j < 3; j++) {
  // j доступна везде
}
console.log(j); // 3

5. Замыкания (Closures)

Замыкание - это функция, которая имеет доступ к переменным из своей родительской области, даже после того, как функция вернула управление:

function createCounter() {
  let count = 0; // Эта переменная "захватывается" замыканием
  
  return function() {
    count++;
    return count;
  };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

// count остается в памяти благодаря замыканию
// Это полезно для инкапсуляции приватных данных

function createUser(name) {
  let _privateData = { name, created: Date.now() };
  
  return {
    getName() {
      return _privateData.name; // Доступ через замыкание
    },
    setName(newName) {
      _privateData.name = newName; // Изменение захваченной переменной
    }
  };
}

const user = createUser('John');
console.log(user.getName()); // 'John'
user.setName('Jane');
console.log(user.getName()); // 'Jane'
// Нельзя обращаться к _privateData напрямую

6. Hoisting (поднятие)

Варианты hoisting для разных типов объявлений:

// var - поднимается и инициализируется undefined
console.log(a); // undefined (не ошибка)
var a = 1;
console.log(a); // 1

// let и const - поднимаются, но не инициализируются (TDZ - Temporal Dead Zone)
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 2;

// Функции поднимаются полностью
console.log(myFunc()); // 'Hello' - работает
function myFunc() {
  return 'Hello';
}

// Функциональные выражения - нет
console.log(myFunc2()); // ReferenceError
var myFunc2 = function() {
  return 'Hello';
};

7. This контекст

This зависит от того, как функция была вызвана:

const obj = {
  name: 'Object',
  getName() {
    return this.name; // this указывает на obj
  },
  getNameArrow: () => {
    return this.name; // this указывает на глобальный scope
  }
};

console.log(obj.getName());      // 'Object'
console.log(obj.getNameArrow()); // undefined

// Явная привязка
function greet() {
  return `Hello, ${this.name}`;
}

const person = { name: 'John' };
console.log(greet.call(person));     // 'Hello, John' - call
console.log(greet.apply(person));    // 'Hello, John' - apply
const boundGreet = greet.bind(person); // bind
console.log(boundGreet());             // 'Hello, John'

8. Модульная область видимости (ES6 Modules)

В модулях есть отдельная область видимости на уровне модуля:

// math.js
const PI = 3.14159;
function sum(a, b) {
  return a + b;
}

export { sum }; // Экспортируем только sum

// main.js
import { sum } from './math.js';

console.log(sum(1, 2)); // 3 - доступна
console.log(PI);        // ReferenceError - не экспортирована

9. Window и Global объекты

Переменные в глобальной области попадают в window (браузер) или global (Node.js):

var globalVar = 'value';
console.log(window.globalVar); // 'value' в браузере
console.log(global.globalVar);  // 'value' в Node.js

let localVar = 'value';
console.log(window.localVar);   // undefined - let не добавляется в window

10. Практический пример с React

// Правильное использование scope в React компоненте
function MyComponent({ externalProp }) {
  // Переменная в области компонента
  const [state, setState] = useState(0);
  
  // Замыкание - callback захватывает state и externalProp
  const handleClick = useCallback(() => {
    // Можно обращаться к state и externalProp благодаря замыканию
    setState(state + 1);
    console.log(externalProp);
  }, [state, externalProp]); // Зависимости для корректного замыкания
  
  return <button onClick={handleClick}>Click</button>;
}

Резюме

  1. Используйте лексическую область видимости - переменные видны вниз и вверх по цепи
  2. Используйте let/const вместо var для блочной области видимости
  3. Помните о замыканиях - они захватывают переменные из родительской области
  4. Пишите чистый код - избегайте глобальных переменных
  5. Понимайте hoisting - var поднимается, let/const нет
  6. Помните о this контексте при работе с методами объектов
Как понимаешь к каким переменным можно обращаться? | PrepBro