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