Skip to main content

Функція-обгортка

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

Теорія

TL;DR

  • Обгортка приймає функцію і повертає нову функцію, яка викликає оригінал всередині себе.
  • Це higher-order function, класичний спосіб додати наскрізну поведінку.
  • Оригінальну функцію не змінюють, тому її можна використовувати і без обгортки.
  • Типові задачі: логування, метрики, try/catch, перевірка прав, кеш, throttle.
  • Той самий патерн лежить в основі декораторів та middleware.

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

javascript
function greet(name) { return `Привіт, ${name}!`; } function withLogging(fn) { return function (...args) { console.log(`Виклик функції ${fn.name} з аргументами:`, args); const result = fn(...args); console.log('Результат:', result); return result; }; } const loggedGreet = withLogging(greet); loggedGreet('Maria');

Вивід:

text
Виклик функції greet з аргументами: [ 'Maria' ] Результат: Привіт, Maria!

Тут withLogging це функція-обгортка, яка додає «зверху» звичайної функції greet додаткову поведінку.

Основна ідея

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

  • додати логування перед викликом;
  • виміряти час виконання;
  • перевірити аргументи;
  • обробити помилки через try/catch.

Щоб обгортка залишалася прозорою, вона має приймати ...args, повертати результат оригіналу і, якщо потрібен коректний this, викликати функцію через fn.apply(this, args).

Обробка помилок

javascript
function riskyOperation() { throw new Error('Щось пішло не так!'); } function safeWrapper(fn) { return function (...args) { try { return fn(...args); } catch (err) { console.error('Помилка під час виклику функції:', err.message); return null; } }; } const safeOp = safeWrapper(riskyOperation); safeOp(); // Помилка під час виклику функції: Щось пішло не так!

Тепер навіть якщо внутрішня функція падає, код навколо неї не ламається.

Вимірювання часу виконання

javascript
function heavyTask() { for (let i = 0; i < 1e7; i++) {} } function measureTime(fn) { return function (...args) { const start = performance.now(); fn(...args); const end = performance.now(); console.log(`Час виконання: ${(end - start).toFixed(2)}ms`); }; } const measuredTask = measureTime(heavyTask); measuredTask(); // Час виконання: 12.34ms

Асинхронна обгортка

Для async функції обгортка теж має бути асинхронною, інакше try/catch не спіймає відхилений promise.

javascript
async function fetchData() { const res = await fetch('https://api.example.com/data'); return res.json(); } function withErrorHandling(fn) { return async function (...args) { try { return await fn(...args); } catch (e) { console.error('Помилка запиту:', e); return null; } }; } const safeFetch = withErrorHandling(fetchData); safeFetch();

Обгортка як декоратор: перевірка прав

javascript
function authWrapper(fn) { return function (user, ...args) { if (!user.isAdmin) { throw new Error('Доступ заборонено'); } return fn(user, ...args); }; } function deletePost(user, postId) { console.log(`Допис ${postId} видалено`); } const deletePostWithAuth = authWrapper(deletePost); deletePostWithAuth({ isAdmin: true }, 42); // Допис 42 видалено deletePostWithAuth({ isAdmin: false }, 42); // Error: Доступ заборонено

Навіщо потрібні функції-обгортки

МетаПриклад
Розширення функціональностіДодати логування, метрики, кешування
БезпекаПеревірити права доступу або токен
Обробка помилокЗагорнути ризиковані операції в try/catch
ПеревикористанняСтворити шаблон поведінки для багатьох функцій
Функціональне програмуванняВикористати higher-order functions

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

ВластивістьОпис
Що цеФункція, яка викликає іншу всередині себе
МетаДодати або змінити поведінку без зміни оригіналу
ТипHigher-order function
Типові прикладиЛогування, кеш, валідація, try/catch, метрики
ПлюсиПеревикористання, безпека, читабельність

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

  • Не повертати результат оригінальної функції: обгортка «з'їдає» значення, і виклик раптом дає undefined.
  • Загортати async функцію синхронною обгорткою: помилка перетворюється на необроблене відхилення promise, а try/catch мовчить.
  • Втрачати this: якщо обгортаєте метод об'єкта, викликайте fn.apply(this, args), а не fn(...args).
  • Забувати, що fn.name і fn.length у нової функції інші, тому код, який читає ім'я чи кількість аргументів, зламається.
  • Нагромаджувати обгортки без міри: п'ять шарів навколо однієї функції роблять stack trace нечитабельним і ховають справжнє місце помилки.

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

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

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