Functional elements

Анонимные функции

Анонимная функция – это функция, которая определяется без идентификатора. В JavaScript эта концепция уже настроена. Если вы использовали JavaScript не только для простейших задач, значит вы, без сомнений, уже знаете о нем. Когда вы используете jQuery, вот что вы печатаете сначала:

$(document).ready(function () {
    //do some stuff
});

Функция, переданная в $(document).ready и есть анонимная функция. Этот концепт очень выгодный в некоторых случаях, когда мы хотим действовать после принципа DRY (Don't repeat yourself; if you're repeating yourself, you're doing it wrong).

Функции высшего порядка

Функции высшего порядка – это функции, которые принимают функции в качестве аргументов или возвращают функции. Мы можем возвратить и провести функции, как аргументы в C#, Java 8, Python, Perl, Ruby… Самый известный язык программирования – JavaScript имеет эти встроенные функции уже очень давно. Вот стандартный пример:

function animate(property, duration, endCallback) {
    //Animation here...
    if (typeof endCallback === 'function') {
        endCallback.apply(null);    }
}
animate('background-color', 5000, function () {
    console.log('Animation finished');
});

В коде выше есть функция 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