#ES6: стрелочные функции
На первый взгляд может показаться, что стрелочные функции являются исключительно "синтаксическим сахаром" и не несут в себе никакой новой функциональности. Действительно, их использование выглядит очень удобным и значительно соркащает объемы необходимого кода, особенно если вы сторонник функционального JavaScript:
// раньше
var sum = function() {
return [].reduce.call(arguments, function(m, n) {
return m + n;
}, 0);
}
// сейчас
var sum = (...args) => args.reduce((m, n) => m + n, 0);
Чтобы разобраться с новой синтаксической конструкцией, рассмотрим простую функцию add
, которая возвращает сумму двух переданных ей аргументов:
// раньше
var add = function(a, b) {
return a + b;
};
// сейчас
var add = (a, b) => a + b;
Создание стрелочной функции состоит из имени add
, передаваемых ей параметров (a, b)
и тела функции a + b
.
Все стрелочные функции создаются с помощью function expression, то есть они всегда будут эквиваленты следующему ES5 коду:
// function expression: два способа в ES6
var f = function() { return 42; }
var f = () => 42;
// function declaration: один способ в ES6
function f() {
return 42;
}
Поэтому следует помнить, что перед использованием стрелочной функции её всегда необходимо создать заранее.
Обычно параметры помещаются в круглые скобки (a, b)
. Если необходимо передать функции всего один параметр, то круглые скобки можно не использовать var f = x => x * 2
, но лучше подобную возможность не использовать и всегда окружать параметр скобками var f = (x) => x * 2
, чтобы избежать недопонимания. В случае, если в параметрах нет необходимости, объявление функции будет выглядеть следующим образом:
var f = () => 42;
f(); // 42
В случае, когда необходимо выполнить всего одну инструкцию (как во всех примерах, рассмотренных выше) достаточно просто указать эту инструкцию, как тело функции:
var add = (a, b) => a + b; // возвращает a + b
В ситуациях, когда одной инструкции оказывается недостаточно, тело функции необходимо заключить в фигурные скобки { ... }
и пользовать ключевым словом return
:
var g = (a, b) => {
let m = Math.pow(2, parseInt(a));
return b + m;
}
Все возможности обычных функций могут быть использованы и со стрелочными, включая параметры по умолчанию, остаточные параметры, реструктурирующее присваивание и так далее.
Чаще всего анонимные стрелочные функции используются при итерациях по элементам массивов с методами map
, forEach
, reduce
, filter
и другими:
const double = (arr) => arr.map( item => item * 2 );
double([1,2,3,4]); // [2, 4, 6, 8]
const filter = (arr) => arr.filter( item => !!item );
filter([false, undefined, 0, 1, 'str']); // [1, "str"]
const sum = (...args) => args.reduce((m, n) => m + n, 0);
sum(10, 15, 20); // 45
Главная причина появления стрелочных функций в ES6 — недопонимание, которое возникает у большинства разработчиков при работе с ключевым словом this
. Чтобы понять, что же такого чудесного принесли с собой стрелочные функции рассмотрим простой пример:
// ES5
var obj = {
btn: document.links[0],
log: function (message) {
console.log(message);
return this;
},
init: function() {
var self = this;
self.btn.addEventListener('click', function() {
self.log('Button Clicked!');
}, false);
}
};
Чтобы выполнить какой-либо метод из объекта до появления стрелочных функций необходимо было воспользоваться одним из методов замены ключевого слова this
: как в этом примере записать его в переменную self
, или воспользоваться методом функций bind
. Данные способы, несмоненно, работали, но выглядели достаточно скверно и могли смутить других разработчиков, которые попытались бы разобраться в коде. Стрелочные функции полностью решают данную проблему. Теперь код, приведённый выше, будет выглядеть следующим образом:
// ES6
var obj = {
btn: document.links[0],
log: function(message) {
console.log(message);
return this;
},
init: function() {
this.btn.addEventListener('click', () => this.log('Button Clicked!'), false);
}
};
Наиболее подробное описание принципов работы стрелочных функций с ключевым словом this
можно найти в этой статье.