Как понимаешь к каким переменным можно обращаться?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
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>;
}
Резюме
- Используйте лексическую область видимости - переменные видны вниз и вверх по цепи
- Используйте let/const вместо var для блочной области видимости
- Помните о замыканиях - они захватывают переменные из родительской области
- Пишите чистый код - избегайте глобальных переменных
- Понимайте hoisting - var поднимается, let/const нет
- Помните о this контексте при работе с методами объектов