JavaScriptJuniorTechnical
Что такое стрелочные функции и чем они отличаются от обычных функций (особенно в отношении this)?
Стрелочные функции не имеют собственного this, arguments и не могут использоваться как конструктор — this берётся лексически из охватывающей области, а не от вызывающего.
Синтаксис и основные отличия
Стрелочные функции (() => {}) введены в ES2015. Они короче обычных function, но ключевое отличие — в модели this.
- Обычная функция:
thisопределяется в момент вызова — зависит от того, кто вызывает (метод объекта,new,call/apply/bind, или глобальный контекст). - Стрелочная функция:
thisзахватывается лексически — берётся из окружающей области в момент определения и никогда не меняется.
Дополнительно стрелочные функции:
- Не имеют собственного объекта
arguments(вместо него используют rest-параметры...args). - Нельзя вызвать через
new— бросаетTypeError. - Не имеют свойства
prototype. - Нельзя использовать как генераторы (
function*).
Пример: this в методе и callback
const timer = {
seconds: 0,
// Обычная функция — this потерян в setTimeout
startBroken() {
setTimeout(function () {
this.seconds += 1; // this === undefined (strict) или window
console.log(this.seconds); // NaN или ошибка
}, 1000);
},
// Стрелочная функция — this === timer
startFixed() {
setTimeout(() => {
this.seconds += 1;
console.log(this.seconds); // 1
}, 1000);
},
};
timer.startFixed();
Когда стрелочная функция НЕ подходит
const obj = {
value: 42,
// Метод объекта — нужен динамический this
getValue: () => obj.value, // Антипаттерн: this будет внешним контекстом
getValueCorrect() { return this.value; }, // Правильно
};
// Прототипный метод
function Person(name) { this.name = name; }
Person.prototype.greet = () => `Hi, ${this.name}`; // Неправильно, this — не экземпляр
Person.prototype.greet = function () { return `Hi, ${this.name}`; }; // Правильно
// addEventListener — this должен указывать на элемент
document.querySelector('#btn').addEventListener('click', () => {
console.log(this); // window, а не кнопка
});
arguments vs rest
function regular() {
console.log(arguments[0]); // работает
}
const arrow = (...args) => {
console.log(args[0]); // нужен rest
// console.log(arguments); // ReferenceError или внешние arguments
};
Подводные камни
- Метод объектного литерала: стрелка внутри
{ method: () => {} }захватываетthisмодуля/глобала, а не объекта — один из самых частых багов. - addEventListener: если нужен
thisкак ссылка на DOM-элемент, нельзя использовать стрелку. - new:
const Foo = () => {}; new Foo()—TypeError: Foo is not a constructor. - bind/call/apply: вызов
.bind(newThis)на стрелочной функции не меняетthis— операция молча игнорируется. - Отладка: у стрелочных функций нет имени по умолчанию в stack trace, если присвоены как
const fn = () => {}без явного имени переменной — затрудняет профилирование. - Генераторы:
const gen = *() => {}— синтаксическая ошибка; для генераторов нуженfunction*. - Prototype chain:
arrowFn.prototype—undefined, поэтому нельзя расширять черезclass extends. - Избыточное применение: использование стрелочных функций везде, в том числе в методах класса как поля (
class Foo { bar = () => {} }), создаёт отдельную копию метода для каждого экземпляра вместо одного метода в прототипе.
Common mistakes
- Смешивать «стрелочные функции» с похожим механизмом без критерия выбора.
- Игнорировать риск: неверно оценить границы применения темы «стрелочные функции» и получить хрупкое решение.
- Показывать только синтаксис и не объяснять поведение в runtime или сборке.
What the interviewer is testing
- Объясняет лексический
this, отсутствие собственногоargumentsи ограничения как конструктора. - Показывает на примере, как работает: стрелочная функция берет
thisиз внешней области и поэтому удобна для callback, но не подходит как метод объекта, которому нужен динамический receiver. - Называет production-нюанс и граничный случай для темы «стрелочные функции».