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

В чем разница между замыканием и контекстом?

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

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

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

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

Замыкание vs Контекст в JavaScript

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

Замыкание (Closure)

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

Как это работает:

// Внешняя функция
function outer(x) {
  console.log("outer called with", x);
  
  // Внутренняя функция
  function inner() {
    console.log("inner accessing x:", x);
    return x * 2;
  }
  
  return inner; // возвращаем функцию, не её результат
}

const multiply = outer(5);
console.log(multiply()); // "inner accessing x: 5" → 10

// Замыкание: inner "помнит" x из outer
// даже когда outer уже выполнена

Ещё примеры замыканий:

// Счётчик с приватной переменной
function createCounter() {
  let count = 0; // Приватная переменная
  
  return {
    increment: () => ++count,
    decrement: () => --count,
    getCount: () => count
  };
}

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

// Переменная count недостижима напрямую
// console.log(count); // ❌ ReferenceError
// Только через методы
// Функция высшего порядка с замыканием
function multiplier(factor) {
  return function(number) {
    return number * factor; // замыкание: доступ к factor
  };
}

const double = multiplier(2);
const triple = multiplier(3);

console.log(double(5)); // 10
console.log(triple(5)); // 15

Классический пример с циклом (ошибка с замыканиями):

// ❌ Неправильно: все функции ссылаются на один i
const functions = [];
for (var i = 0; i < 3; i++) {
  functions.push(() => {
    console.log("Value of i:", i);
  });
}

functions[0](); // "Value of i: 3"
functions[1](); // "Value of i: 3"
functions[2](); // "Value of i: 3"
// Все выводят 3, потому что i одна для всех
// ✅ Правильно: let или IIFE создают отдельную область
const functions = [];
for (let i = 0; i < 3; i++) { // let вместо var
  functions.push(() => {
    console.log("Value of i:", i);
  });
}

functions[0](); // "Value of i: 0"
functions[1](); // "Value of i: 1"
functions[2](); // "Value of i: 2"
// Каждая функция имеет свой i

Контекст (Context)

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

Как определяется контекст:

// 1. Обычный вызов (this = undefined в strict mode, window в обычном)
function greet() {
  console.log(this); // undefined (strict) или window (non-strict)
}
greet();

// 2. Как метод объекта (this = сам объект)
const user = {
  name: "Alice",
  greet() {
    console.log("Hello", this.name); // this = user
  }
};
user.greet(); // "Hello Alice"

// 3. Через new (this = новый объект)
function User(name) {
  this.name = name;
}
const user1 = new User("Bob");
console.log(user1.name); // "Bob"

// 4. Через call/apply/bind (явно задаём this)
function introduce() {
  console.log("I am", this.name);
}
const person = { name: "Charlie" };
introduce.call(person); // "I am Charlie"

call, apply, bind:

const user = {
  name: "Diana",
  sayHello(greeting) {
    console.log(greeting, "my name is", this.name);
  }
};

const admin = { name: "Eve" };

// call: вызывает функцию сразу с заданным this
user.sayHello.call(admin, "Hi"); // "Hi my name is Eve"

// apply: как call, но аргументы в массиве
user.sayHello.apply(admin, ["Hey"]); // "Hey my name is Eve"

// bind: возвращает новую функцию с привязанным this
const adminSayHello = user.sayHello.bind(admin);
adminSayHello("Hello"); // "Hello my name is Eve"

this в стрелочных функциях:

// ❌ Стрелочные функции НЕ имеют своего this
const user = {
  name: "Frank",
  greet: () => {
    console.log(this.name); // this = window, не user!
  }
};
user.greet(); // undefined

// ✅ Правильно: обычная функция
const user = {
  name: "Frank",
  greet() {
    console.log(this.name); // this = user
  }
};
user.greet(); // "Frank"

// ✅ Или стрелочная с замыканием
const user = {
  name: "Frank",
  greet: function() {
    const arrowFunc = () => {
      console.log(this.name); // this из outer функции = user
    };
    arrowFunc();
  }
};
user.greet(); // "Frank"

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

АспектЗамыканиеКонтекст
Что этоФункция + переменные из scopeЗначение this в функции
Когда создаетсяПри определении функцииПри вызове функции
Как меняетсяАвтоматически (lexical scope)Зависит от способа вызова
Можно ли контролироватьТолько через структуру кодаcall/apply/bind или стрелочные
Жизненный циклЖивет столько же, сколько функцияОпределяется каждый раз при вызове

Реальные примеры

Замыкание в React:

function Counter() {
  const [count, setCount] = useState(0); // замыкание: count и setCount
  
  const increment = () => {
    setCount(count + 1); // доступ к count через замыкание
  };
  
  return <button onClick={increment}>Count: {count}</button>;
}

Контекст в React:

const UserContext = createContext<User | null>(null);

function UserProvider({ children }) {
  const user = { name: "Alice" };
  
  return (
    <UserContext.Provider value={user}>
      {children}
    </UserContext.Provider>
  );
}

function Profile() {
  const user = useContext(UserContext); // получаем контекст (не this!)
  return <div>{user?.name}</div>;
}

Event handler: замыкание + контекст

class Button extends React.Component {
  constructor(props) {
    super(props);
    this.state = { clicked: false };
  }
  
  handleClick() {
    // this.state доступен благодаря контексту (this)
    console.log("Clicked", this.state.clicked);
  }
  
  render() {
    // () => { this.handleClick() } — замыкание на this
    // this в handleClick — контекст
    return (
      <button onClick={() => this.handleClick()}>
        Click me
      </button>
    );
  }
}

Ключевые отличия

  • Замыкание — что переменные видны функции
  • Контекст — что это переменная this
  • Замыкание — определяется при написании кода (лексически)
  • Контекст — определяется при запуске кода (динамически)
  • Замыкание — статичное, не меняется
  • Контекст — динамичное, меняется в зависимости от вызова

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

В чем разница между замыканием и контекстом? | PrepBro