Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Функція-декоратор». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Функція-декоратор** - це особливий вид **функції-обгортки**, яка **модифікує поведінку іншої функції**, **не змінюючи її вихідний код**. **Ключове:** декоратор - це функція, що приймає іншу функцію й повертає нову, з тим самим інтерфейсом, але розширеною поведінкою.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**функція-декоратор** - це особливий вид **функції-обгортки**, яка **модифікує поведінку іншої функції**, **не змінюючи її вихідний код**. Це потужний патерн, який часто зустрічається у функціональному програмуванні, Python і сучасних JS-фреймворках (наприклад, NestJS, React decorators, MobX тощо). Розберемо детально. --- ## Визначення > **Функція-декоратор** - це **функція, що приймає іншу функцію і повертає нову**, з тим самим інтерфейсом, але **розширеною поведінкою**. По суті, це "обгортка з наміром" - вона **декорує** (прикрашає, додає можливості) вихідну функцію, не змінюючи її напряму. --- ## Базовий приклад ```javascript function decorator(fn) { return function(...args) { console.log('Перед викликом функції'); const result = fn(...args); console.log('Після виклику функції'); return result; }; } function sayHello(name) { console.log(`Привіт, ${name}!`); } const decorated = decorator(sayHello); decorated('Богдан'); ``` Виведе: ```javascript Перед викликом функції Привіт, Богдан! Після виклику функції ``` Тут `decorator` додав "поведінку до і після", не змінюючи саму `sayHello`. --- ## Приклад 2 - декоратор для вимірювання часу виконання ```javascript function measureTime(fn) { return function(...args) { const start = performance.now(); const result = fn(...args); const end = performance.now(); console.log(`Час виконання: ${(end - start).toFixed(2)}ms`); return result; }; } function heavyCalc(n) { for (let i = 0; i < n; i++) {} } const timedCalc = measureTime(heavyCalc); timedCalc(1e7); ``` --- ## Приклад 3 - декоратор для try/catch ```javascript function safe(fn) { return function(...args) { try { return fn(...args); } catch (err) { console.error('Помилка:', err.message); } }; } function risky() { throw new Error('Щось пішло не так'); } const safeRisky = safe(risky); safeRisky(); // Помилка: Щось пішло не так ``` Такий декоратор часто використовують, щоб **автоматично ловити помилки** у десятках функцій, не дублюючи try/catch. --- ## Приклад 4 - декоратори у стилі "композиції" Можна комбінувати декілька декораторів: ```javascript const log = fn => (...args) => { console.log(`Виклик ${fn.name} з аргументами:`, args); return fn(...args); }; const time = fn => (...args) => { const start = performance.now(); const result = fn(...args); console.log(`${fn.name} виконана за ${performance.now() - start}ms`); return result; }; function sum(a, b) { return a + b; } const decoratedSum = log(time(sum)); decoratedSum(5, 7); ``` Декоратори можна **комбінувати**, як фільтри: кожен додає "шар" функціональності. --- ## Приклад 5 - декоратори класів і методів (синтаксис ES7) JS підтримує **декоратори на рівні класів** (у NestJS, Angular, MobX та ін.): ```javascript function Log(target, property, descriptor) { const original = descriptor.value; descriptor.value = function(...args) { console.log(`Виклик ${property} з:`, args); return original.apply(this, args); }; return descriptor; } class User { @Log sayHello(name) { console.log(`Привіт, ${name}!`); } } new User().sayHello('Богдан'); ``` Тут `@Log` автоматично "обгортає" метод `sayHello`. Це синтаксичний цукор для: ```javascript User.prototype.sayHello = Log(User.prototype, 'sayHello', descriptor).value; ``` --- ## Декоратори != просто обгортки | Відмінність | Обгортка | Декоратор | |---|---|---| | Мета | Додати логіку навколо функції | Змінити або доповнити поведінку функції | | Повертає | Зазвичай нову функцію | Теж нову, але з тим самим інтерфейсом | | Часто використовується | Для захисту (try/catch), логування, throttling | Для анотацій, DI, валідації, кешування | | Рівень | Будь-яка функція | Часто методи або класи | | У JS (ES) | Не має спец. синтаксису до ES2022 | Має синтаксис `@decorator` | --- ## ПІДСУМОК | Властивість | Опис | |---|---| | Що це | Функція, що приймає іншу функцію і повертає змінену | | Мета | Додати функціональність без зміни вихідного коду | | Тип | Функція вищого порядку (higher-order function) | | Типові приклади | Логування, кеш, метрики, безпека, анотації | | Підтримка в ES | ES7+ (через синтаксис `@decorator`) |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.