--- title: Arrow functions slug: Web/JavaScript/Reference/Functions/Arrow_functions tags: - Средно напреднали - Функции - Функции със стрелка - референция translation_of: Web/JavaScript/Reference/Functions/Arrow_functions ---
Функционалният израз със стрелка има по-кратък синтаксис, отколкото стандартното дефиниране на функция и няма свой собствен this, arguments, super, или new.target. Тези функции не са подходящи за изполване като метод функции(methods) и не могат да бъдат използвани като конструктори.
(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
// равнозначно на: => { return expression; }
// Скобите не са задължителни, когато има само един входен параметър:
(singleParam) => { statements }
singleParam => { statements }
// Списъка с аргументи за функции без аргументи трябва да бъде написан, като се използват скоби.
() => { statements }
// Резултата може да бъде ограден в скоби за да бъде върнат под формата на обект(object literal 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]
// Когато има само един входен параметър можем да премахнем скобите:
elements.map(element => {
return element.length;
}); // [8, 6, 7, 9]
// Когато единственото нещо в функцията е връщане на резултат, можем да премахнем `return`
// и също така да премахнем скобите
elements.map(element => element.length); // [8, 6, 7, 9]
// In this case, because we only need the length property, we can use destructing parameter:
// Notice that the string `"length"` corrosponds to the property we want to get whereas the
// obviously non-special `lengthFooBArX` is just the name of a variable which can be changed
// to any valid variable name you want
elements.map(({ "length": lengthFooBArX }) => lengthFooBArX); // [8, 6, 7, 9]
// This destructing parameter assignment can be written as seen below. However, note that there
// is no specific `"length"` to select which property we want to get. Instead, the literal name
// itself of the variable `length` is used as the property we want to retrieve from the object.
elements.map(({ length }) => length); // [8, 6, 7, 9]
thisДопреди функциите със стрелка, всяка нова функция дефинираше своя собствена стойност this (въз основа на това как се нарича функцията, нов обект в случай на конструктор, недифинарна при извикване на функции в строг режим,основният обект ако функцията се извиква като "object method", etc.). Това се оказа по-малко от идеалното с обектно-ориентирания стил на програмиране.
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 (because it's where growUp() is executed.),
// which is different from the `this`
// defined by the Person() constructor.
this.age++;
}, 1000);
}
var p = new Person();
В ECMAScript 3/5, проблемът с this беше поправим като присвоим стойността на 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);
}
Като алтернатива, може да бъде създадена свързана функция така че this стойността може да бъде предадена на свързаната целева функция (функцията growUp() в примера по-горе).
Функцията със стрелка няма свой собствен this; Стойността this от използвания лексикален контекст и др. Функциите със стрелки следват нормалните правила на промелнива. Така че, докато търсим за this, който не присъства в текущият обхват на функцията, те взимат this от околният обхват. По този начин,в следния код, this в рамките на функцията, която се предава на setInterval функцията, има същата стойност като на тази в околната лексикална функция:
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| properly refers to the Person object
}, 1000);
}
var p = new Person();
Като се има в предвид , че this идва от околния лексикален контекст, строгите правила за режима по отношение на this се игнорират.
var f = () => { 'use strict'; return this; };
f() === window; // or the global object
Всички други правила за строг режим се прилагат нормално
Тъй като функциите със стрелка нямат свой собствен this, методите call() или apply() могат само да предават параметри. thisArg се игнорира.
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Функциите със стрелка нямат свой собствен обект от аргументи .Следователно в този пример аргументите са просто препратка към аргументите на заобикалящото ги поле:
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();
}
foo(3); // 6
В повечето случаи, използването на rest parameters(остатъчни параметри) е добра алтернатива от използването на обект с аргументи.
function foo(n) {
var f = (...args) => args[0] + n;
return f(10);
}
foo(1); // 11
Както бе посочено по-горе, изразите на функциите със стрелките са най-подходящи за функциите, различни от метода. Нека видим какво се случва, когато се опитаме да ги използваме като методи:
'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 {...}
Функциите със стрелка нямат свой собствен this. Друг пример затова е : {{jsxref("Object.defineProperty()")}}:
'use strict';
var 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'
}
});
newФункциите със стрелка не мога да бъдат използвани като конструктории ще генерират грешка , когато се изпозват с оператора new.
var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor
prototypeФункциите със стрелки нямат свойството prototype.
var Foo = () => {};
console.log(Foo.prototype); // undefined
yieldКлючовата дума yield не може да бъде използвана в тялото на функцията със стрелка ( освен когато е позволено в рамките на функциите, които са вложени в нея ). В резултат на това функциите със стрелки не могат да се използват като генератори.
Функциите със стрелка могат да имат или "сбито тяло" или обичайното "блоково тяло".
В сбитото тяло е посочен само израз, който се превръща в неявна връщана стойност. В блоково тяло трябва да използвате изрично return декларация за връщане.
var func = x => x * x;
// concise body syntax, implied "return"
var func = (x, y) => { return x + y; };
// with block body, explicit "return" needed
Имайте в предвид , че връщането на литерали на обекти, използвайки сбит синтаксис params => {object:literal} няма да работи според очакванията.
var func = () => { foo: 1 };
// Calling func() returns undefined!
var func = () => { foo: function() {} };
// SyntaxError: function statement requires a name
Това е защото кодът вътре в скобите ({}) се анализита като оследователност от изрази (или fooсе третира като етикет, а не като ключ в буквален обект).
Запомнете, че трябва да поставяте буквалният обект в скоби , както е показано в примера по-долу.
var func = () => ({foo: 1});
Функцията със стрелка не може да съдържа прекъсната линия между нейните параметри и стрелка.
var func = (a, b, c)
=> 1;
// SyntaxError: expected expression, got '=>'
Все пак това може да бъде променено, чрез използване на скоби или поставяне на разделителната линия в аргументите, както е показано в примера по-долу, за да се гарантира, че кодът остава красив и пухкав.
var func = ( a, b, c ) => ( 1 ); // no SyntaxError thrown
Въпреки че, стрелката във функцията със стрелка не е оператор, функциите със стрелка имат специални правила, които взаимодействат по различен начин с оператора за предимство сравнено с нормалните функции.
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')}} | Initial definition. |
| {{SpecName('ESDraft', '#sec-arrow-function-definitions', 'Arrow Function Definitions')}} | {{Spec2('ESDraft')}} |
{{Compat("javascript.functions.arrow_functions")}}