Spec-Zone.ru › JavaScript

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

Базовый уровень Широко доступно

Эта функция хорошо зарекомендовала себя и работает на многих устройствах и в различных версиях браузеров. Она доступна в браузерах с июля 2015 года.

Стрелочная функция — это компактная альтернатива традиционному выражению функции, с некоторыми семантическими различиями и намеренными ограничениями в использовании:

  • У стрелочных функций нет собственных привязок к this, arguments или super, и их не следует использовать в качестве методов.
  • Стрелочные функции нельзя использовать в качестве конструкторов. Их вызов с new вызывает TypeError. У них также нет доступа к ключевому слову new.target.
  • Стрелочные функции не могут использовать yield внутри своего тела и не могут быть созданы как генераторные функции.

Попробуйте

const materials = ["Hydrogen", "Helium", "Lithium", "Beryllium"];

console.log(materials.map((material) => material.length));
// Expected output: Array [8, 6, 7, 9]

Синтаксис

() => expression

param => expression

(param) => expression

(param1, paramN) => expression

() => {
  statements
}

param => {
  statements
}

(param1, paramN) => {
  statements
}

Параметры остатка, параметры по умолчанию и деструктуризация в параметрах поддерживаются и всегда требуют скобок:

(a, b, ...r) => expression
(a = 400, b = 20, c) => expression
([a, b] = [10, 20]) => expression
({ a, b } = { a: 10, b: 20 }) => expression

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

async param => expression
async (param1, param2, ...paramN) => {
  statements
}

Описание

Разложим традиционную анонимную функцию до простейшей стрелочной функции шаг за шагом. Каждый шаг на пути является допустимой стрелочной функцией.

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

// Traditional anonymous function
(function (a) {
  return a + 100;
});

// 1. Remove the word "function" and place arrow between the argument and opening body brace
(a) => {
  return a + 100;
};

// 2. Remove the body braces and word "return" — the return is implied.
(a) => a + 100;

// 3. Remove the parameter parentheses
a => a + 100;

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

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

// Traditional anonymous function
(function (a, b) {
  return a + b + 100;
});

// Arrow function
(a, b) => a + b + 100;

const a = 4;
const b = 2;

// Traditional anonymous function (no parameters)
(function () {
  return a + b + 100;
});

// Arrow function (no parameters)
() => a + b + 100;

Фигурные скобки можно опустить только в том случае, если функция непосредственно возвращает выражение. Если тело содержит инструкции, фигурные скобки обязательны. В этом случае значения возврата должны быть явно указаны с помощью ключевого слова return. Стрелочные функции не могут угадать, что или когда вы хотите вернуть.

// Traditional anonymous function
(function (a, b) {
  const chuck = 42;
  return a + b + chuck;
});

// Arrow function
(a, b) => {
  const chuck = 42;
  return a + b + chuck;
};

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

// Traditional Function
function bob(a) {
  return a + 100;
}

// Arrow Function
const bob2 = (a) => a + 100;

Тело функции

Стрелочные функции могут иметь либо тело выражения, либо обычное блочное тело.

В теле выражения указывается только одно выражение, которое становится неявным возвращаемым значением. Блочное тело аналогично традиционным телам функций, где возвращаемые значения должны быть явно указаны с помощью ключевого слова return. Стрелочные функции не обязаны возвращать значение. Если выполнение блочного тела достигает конца без встречи с инструкцией return, функция возвращает undefined, как и другие функции.

// Expression body
const add = (a, b) => a + b; // Implicitly returns a + b

// Block body
const add2 = (a, b) => {
  console.log(a, b);
  return a + b; // Must explicitly return a value
};

// No return value
const add3 = (b) => {
  a += b;
  // No return statement, so returns undefined
};

Возврат литералов объектов с использованием синтаксиса тела выражения (params) => { object: literal } не работает должным образом.

const func = () => { foo: 1 };
// Calling func() returns undefined!

const func2 = () => { foo: function () {} };
// SyntaxError: function statement requires a name

const func3 = () => { foo() {} };
// SyntaxError: Unexpected token '{'

Это происходит потому, что JavaScript рассматривает стрелочную функцию как имеющую тело выражения только в том случае, если токен, следующий за стрелкой, не является левой фигурной скобкой, поэтому код внутри фигурных скобок ({}) интерпретируется как последовательность инструкций, где foo является меткой, а не ключом в литерале объекта.

Чтобы исправить это, заключите литерал объекта в скобки:

const func = () => ({ foo: 1 });

Нельзя использовать в качестве методов

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

"use strict";

const obj = {
  i: 10,
  b: () => console.log(this.i, this),
  c() {
    console.log(this.i, this);
  },
};

obj.b(); // logs undefined, Window { /* … */ } (or the global object)
obj.c(); // logs 10, Object { /* … */ }

Еще один пример, связанный с Object.defineProperty():

"use strict";

const obj = {
  a: 10,
};

Object.defineProperty(obj, "b", {
  get: () => {
    console.log(this.a, typeof this.a, this); // undefined 'undefined' Window { /* … */ } (or the global object)
    return this.a + 10; // represents global object 'Window', therefore 'this.a' returns 'undefined'
  },
});

Поскольку тело класса имеет контекст this, стрелочные функции в качестве полей класса замыкают контекст this класса, и this внутри тела стрелочной функции будет корректно указывать на экземпляр (или сам класс, для статических полей). Однако, поскольку это замыкание, а не собственная привязка функции, значение this не будет меняться в зависимости от контекста выполнения.

class C {
  a = 1;
  autoBoundMethod = () => {
    console.log(this.a);
  };
}

const c = new C();
c.autoBoundMethod(); // 1
const { autoBoundMethod } = c;
autoBoundMethod(); // 1
// If it were a normal method, it should be undefined in this case

Свойства стрелочных функций часто называют "методами с автоматической привязкой", потому что эквивалент с обычными методами выглядит так:

class C {
  a = 1;
  constructor() {
    this.method = this.method.bind(this);
  }
  method() {
    console.log(this.a);
  }
}

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

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

Отсутствие привязки аргументов

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

function foo(n) {
  const f = () => arguments[0] + n; // foo's implicit arguments binding. arguments[0] is n
  return f();
}

foo(3); // 3 + 3 = 6

В большинстве случаев использование параметров остатка является хорошей альтернативой использованию объекта arguments.

function foo(n) {
  const f = (...args) => args[0] + n;
  return f(10);
}

foo(1); // 11

Нельзя использовать в качестве конструкторов

Стрелочные функции нельзя использовать в качестве конструкторов, и они вызовут ошибку при вызове с new. У них также нет свойства prototype.

const Foo = () => {};
const foo = new Foo(); // TypeError: Foo is not a constructor
console.log("prototype" in Foo); // false

Нельзя использовать в качестве генераторов

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

Перенос строки перед стрелкой

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

const func = (a, b, c)
  => 1;
// SyntaxError: Unexpected token '=>'

Для целей форматирования вы можете разместить перенос строки после стрелки или использовать скобки/фигурные скобки вокруг тела функции, как показано ниже. Вы также можете размещать переносы строк между параметрами.

const func = (a, b, c) =>
  1;

const func2 = (a, b, c) => (
  1
);

const func3 = (a, b, c) => {
  return 1;
};

const func4 = (
  a,
  b,
  c,
) => 1;

Приоритет стрелки

Хотя стрелка в стрелочной функции не является оператором, стрелочные функции имеют специальные правила разбора, которые по-разному взаимодействуют с приоритетом операторов по сравнению с обычными функциями.

let callback;

callback = callback || () => {};
// SyntaxError: invalid arrow-function arguments

Поскольку => имеет более низкий приоритет, чем большинство операторов, скобки необходимы, чтобы избежать callback || (), интерпретируемых как список аргументов стрелочной функции.

callback = callback || (() => {});

Примеры

Использование стрелочных функций

// An empty arrow function returns undefined
const empty = () => {};

(() => "foobar")();
// Returns "foobar"
// (this is an Immediately Invoked Function Expression)

const simple = (a) => (a > 15 ? 15 : a);
simple(16); // 15
simple(10); // 10

const max = (a, b) => (a > b ? a : b);

// Easy array filtering, mapping, etc.
const arr = [5, 6, 13, 0, 1, 18, 23];

const sum = arr.reduce((a, b) => a + b);
// 66

const even = arr.filter((v) => v % 2 === 0);
// [6, 0, 18]

const double = arr.map((v) => v * 2);
// [10, 12, 26, 0, 2, 36, 46]

// More concise promise chains
promise
  .then((a) => {
    // …
  })
  .then((b) => {
    // …
  });

// Arrow functions without parameters
setTimeout(() => {
  console.log("I happen sooner");
  setTimeout(() => {
    // deeper code
    console.log("I happen later");
  }, 1);
}, 1);

Использование call, bind и apply

Методы call(), apply() и bind() работают ожидаемым образом с традиционными функциями, поскольку мы устанавливаем область видимости для каждого из методов:

const obj = {
  num: 100,
};

// Setting "num" on globalThis to show how it is NOT used.
globalThis.num = 42;

// A traditional function to operate on "this"
function add(a, b, c) {
  return this.num + a + b + c;
}

console.log(add.call(obj, 1, 2, 3)); // 106
console.log(add.apply(obj, [1, 2, 3])); // 106
const boundAdd = add.bind(obj);
console.log(boundAdd(1, 2, 3)); // 106

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

const obj = {
  num: 100,
};

// Setting "num" on globalThis to show how it gets picked up.
globalThis.num = 42;

// Arrow function
const add = (a, b, c) => this.num + a + b + c;

console.log(add.call(obj, 1, 2, 3)); // 48
console.log(add.apply(obj, [1, 2, 3])); // 48
const boundAdd = add.bind(obj);
console.log(boundAdd(1, 2, 3)); // 48

Пожалуй, самое большое преимущество использования стрелочных функций заключается в работе с методами, такими как setTimeout() и EventTarget.prototype.addEventListener(), которые обычно требуют некоторого вида замыкания, call(), apply() или bind(), чтобы гарантировать, что функция выполняется в правильной области видимости.

С традиционными выражениями функций код, подобный этому, не работает должным образом:

const obj = {
  count: 10,
  doSomethingLater() {
    setTimeout(function () {
      // the function executes on the window scope
      this.count++;
      console.log(this.count);
    }, 300);
  },
};

obj.doSomethingLater(); // logs "NaN", because the property "count" is not in the window scope.

Со стрелочными функциями область видимости this сохраняется легче:

const obj = {
  count: 10,
  doSomethingLater() {
    // The method syntax binds "this" to the "obj" context.
    setTimeout(() => {
      // Since the arrow function doesn't have its own binding and
      // setTimeout (as a function call) doesn't create a binding
      // itself, the "obj" context of the outer method is used.
      this.count++;
      console.log(this.count);
    }, 300);
  },
};

obj.doSomethingLater(); // logs 11

Спецификации

Спецификация
ECMAScript® 2027 Language Specification
# sec-arrow-function-definitions

Совместимость с браузерами

Десктоп Мобильные Сервер
Chrome Edge Firefox Opera Safari Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet WebView Android WebView on iOS Bun Deno Node.js
arrow_functions
45
12
22Первоначальная реализация стрелочных функций в Firefox сделала их автоматически строгими. Это было изменено начиная с Firefox 39. Использование 'use strict'; теперь обязательно.
До Firefox 39, символ переноса строки (\n) некорректно разрешался после аргументов стрелочных функций. Это было исправлено в соответствии со спецификацией ES2015, и код, подобный () \n => {}, теперь вызовет SyntaxError в этой и последующих версиях.
32
10
45
22Первоначальная реализация стрелочных функций в Firefox для Android сделала их автоматически строгими. Это было изменено начиная с Firefox для Android 39. Использование 'use strict'; теперь обязательно.
До Firefox для Android 39, символ переноса строки (\n) некорректно разрешался после аргументов стрелочных функций. Это было исправлено в соответствии со спецификацией ES2015, и код, подобный () \n => {}, теперь вызовет SyntaxError в этой и последующих версиях.
32
10
5.0
45
10
1.0.0
1.0
4.0.0
trailing_comma
58
12
52
45
10
58
52
43
10
7.0
58
10
1.0.0
1.0
8.0.0

См. также

  • Функции
  • Функции
  • function
  • function expression
  • ES6 In Depth: Стрелочные функции на hacks.mozilla.org (2015)

© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API