--- title: Стрілкові функції slug: Web/JavaScript/Reference/Functions/Arrow_functions translation_of: Web/JavaScript/Reference/Functions/Arrow_functions original_slug: Web/JavaScript/Reference/Functions/Стрілкові_функції ---
Вирази стрілкових функцій мають більш короткий синтаксис, аніж функціональні вирази і не мають свого власного this
, arguments, super, і new.target. Вони не можуть бути використані як конструктор і завжди анонімні.
(параметр1,параметр2, …, параметрN) => { оператори } (параметр1, параметр2, …, параметрN) => вираз // еквівалентно до запису: (параметр1,параметр2, …, параметрN) => { return вираз; } // Якщо у функції тільки один параметр, то дужки не обов'язкові: (параметр) => { оператори } параметр => { оператори } параметр => вираз // Список параметрів для функції без параметрів повинен бути записаний у парі фігурних дужок. () => { оператори }
// Візьміть тіло функції у дужки, якщо вона повертає об'єкт params => ({foo: bar}) // Залишкові параметри та параметри за замовчуванням підтримуються як і в звичайних функціях (параметр1, параметр2, ...залишкові параметри) => { оператори } (параметр1 = значення_за_замовчуванням, параметр2, …, параметрN = значення_за_замовчуваннямN) => { оператори } // Деструктиризація в списку параметрів також підтримується: let 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 materials = [ 'Hydrogen', 'Helium', 'Lithium', 'Beryllium' ]; materials.map(function(material) { return material.length; }); // [8, 6, 7, 9] materials.map((material) => { return material.length; }); // [8, 6, 7, 9] materials.map(material => material.length); // [8, 6, 7, 9]
this
До появи стрілкових функцій кожна нова функція мала власне значення this
:
Це все було далеким від ідеалів об'єктно-орієнтованого програмування.
function Person() { // The Person() constructor defines `this` as an instance of itself. this.age = 0; setInterval(function growUp() { // In non-strict mode, the growUp() function defines `this` // as the global object, which is different from the `this` // defined by the Person() constructor. this.age++; }, 1000); } var p = new Person();
В ECMAScript 3/5 ця проблема вирішувалась шляхом присвоєння значення this
змінній, оголошеній всередині функції.
function Person() { var that = this; that.age = 0; setInterval(function growUp() { // The callback refers to the `that` variable of which // the value is the expected object. that.age++; }, 1000); }
Або можна створити bound function (прив'язану функцію), в яку передати значення this
для функції (функція growUp()
в прикладі вище).
Стрілкова функція не має власного контексту this
, а використовує this
з контексту вище. Тому в коді, наведеному нижче, this
для функції setInterval
має таке ж значення, як і this
зовнішньої функції:
function Person(){ this.age = 0; setInterval(() => { this.age++; // |this| properly refers to the person object }, 1000); } var p = new Person();
Given that this
comes from the surrounding lexical context, strict mode rules with regard to this
are ignored.
var f = () => { 'use strict'; return this; }; f() === window; // or the global object
All other strict mode rules apply normally.
Since arrow functions do not have their own this
, the methods call()
or apply()
can only pass in parameters. thisArg
is ignored.
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)); // This would log to 2 console.log(adder.addThruCall(1)); // This would log to 2 still
arguments
Arrow functions do not have their own arguments
object. Thus, in this example, arguments
is simply a reference to the arguments of the enclosing scope:
var arguments = [1, 2, 3]; var arr = () => arguments[0]; arr(); // 1 function foo(n) { var f = () => arguments[0] + n; // foo's implicit arguments binding. arguments[0] is n return f(10); } foo(1); // 2
In most cases, using rest parameters is a good alternative to using an arguments
object.
function foo(n) { var f = (...args) => args[0] + n; return f(10); } foo(1); // 11
As stated previously, arrow function expressions are best suited for non-method functions. Let's see what happens when we try to use them as methods:
'use strict'; var obj = { i: 10, b: () => console.log(this.i, this), c: function() { console.log(this.i, this); } } obj.b(); // prints undefined, Window {...} (or the global object) obj.c(); // prints 10, Object {...}
Arrow functions do not have their own this
. Another example involving {{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; // represents global object 'Window', therefore 'this.a' returns 'undefined' } });
new
operatorArrow functions cannot be used as constructors and will throw an error when used with new
.
var Foo = () => {}; var foo = new Foo(); // TypeError: Foo is not a constructor
prototype
propertyArrow functions do not have a prototype
property.
var Foo = () => {}; console.log(Foo.prototype); // undefined
yield
keywordThe yield
keyword may not be used in an arrow function's body (except when permitted within functions further nested within it). As a consequence, arrow functions cannot be used as generators.
Arrow functions can have either a "concise body" or the usual "block body".
In a concise body, only an expression is specified, which becomes the explicit return value. In a block body, you must use an explicit return
statement.
var func = x => x * x; // concise body syntax, implied "return" var func = (x, y) => { return x + y; }; // with block body, explicit "return" needed
Keep in mind that returning object literals using the concise body syntax params => {object:literal}
will not work as expected.
var func = () => { foo: 1 }; // Calling func() returns undefined! var func = () => { foo: function() {} }; // SyntaxError: function statement requires a name
This is because the code inside braces ({}) is parsed as a sequence of statements (i.e. foo
is treated like a label, not a key in an object literal).
Remember to wrap the object literal in parentheses.
var func = () => ({foo: 1});
An arrow function cannot contain a line break between its parameters and its arrow.
var func = () => 1; // SyntaxError: expected expression, got '=>'
Although the arrow in an arrow function is not an operator, arrow functions have special parsing rules that interact differently with operator precedence compared to regular functions.
let callback; callback = callback || function() {}; // ok callback = callback || () => {}; // SyntaxError: invalid arrow-function arguments callback = callback || (() => {}); // ok
// An empty arrow function returns undefined let empty = () => {}; (() => 'foobar')(); // Returns "foobar" // (this is an Immediately Invoked Function Expression // see 'IIFE' in glossary) var simple = a => a > 15 ? 15 : a; simple(16); // 15 simple(10); // 10 let max = (a, b) => a > b ? a : b; // Easy array filtering, mapping, ... 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] // More concise promise chains promise.then(a => { // ... }).then(b => { // ... }); // Parameterless arrow functions that are visually easier to parse setTimeout( () => { console.log('I happen sooner'); setTimeout( () => { // deeper code console.log('I happen later'); }, 1); }, 1);
Специфікація | Статус | Коментар |
---|---|---|
{{SpecName('ES2015', '#sec-arrow-function-definitions', 'Arrow Function Definitions')}} | {{Spec2('ES2015')}} | Початкова виознака. |
{{SpecName('ESDraft', '#sec-arrow-function-definitions', 'Arrow Function Definitions')}} | {{Spec2('ESDraft')}} |
{{Compat("javascript.functions.arrow_functions")}}