Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Що таке декоратори в JavaScript і в якому вони стані?

Декоратор - функція, що отримує елемент класу (метод, поле, аксесор чи весь клас) і змінює чи доповнює його поведінку. Записується через @ перед оголошенням:

function logged(method, context) {
  return function (...args) {
    console.log(`виклик ${String(context.name)}`, args);
    return method.apply(this, args);
  };
}

class OrderService {
  @logged
  place(order) { /* ... */ }
}

Стан стандарту. Декоратори - пропозиція TC39 на стадії 3: синтаксис і семантика узгоджені, але рушії браузерів і Node.js нативно їх ще не виконують. Використовуються через компіляцію:

  • TypeScript 5.0+ підтримує стандартні декоратори без прапорців;
  • Babel - через плагін.

Дві несумісні версії. Це головне джерело плутанини:

  • «експериментальні» (legacy) декоратори - TypeScript з experimentalDecorators: true. На них побудовані Angular, NestJS, TypeORM, MobX (старі версії). Вони отримують дескриптор властивості й підтримують декоратори параметрів;
  • стандартні декоратори (стадія 3) - інший API: отримують значення й об'єкт context (kind, name, addInitializer, access, metadata). Декораторів параметрів у них немає.

Декоратор, написаний для однієї версії, не працює з іншою. Перехід фреймворків на стандартні декоратори - поступовий.

Що можна декорувати:

  • методи - обгортки: логування, кешування, повтор при помилці, перевірка прав;
  • поля - перетворення початкового значення;
  • аксесори з accessor - нове ключове слово, що створює пару гетер/сетер з прихованим сховищем. Основа для реактивних полів (Lit, MobX);
  • класи - реєстрація, додавання поведінки.
class Counter {
  @reactive accessor count = 0;   // гетер/сетер, які декоратор може перехопити
}

Метадані (окрема пропозиція, теж стадія 3): context.metadata - об'єкт, куди декоратори записують інформацію про клас. Замінює reflect-metadata, на якому побудовані DI-контейнери NestJS і Angular.

Порівняння з PHP: атрибути PHP 8 (#[Route('/orders')]) - лише метадані, які читає фреймворк через рефлексію. Декоратори JavaScript - виконуваний код, що змінює елемент у момент визначення класу.

Чи варто використовувати в застосунку: якщо фреймворк побудований на них (Angular, NestJS, Lit) - так, у тій версії, яку він вимагає. У власному коді - обережно: компіляція обов'язкова, а стандарт ще не в рушіях. Звичайна функція вищого порядку (const place = logged(placeImpl)) дає той самий ефект без нового синтаксису.

Докладніше в документації: Пропозиція TC39: декоратори

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання