Decorator function
A decorator function is a special kind of wrapper function that modifies the behavior of another function without changing its source code.
This is a powerful pattern often found in functional programming, Python, and modern JS frameworks (for example, NestJS, React decorators, MobX, etc.). Let's look at it in detail.
Definition
A decorator function is a function that takes another function and returns a new one, with the same interface but extended behavior.
Essentially, this is a "wrapper with intent" - it decorates (embellishes, adds capabilities to) the source function without changing it directly.
Basic example
function decorator(fn) {
return function(...args) {
console.log('Before calling the function');
const result = fn(...args);
console.log('After calling the function');
return result;
};
}
function sayHello(name) {
console.log(`Hello, ${name}!`);
}
const decorated = decorator(sayHello);
decorated('Bohdan');Output:
Before calling the function
Hello, Bohdan!
After calling the functionHere decorator added "behavior before and after" without changing sayHello itself.
Example 2 - a decorator for measuring execution time
function measureTime(fn) {
return function(...args) {
const start = performance.now();
const result = fn(...args);
const end = performance.now();
console.log(`Execution time: ${(end - start).toFixed(2)}ms`);
return result;
};
}
function heavyCalc(n) {
for (let i = 0; i < n; i++) {}
}
const timedCalc = measureTime(heavyCalc);
timedCalc(1e7);Example 3 - a decorator for try/catch
function safe(fn) {
return function(...args) {
try {
return fn(...args);
} catch (err) {
console.error('Error:', err.message);
}
};
}
function risky() {
throw new Error('Something went wrong');
}
const safeRisky = safe(risky);
safeRisky(); // Error: Something went wrongSuch a decorator is often used to automatically catch errors across dozens of functions without duplicating try/catch.
Example 4 - decorators in "composition" style
Several decorators can be combined:
const log = fn => (...args) => {
console.log(`Calling ${fn.name} with arguments:`, args);
return fn(...args);
};
const time = fn => (...args) => {
const start = performance.now();
const result = fn(...args);
console.log(`${fn.name} executed in ${performance.now() - start}ms`);
return result;
};
function sum(a, b) {
return a + b;
}
const decoratedSum = log(time(sum));
decoratedSum(5, 7);Decorators can be combined, like filters: each adds a "layer" of functionality.
Example 5 - class and method decorators (ES7 syntax)
JS supports decorators at the class level (in NestJS, Angular, MobX, etc.):
function Log(target, property, descriptor) {
const original = descriptor.value;
descriptor.value = function(...args) {
console.log(`Calling ${property} with:`, args);
return original.apply(this, args);
};
return descriptor;
}
class User {
@Log
sayHello(name) {
console.log(`Hello, ${name}!`);
}
}
new User().sayHello('Bohdan');Here @Log automatically "wraps" the sayHello method.
This is syntactic sugar for:
User.prototype.sayHello = Log(User.prototype, 'sayHello', descriptor).value;Decorators != just wrappers
| Difference | Wrapper | Decorator |
|---|---|---|
| Purpose | Add logic around a function | Change or extend a function's behavior |
| Returns | Usually a new function | Also a new one, but with the same interface |
| Often used | For protection (try/catch), logging, throttling | For annotations, DI, validation, caching |
| Level | Any function | Often methods or classes |
| In JS (ES) | No special syntax before ES2022 | Has @decorator syntax |
SUMMARY
| Property | Description |
|---|---|
| What it is | A function that takes another function and returns a modified one |
| Purpose | Add functionality without changing the source code |
| Type | Higher-order function |
| Typical examples | Logging, caching, metrics, security, annotations |
| Support in ES | ES7+ (via @decorator syntax) |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.