У звичайній функції this визначається в момент виклику, а не там, де функцію написано:
obj.method()-thisцеobj;- просто
fn()-undefinedу строгому режимі (у модулях і класах він завжди строгий), глобальний об'єкт - у нестрогому; new Fn()- новий об'єкт;fn.call(ctx),fn.apply(ctx),fn.bind(ctx)- явно заданийctx;- в обробнику
addEventListener- елемент, на якому висить обробник.
Типова пастка - метод, переданий як колбек:
class Timer {
seconds = 0;
tick() { this.seconds++; }
}
const timer = new Timer();
setInterval(timer.tick, 1000); // this === undefined -> TypeError
Метод «відірвався» від об'єкта, і викликається вже як просто функція.
Стрілкова функція не має власного this - вона бере this з місця, де її створено (лексично), і змінити його не можна навіть через call чи bind:
setInterval(() => timer.tick(), 1000); // працює
// або поле-стрілка в класі:
class Timer2 { seconds = 0; tick = () => { this.seconds++; }; }
Ще відмінності стрілкових функцій: немає власного arguments, їх не можна викликати через new, вони не мають prototype.
Коли НЕ стрілка: методи об'єкта, яким потрібен this цього об'єкта ({ name: 'x', greet: () => this.name } не працює), і обробники, де потрібен this як елемент.