Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Функція-фабрика». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Функція-фабрика (function factory) це функція, яка повертає іншу функцію.** Вона «виробляє» нові функції за переданими параметрами, звідси й назва. Кожна створена функція замикає (closure) власні аргументи фабрики, тому має незалежну поведінку і власний приватний стан. Це дає перевикористання логіки без дублювання коду та інкапсуляцію даних. ```javascript function multiplyBy(factor) { return function (number) { return number * factor; }; } const double = multiplyBy(2); console.log(double(5)); // 10 ``` **Ключове:** фабрика це шаблон плюс closure: один опис поведінки, з якого народжується скільки завгодно спеціалізованих функцій з незалежним станом.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Функція-фабрика (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 тримає посилання на всі захоплені змінні. Якщо фабрика захопила великий об'єкт, він не звільниться, поки жива повернута функція. - Робити фабрику з трьох рівнів вкладеності там, де вистачило б одного аргументу: код стає важчим для читання без жодної вигоди.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.