From 074785cea106179cb3305637055ab0a009ca74f2 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:42:52 -0500 Subject: initial commit --- .../reference/functions/arrow_functions/index.html | 378 +++++++++++++++++++++ 1 file changed, 378 insertions(+) create mode 100644 files/ru/web/javascript/reference/functions/arrow_functions/index.html (limited to 'files/ru/web/javascript/reference/functions/arrow_functions') diff --git a/files/ru/web/javascript/reference/functions/arrow_functions/index.html b/files/ru/web/javascript/reference/functions/arrow_functions/index.html new file mode 100644 index 0000000000..b903c96852 --- /dev/null +++ b/files/ru/web/javascript/reference/functions/arrow_functions/index.html @@ -0,0 +1,378 @@ +--- +title: Стрелочные функции +slug: Web/JavaScript/Reference/Functions/Arrow_functions +tags: + - ECMAScript6 + - JavaScript + - Функции +translation_of: Web/JavaScript/Reference/Functions/Arrow_functions +--- +
{{jsSidebar("Functions")}}
+ +

Сводка

+ +

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

+ +

Синтаксис

+ +

Базовый синтаксис

+ +
(param1, param2, …, paramN) => { statements }
+(param1, param2, …, paramN) => expression
+// эквивалентно: (param1, param2, …, paramN) => { return expression; }
+
+// Круглые скобки не обязательны для единственного параметра:
+(singleParam) => { statements }
+singleParam => { statements }
+
+// Функция без параметров нуждается в круглых скобках:
+() => { statements }
+() => expression
+// Эквивалентно: () => { return expression; }
+
+ +

Расширенный синтаксис

+ +
// Когда возвращаете литеральное выражение объекта, заключите тело в скобки
+params => ({foo: bar})
+
+// Rest параметры и параметры по умолчанию поддерживаются
+(param1, param2, ...rest) => { statements }
+(param1 = defaultValue1, param2, …, paramN = defaultValueN) => { statements }
+
+// Деструктуризация тоже поддерживается
+var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
+f();  // 6
+
+ +

Подробные примеры синтаксиса можно посмотреть здесь.

+ +

Описание

+ +

Смотрите также "ES6 In Depth: Arrow functions" on hacks.mozilla.org.

+ +

Два фактора повлияли на появление стрелочных функции: более короткий синтаксис и лексика this.

+ +

Короткие функции

+ +

В некоторых функциональных шаблонах приветствуются более короткие функции. Сравните:

+ +
var elements = [
+  'Hydrogen',
+  'Helium',
+  'Lithium',
+  'Beryllium'
+];
+
+elements.map(function(element) {
+  return element.length;
+}); // Это выражение вернет массив [8, 6, 7, 9]
+
+// Функцию выше можно записать как стрелочную функцию:
+elements.map((element) => {
+  return element.length;
+}); // [8, 6, 7, 9]
+
+// Если единственным оператором в выражении стрелочной функции является return,
+// можно удалить return и окружающие фигурные скобки
+
+elements.map(element => element.length); // [8, 6, 7, 9]
+
+// В данном случае, поскольку нам нужно только свойство length, мы можем использовать деструктуризированный параметр:
+// Обратите внимание, что строка `"length"` соответствует свойству, которое мы хотим получить,
+// в то время как `lengthFooBArX` это просто имя переменной, которую можно назвать как вы хотите
+elements.map(({ "length": lengthFooBArX }) => lengthFooBArX); // [8, 6, 7, 9]
+
+// Это задание деструктуризированного параметра может быть записано, как показано ниже. Тем не менее, обратите внимание,
+// что нет строки `"length"`, чтобы выбрать, какое свойство мы хотим получить. Вместо этого в качестве свойства,
+// которое мы хотим извлечь из объекта, используется само литеральное имя переменной `length`
+elements.map(({ length }) => length); // [8, 6, 7, 9]
+
+ +

Отсутствие связывания с this

+ +

До появления стрелочных функций, каждая новая функция имела своё значение this (новый объект в случае конструктора, undefined в strict режиме вызова функции, контекст объекта при вызове функции как "метода объекта" и т.д.). Это очень раздражало при использовании объектно-ориентированного стиля программирования.

+ +
function Person() {
+  // В конструкторе Person() `this` указывает на себя.
+  this.age = 0;
+
+  setInterval(function growUp() {
+    // В нестрогом режиме, в функции growUp() `this` указывает
+    // на глобальный объект, который отличается от `this`,
+    // определяемом в конструкторе Person().
+    this.age++;
+  }, 1000);
+}
+
+var p = new Person();
+
+ +

В ECMAScript 3/5, данная проблема решалась присваиванием значения this переменной:

+ +
function Person() {
+  var that = this;
+  that.age = 0;
+
+  setInterval(function growUp() {
+    // Функция с обратным вызовом(callback) содержит переменную that, которая
+    // ссылается на требуемый объект this.
+    that.age++;
+  }, 1000);
+}
+ +

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

+ +

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

+ +
function Person(){
+  this.age = 0;
+
+  setInterval(() => {
+    this.age++; // `this` указывает на объект Person
+  }, 1000);
+}
+
+var p = new Person();
+ +

Строгий режим исполнения

+ +

Поскольку значение this определяется лексикой, правила строгого режима (strict mode) относительно this игнорируются:

+ +
var f = () => { 'use strict'; return this; };
+f() === window; // или глобальный объект
+ +

Все остальные правила строгого режима применяются как обычно.

+ +

Вызов с помощью call или apply

+ +

Так как значение this определяется лексикой, вызов стрелочных функций с помощью методов call() или apply(), даже если передать аргументы в эти методы, не влияет на значение this:

+ +
var adder = {
+  base : 1,
+
+  add : function(a) {
+    var f = v => v + this.base;
+    return f(a);
+  },
+
+  addThruCall: function(a) {
+    var f = v => v + this.base;
+    var b = {
+      base : 2
+    };
+
+    return f.call(b, a);
+  }
+};
+
+console.log(adder.add(1));         // Выводит 2
+console.log(adder.addThruCall(1)); // Всё равно выводит 2
+
+ +

Не имеет собственного объекта arguments

+ +

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

+ +
var arguments = 42;
+var arr = () => arguments;
+
+arr(); // 42
+
+function foo() {
+  var f = (i) => arguments[0] + i; // Неявное связывание ссылки arguments
+                                   // стрелочной функции f
+                                   // c объектом arguments функции foo
+  return f(2);
+}
+
+foo(1); // 3
+ +

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

+ +
function foo() {
+  var f = (...args) => args[0];
+  return f(2);
+}
+
+foo(1); // 2
+
+ +

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

+ +

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

+ +
'use strict';
+var obj = {
+  i: 10,
+  b: () => console.log(this.i, this),
+  c: function() {
+    console.log(this.i, this);
+  }
+}
+obj.b(); // prints undefined, Window {...} (или глобальный объект)
+obj.c(); // prints 10, Object {...}
+
+ +

Стрелочные функции не объявляют привязку ("bind") их контекста this. Другой пример включает {{jsxref("Object.defineProperty()")}}:

+ +
'use strict';
+var obj = {
+  a: 10
+};
+
+Object.defineProperty(obj, 'b', {
+  get: () => {
+    console.log(this.a, typeof this.a, this);
+    return this.a + 10;
+    // представляет глобальный объект 'Window', но 'this.a' возвращает 'undefined'
+  }
+});
+ +

Использование оператора new

+ +

Стрелочные функции не могут быть использованы как конструктор и вызовут ошибку при использовании с new:

+ +
var a = new (function() {})
+// переменной "a" будет присвоено значение экземпляра анонимной функции
+
+var b = new (() => {})
+// будет выброшено исключениe
+// Uncaught TypeError: (intermediate value) is not a constructor
+ +

Использование ключевого слова yield

+ +

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

+ +

Тело функции

+ +

Тело стрелочной функции может иметь краткую (concise body) или блочную (block body) форму.

+ +

Блочная форма не возвращает значение, необходимо явно вернуть значение.

+ +
var func = x => x * x;                  // краткий синтаксис,
+                                        // неявно возвращает результат
+var func = (x, y) => { return x + y; }; // блочный синтаксис,
+                                        // явно возвращает результат
+ +

Возвращаемые объектные строки (литералы)

+ +

Помните о том, что возвращаемые объектные строки используют сокращённый синтаксис: params => {object:literal} будет работать не так, как ожидается.

+ +
var func = () => { foo: 1 };
+// Вызов func() возвращает undefined!
+
+var func = () => { foo: function() {} };
+// SyntaxError: function statement requires a name
+ +

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

+ +

Не забывайте оборачивать скобками объектные строки.

+ +
var func = () => ({ foo: 1 });
+ +

Разрывы строк

+ +

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

+ +
var func = ()
+           => 1;
+// SyntaxError: expected expression, got '=>'
+
+ +

Разбор порядка следования

+ +

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

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

Больше примеров

+ +
// Пустая стрелочная функция возвращает undefined
+let empty = () => {};
+
+(() => 'foobar')();
+// Вернёт "foobar"
+// (Это Immediately Invoked Function Expression
+// смотри 'IIFE' в справочнике)
+
+var simple = a => a > 15 ? 15 : a;
+simple(16); // 15
+simple(10); // 10
+
+let max = (a, b) => a > b ? a : b;
+
+// Удобные операции над массивами: filter, map, ...
+
+var arr = [5, 6, 13, 0, 1, 18, 23];
+
+var sum = arr.reduce((a, b) => a + b);
+// 66
+
+var even = arr.filter(v => v % 2 == 0);
+// [6, 0, 18]
+
+var double = arr.map(v => v * 2);
+// [10, 12, 26, 0, 2, 36, 46]
+
+// Более короткие цепочки promise-ов
+promise.then(a => {
+  // ...
+}).then(b => {
+   // ...
+});
+
+// Стрелочные функции без параметров, которые визуально легче разбирать
+setTimeout( () => {
+  console.log('Я буду раньше');
+  setTimeout( () => {
+    // deeper code
+    console.log('Я буду позже');
+  }, 1);
+}, 1);
+
+ +

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

+ + + + + + + + + + + + + + +
СпецификацияСтатусКомментарий
{{SpecName('ES6', '#sec-arrow-function-definitions', 'Arrow Function Definitions')}}{{Spec2('ES6')}}Изначальное определение.
+ +

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

+ + + +

{{Compat("javascript.functions.arrow_functions")}}

+ +

Замечания для Firefox

+ + + +

See also

+ + -- cgit v1.2.3-54-g00ecf