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

Какой this у Callback при вызове через setTimeout?

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

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

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

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

Какой this у Callback при вызове через setTimeout?

При использовании setTimeout (или других функций, таких как setInterval, обработчики событий и т.д.), контекст выполнения (this) внутри callback-функции зависит от способа её передачи и режима выполнения JavaScript (строгий или нестрогий). В большинстве современных случаев разработки используется строгий режим ('use strict'), что влияет на поведение this.

Основное правило

Когда callback передаётся как обычная функция (не как метод объекта), и вызывается из глобального контекста таймеров (или других API браузера/Node.js), значение this становится:

  • В нестрогим режиме: глобальный объект. В браузере это window, в Node.js — global.
  • В строгим режиме ('use strict'): undefined.

Это происходит потому, что callback вызывается как обычная функция, не как метод объекта. В JavaScript значение this внутри функции определяется способом её вызова, а не местом её объявления.

Примеры и демонстрация

Рассмотрим практические примеры, чтобы понять поведение.

Пример 1: Callback как обычная функция

// Без строгого режима (не рекомендуется в современной разработке)
function myCallback() {
    console.log(this); // В браузере: window, в Node.js: global
}

setTimeout(myCallback, 100);
// С использованием строгого режима
'use strict';

function myCallback() {
    console.log(this); // undefined
}

setTimeout(myCallback, 100);

Пример 2: Callback как метод объекта

Если передать метод объекта, он "отвязывается" от своего контекста.

'use strict';

const myObject = {
    name: 'My Object',
    logName: function() {
        console.log(this.name); // this будет undefined, вызовет ошибку
    }
};

setTimeout(myObject.logName, 100); // TypeError: Cannot read property 'name' of undefined

Здесь myObject.logName передаётся как функция, и при вызове через setTimeout она выполняется без связи с myObject.

Как сохранить правильный контекст (this)?

Для сохранения нужного контекста существует несколько стандартных подходов:

  1. Явная привязка с помощью .bind()
    Метод `Function.prototype.bind()` создаёт новую функцию, которая при вызове будет иметь заданный контекст.

```javascript
'use strict';

const myObject = {
    name: 'My Object',
    logName: function() {
        console.log(this.name); // My Object
    }
};

setTimeout(myObject.logName.bind(myObject), 100);
```

2. Использование стрелочной функции (Arrow Function)

    Стрелочные функции **не имеют своего `this`**. Они используют `this` окружающего лексического контекста (контекста, в котором они были созданы).

```javascript
'use strict';

const myObject = {
    name: 'My Object',
    logName: function() {
        // Внутри этой обычной функции this === myObject
        setTimeout(() => {
            // Стрелочная функция захватывает this из logName
            console.log(this.name); // My Object
        }, 100);
    }
};

myObject.logName();
```
    Важно: если передать стрелочную функцию напрямую в `setTimeout`, она захватит `this` из места её объявления, что может быть глобальным контекстом или `undefined`.

```javascript
'use strict';

const myObject = {
    name: 'My Object'
};

// Стрелочная функция объявлена в глобальном контексте, её this - undefined (строгий режим)
setTimeout(() => {
    console.log(this); // undefined
    console.log(this.name); // TypeError
}, 100);
```

3. Сохранение контекста в переменную (например, self, that)

    Старый, но рабочий подход.

```javascript
'use strict';

const myObject = {
    name: 'My Object',
    logName: function() {
        const self = this; // Запоминаем текущий this
        setTimeout(function() {
            console.log(self.name); // Используем сохранённый контекст
        }, 100);
    }
};

myObject.logName();
```

Почему так происходит?

Механизм setTimeout является частью Web API (или API Node.js). Когда вы передаёте функцию, она добавляется в очередь макрозадач (task queue). Когда время выходит, функция вызывается из глобального контекста планировщика. Она не вызывается как метод (myObject.logName()), а как обычная функция (logName()), поэтому правила для this применяются соответственно.

Заключение

  • При вызове через setTimeout, callback-функция обычно теряет исходный контекст this.
  • В строгим режиме её this становится undefined, в нестрогим — глобальным объектом.
  • Для сохранения нужного контекста используйте:
    *   **`.bind()`** для явной привязки.
    *   **Стрелочные функции** для захвата лексического `this` (если они созданы в нужном контексте).
    *   Сохранение контекста в **переменную**.

Понимание этих принципов критично для корректной работы с асинхронными операциями, обработчиками событий и любыми API, где функции передаются как callbacks.

Какой this у Callback при вызове через setTimeout? | PrepBro