Functional elements
Анонимные функции
Анонимная функция – это функция, которая определяется без идентификатора. В JavaScript эта концепция уже настроена. Если вы использовали JavaScript не только для простейших задач, значит вы, без сомнений, уже знаете о нем. Когда вы используете jQuery, вот что вы печатаете сначала:
Функция, переданная в $(document).ready и есть анонимная функция. Этот концепт очень выгодный в некоторых случаях, когда мы хотим действовать после принципа DRY (Don't repeat yourself; if you're repeating yourself, you're doing it wrong).
Функции высшего порядка
Функции высшего порядка – это функции, которые принимают функции в качестве аргументов или возвращают функции. Мы можем возвратить и провести функции, как аргументы в C#, Java 8, Python, Perl, Ruby… Самый известный язык программирования – JavaScript имеет эти встроенные функции уже очень давно. Вот стандартный пример:
В коде выше есть функция animate. Она принимает в качестве свойств аргументов, которые должны быть анимированными, продолжительность и колбек, на которые мы должны ссылаться, когда анимация будет завершена. Мы также имеем этот пример в jQuery. Есть множество методов jQuery, которые принимают функции как аргументы, например $.get:
Есть еще один вид функций высшего порядка – вид, который возвращает функции. Есть много случаев в JavaScript, когда возврат функции – большой шаг вперед. Например, когда мы хотим использовать кэширование:
У нас есть переменный кэш в локальных пределах функции-родителя. В каждом вызове сначала будет проверено, была ли функция уже вызвана этими аргументами, если да, то результат будет возвращен немедленно, иначе его кэшируют и возвратят. Представьте такой случай:
У нас есть функция bar, которая принимает единый аргумент – baz и возвращает сумму baz и global foo. Когда мы используем memo, мы готовим bar к кэшированию и сохраняем ссылку на кэшированную копию в переменной cashed. Когда мы вызываем переменную cashed впервые, она исчисляется аргументом 1, ее тело вызывается, и поэтому результатом будет 2. После этого мы повышаем foo и вызываем cashed снова. Теперь у нас одинаковый результат (как и должно быть в чисто функциональных языках), но это неправильный результат.
Это случается потому, что у нас есть некоторое подобие состояния. Состояние – это нечто, что в последнее время относят к разделу монад (неодинакового вида состояния).
Замыкания
Давайте снова посмотрим на memo. У нас есть переменная cashed, она определена в лексической области функции, которая возвращает кэшированную функцию. Эта переменная также доступна с возвращенной функции, потому что создано замыкание. Это еще один элемент из функционального программирования. И он весьма распространен. Еще один способ для реализации приватности в JavaScript – это использование замыканий:
В примере выше был объект, который называется таймлайн. Это результат немедленно вызываемых функций (IIFE), которые возвращают объект со свойствами getArticles и setArticles, которые представляют текущий публичный интерфейс таймлайна. Внутри лексической области IIFE есть определение массива articles и функция сортировки, которую нельзя вызвать прямо используя объект таймлайна.
Рекурсия
Еще один элемент, одинаковый почти во всех языках программирования – рекурсия. Это функция, которая вызывает себя из себя же самой:
Выше – базовый пример, который показывает имплементацию факториала с использованием рекурсии.
Управление состояниями (Монады)
Обычно чисто функциональные языки программирования, как Haskell, управляют состояниями с помощью монад. Здесь приведена реализация монад в JavaScript. Возьмем пример Douglas Crockford:
Пример, который показывает, как мы можем создать I/O монаду:
Каррирование
Каррирование (Schönfinkelization или Currying) – это функциональное преобразование, которое позволяет заполнять аргументы функции шаг за шагом. Когда функция принимает последний аргумент, она возвращает результат. Эта функция была введена Moses Schönfinkel и позднее еще раз открыта Haskell Curry (потому и каррирование). Вот пример Stoyan Stefanov реализации ее в JavaScript:
Вот базовый пример использования функции для решения квадратного уравнения:
Если мы хотим заполнить аргументы функции один за другим, мы используем:
Если вы хотите использовать встроенные в язык свойства вместо функции каррирования, вы можете также использовать Function.prototype.bind. С тех пор, как он установлен в прототип функции конструктора всех функций, вы можете использовать его как метод во всех функциях. Метод bind создает новую функцию со специфическими контекстом и параметрами. Например, у нас может быть такая функция:
Теперь мы применяем метод bind:
Last updated