Higher-Order Functions
Функция высшего порядка (HOF) — функция, которая принимает другую функцию как аргумент и/или возвращает функцию как результат. Основа функционального программирования и большинства паттернов в JS.
Что это / Зачем
- HOF — фундамент функционального стиля
- Позволяет параметризовать поведение, а не только данные
map,filter,reduce,addEventListener— все HOF- Замыкания, каррирование, декораторы, мемоизация — всё построено на HOF
Четыре вида использования HOF
// 1. Принимает функцию
arr.forEach((x) => console.log(x));
// 2. Возвращает функцию
const multiplier = (n) => (x) => x * n;
// 3. И принимает, и возвращает (декораторы)
const withLog = (fn) => (...args) => {
console.log('call:', args);
return fn(...args);
};
// 4. Каррированная функция — цепочка HOF
const curried = (a) => (b) => (c) => a + b + c;
Примеры
Математическая HOF: inverse
const inverse = (fn) => (x) => 1 / fn(x);
const sqrtInv = inverse(Math.sqrt); // 1 / Math.sqrt(x)
Каррирование цепочкой лямбд
const add = (a) => (b) => a + b;
add(2)(3); // 5
// На каждом вызове — новое замыкание
const add2 = add(2);
const add3 = add(3);
// add2 и add3 — разные функции с разным замыканием
Замыкание на выходе функции
function makeCounter() {
let count = 0;
return => ++count;
}
const c1 = makeCounter; // отдельное замыкание
const c2 = makeCounter; // другое замыкание
c1; c1; // 2
c2; // 1 (независимо)
Декоратор
const logable = (fn) => (...args) => {
console.log(`${fn.name}(${args.join(',')})`);
const result = fn(...args);
console.log('result:', result);
return result;
};
Каррированный таймер
const timeout = (msec) => (callback) => setTimeout(callback, msec);
const after2s = timeout(2000);
after2s( => console.log('Прошло 2 секунды'));
Контракт error-first callback
// Node-style: первый аргумент — ошибка, дальше результат
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) return console.error(err);
console.log(data);
});
- Универсальный контракт для асинхронных HOF
errвсегда первый — проще проверкаsetTimeoutНЕ следует контракту — нужен wrapper
Wrapper для setTimeout под контракт
const timeout = (msec, callback) =>
setTimeout( => callback(null), msec); // null = no error
Ключевые правила
- HOF — это просто функции, использующие свойство «функция как объект первого класса»
- Возвращаемая функция замыкает контекст внешней
- Каждый вызов HOF создаёт новое замыкание
- Каррирование = частный случай HOF (цепочка возвращаемых функций)
Подводные камни
- Создание функции внутри HOF на каждом вызове — расходы на память и оптимизатор
- Цепочка
thenPromise — HOF; ошибки можно «потерять» без.catch - Listener (через subscribe) ≠ callback — слушатель срабатывает многократно
- В синхронных HOF (
map) callback срабатывает раньшеreturnHOF — это часто путает
🎓 Источник: Higher-order functions, callbacks, and events
- 📅 2018-10-11 · YouTube · ID:
1vqATwbGHnc - Тезисы:
- HOF — фундамент почти всех паттернов JS
- 4 вида использования: принимает, возвращает, и то и другое, каррирование
- Чистая HOF не имеет побочных эффектов — обернуть «грязную» можно в HOF-декоратор
- Listener против callback: первый срабатывает многократно, второй — один раз
- ООП можно собрать без
class— через сумматор-замыкание и shared методы
- Цитата: «Функция высшего порядка — это функция, у которой минимум один аргумент — это другая функция, либо она возвращает другую функцию.»