Igor Kashirskiy
Igor Kashirskiy
Фронтенд-разработчик и переводчик
Читать 4 минуты

Когда (и почему) нужно использовать стрелочные функции ES6 — и когда этого делать не следует

Перевод статьи Cynthia Lee - When (and why) you should use ES6 arrow functions — and when you shouldn’t

Стрелочные функции (также называемые "толстые стрелочные функции") - несомненно самая популярная особенность ES6. Они представляют новый способ краткой записи функций.

Вот функция, записанная синтаксисом ES5:

function timesTwo(params) {
return params * 2
}timesTwo(4); // 8

А вот то же самое, выраженное с помощью стрелочной функции:

var timesTwo = params => params * 2timesTwo(4);  // 8

Намного короче! Мы можем опустить фигурные скобки и оператор return из-за неявного возврата (но только в том случае, если отсутствует блок кода - об этом еще поговорим ниже).

Важно понимать насколько иначе ведут себя стрелочные функции, в сравнении с обычными функциями ES5.

Разнообразие

Image for post

Разнообразие - это приправа жизни.

Первое, что вы заметите при быстром знакомстве - это разнообразие синтаксиса в стрелочных функциях. Познакомимся с наиболее часто встречающимися вариантами:

1. Без параметров

Если параметров нет - вы можете поставить пустые скобки перед =>.

() => 42

Вообще-то, скобки даже не нужны!

_ => 42

2. Единственный параметр

В этих функциях скобки опциональны:

x => 42  || (x) => 42

3. Множество параметров

Для этих функций необходимы скобки:

(x, y) => 42

4. Операторы в функции (как противоположность функциональному выражению)

В самой общей форме, результатом функционального выражения является значение, в то время как результатом применения операторов в функции является действие.

В случае стрелочных функций важно помнить, что использование операторов в функции требует фигурных скобок. А если присутствуют фигурные скобки - также обязательно присутствие оператора return.

Вот пример стрелочной функции, в которой применен оператор if:

var feedTheCat = (cat) => {
if (cat === 'голоден') {
return 'Накормить кота';
} else {
return 'Кота не кормить';
}
}

5. “Блочное тело функции”

Если тело вашей функции представляет собой блок кода, то вам следует явно указать оператор return:

var addValues = (x, y) => {
return x + y
}

6. Литералы объекта

Если вы планируете вернуть литерал объекта - он должен быть обернут в скобки. Это заставит интерпретатор вычислить содержимое скобок, в результате чего будет возвращен литерал объекта.

x =>({ y: x })

Синтаксически анонимные

Image for post

Важно отметить, что стрелочные функции анонимные, это означает, что у них нет имен.

Эта анонимность создает некоторые проблемы:

  1. Сложнее процесс отладки

Когда вы получаете ошибку, у вас нет возможности отследить имя функции или точную строку, где эта ошибка появилась.

2. Нельзя сослаться на саму функцию

Если вашей функции требуется сослаться на саму себя по любой причине (например рекурсия, или обработчик событий, который требуется отвязать) - это не сработает.

Главная выгода: нет привязки ‘this’

Image for post

Фото davide ragusa на Unsplash

В классическом функциональном выражении, ключевое слово 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 будет равен undefined.

// ES6
var obj = {
id: 42,
counter: function counter() {
setTimeout(() => {
console.log(this.id);
}, 1000);
}
};

Стрелочная функция ES6 не может быть привязана к ключевому слову this, поэтому она поднимется по лексическому контексту и использует значение this, заданное в области видимости, в которой была определена сама.

Когда не следует использовать Стрелочные Функции

После изучения стрелочных функций я надеюсь, что вы понимаете - они не замена обычным функциям.

Вот несколько случаев, в которых их использовать не стоит:

  1. Методы объекта

При вызове cat.jumps, количество жизней не уменьшится. Это произойдет потому что this не привязано ни к чему, и унаследует значение this своего родительского контекста.

var cat = {
lives: 9,
jumps: () => {
this.lives--;
}
}

2. Колбек-функции с динамическим контекстом

Если вам требуется динамический контекст, то стрелочные функции не совсем правильный выбор. Взгляните на этот обработчик события:

var button = document.getElementById('press');
button.addEventListener('click', () => {
this.classList.toggle('on');
});

Если мы кликнем по кнопке - мы получим TypeError. Произойдет это потому что this не привязан к кнопке, но, вместо этого, привязан к родительскому контексту.

3. Когда они делают код менее читаемым

Стоит принять во внимание разнообразие синтаксиса, рассмотренное нами ранее. В случае с обычными функциями люди знают чего ожидать. Со стрелочными функциями может быть непросто расшифровать с ходу, что же имелось в виду.

Когда их следует использовать

Стрелочные функции просто шикарны в каждом случае, когда требуется привязать this к контексту, а не к самой функции.

Несмотря на тот факт, что они анонимные, я также люблю использовать их с методами, такими как map и reduce, поскольку мне кажется, что это делает мой код более читаемым. Для меня этот плюс перевешивает возможные методы такого подхода.

65 просмотров
Добавить
Еще
Igor Kashirskiy
Фронтенд-разработчик и переводчик
Подписаться