Функционалният израз със стрелка има по-кратък синтаксис, отколкото стандартното дефиниране на функция и няма свой собствен this
, arguments
, super
, или new.target
. Тези функции не са подходящи за изполване като метод функции(methods) и не могат да бъдат използвани като конструктори.
The source for this interactive example is stored in a GitHub repository. If you'd like to contribute to the interactive examples project, please clone https://github.com/mdn/interactive-examples and send us a pull request.
Синтаксис
Основен синтаксис
(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
. Друг пример затова е : 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
Parsing order
Въпреки че, стрелката във функцията със стрелка не е оператор, функциите със стрелка имат специални правила, които взаимодействат по различен начин с оператора за предимство сравнено с нормалните функции.
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);
Спецификации
Спецификации | Статус | Коментар |
---|---|---|
ECMAScript 2015 (6th Edition, ECMA-262) The definition of 'Arrow Function Definitions' in that specification. |
Standard | Initial definition. |
ECMAScript (ECMA-262) The definition of 'Arrow Function Definitions' in that specification. |
Living Standard |
Съвместимост с браузера
BCD tables only load in the browser