Источник: Nuances of Programming
В JavaScript, функции являются “функциями первого класса”, соответственно они могут:
- храниться в переменной, объекте или массиве.
- передаваться как аргументы в другую функцию.
- и даже могут быть возвращены из функции.
Хранение функций
В JavaScript функции могут храниться тремя способами:
- храниться в переменной: let fn = function doSomething() {}
- храниться в объекте : let obj = { doSomething : function(){} }
- храниться в массиве : arr.push(function doSomething() {})
В первом и третьем примере я использовал так называемое “функциональное выражение” (Function Expression).
“Функциональные выражения” определяют функцию как часть большего выражения. Это когда строка кода начинается не с ключевого слова function.
В случае, если мы напишем строку с ключевого словаfunction,то это будет “определение функции” (Function Declaration) и к функции будет применятся “поднятие функций”(hoisting).
Функции как аргументы
В следующем примере функцияdoSomethingотправляется в виде аргумента в функциюdoAction().
doAction(function doSomething(){});
doSomething — это “функция обратного вызова”.
Функции обратного вызова передаются в качестве “коллбека”(от “callback“) в качестве аргумента в другие функции. Коллбеки часто встречаемая практика в мире Javascript.
Функции высшего порядка
Функции высшего порядка — это функции, которые принимают в качестве аргументов другие функции, либо возвращают функцию. А также могут делать оба действия одновременно.
Давайте взглянем на встроенные методы, которые как раз являются функциями высшего порядка : filter(), map() и reduce().
filter()вызывается на массиве и принимает функцию в качестве первого аргумента, которая определяет условие фильтрации, которое может быть бесконечно гибким.
map() превращает список значений в иные(модифицированные вами в переданной функции) значения, не изменяя оригинальный массив.
Как вы можете заметить, работать с коллекциями в функциональном стиле гораздо проще.
А теперь давайте сами создадим функцию высшего порядка doWithLoading(). Она будет принимать функцию в качестве параметра и исполнять её. Перед началом исполнения мы выведем сообщение о начале исполнения, а по завершению о том, что функцию выполнена.
Функции возвращающие функцию
Ниже пример функции, которая возвращает другую функцию:
function createGenerator(){
return function generateNewID(){}
}
Замыкание
Вот пример функции, createGenerator() которая создает другую функциюgenerateNewID() с приватным состоянием. Каждый раз когда мы вызываем createGenerato,мы запоминаем индекс последнего вызова и возвращаем строку с номером текущего вызова.
Используя замыкания, теперь мы умеем создавать функции с приватным состоянием.
Декораторы
Декораторы — это функции высшего порядка, которые принимают функцию в виде аргумента и возвращают другую функцию. Возвращаемая функция — это модифицированная функция с аргумента. Но, фишка в том, что мы не изменяем код оригинальной функции.
Самый простой декоратор, который может быть найден в популярной библиотеке, например underscore.js или lodash.js — это функцияonce(). Она кэширует результат вызова функции и при повторном вызов возвращает данные с кэша, не вычисляя их повторно. В мире ООП обычно называется Синглтон. Ниже вы можете увидеть имплементацию данного декоратора.
Функции-декораторы мощная штука для создания произвольного поведения уже существующих функций без изменения кода оных.
Свойства функций
Функция — это объект, поэтому она может иметь свои собственные свойства, например name и length или методыtoString(), bind(), apply() и call().
Частичное применение — это предоставление для функции меньшего количества аргументов, чем она ожидает.
Метод bind() является таким примером. Обратите внимание на первый аргумент, который ожидаетthis.
function log(level, message){}
var logInfo = log.bind(null, "Info");
logInfo("message");
Заметили, как мы создали функциюlogInfo() ? Теперь она принимает только один аргумент(message), минуя this.
Лямбда функции
Лямбда функции — это функции, которые используются как значение.
Eric Elliott in Programming JavaScript Applications
Поскольку в JavaScript, функции являются объектами первого класса, их можно использовать как лямбда функции. Лямбда функции могут быть именованные и безымянные. Мне кажется, что вам привычней использовать именованные функции.
Ниже пример renderFirstItem функции использованной как лямбда:
Заключение
Функции первого класса и Замыкания, концепции которые предоставляют возможность писать в функциональном стиле. В результате мы можем использовать функции высшего порядка для удобной работы с массивами, а также использовать их в виде декораторов.
Также функции первого класса позволяют нам абстрагировать некий функционал и работать с функцией как с примитивом.
В JavaScript функции тоже объекты. А объекты могут иметь методы, например call, apply, bind,которые могут использовать частичное применение функций чтобы установить контекст this.
Лучшая вещь в JavaScript — это имплементация функций. Это дает возможность делать всё правильно.
Douglas Crockford in JavaScript The Good Parts
Читайте нас в телеграмме и vk
Перевод статьи Cristi Salcescu: Discover the power of first class functions