Функція вищого порядку
Функція вищого порядку (higher-order function), це функція, яка приймає іншу функцію як аргумент або повертає функцію як результат. Достатньо однієї з цих двох властивостей, щоб функцію вважали функцією вищого порядку.
Теорія
TL;DR
- Функція вищого порядку приймає функцію як аргумент або повертає функцію.
- Це можливо тому, що в JavaScript функції є об'єктами першого класу.
- Функцію можна передати як значення, зберегти у змінній, повернути з іншої функції.
- Вбудовані приклади:
map,filter,reduce,setTimeout,addEventListener. - Дають гнучкість, перевикористання логіки та абстракції над колекціями і подіями.
- Це основний інструмент функціонального програмування.
Швидкий приклад
function repeat(n, action) {
for (let i = 0; i < n; i++) {
action(i);
}
}
repeat(3, console.log);
// 0
// 1
// 2repeat, це функція вищого порядку, бо вона викликає передану функцію action.
Функції як об'єкти першого класу
У JavaScript функції є об'єктами першого класу (first-class citizens), а отже їх можна:
- передавати як значення,
- зберігати у змінних,
- повертати з інших функцій.
Функції, які використовують інші функції у такий спосіб, і називають функціями вищого порядку.
const greet = function (name) { // зберігаємо у змінній
return `Hello, ${name}`;
};
const actions = [greet]; // кладемо в масив
console.log(actions[0]('Maria')); // Hello, MariaПриймає функцію як аргумент
function repeat(n, action) {
for (let i = 0; i < n; i++) {
action(i);
}
}
repeat(3, console.log);
// 0
// 1
// 2Функція, яку передають усередину, зазвичай називають колбеком (callback). Сама repeat нічого не знає про те, що робитиме action: вона відповідає лише за повторення. Саме цей поділ відповідальності і робить код гнучким.
Повертає нову функцію
function multiplier(factor) {
return function (num) {
return num * factor;
};
}
const double = multiplier(2);
console.log(double(5)); // 10multiplier, це функція вищого порядку, бо повертає іншу функцію. Повернена функція пам'ятає factor завдяки closure (замиканню), тому double назавжди множить на 2, а multiplier(10) дасть незалежну функцію, що множить на 10.
Вбудовані приклади в JavaScript
Багато методів масивів, це функції вищого порядку:
[1, 2, 3].map(x => x * 2); // приймає функцію
[1, 2, 3].filter(x => x > 1); // приймає функцію
[1, 2, 3].reduce((a, b) => a + b, 0); // приймає функціюТе саме стосується браузерних і платформних API: setTimeout(fn, 0), addEventListener('click', fn), promise.then(fn), arr.sort(compareFn). Усі вони приймають функцію і вирішують, коли і з якими аргументами її викликати.
Навіщо вони потрібні
- Підвищують гнучкість і перевикористовність коду: одна узагальнена функція обслуговує багато сценаріїв.
- Дають змогу будувати абстракції, наприклад обробку колекцій, подій, повторних спроб.
- Це основний інструмент функціонального програмування.
| Властивість | Опис |
|---|---|
| Що робить | Приймає або повертає функції |
| Приклади | map, filter, reduce, setTimeout, addEventListener |
| Переваги | Повторне використання логіки, компактність коду |
| Ключова ідея | Функції, такі самі дані, як числа чи рядки |
Функція вищого порядку, це функція, яка працює з іншими функціями як з даними: приймає їх як аргументи або повертає як результат.
Типові помилки
- Викликати функцію замість того, щоб передати її.
setTimeout(sayHi(), 1000)передає результат виклику, а не саму функцію; правильноsetTimeout(sayHi, 1000). - Передавати метод і губити
this.element.addEventListener('click', obj.handle)втрачає контекст; потрібніobj.handle.bind(obj)або стрілкова обгортка. - Плутати колбек із функцією вищого порядку. Вищого порядку, це та функція, яка приймає колбек, а не сам колбек.
- Передавати
parseIntнапряму вmap.['1','2','3'].map(parseInt)дасть[1, NaN, NaN], боmapпередає ще й індекс, який стає системою числення. - Думати, що будь-яка функція з аргументом-об'єктом уже вища за порядком. Значення має бути саме функцією, а не звичайними даними.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.