W3docs

Стрелочные функции JavaScript

Стрелочные функции JavaScript в деталях: лексический this, отсутствие arguments и super, почему нельзя использовать new, и когда их не применять.

Введение в стрелочные функции JavaScript

Стрелочные функции, появившиеся в ES6 (ECMAScript 2015), стали одной из ключевых возможностей JavaScript и предоставляют более простой способ записи функциональных выражений. Они особенно популярны, поскольку упрощают код и помогают решать распространённые проблемы с ключевым словом this.

На этой странице рассматривается не синтаксис (он описан в разделе Стрелочные функции: основы), а причины такого поведения стрелочных функций. Коротко: стрелочная функция не имеет собственных привязок. У неё нет собственного this, собственного arguments, собственного super и метода [[Construct]]. При обращении к любому из этих значений внутри стрелочной функции JavaScript ищет их в окружающей (лексической) области видимости — точно так же, как и обычную переменную. Почти все особенности и преимущества стрелочных функций вытекают именно из этого одного правила.

Определение стрелочных функций

Стрелочные функции позволяют использовать более короткий синтаксис по сравнению с традиционными функциональными выражениями. Вот базовое сравнение:


javascript— editable

Версия со стрелочной функцией не только короче, но и устраняет необходимость в ключевом слове function и фигурных скобках при наличии одного выражения.

Варианты синтаксиса

Стрелочные функции можно записывать в различных формах в зависимости от количества параметров и сложности тела функции:

  • Без параметров: используйте пустые скобки:

javascript— editable
  • Один параметр: скобки необязательны:

javascript— editable
  • Несколько параметров: скобки обязательны:

javascript— editable
  • Несколько строк: используйте фигурные скобки и явный return (если функция возвращает значение):

javascript— editable

У стрелочных функций нет собственного this

Самое важное свойство стрелочных функций — отсутствие собственного this. Обычная функция определяет своё this в момент вызова в зависимости от того, как она вызвана (подробнее — в разделе Методы объекта, "this"). Стрелочная функция игнорирует это и берёт this из той области видимости, где она была определена — это называется лексическим this.

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


javascript— editable

Замените стрелочную функцию обычной function(member) { ... }, и this внутри forEach станет undefined, что вызовет ошибку Cannot read properties of undefined. До появления стрелочных функций разработчики обходили это с помощью const self = this; или .bind(this) — см. раздел Привязка функции. Стрелочные функции избавляют от необходимости в таких приёмах.

То же лексическое правило решает классическую проблему с таймером, когда колбэк выполняется в отрыве от своего объекта:


javascript— editable

Поскольку this зафиксирован лексически, изменить его невозможно. Вызов .call(), .apply() или .bind() на стрелочной функции не влияет на this — привязка игнорируется:


javascript— editable

У стрелочных функций нет arguments

Стрелочные функции также не имеют собственного объекта arguments. Обращение к arguments внутри стрелочной функции приводит к поиску в окружающей функции — что удобно для обёрток и декораторов:


javascript— editable

Если вам действительно нужны аргументы самой стрелочной функции, используйте остаточные параметры (...args), которые работают везде:


javascript— editable

Стрелочные функции нельзя использовать как конструкторы

Поскольку у стрелочной функции нет внутреннего метода [[Construct]] и свойства prototype, её нельзя использовать с оператором new:


javascript— editable

По той же причине стрелочные функции не могут обращаться к super для доступа к родительскому классу, поэтому они никогда не используются как конструкторы классов или методы классов, опирающиеся на super.

Когда не следует использовать стрелочные функции

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

Методы объекта

Когда функция является методом объекта, обычно ожидается, что this будет указывать на этот объект. Стрелочная функция берёт this из внешней области видимости (часто это модуль или глобальная область), поэтому она не увидит собственные свойства объекта:


javascript— editable

Используйте обычное краткое описание метода (или функциональное выражение) для методов объекта. Подробнее — в разделе Методы объекта, "this".

Методы прототипа и конструкторы

Поскольку стрелочные функции не могут использоваться как конструкторы и не имеют собственного this, они не могут определять методы прототипа или служить функциями-конструкторами. Методы, добавляемые к прототипу, должны быть обычными функциями, чтобы каждый экземпляр правильно разрешал this.

Обработчики событий DOM (в браузере)

При подключении обработчика через addEventListener браузер вызывает его с this, указывающим на элемент, получивший событие. Стрелочная функция игнорирует это и сохраняет внешний this, поэтому используйте обычную функцию, если вам нужно обращаться к элементу через this (впрочем, всегда можно воспользоваться event.currentTarget).

Продвинутые техники

Возврат литералов объекта

Чтобы вернуть литерал object из стрелочной функции, оберните объект в скобки:


javascript— editable

IIFE со стрелочными функциями

Стрелочные функции можно использовать для немедленно вызываемых функциональных выражений (IIFE):


javascript— editable

Итоги

Стрелочные функции лучше всего понимать через то, чего в них нет. Они не имеют:

  • Собственного this — он берётся из окружающей области видимости (лексический this), и .call/.apply/.bind не могут его изменить. Идеально для колбэков, неуместно для методов объекта.
  • Собственного arguments — используйте остаточные параметры (...args), если они нужны.
  • super — поэтому они не могут быть методами класса, вызывающими родителя.
  • [[Construct]] и prototype — поэтому их нельзя использовать с new или как методы прототипа.

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

Связанные главы

Практика

Практика
Какие из следующих утверждений верны для стрелочных функций в JavaScript?
Какие из следующих утверждений верны для стрелочных функций в JavaScript?
Was this page helpful?