Skip to main content

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

javascript
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:

javascript
Before calling the function Hello, Bohdan! After calling the function

Here decorator added "behavior before and after" without changing sayHello itself.


Example 2 - a decorator for measuring execution time

javascript
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

javascript
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 wrong

Such 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:

javascript
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.):

javascript
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:

javascript
User.prototype.sayHello = Log(User.prototype, 'sayHello', descriptor).value;

Decorators != just wrappers

DifferenceWrapperDecorator
PurposeAdd logic around a functionChange or extend a function's behavior
ReturnsUsually a new functionAlso a new one, but with the same interface
Often usedFor protection (try/catch), logging, throttlingFor annotations, DI, validation, caching
LevelAny functionOften methods or classes
In JS (ES)No special syntax before ES2022Has @decorator syntax

SUMMARY

PropertyDescription
What it isA function that takes another function and returns a modified one
PurposeAdd functionality without changing the source code
TypeHigher-order function
Typical examplesLogging, caching, metrics, security, annotations
Support in ESES7+ (via @decorator syntax)

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.