1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
|
---
title: Стрелочные функции
slug: Web/JavaScript/Reference/Functions/Arrow_functions
tags:
- ECMAScript6
- JavaScript
- Функции
translation_of: Web/JavaScript/Reference/Functions/Arrow_functions
---
<div>{{jsSidebar("Functions")}}</div>
<h2 id="Сводка">Сводка</h2>
<p><strong>Выражения стрелочных функций</strong> имеют более короткий синтаксис по сравнению с <a href="/ru/docs/Web/JavaScript/Reference/Operators/function">функциональными выражениями</a> и лексически привязаны к значению <a href="/ru/docs/Web/JavaScript/Reference/Operators/this">this</a> (но не привязаны к собственному <a href="/ru/docs/Web/JavaScript/Reference/Operators/this">this</a>, <a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions/arguments">arguments</a>, <a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/super">super</a>, или <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target">new.target</a>). Выражение стрелочных функций не позволяют задавать имя, поэтому стрелочные функции <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Function/name">анонимны</a>, если их ни к чему не присвоить.</p>
<h2 id="Syntax" name="Syntax">Синтаксис</h2>
<h3 id="Базовый_синтаксис">Базовый синтаксис</h3>
<pre class="brush: js">(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
// эквивалентно: (param1, param2, …, paramN) => { return expression; }
// Круглые скобки не обязательны для единственного параметра:
(singleParam) => { statements }
singleParam => { statements }
// Функция без параметров нуждается в круглых скобках:
() => { statements }
() => expression
// Эквивалентно: () => { return expression; }
</pre>
<h3 id="Расширенный_синтаксис">Расширенный синтаксис</h3>
<pre class="brush: js">// Когда возвращаете литеральное выражение объекта, заключите тело в скобки
params => ({foo: bar})
// <a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions/Rest_parameters">Rest параметры</a> и <a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions/Default_parameters">параметры по умолчанию</a> поддерживаются
(param1, param2, ...rest) => { statements }
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => { statements }
// <a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment">Деструктуризация</a> тоже поддерживается
var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f(); // 6
</pre>
<p>Подробные примеры синтаксиса можно посмотреть <a href="http://wiki.ecmascript.org/doku.php?id=harmony:arrow_function_syntax" title="http://wiki.ecmascript.org/doku.php?id=harmony:arrow_function_syntax">здесь</a>.</p>
<h2 id="Описание">Описание</h2>
<p>Смотрите также <a href="https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/">"ES6 In Depth: Arrow functions" on hacks.mozilla.org</a>.</p>
<p>Два фактора повлияли на появление стрелочных функции: более короткий синтаксис и лексика <code>this</code>.</p>
<h3 id="Короткие_функции">Короткие функции</h3>
<p>В некоторых функциональных шаблонах приветствуются более короткие функции. Сравните:</p>
<pre class="brush: js">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]
</pre>
<h3 id="Отсутствие_связывания_с_this">Отсутствие связывания с <code>this</code></h3>
<p>До появления стрелочных функций, каждая новая функция имела своё значение <code><a href="/ru/docs/Web/JavaScript/Reference/Operators/this">this</a></code> (новый объект в случае конструктора, undefined в <a href="/ru/docs/Web/JavaScript/Reference/Strict_mode">strict</a> режиме вызова функции, контекст объекта при вызове функции как "метода объекта" и т.д.). Это очень раздражало при использовании объектно-ориентированного стиля программирования.</p>
<pre class="brush: js">function Person() {
// В конструкторе Person() `this` указывает на себя.
this.age = 0;
setInterval(function growUp() {
// В нестрогом режиме, в функции growUp() `this` указывает
// на глобальный объект, который отличается от `this`,
// определяемом в конструкторе Person().
this.age++;
}, 1000);
}
var p = new Person();
</pre>
<p>В ECMAScript 3/5, данная проблема решалась присваиванием значения <code>this</code> переменной:</p>
<pre class="brush: js">function Person() {
var that = this;
that.age = 0;
setInterval(function growUp() {
// Функция с обратным вызовом(<a href="/en-US/docs/Mozilla/js-ctypes/Using_js-ctypes/Declaring_and_Using_Callbacks">callback</a>) содержит переменную that, которая
// ссылается на требуемый объект this.
that.age++;
}, 1000);
}</pre>
<p>Кроме этого, может быть создана <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Function/bind">привязанная функция</a>, в которую передаётся требуемое значение <code><a href="/ru/docs/Web/JavaScript/Reference/Operators/this">this</a></code> для функции (функция <code>growUp()</code> в примере выше).</p>
<p>Стрелочные функции не содержат собственный контекст <code><a href="/ru/docs/Web/JavaScript/Reference/Operators/this">this</a></code>, а используют значение <code><a href="/ru/docs/Web/JavaScript/Reference/Operators/this">this</a></code> окружающего контекста. Поэтому нижеприведенный код работает как предполагалось:</p>
<pre class="brush: js">function Person(){
this.age = 0;
setInterval(() => {
this.age++; // `this` указывает на объект Person
}, 1000);
}
var p = new Person();</pre>
<h4 id="Строгий_режим_исполнения">Строгий режим исполнения</h4>
<p>Поскольку значение <code>this</code> определяется лексикой, правила строгого режима (<a href="/ru/docs/Web/JavaScript/Reference/Strict_mode">strict mode</a>) относительно <code>this</code> игнорируются:</p>
<pre class="brush: js">var f = () => { 'use strict'; return this; };
f() === window; // или глобальный объект</pre>
<p>Все остальные правила строгого режима применяются как обычно.</p>
<h4 id="Вызов_с_помощью_call_или_apply">Вызов с помощью call или apply</h4>
<p>Так как значение <code>this</code> определяется лексикой, вызов стрелочных функций с помощью методов <code>call()</code> или <code>apply()</code>, даже если передать аргументы в эти методы, не влияет на значение <code>this</code>:</p>
<pre class="brush: js">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
</pre>
<h3 id="Не_имеет_собственного_объекта_arguments">Не имеет собственного объекта arguments</h3>
<p>Стрелочные функции не имеют собственного объекта arguments, поэтому в теле стрелочных функций arguments будет ссылаться на переменную в окружающей области.</p>
<pre class="brush: js">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</pre>
<p>В большинстве случаев лучшей заменой объекта arguments в стрелочных функциях являются <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters">rest параметры</a>:</p>
<pre class="brush: js">function foo() {
var f = (...args) => args[0];
return f(2);
}
foo(1); // 2
</pre>
<h3 id="Использование_стрелочных_функций_как_методов">Использование стрелочных функций как методов</h3>
<p>Как показано ранее, стрелочные функции лучше всего подходят для функций без методов. Посмотрим, что будет, когда мы попробуем их использовать как методы:</p>
<pre class="brush: js">'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 {...}
</pre>
<p>Стрелочные функции не объявляют привязку ("bind") их контекста <code>this</code>. Другой пример включает {{jsxref("Object.defineProperty()")}}:</p>
<pre class="brush: js">'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'
}
});</pre>
<h3 id="Использование_оператора_new">Использование оператора <code>new</code></h3>
<p>Стрелочные функции не могут быть использованы как конструктор и вызовут ошибку при использовании с <code>new</code>:</p>
<pre class="brush: js">var a = new (function() {})
// переменной "a" будет присвоено значение экземпляра анонимной функции
var b = new (() => {})
// будет выброшено исключение
// Uncaught TypeError: (intermediate value) is not a constructor</pre>
<h3 id="Использование_ключевого_слова_yield">Использование ключевого слова <code>yield</code></h3>
<p>Ключевое слово <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield">yield</a></code> не может быть использовано в теле стрелочной функции (за исключением случаев, когда разрешается использовать в функциях, вложенных в тело стрелочной функции). Как следствие стрелочные функции не могут быть использованы как генераторы.</p>
<h2 id="Тело_функции">Тело функции</h2>
<p>Тело стрелочной функции может иметь краткую (concise body) или блочную (block body) форму.</p>
<p>Блочная форма не возвращает значение, необходимо явно вернуть значение.</p>
<pre class="brush: js">var func = x => x * x; // краткий синтаксис,
// неявно возвращает результат
var func = (x, y) => { return x + y; }; // блочный синтаксис,
// явно возвращает результат</pre>
<h2 id="Возвращаемые_объектные_строки_литералы">Возвращаемые объектные строки (литералы)</h2>
<p>Помните о том, что возвращаемые <a href="/ru/docs/Web/JavaScript/Guide/Grammar_and_types#Литерал_объекта/">объектные строки</a> используют сокращённый синтаксис: <code>params => {object:literal}</code> будет работать не так, как ожидается.</p>
<pre class="brush: js">var func = () => { foo: 1 };
// Вызов func() возвращает undefined!
var func = () => { foo: function() {} };
// SyntaxError: function statement requires a name</pre>
<p>Это происходит потому что код в скобках ({}) распознаётся как цепочка выражений (т.е. <code>foo</code> трактуется как наименование, а не как ключ в объектной строке).</p>
<p>Не забывайте оборачивать скобками объектные строки.</p>
<pre class="brush: js">var func = () => ({ foo: 1 });</pre>
<h2 id="Разрывы_строк">Разрывы строк</h2>
<p>Стрелочная функция не может содержать разрывы строк между параметрами и стрелкой.</p>
<pre class="brush: js line-numbers language-js">var func = ()
=> 1;
// SyntaxError: expected expression, got '=>'
</pre>
<h2 id="Разбор_порядка_следования">Разбор порядка следования</h2>
<p>Поскольку стрелка в стрелочной функции не является оператором, то стрелочные функции имеют специальные правила разбора (парсинга), которые взаимодействуют с <a href="/ru/docs/Web/JavaScript/Reference/Operators/Operator_Precedence/">приоритетами операторов</a> иначе, чем в обычных функциях.</p>
<pre class="brush: js">let callback;
callback = callback || function() {}; // ok
callback = callback || () => {};
// SyntaxError: invalid arrow-function arguments
callback = callback || (() => {}); // ok
</pre>
<h2 id="Больше_примеров">Больше примеров</h2>
<pre class="brush: js">// Пустая стрелочная функция возвращает undefined
let empty = () => {};
(() => 'foobar')();
// Вернёт "foobar"
// (Это Immediately Invoked Function Expression
// смотри '<a href="https://developer.mozilla.org/ru/docs/%D0%A1%D0%BB%D0%BE%D0%B2%D0%B0%D1%80%D1%8C/IIFE">IIFE</a>' в справочнике)
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);
</pre>
<h2 id="Спецификации">Спецификации</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col">Спецификация</th>
<th scope="col">Статус</th>
<th scope="col">Комментарий</th>
</tr>
<tr>
<td>{{SpecName('ES6', '#sec-arrow-function-definitions', 'Arrow Function Definitions')}}</td>
<td>{{Spec2('ES6')}}</td>
<td>Изначальное определение.</td>
</tr>
</tbody>
</table>
<h2 id="Совместимость_с_браузерами">Совместимость с браузерами</h2>
<p>{{Compat("javascript.functions.arrow_functions")}}</p>
<h3 id="Замечания_для_Firefox">Замечания для Firefox</h3>
<ul>
<li>Первоначальная реализация стрелочных функций в Firefox автоматически переводила их в строгий режим. Это поведение было изменено в <a href="/en-US/docs/Mozilla/Firefox/Releases/24" title="/en-US/docs/Mozilla/Firefox/Releases/24">Firefox 24</a>. Использование <code>"use strict";</code> стало обязательным.</li>
<li>Стрелочные функции семантически отличаются от нестандартных <a href="/ru/docs/Web/JavaScript/Reference/Operators/Expression_closures">Expression Closures</a>, добавленных в <a href="/en-US/Firefox/Releases/3">Firefox 3</a> (подробности в <a href="/en-US/docs/Web/JavaScript/New_in_JavaScript/1.8">Javascript 1.8</a>); в Expression Closures значение <code>this</code> не привязано лексически.</li>
<li>До <a href="https://developer.mozilla.org/en-US/Firefox/Releases/39">Firefox 39</a>, перенос строки (<code>\n</code>) был ошибочно разрешён после аргументов стрелочной функции. Это было исправлено для соблюдения спецификации ES2015, и код вроде: <code>() \n => {}</code> теперь вызывает {{jsxref("SyntaxError")}} в этой и более поздних версиях.</li>
</ul>
<h2 id="See_also">See also</h2>
<ul>
<li><a href="https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/">"ES6 In Depth: Arrow functions" on hacks.mozilla.org</a></li>
</ul>
|