Короткий способ объявить функцию
Стрелочные функции в JavaScript — это более компактный синтаксис для объявления функций. Они появились в ES2015 и сегодня стали стандартом де-факто для коротких инлайн-функций: особенно для колбэков в методах массивов, обработчиков промисов и слушателей событий.
Схема простая: параметры, затем =>, а после — тело функции.
Результат тот же, что и у классической записи:
const add = function (a, b) {
return a + b;
};
Меньше букв — это приятно, но по-настоящему стрелочные функции в JavaScript ценят за две другие вещи: неявный return и особое поведение this. О них — дальше.
Неявный return
Если тело функции — это одно выражение, можно выбросить фигурные скобки вместе с return. Значение выражения вернётся само:
Вот где стрелочные функции действительно раскрываются — однострочные преобразования читаются как математическая запись:
Как только тебе нужно больше одного выражения, снова возвращаешься к фигурным скобкам и явному return:
Забыть return внутри фигурных скобок — самая распространённая ошибка при работе со стрелочными функциями. Запись x => { x * 2 } вернёт undefined: фигурные скобки превращают тело в блок, и выражение внутри просто теряется.
Скобки вокруг параметров
Если параметр ровно один, скобки можно опустить:
С нулём, двумя или более параметрами скобки обязательны:
Некоторые команды предпочитают всегда писать скобки ради единообразия. Оба варианта рабочие — выберите один и придерживайтесь его.
Как вернуть объектный литерал
А вот и подводный камень. Если попытаться неявно вернуть объект, то фигурные скобки будут восприняты как тело функции:
Выведется undefined. JavaScript трактует { name: name } как блок с помеченным оператором, а не как объектный литерал. Чтобы заставить его быть выражением, оберните объект в круглые скобки:
Скобки () вокруг { ... } решают проблему. Запомните этот приём — вы столкнётесь с ним в первую же неделю работы со стрелочными функциями.
Лексический this
Главная причина, по которой появились стрелочные функции, — вовсе не короткий синтаксис. Дело в том, что у них нет собственного this. Они наследуют его из окружающей области видимости.
Чтобы понять, почему это важно, посмотрим на обычную функцию в роли колбэка:
Внутри function () { ... }, переданной в setInterval, this — это уже не counter. Обычные функции получают собственный this в зависимости от того, как их вызвали, а setInterval вызывает колбэк с this, равным undefined (в strict mode) или глобальному объекту.
Стрелочная функция же сохраняет this из окружающего метода — это и есть лексический this:
Внутри стрелочной функции this по-прежнему указывает на counter, потому что стрелка не создаёт собственный this. Раньше, до появления стрелочных функций, эту проблему обходили через const self = this; или .bind(this). Эти приёмы всё ещё работают, но сегодня нужны крайне редко.
Чего нет у стрелочных функций
Лексический this — это лишь часть более общей картины: у стрелочных функций нет сразу нескольких вещей, которые есть у обычных.
- Нет собственного
this— он наследуется из внешней области видимости. - Нет объекта
arguments— вместо него используйте rest-параметры (...args). - Нельзя вызвать через
new— стрелочная функция не может быть конструктором. - Нет свойства
prototype— это прямое следствие предыдущего пункта.
...args даёт тот же приём «принять сколько угодно аргументов», что и arguments, но с приятным бонусом — это настоящий массив. А вот вызов new Greeter(...) падает с ошибкой, потому что стрелочные функции не могут быть конструкторами.
Когда не стоит использовать стрелочную функцию
Стрелочные функции — выбор по умолчанию для колбэков, но в паре случаев они всё-таки не подходят:
Если описать метод объекта стрелкой, this не привяжется к самому объекту — он будет взят оттуда, где написан объектный литерал (обычно это модуль или глобальная область). Для методов используйте сокращённый синтаксис (greet() { ... }).
То же самое касается методов в прототипах классов, обработчиков событий, где this должен указывать на элемент, и любых функций, которые вы планируете вызывать через new. В этих случаях нужна обычная function.
Короткая шпаргалка: когда использовать стрелочные функции
- Короткий колбэк из одного выражения? Стрелочная функция.
- Нужно, чтобы
thisостался привязан к внешней области? Стрелочная функция. - Определяете метод объекта или прототипа класса? Обычная функция (или сокращённый синтаксис метода).
- Пишете конструктор? Обычная функция, а ещё лучше —
class.
В любом реальном JavaScript-проекте вы встретите оба стиля. Понимание того, какой из них уместнее, приходит после пары недель чтения чужого кода — дальше выбор делается на автомате.
Дальше: параметры и значения по умолчанию
У стрелочных и обычных функций одинаковые возможности работы с параметрами: значения по умолчанию, остаточные параметры (rest), деструктуризация аргументов и прочее. Об этом — на следующей странице, и всё это применимо ко всем видам функций, которые мы уже разобрали.
Часто задаваемые вопросы
Что такое стрелочная функция в JavaScript?
Стрелочная функция — это сокращённая запись функции через синтаксис =>. Например, const add = (a, b) => a + b; — это стрелочная функция, которая принимает два аргумента и возвращает их сумму. Помимо более короткого синтаксиса, у стрелочных функций нет собственных this, arguments и super — всё это они берут из внешней области видимости.
Чем стрелочные функции отличаются от обычных?
У обычных функций, объявленных через function, есть свой this, свой объект arguments, и их можно вызывать через new как конструкторы. У стрелочных ничего из этого нет — this они наследуют оттуда, где были определены. И ещё момент: стрелочные функции не поднимаются (hoisting) так, как объявления через function.
Когда стоит использовать стрелочную функцию?
Стрелочные удобны для коротких коллбэков вроде arr.map(x => x * 2), а также везде, где важно, чтобы this оставался привязан к внешнему контексту — например, внутри метода класса, который передаёт обработчик в setTimeout или вешает слушатель события. А вот для методов объектов, конструкторов и обычных функций верхнего уровня лучше оставить классический function.