Почему this не тот внутри функции в JavaScript и как это исправить?
Внутри метода объекта вызываю функцию, а this вдруг становится undefined или указывает не на объект. Особенно в обработчике события или setTimeout. Почему this теряется и как привязать его правильно?
2 ответа
Главное про this: в обычной функции он определяется тем, как функцию вызвали, а не где её написали. Поэтому при «отрыве» метода this слетает.
Классический пример:
const user = {
name: 'Аня',
greet() {
console.log('Привет, ' + this.name);
}
};
user.greet(); // 'Привет, Аня' — вызвали как user.greet()
const fn = user.greet;
fn(); // 'Привет, undefined' — this потерян
То же с setTimeout и обработчиками — функция вызывается «сама по себе», this уже не объект.
Решение 1 — стрелочная функция. У стрелок нет своего this, они берут его из окружающего кода:
const user = {
name: 'Аня',
greetLater() {
setTimeout(() => {
console.log(this.name); // 'Аня' — стрелка взяла this из greetLater
}, 1000);
}
};
user.greetLater();
Решение 2 — bind, жёстко привязать this:
const fn = user.greet.bind(user);
fn(); // 'Привет, Аня'
Часто нужно в обработчиках:
btn.addEventListener('click', this.handleClick.bind(this));
Грабли наоборот: не делай метод объекта стрелкой, если хочешь обращаться к объекту через this — стрелка возьмёт this снаружи (часто window/undefined), а не сам объект. Для методов объекта — обычная функция, для колбэков внутри — стрелка.
Быстрый разбор «кто такой this» по способу вызова:
obj.method()→thisэтоobj.func()(просто так) →thisэтоundefined(в strict mode) илиwindow.- стрелочная функция →
thisберётся из места объявления. func.call(x)/func.bind(x)→thisэтоx.
Когда видишь «this не тот», первым делом посмотри, как именно вызывается функция. Обычно она оторвалась от объекта (передана в setTimeout/слушатель). Стрелка или bind решают почти все такие случаи.