Decorators (ES7+) – Giving Superpowers to Functions and Classes 🦸‍♂️✨

JavaScript Guide

Sometimes in JavaScript, you want to give a function or class extra powers, like:

  • Logging every time it’s called
  • Automatically validating parameters
  • Caching heavy computations

But adding all this code inside every function… 😵‍💫 Total code chaos!

That’s where Decorators come in: they let you add superpowers to functions or classes without touching their code.


🧩 1. What is a Decorator?

A decorator is a magic function that takes a function or class and enhances it.

  • The original function or class remains unchanged
  • Decorators add extra behavior
  • They’re reusable and keep your code clean

Analogy:

  • Function = a hero 🦸
  • Decorator = the hero’s magical cape ✨
  • Result = a superpowered hero 💥

🔹 2. Simple Example: Logging Decorator

Scenario: Log whenever a function is called

Regular JS:

function greet(name) {
  console.log(`Hello ${name}!`);
  console.log("greet function was called!");
}

greet("Alice");

⚠️ Problem: If you have 50 functions, you need to add this everywhere 😵
Repetitive and hard to maintain.


With Decorator:

function log(target, key, descriptor) {
  const original = descriptor.value; // Original function
  descriptor.value = function(...args) {
    console.log(`${key} called with arguments: ${args}`);
    return original.apply(this, args); // Call the original function
  };
  return descriptor;
}

class Greeter {
  @log
  greet(name) {
    console.log(`Hello ${name}!`);
  }
}

const g = new Greeter();
g.greet("Alice");

✅ Output:

greet called with arguments: Alice
Hello Alice!

📌 Explanation:

  • @log → gives the function a superpower ✨
  • target → the class or object the function belongs to
  • key → method name
  • descriptor.value → original function
  • apply(this, args) → calls the original function with its arguments

💡 Pro tip: Logging decorators are lifesavers during debugging.


🧠 3. Validation Decorator

Sometimes functions need safety checks: prevent missing or invalid parameters.

function validate(target, key, descriptor) {
  const original = descriptor.value;
  descriptor.value = function(name) {
    if (!name) {
      throw new Error("Name is required!");
    }
    return original.apply(this, [name]);
  };
  return descriptor;
}

class UserGreeter {
  @validate
  greet(name) {
    console.log(`Hi ${name}!`);
  }
}

const u = new UserGreeter();
u.greet(""); // ❌ Error: Name is required!
u.greet("Alice"); // ✅ Hi Alice!

📌 Fun analogy:
This decorator = a bouncer at the door 🚪
No name? “You shall not pass!”

💡 Tip:
Validation decorators are perfect for forms and user input
Eliminates repetitive code


🧩 4. Caching Decorator

Some functions are heavy computations.
Decorators can store results, making repeated calls super fast ⚡

function cache(target, key, descriptor) {
  const original = descriptor.value;
  const memory = {};
  descriptor.value = function(num) {
    if(memory[num] !== undefined) {
      console.log(`Fetched from cache: ${num}`);
      return memory[num];
    }
    const result = original.apply(this, [num]);
    memory[num] = result;
    return result;
  };
  return descriptor;
}

class Calculator {
  @cache
  factorial(n) {
    console.log(`Calculating: ${n}!`);
    return n <= 1 ? 1 : n * this.factorial(n - 1);
  }
}

const c = new Calculator();
console.log(c.factorial(5)); // Calculating...
console.log(c.factorial(5)); // Fetched from cache!

📌 Explanation:

  • memory → cache object
  • If the result was calculated before, it returns the cached value
  • apply → runs the original function

💡 Pro tip:

  • Great for CPU-intensive functions
  • Use caching decorators for API calls or heavy computations

🧠 5. Combining Decorators

A function can have logging, validation, and caching decorators applied together.
Order matters: validation → caching → logging usually makes sense.

class SuperGreeter {
  @log
  @cache
  @validate
  greet(name) {
    console.log(`Hi ${name}!`);
  }
}

Note: Decorators are applied top-down, so order affects behavior.


🎉 6. Usage Rules and Tips

  • Should be reusable
  • Should not modify the original function or class
  • Keep complex code clean and readable
  • Combine multiple decorators for extra superpowers

💡 Bonus Tip:
Logging + Validation + Caching = “Superpowered Function”
Modern, clean, and maintainable approach in new JS projects


🎯 7. Conclusion: Decorators Make You a JS Superhero

  • Code becomes shorter, cleaner, and readable
  • Add extra features to functions and classes effortlessly
  • Automate repetitive tasks like logging, validation, caching
  • Feel like a JavaScript superhero 🦸‍♂️✨

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir