Decorators: декораторы классов и методов (экспериментальный)

Что такое декораторы и зачем они нужны? 🛠️

Декораторы в JavaScript — это специальные функции, которые модифицируют поведение классов, методов или свойств. Они позволяют добавлять новую функциональность, не меняя исходный код.

💡 Декораторы — это пока экспериментальная возможность (Stage 3). Для работы включите флаг --experimental-decorators или настройте Babel.


Как выглядят декораторы? ✨

Синтаксис декораторов прост — это функция с префиксом @. Например:

@logTime
class Calculator {
  @memoize
  add(a, b) {
    return a + b;
  }
}

Здесь:

  • @logTime — декоратор класса, логирующий время создания экземпляра.
  • @memoize — декоратор метода, кэширующий результаты вызовов.

Виды декораторов 🏷️

1. Декораторы класса

Принимают конструктор класса и могут его модифицировать или заменить.

Пример: Добавляем свойство version всем экземплярам.

function addVersion(constructor) {
  constructor.prototype.version = '1.0.0';
}

@addVersion
class Car {}

const myCar = new Car();
console.log(myCar.version); // '1.0.0'

2. Декораторы методов

Принимают три параметра: целевой объект, имя метода и дескриптор свойства.

Пример: Логируем вызовы метода.

function log(target, name, descriptor) {
  const original = descriptor.value;

  descriptor.value = function(...args) {
    console.log(`Called: ${name}(${args})`);
    return original.apply(this, args);
  };

  return descriptor;
}

class Math {
  @log
  square(n) {
    return n * n;
  }
}

const m = new Math();
m.square(4); // Выведет: "Called: square(4)"

3. Декораторы свойств

Работают аналогично методам, но для свойств класса.

Пример: Делаем свойство только для чтения.

function readonly(target, key, descriptor) {
  descriptor.writable = false;
  return descriptor;
}

class User {
  @readonly
  role = 'admin';
}

const u = new User();
u.role = 'user'; // Ошибка! Свойство только для чтения.

Комбинирование декораторов 🔄

Декораторы можно накладывать несколько раз — они применяются сверху вниз:

@decorator1
@decorator2
class Example {}

Порядок выполнения: decorator2 → decorator1.


Реальный пример: Кэширование методов 🗃️

Декоратор @memoize сохраняет результаты вызовов, избегая повторных вычислений:

function memoize(target, name, descriptor) {
  const cache = new Map();
  const original = descriptor.value;

  descriptor.value = function(...args) {
    const key = JSON.stringify(args);
    if (cache.has(key)) return cache.get(key);

    const result = original.apply(this, args);
    cache.set(key, result);
    return result;
  };

  return descriptor;
}

class Fibonacci {
  @memoize
  calc(n) {
    return n <= 1 ? n : this.calc(n - 1) + this.calc(n - 2);
  }
}

const fib = new Fibonacci();
console.log(fib.calc(100)); // Быстро, благодаря кэшу!

Ограничения и подводные камни ⚠️

  1. Нельзя декорировать функции (только классы, методы и свойства).
  2. Не поддерживается в стандарте ES2023 (пока Stage 3).
  3. Проблемы с this — контекст может теряться, если не аккуратно писать декораторы.

🔥 Совет: Для продакшена используйте Babel с плагином @babel/plugin-proposal-decorators.


Где это применяется на практике? 🌍

  1. Валидация данных — проверка аргументов методов.
  2. Авторизация — ограничение доступа к методам.
  3. Логирование — трассировка вызовов.
  4. Оптимизация — кэширование и мемоизация.

Итоги 🏁

Декораторы — мощный инструмент для:

  • ✅ Улучшения читаемости кода.
  • ✅ Повторного использования логики.
  • ✅ Модификации поведения без изменения исходников.

Экспериментируйте, но помните — это пока не стандарт!

// Ваш код после этого урока:
@supercharge
class MyProject {
  @debug
  awesomeMethod() {
    // Магия декораторов ✨
  }
}
Скрыть рекламу навсегда

🌱 Индвидидулаьные занятия

Индивидуальные онлайн-занятия по программированию для детей и подростков

Личный подход, без воды, с фокусом на понимание и реальные проекты.

🚀 Записаться на занятие