Arrow Function
Стрелочная функция — компактный синтаксис для создания функций с лексическим
this, без собственногоarguments,superиnew.target.
Зачем нужно
Стрелочные функции решают две главные проблемы: многословность callback-функций и потерю контекста this. Они делают код короче и предсказуемее при работе с методами массивов, промисами и обработчиками.
Где используется
Callback-функции, методы массивов (map/filter/reduce), промисы (.then/.catch), короткие утилиты, React-компоненты.
Предпосылки
Function Declaration, Function Expression, this
Синтаксис
Полная форма (block body)
const add = (a, b) => {
return a + b;
};
Сокращённая форма (concise body)
const add = (a, b) => a + b; // return подразумевается
Один параметр — скобки необязательны
const double = x => x * 2;
const greet = name => `Привет, ${name}!`;
Без параметров — скобки обязательны
const now = () => Date.now();
const random = () => Math.random;
Возврат объекта — обернуть в скобки
const createUser = (name, age) => ({ name, age });
console.log(createUser('Иван', 25));
// { name: 'Иван', age: 25 }
Лексический this
Главное отличие стрелочных функций — они НЕ создают собственный this:
const team = {
name: 'Альфа',
members: ['Иван', 'Мария', 'Петр'],
// Обычная функция — this теряется в callback
showMembersBroken {
this.members.forEach(function(member) {
// this === undefined (strict mode) или window
console.log(`${this.name}: ${member}`); // Ошибка!
});
},
// Стрелочная функция — this берётся из showMembers
showMembers {
this.members.forEach(member => {
console.log(`${this.name}: ${member}`); // "Альфа: Иван" и т.д.
});
}
};
Вложенные стрелки
class Timer {
constructor {
this.seconds = 0;
}
start {
// this из start — экземпляр Timer
setInterval(() => {
this.seconds++; // this === экземпляр Timer
console.log(this.seconds);
}, 1000);
}
}
Нет объекта arguments
// Обычная функция — есть arguments
function regularFn() {
console.log(arguments); // Arguments [1, 2, 3]
}
// Стрелочная — нет arguments
const arrowFn = () => {
// console.log(arguments); // ReferenceError
};
// Решение: rest-параметры
const arrowWithRest = (...args) => {
console.log(args); // [1, 2, 3] — обычный массив
};
arrowWithRest(1, 2, 3);
Нельзя использовать как конструктор
const Person = (name) => {
this.name = name;
};
// new Person('Иван'); // TypeError: Person is not a constructor
// Решение: обычная функция или класс
function PersonFn(name) {
this.name = name;
}
const ivan = new PersonFn('Иван'); // OK
Нет prototype
const arrow = () => {};
console.log(arrow.prototype); // undefined
function regular() {}
console.log(regular.prototype); // {constructor: f}
Практические примеры
Методы массивов
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const evens = numbers.filter(n => n % 2 === 0);
const doubled = numbers.map(n => n * 2);
const sum = numbers.reduce((acc, n) => acc + n, 0);
console.log(evens); // [2, 4, 6, 8, 10]
console.log(doubled); // [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
console.log(sum); // 55
Цепочка преобразований
const users = [
{ name: 'Алиса', age: 25 },
{ name: 'Боб', age: 17 },
{ name: 'Чарли', age: 30 },
{ name: 'Дина', age: 15 },
];
const adultNames = users
.filter(u => u.age >= 18)
.map(u => u.name)
.sort((a, b) => a.localeCompare(b));
console.log(adultNames); // ['Алиса', 'Чарли']
Промисы
fetch('/api/users')
.then(response => response.json())
.then(users => users.filter(u => u.active))
.then(activeUsers => console.log(activeUsers))
.catch(err => console.error('Ошибка:', err));
Короткие утилиты
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);
const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);
const add10 = x => x + 10;
const multiply2 = x => x * 2;
const toString = x => `Результат: ${x}`;
const transform = pipe(add10, multiply2, toString);
console.log(transform(5)); // "Результат: 30"
Когда НЕ использовать
Методы объектов
const obj = {
value: 42,
// Плохо — this не привязан к obj
getValue: => this.value, // undefined
// Хорошо — shorthand метод
getValue { return this.value; } // 42
};
Обработчики событий DOM (когда нужен this элемента)
// this будет window/undefined, а не элемент
button.addEventListener('click', () => {
console.log(this); // window, не button!
});
// Решение 1: обычная функция
button.addEventListener('click', function {
console.log(this); // button
});
// Решение 2: использовать event.target
button.addEventListener('click', (event) => {
console.log(event.target); // button
});
Прототипные методы
function Person(name) {
this.name = name;
}
// Плохо
Person.prototype.greet = () => {
return `Привет, ${this.name}`; // this — не экземпляр
};
// Хорошо
Person.prototype.greet = function {
return `Привет, ${this.name}`;
};
Сводка: стрелочная vs обычная
| Свойство | Обычная | Стрелочная |
|---|---|---|
this |
Свой, зависит от вызова | Лексический (от окружения) |
arguments |
Есть | Нет |
new |
Можно | Нельзя |
prototype |
Есть | Нет |
super |
Есть | Нет собственного |
yield |
Можно (генератор) | Нельзя |
| Hoisting | Declaration — да | Нет |
Частые ошибки
1. Забытые скобки при возврате объекта
// Неправильно — блок кода, не объект!
const getUser = () => { name: 'Иван', age: 25 };
console.log(getUser); // undefined
// Правильно — обернуть в
const getUser2 = () => ({ name: 'Иван', age: 25 });
2. Многострочная стрелка без return
// Concise body — return автоматический
const add = (a, b) => a + b; // OK
// Block body — нужен явный return!
const addBroken = (a, b) => {
a + b; // ничего не возвращает!
};
const addFixed = (a, b) => {
return a + b;
};
3. this в стрелке верхнего уровня
// На верхнем уровне модуля this === undefined (ESM) или module.exports (CJS)
const getThis = () => this;
console.log(getThis); // undefined в модуле, window в скрипте
Практика
- Перепиши callback-функции в
map/filter/reduceна стрелочные - Создай объект с методом, использующим
forEachсо стрелочной функцией - Напиши функцию
compose, принимающую массив функций - Попробуй использовать
newсо стрелочной функцией и увидь ошибку - Сравни поведение
thisв стрелочной и обычной функции внутри метода объекта
Связанные темы
Ресурсы
- MDN — Arrow Functions
- JavaScript.info — Стрелочные функции
- JavaScript.info — Особенности стрелочных функций
🎓 Источник: Функции, стрелочные функции, контексты, замыкания
- 📅 2018-09-27 · YouTube · ID:
pn5myCmpV2U - Тезисы:
- Lambda Expression: expression справа возвращается без
return; с блоком{}—returnнужен явно - У лямбды нет своего
this, она берёт его из контекста выше - Лямбды нельзя привязать через
bindк контексту — только обычныеfunction
- Lambda Expression: expression справа возвращается без
- Цитата: «Если у нас функция объявлена при помощи ключевого слова function, у нее может быть объектный контекст. А если это lambda функция, у нее нет объектного контекста.»
⚡ Источник: Regular Function vs Arrow Function · AsForJS
- 📅 2022-08-14 · YouTube · ID:
IKB61INTyrs - Тезисы:
- Стрелочная функция в V8 часто создаётся без
CreateFunctionContext— оптимизатор не создаёт лишних структур => constValue— единственная настоящая константа в JS (математически доказуемо)- Оптимизатор V8 предпочитает стрелочные функции для вложенных конструкций
- Стрелочные функции дешевле обычных function expression в нагретом коде
- Стрелочная функция в V8 часто создаётся без
- Цитата: «Эта конструкция, это единственный на текущий момент способ создания реальных констант в академическом смысле этого слова в джаваскрипте.»
⚡ Источник: Как работает this в javascript · AsForJS
- 📅 2023-05-07 · YouTube · ID:
4tg4qokVS9o - Тезисы:
- У стрелочной функции нет скрытого параметра
this— это её единственное отличие - При обращении к
thisвнутри стрелки разрешение идёт по цепочке окружений как для любого идентификатора - Важно место определения стрелки, не место её вызова
- Возврат стрелки из метода фиксирует
thisметода навсегда — где бы стрелку потом ни вызвали
- У стрелочной функции нет скрытого параметра
- Цитата: «Самое простое отличие — это запомнить себе, что нормальная функция — это любая функция, которая не является arrow function, стрелочной функцией.»
- Код:
const theObject = { name: 'Murych', returnFn { return => console.log(this.name); } }; const superObject = { run(fn) { fn; } }; superObject.run(theObject.returnFn); // 'Murych' // Стрелка запомнила this момента создания (theObject)