Стрелочные функции (или «толстые стрелочные функции»), без сомнения, одна из самых популярных фич ES6. Это новый способ краткой записи функций.
Так, выглядит синтаксис функции с ES5:
function timesTwo(params) {
return params * 2
}
timesTwo(4); // 8
Тоже самое, но с использованием стрелочной функции:
var timesTwo = params => params * 2
timesTwo(4); // 8
Значительно короче! Мы можем опустить фигурные скобки и оператор return, благодаря неявному возврату (но, при условии отсутствия блоков — об этом позже).
Важно понять, чем отличается поведение стрелочных функций от обычных ES5-функций.
Вариативность
Что сразу бросается в глаза, так, это вариативность синтаксиса стрелочных функций. Давайте пробежимся по самым распространённым случаям:
1. Без параметров
Если вам не нужно указывать параметры — просто поставьте пустые скобки перед =>
.
() => 42
Вообще-то, даже скобки писать необязательно!
_ => 42
2. Единственный параметр
С такими функциями — скобки необязательны:
x => 42 || (x) => 42
3. Множество параметров
Для таких функций требуются скобки:
(x, y) => 42
4. Statements (как противоположность expressions)
В самой простой форме, результатом function expression будет — значение, а function statement — действие.
Используя стрелочные функции, важно помнить, что statements требует наличия фигурных скобок. А где фигурные скобки, там и оператор return.
Пример стрелочной функции с if statement:
var feedTheCat = (cat) => {
if (cat === 'hungry') {
return 'Feed the cat';
} else {
return 'Do not feed the cat';
}
}
5. «Block body»
Если ваша функция в блоке, необходимо использовать оператор return
:
var addValues = (x, y) => {
return x + y
}
6. Литерал объекта
Если вы возвращаете литерал объекта, то его нужно выделить скобками. Интерпретатор определит, что находится внутри скобок и вернёт литерал объекта.
x =>({ y: x })
Синтаксическая анонимность
Важно помнить, что стрелочные функции — анонимны, т.е. не названы.
Анонимность является причиной некоторых проблем:
1. Усложнение отладки
Получив ошибку, вы не сможете отследить имя функции или номер строки, где появилась ошибка.
2. Невозможность самореференции
Если вашей функции нужно сослаться самой на себя (например: рекурсия, обработчик событий, который необходимо отвязать), то это не сработает.
Главное преимущество: нет привязки к ‘this’
В классическом выражении функции, ключевое слово this
привязывается к различным значениям, в зависимости от контекста, в котором оно вызвано. В стрелочных функциях, ключ this
– лексически привязан. Другими словами, this
используется из той части кода, в которой содержится стрелочная функция.
Например, посмотрите на функцию setTimeout
:
// ES5
var obj = {
id: 42,
counter: function counter() {
setTimeout(function() {
console.log(this.id);
}.bind(this), 1000);
}
};
На примере ES5, требуется использовать .bind(this)
, чтобы добраться до нужной функции. Иначе, по умолчанию, this
не будет определён.
// ES6
var obj = {
id: 42,
counter: function counter() {
setTimeout(() => {
console.log(this.id);
}, 1000);
}
};
Стрелочные функции ES6, не могут быть привязаны к ключевому слову this
. JS будет искать значение this
выше, в той области, где оно было определено.
Когда НЕ следует использовать стрелочные функции
После знакомства со стрелочными функциями, надеюсь вы поняли, что они не заменяют обычные функции.
Вот несколько случаев, когда не стоит их использовать:
1. Объектные методы
Когда вы вызываете cat.jumps,
значение lives не уменьшается. Потому что this
не привязано ни к чему, и наследует значение this
из пространства родителя.
var cat = {
lives: 9,
jumps: () => {
this.lives--;
}
}
2. Callback функции с динамическим контекстом
Если вам нужно чтобы контекст был динамический, стрелочные функции — не лучший выбор. Взгляните на этот обработчик событий:
var button = document.getElementById('press');
button.addEventListener('click', () => {
this.classList.toggle('on');
});
Если нажать эту кнопку — мы получим TypeError. Потому что this
не привязан к этой кнопке, а привязан к своему родителю.
3. Когда они делают ваш код менее читабельным
Стоит принять во внимание вариативность синтаксиса, о чём мы говорили ранее. С обычными функциями, люди понимают, чего ожидать. А вот со стрелочными функциями могут возникнуть определенные трудности с расшифровкой.
Когда следует их использовать
Стрелочные функции прекрасно показывают себя там, где нужно привязать this
к контексту, а не к самой функции.
Несмотря на анонимность, мне нравится использовать их с такими методами, как map
и reduce
, потому что это делает мой код легко читаемым. Для меня, достоинства перевешивают недостатки.
Перевод статьи Cynthia Lee : When (and why) you should use ES6 arrow functions — and when you shouldn’t