> В чем разница между стрелочной и обычной функцией в контексте this в JavaScript? (JavaScript)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: Иннотех, Точка, Garage Eight, VK, Домклик, IT-One, Библио-Глобус, ООО Рокет Тех, Rutube, intelsy, Сфера, Арго, TYMY, Purrweb, SmartWay

Стек: JavaScript

> Пример ответа

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

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

Подробное объяснение

У обычной функции this определяется в момент вызова (execution context). Правила простые:

  • если функция вызвана как метод объекта - this указывает на объект;
  • если через call, apply или bind - на переданный аргумент;
  • если через new - на новый созданный объект;
  • если просто как функция (в строгом режиме) - undefined, в нестрогом - глобальный объект.

У стрелочной функции this фиксируется лексически: он равен this того окружения, где функция была создана. Это значит, что стрелочная функция не может быть методом объекта в классическом смысле - this внутри неё не будет указывать на объект при вызове через точку. Также стрелочные функции нельзя использовать с new, call, apply или bind для изменения this - эти методы просто игнорируют переданный контекст.

Дополнительно: у стрелочных функций нет собственного arguments, super и new.target - они тоже наследуются из внешней области. Это важно учитывать при проектировании API и написании универсальных функций.

На практике

Для senior-позиции важно не просто перечислить отличия, а показать понимание последствий:

  • в React-компонентах (классовых) стрелочные функции как методы класса решают проблему потери контекста в обработчиках событий;
  • в функциональных компонентах с хуками стрелочные функции в useCallback/useEffect захватывают актуальный this из замыкания, но сам this там обычно не используется;
  • при написании библиотек и утилит, где функция может вызываться разными способами, лучше использовать обычные функции, чтобы сохранить гибкость контекста;
  • стрелочные функции удобны для колбэков, где нужен доступ к внешнему this (например, внутри методов класса при работе с setTimeout, addEventListener, Promise).

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

Пример кода

JAVASCRIPT
const obj = {
value: 42,
regular: function() {
console.log(this.value); // 42
},
arrow: () => {
console.log(this.value); // undefined (this = внешний контекст)
}
};
obj.regular(); // 42
obj.arrow(); // undefined
// Классический кейс с колбэком
class Counter {
constructor() {
this.count = 0;
// стрелочная функция сохраняет this из конструктора
this.increment = () => {
this.count++;
};
}
}
const counter = new Counter();
setTimeout(counter.increment, 100);
// через 100мс counter.count === 1
// Обычная функция потеряла бы контекст
function RegularCounter() {
this.count = 0;
this.increment = function() {
this.count++;
};
}
const regularCounter = new RegularCounter();
setTimeout(regularCounter.increment, 100);
// через 100мс regularCounter.count === 0, this - глобальный объект

Как отвечать на собеседовании

Начните с главного отличия: лексический this у стрелочных функций против динамического у обычных. Затем приведите пример, который это демонстрирует. После этого перечислите связанные ограничения: отсутствие arguments, super, new.target, невозможность использования с new и игнорирование call/apply/bind. Завершите практическим примером из реальной разработки - например, обработчик событий в классе или колбэк в setTimeout. Если спросят про производительность или память, упомяните, что стрелочные функции создают новое замыкание при каждом создании, но в современных движках это оптимизируется, и разница обычно незначительна.

Что проверяет интервьюер

Интервьюер оценивает:

  • понимание разницы между лексическим и динамическим контекстом;
  • знание всех способов вызова обычной функции и как они влияют на this;
  • умение предсказать поведение кода с колбэками и обработчиками событий;
  • осведомлённость о связанных ограничениях (arguments, new, bind);
  • способность объяснить, когда какой тип функции уместен.

Для senior-уровня важно показать, что вы не просто заучили правила, а понимаете, как это влияет на архитектуру кода и потенциальные баги.

Типичные ошибки

  • утверждение, что стрелочные функции "привязывают this к объекту, в котором определены" - на самом деле к лексическому окружению, а не к объекту;
  • попытка использовать стрелочную функцию как метод объекта и ожидание, что this будет указывать на объект;
  • игнорирование того, что call/apply/bind не работают со стрелочными функциями для изменения this;
  • забывание, что у стрелочных функций нет собственного arguments - это частая причина багов при переносе кода;
  • использование стрелочных функций в качестве конструкторов - приведёт к ошибке TypeError;
  • путаница между this в стрелочной функции и this в обычной функции внутри того же замыкания - стрелочная всегда берёт внешний, обычная - зависит от вызова.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью