Функции высшего порядка (Higher-Order Function) в JavaScript

В JavaScript любая функция - это объект, и следовательно, ею можно манипулировать как объектом, в частности:

  1. передавать как аргумент и возвращать в качестве результата при вызове других функций (функций высшего порядка);
  2. создавать анонимно и присваивать в качестве значений переменных или свойств объектов.

Таким образом, в JavaScript функции могут:

  • храниться в переменной, объекте или массиве;
  • передаваться как аргументы в другую функцию;
  • возвращаться из других функций (функций высшего порядка).

Функции, обладающие указанными свойствами, в JavaScript называют «функциями первого класса».

Функции первого класса – это специальный тип объектов (Function-объект), позволяющий формализовать средствами языка определённую логику поведения и обработки  данных, и который можно задавать как значение переменной, передавать и возвращать по ссылке как любые другие переменные.

Функция высшего порядка (Higher-Order Function) - это функция, которая оперирует другими функциями и может:

  • принимать другую функцию в качестве аргумента или
  • возвращать другую функцию в качестве результата.
Хранение функций в JS

В JavaScript функции могут храниться тремя способами:

[свернуть]

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

Что такое функциональное программирование

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

Читайте также Шпаргалка по функциональному программированию

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

В JavaScript функции являются особым типом объектов - Function объектами, которым в ходе исполнения кода можно присваивать случайные свойства. Например:

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

[свернуть]

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

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

Некоторые функции высшего порядка встроены в язык, например, Array.prototype.map, Array.prototype.filter и Array.prototype.reduce.

Функции как аргументы

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

В следующем примере функции nameLn  и nameUpCase являются аргументами функции mapArr:

Обратите внимание на синтаксис: при передаче функции в качестве параметра скобки () не указываются ( т.е. в параметре функция не вызывается, например, function mapArr(arr, fn) или mapArr(arr, nameLn) ).

Встроенные методы JS, которые являются функциями высшего порядка : filter(), map() и reduce()

Метод filter() вызывается на массиве и принимает в качестве первого аргумента функцию, которая определяет условие фильтрации.

Метод map() превращает список значений в иные (модифицированные в переданной функции) значения, не изменяя оригинальный массив.

Метод reduce() аккумулирует все значения коллекции в единое значение. Второй аргумент может быть любым доступным типом в Javascript.

[свернуть]

Функции, возвращающие функцию

Ниже пример функции, которая возвращает другую функцию:

Ещё пример

  1. Строка 1. Мы объявляем переменную с именем minus в глобальном контексте выполнения и назначаем ей определение функции c параметром firstNum. Строки 2-7 описывают указанное определение функции. В текущий момент тело этой функции не выполняется. Просто сохраняем определение функции в переменной minus.
  2. Строка 9.  Скобки () указывают, что нужно выполнить или вызвать функцию с именем minus  которая была создана на шаге 1, и передать ей параметр 10:
    1. вызов функции minus  (теперь мы находимся в строке 1);
    2. создается новый локальный контекст выполнения, мы можем создавать локальные переменные в новом контексте выполнения;
    3. движок добавляет новый контекст в стек вызовов. В контексте функции minus  объявляется переменная firstNum;
    4. переменной firstNum присваивается значение 10. Переходим к телу функции.
  3. Строка 2. Значение переменной firstNum проверяется на пустоту. Если передано пустое значение, переменной firstNum присваивается значение 0.
  4. Строка 3. Функция minus возвращает анонимную функцию с аргументом lastNum. Переходим в строку 9.
  5. Строка 9.  Скобки у функции minus(10)() указывают, что нужно выполнить или вызвать возвращенную ею анонимную функцию, и передать ей параметр (6):
    1. вызов анонимной функции (теперь мы находимся в строке 3);
    2. создается новый локальный контекст выполнения (внутри контекста функции minus), мы можем создавать локальные переменные в новом контексте анонимной функции;
    3. движок добавляет новый контекст в стек вызовов. В контексте анонимной функции объявляется переменная lastNum;
    4. переменной lastNum присваивается значение 6. Переходим к телу функции.
  6. Строка 4. Значение переменной lastNum проверяется на пустоту. Если передано пустое значение, переменной lastNum присваивается значение 0.
  7. Строка 5. Выполняется вычитание содержимого переменной firstNum (найденного движком в контексте функции minus) и содержимого переменной lastNum. Результат операции вычитания (4) возвращается из анонимной функции. Переходим на строку 9.
  8. Локальный контекст выполнения уничтожается, он удаляется из стека вызовов, переменные firstNum и lastNum больше не существуют.

[свернуть]

Замыкание функции

Подробнее см. Замыкание в JavaScript

Замыкание функции — это комбинация функции и лексического окружения, в котором эта функция была определена; замыкание обеспечивает доступ внутренней функции к области видимости (Scope) внешней функции (при этом переменные внутренней функции для внешнего окружения недоступны).

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

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

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

Замыкание позволяет:

  • ограничить доступ к данным (ограничить их область видимости);
  • создать своеобразное автономное хранилище данных.

Ниже пример функции  createGenerator(), которая создает другую функцию genNewID() с приватным состоянием. Каждый раз когда мы вызываем createGenerator(), функцией genNewID() запоминается индекс последнего вызова index и возвращается строка с номером текущего вызова.

Декораторы

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

В простейшем виде декоратор — это способ оборачивания одного фрагмента кода в другой.

Пример

Подробнее о декораторах

Создаётся новая функция, которая назначается константе wrap. Эта функция может быть вызвана точно так же, как и функция doGreeting, и делать она будет то же самое. Разница заключается в том, что до и после вызова оборачиваемой функции будет выполнено логирование, выводящее сообщения // Starting и // Finished.

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

[свернуть]

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

Добавить комментарий

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.