Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Втрата контексту». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`this`** у JS залежить від способу виклику функції, а не від того, де вона оголошена, тому якщо метод передати як посилання, він викликається вже не "через об'єкт", і `this` втрачається. **Ключове:** контекст можна зберегти через `bind()`, стрілкову функцію, збереження `this` у змінну, `call`/`apply` або прив'язку методу в конструкторі класу.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Чому втрачається `this` `this` у JS залежить **від способу виклику функції**, а не від того, де вона оголошена. Якщо ти **передаєш метод як посилання**, він уже не викликається "через об'єкт", і `this` стає `undefined` (або `window` у нестрогому режимі): ```javascript const user = { name: 'Tim', sayHi() { console.log(`Привіт, я ${this.name}`); } }; setTimeout(user.sayHi, 1000); // "Привіт, я undefined" ``` Чому так: - `setTimeout` викликає функцію як `callback()`, а не як `user.sayHi()`, тому `this` втрачає зв'язок з об'єктом `user`. --- ## Спосіб 1 - `bind()` Метод `Function.prototype.bind()` створює **нову функцію з жорстко прив'язаним контекстом**. ```javascript setTimeout(user.sayHi.bind(user), 1000); // Привіт, я Tim ``` `bind` повертає нову функцію, в якій `this` завжди вказує на `user`, незалежно від способу виклику. --- ## Спосіб 2 - стрілкові функції Стрілкові функції **не мають власного** `this`, а **успадковують його із зовнішнього контексту** (лексично). ```javascript const user = { name: 'Tim', sayHiLater() { setTimeout(() => { console.log(`Привіт, я ${this.name}`); }, 1000); } }; user.sayHiLater(); // Привіт, я Tim ``` Тут стрілкова функція "замкнула" `this` від `sayHiLater`. --- ## Спосіб 3 - зберегти `this` у змінну Класичний "старий" спосіб до появи стрілкових функцій. ```javascript const user = { name: 'Tim', sayHiLater() { const self = this; setTimeout(function() { console.log(`Привіт, я ${self.name}`); }, 1000); } }; user.sayHiLater(); // Привіт, я Tim ``` Тут `self` (або `that`) зберігає посилання на контекст `user`. --- ## Спосіб 4 - викликати функцію через `call` або `apply` Можна вручну задати контекст при виклику. ```javascript function greet() { console.log(`Привіт, ${this.name}`); } const user = { name: 'Tim' }; greet.call(user); // Привіт, Tim greet.apply(user); // Привіт, Tim ``` Це *тимчасова прив'язка*: працює тільки в момент виклику. --- ## Спосіб 5 - використовувати клас (методи викликаються з екземпляром) Всередині класів `this` зазвичай не втрачається, якщо ти викликаєш метод через екземпляр: ```javascript class User { constructor(name) { this.name = name; } sayHi() { console.log(`Привіт, ${this.name}`); } } const tim = new User('Tim'); tim.sayHi(); // Привіт, Tim ``` Але якщо метод передати "у відриві", контекст знову втратиться: ```javascript const fn = tim.sayHi; fn(); // undefined ``` Щоб уникнути цього, можна забіндити метод у конструкторі нижче. --- ## Спосіб 6 - прив'язка в конструкторі (для класів і React) ```javascript class User { constructor(name) { this.name = name; this.sayHi = this.sayHi.bind(this); // назавжди фіксуємо контекст } sayHi() { console.log(`Привіт, ${this.name}`); } } const tim = new User('Tim'); setTimeout(tim.sayHi, 1000); // Привіт, я Tim ``` Це особливо корисно в React-класах (`this.handleClick = this.handleClick.bind(this)`). --- ## Спосіб 7 - властивості-класи (class fields) Сучасний спосіб: методи, оголошені як **стрілкові функції всередині класу**, автоматично успадковують `this`. ```javascript class User { name = 'Tim'; sayHi = () => { console.log(`Привіт, ${this.name}`); }; } const tim = new User(); setTimeout(tim.sayHi, 1000); // Привіт, Tim ``` Це синтаксис ES2022 (підтримується в усіх сучасних браузерах). --- ## Спосіб 8 - не передавати метод напряму Іноді простіше просто викликати метод **всередині анонімної обгортки**, щоб не втратити `this`: ```javascript setTimeout(() => user.sayHi(), 1000); // Привіт, я Tim ``` Тут `user.sayHi()` викликається з правильним контекстом. --- ## Підсумок | Метод | Що робить | Де часто застосовують | |---|---|---| | `.bind(this)` | Створює функцію з фіксованим контекстом | Колбеки, React, таймери | | **Стрілкова функція** | Успадковує `this` із зовнішньої області | setTimeout, async, проміси | | `self = this` | Старий спосіб зберегти посилання | Старий код, колбеки | | `call` **/** `apply` | Тимчасове встановлення контексту | Одноразові виклики | | **Прив'язка в класі** | Через `bind` у `constructor` або стрілку | React-класи, ООП | | **Анонімна обгортка** | Викликає метод у контексті | Прості колбеки |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.