Skip to main content

Функція-фабрика

Функція-фабрика (function factory) це функція, яка повертає інші функції. Під час виклику вона створює і віддає нову функцію з поведінкою, що залежить від переданих аргументів, тому її й називають фабрикою.

Теорія

TL;DR

  • Фабрика це функція, результатом якої є інша функція.
  • Побудована на closure: створена функція пам'ятає аргументи фабрики.
  • Кожен виклик фабрики дає незалежний екземпляр з власним станом.
  • Основні вигоди: перевикористання логіки, інкапсуляція даних, гнучкість.
  • Типові приклади: лічильники, фільтри, логери, часткове застосування (partial application).

Швидкий приклад

javascript
function createGreeter(greeting) { return function (name) { console.log(`${greeting}, ${name}!`); }; } const sayHi = createGreeter('Hello'); const sayBye = createGreeter('Goodbye'); sayHi('Maria'); // Hello, Maria! sayBye('Oleh'); // Goodbye, Oleh!

Тут createGreeter це фабрика, а sayHi і sayBye це функції, «вироблені» нею. Кожна з них замикає своє значення greeting.

Власний стан через closure

Найцінніша властивість фабрики: кожен її виклик створює окреме оточення змінних, до якого має доступ лише повернута функція.

javascript
function createCounter(start = 0) { let count = start; return function () { count++; return count; }; } const counterA = createCounter(); const counterB = createCounter(10); console.log(counterA()); // 1 console.log(counterA()); // 2 console.log(counterB()); // 11

counterA і counterB не заважають одне одному: у кожного свій count, і ззовні до нього не дістатися інакше, ніж через повернуту функцію. Це і є інкапсуляція без класів і без this.

Конфігурація поведінки: фільтри

Фабрика дозволяє винести в параметр те, що змінюється, і не дублювати решту коду.

javascript
function createFilter(minValue) { return function (numbers) { return numbers.filter(n => n >= minValue); }; } const filterAbove10 = createFilter(10); console.log(filterAbove10([5, 8, 13, 21])); // [13, 21]

Часткове застосування (partial application)

Коли фабрика фіксує частину аргументів майбутнього виклику, отримуємо часткове застосування, близький родич каррінгу (currying).

javascript
function multiplyBy(factor) { return function (number) { return number * factor; }; } const double = multiplyBy(2); const triple = multiplyBy(3); console.log(double(5)); // 10 console.log(triple(5)); // 15

Це зручний спосіб створювати спеціалізовані функції «на льоту» і передавати їх у map, filter чи обробники подій.

Реальний випадок: логер

javascript
function createLogger(prefix) { return function (message) { console.log(`[${prefix}] ${message}`); }; } const info = createLogger('INFO'); const error = createLogger('ERROR'); info('Server started'); // [INFO] Server started error('Something went wrong'); // [ERROR] Something went wrong

Один шаблон, різні функції для різних контекстів.

Чому це зручно

ПеревагаОпис
Перевикористання кодуФабрика створює багато схожих функцій без дублювання логіки
Інкапсуляція данихВикористовує closure, щоб зберігати внутрішній стан
ГнучкістьМожна створювати функції з динамічною поведінкою
Функціональний стильДобре поєднується з map, filter, reduce

Підсумкова таблиця

ВластивістьОпис
Що цеФункція, яка повертає іншу функцію
Основна ідея«Генерувати» функції за спільним шаблоном
На чому базуєтьсяClosure
Де застосовуєтьсяКонфігурації, обробники, логери, лічильники, фабричні патерни
ПеревагиМенше повторів, більше гнучкості та читабельності

Типові помилки

  • Плутати функцію-фабрику з фабрикою об'єктів: перша повертає функцію, друга повертає об'єкт (хоча обидві спираються на ту саму ідею).
  • Виносити стан за межі фабрики, наприклад у змінну модуля. Тоді всі «вироблені» функції ділять один лічильник і незалежність зникає.
  • Створювати фабрику всередині рендера чи циклу без потреби: щоразу народжується нова функція, а це зайві алокації та зламана мемоізація в UI-фреймворках.
  • Забувати, що closure тримає посилання на всі захоплені змінні. Якщо фабрика захопила великий об'єкт, він не звільниться, поки жива повернута функція.
  • Робити фабрику з трьох рівнів вкладеності там, де вистачило б одного аргументу: код стає важчим для читання без жодної вигоди.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.