Для чего на самом деле нужны стрелочные функции в JavaScript

Привет, Хабр! Представляю вашему вниманию перевод статьи «The real reason why JavaScript has arrow functions» автора Martin Novák.


* фраза-мем из игры Skyrim

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

Это пример того же кода, написанного также и в традиционном стиле:

const arrowFunction = (arg1, arg2) => arg1 + arg2;

const traditionalFunction = function(arg1, arg2) {
  return arg1 + arg2;
};

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

const arrowFunction = (arg1, arg2) => {
  const result = arg1 + arg2;
  return result;
};

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

В Python их синтаксис выглядит следующим образом:

lambdaFunction = lambda a, b : a + b

Упрощай


Использование стрелочных функций мотивирует вас упрощать код в соответствии с KISS принципом (Keep-it-simple-stupid) и принципом единственной ответственности (каждая функция отвечает только за одно конкретное действие).

В целом, я пишу их без фигурных скобок {}. Если функцию тяжело читать или в ней нужно применить несколько выражений, советую разбить ее на несколько более мелких.
Данный код проще в написании, удобнее в повторном использовании и тестировании. Также, функции могут получать более описательные имена, чтобы точно показать работу, которую они выполняют.

Функции первого класса


В JavaScript присутствуют функции первого класса. Это такие функции, которые используются, как обычные переменные. Они могут выступать аргументами для других функций или возвращать их в качестве результата. Пример, с которым вы, скорее всего, знакомы:

document.querySelector('#myButton').addEventListner('click', function() {
  alert('click happened');
});

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

Пример возвращения функции другой — представлен ниже:

const myFirstClassFunction = function(a) {
  return function(b) {
    return a + b;
  };
};

myFirstClassFunction(1)(2); // => 3

Однако, со стрелочной функцией, все выглядит гораздо “чище”:

const myFirstClassArrow = a => b => a + b;

myFirstClassArrow(1)(2); // => 3

Здесь все просто: то, что написано до последней стрелки — аргументы, а после нее — вычисление. По факту, мы работаем с несколькими функциями, а также мы можем использовать несколько вызовов fn(call1)(call2);

Частичное применение


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

const add = a => b => a + b;

const increaseCounter = counter => add(1)(counter);
increaseCounter(5); // => 6

const pointFreeIncreaseCounter = add(1);
pointFreeIncreaseCounter(5); // => 6

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

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

Функциональное программирование


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

Функциональное программирование это альтернатива ООП, которое предпочитают многие разработчики (включая автора статьи). Вы можете привести аргументы в защиту любого стиля, но я считаю — функциональное программирование — крутая штука и вам должно становиться не по себе от одной только мысли, что вы когда-то думали по-другому.

Чистые функции полагаются только на входные данные и всегда возвращают какое-то значение. Они никогда не изменяют (мутируют) другие переменные и не зависят внешних данных, за пределами входных значений. Это приводит к ссылочной прозрачности, которая упрощает программирование.

И да, всегда есть возможность писать огромное количество кода, не изменяя ни одной переменной.

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

Стрелочные функции — заключение


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

Реальный функциональный пример


Чтобы понять, что же скрывается в кроличьей норе, давайте взглянем на пример использования open-source библиотеки @7urtle/lambda

import {trim, upperCaseOf, lengthOf, lastLetterOf, includes, compose} from '@7urtle/lambda';

const endsWithPunctuation = input =>
  includes(lastLetterOf(input))('.?,!');

const replacePunctuationWithExclamation = input =>
  substr(lengthOf(input) - 1)(0)(input) + '!';

const addExclamationMark = input =>
  endsWithPunctuation(input)
    ? replacePunctuationWithExclamation(input)
    : input + '!';

const shout = compose(addExclamationMark, upperCaseOf, trim);

shout(" Don't forget to feed the turtle.");
// => НЕ ЗАБУДЬ ПОКОРМИТЬ ЧЕРЕПАХУ!

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

JavaScript может быть сложным в его непоследовательности между использованием Си-подобного синтаксиса и особенностей функционального программирования. Чтобы помочь людям лучше разобраться и предоставить доступ к материалам для изучения, я разработал библиотеку @7urtle/lambda. Вы можете освоить функциональное программирование в своем ритме и сайт www.7urtle.com поможет вам изучить данную парадигму, предоставив вам все необходимые инструменты.

Комментарии 8

    +9
    Очень смешно, конечно, утверждать, что на самом деле стрелочные функции нужны для сокращения кода путём исключения слов function и return. У этого способа описания функций и функциональные особенности имеются.
      +12

      Капец, ни слова про this

        +1

        Это же альтернатива ООП! Какой this?!))

          –9

          Какое ооп в жс?)

            0

            Обычное. Прототипное программирование — это тоже ООП.

        0
        const traditionalFunction = function(arg1, arg2) {
          return arg1 + arg2;
        };

        Гнать за такое из профессии...

          +2
          Если разбивать код на множество мелких предельно простых функций, то возникает проблема систематизации и каталогизации этих функций. Проще говоря, если у вас 100 функций для проверки содержимого строки, то вспомнить и найти, как называется именно та, которая вам нужна, сложнее, чем написать её заново. Даже если у вас крутое IDE, читающее мысли.

          Проблема усугубляется, если не вы — разработчик этой мегабиблиотеки.

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

          В этом плане я не вижу большой выгоды между «функция, складывающая 2 числа» и просто выражением «a + b». Во втором случае понятно — что происходит и не возникает существенных накладных расходов.
            0

            Функцию, складывающую два числа, можно передавать как параметр в другую функцию, частично применять, типа делать из функции, складывающую два числа делать функцию, увеличивающую число на 1, 5 или 10. И все эти микрофункции комбинировать между собой для решения задачи. Другое дело, что частенько получается write only код, который даже в дебаггере сложно пройти.

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

          Самое читаемое