Что такое this в JavaScript и как оно ведёт себя в стрелочных функциях?

MiddleJavaScript #javascript #this #arrow-functions

Вопрос

Что такое this в JavaScript и чем отличается его поведение в обычных и стрелочных функциях?

Короткий ответ

В обычной функции this определяется тем, как функция вызвана (динамически, в момент вызова). В стрелочной функции своего this нет — она берёт this лексически, из окружающей области видимости, в которой была объявлена.

Подробный ответ

Для обычных функций this зависит от способа вызова:

  • Как метод объекта (obj.method()) — this равен obj.
  • Как обычная функция (fn()) — this равен undefined в strict mode (или globalThis без strict mode).
  • Через new — this равен новому создаваемому объекту.
  • Через call/apply/bind — this явно задаётся первым аргументом.

Стрелочные функции не имеют собственного this: они не создают новый контекст, а захватывают this из ближайшей объемлющей обычной функции на момент объявления — точно так же, как замыкание захватывает переменные. Из-за этого стрелочные функции нельзя использовать как методы объекта, если внутри нужен this самого объекта, зато они удобны для колбэков внутри методов.

Пример

const timer = {
  seconds: 0,
  // Обычная функция — `this` определится вызовом setInterval,
  // внутри колбэка this !== timer
  startBroken() {
    setInterval(function () {
      this.seconds++ // this — не timer, будет ошибка/NaN
    }, 1000)
  },
  // Стрелочная функция — берёт this из startFixed(), т.е. timer
  startFixed() {
    setInterval(() => {
      this.seconds++ // this === timer, работает корректно
    }, 1000)
  }
}

class Button {
  label = 'OK'
  // Стрелочная функция как поле класса — this всегда привязан к экземпляру,
  // удобно передавать как обработчик события без .bind(this)
  handleClick = () => {
    console.log(this.label)
  }
}

Дополнительные вопросы

  • Почему this внутри стрелочной функции, объявленной в глобальной области, равен undefined/globalThis?
  • Чем bind отличается от call и apply?
  • Как ведёт себя this внутри обработчика события DOM (element.addEventListener) для обычной и стрелочной функции?