Skip to main content

How to use decorators in JavaScript?

ยท 3 min read

Decorators are a simple way to wrap code and a design pattern that extends the functionality of wrapped code without modifying it.

Although decorators are widely used in languages such as TypeScript and Python, support for JavaScript decorators is still a stage 2 proposal. However, we can use JavaScript decorators with the Babel and TypeScript compilers.

In JavaScript, decorators have a special syntax. They are prefixed with the @ symbol before the code we need to decorate. Additionally, you can use more than one decorator at a time.

@readonly
class Example {
@log()
exampleFunction() {}
}

The concept of decorators is not new to JavaScript, because higher-order functions are another form of function decorators.

In general, we can distinguish three types of decorators in JavaScript:

  • Function decorator : Wraps functions around functions.

  • Class decorator : applies to the entire class at once.

  • Class member decorator : applies to members of a class

Currently, you cannot run class decorators in a browser or node.js environment because they require translator support. However, if you use functional decorators, you can run them anywhere.

Function decoratorโ€‹

We can try wrapping one function around another to extend functionality without changing the original function.

function logDecorator(fn) {
return function () {
console.log(`call ${fn.name} and params ${[...arguments]}`);
fn.apply(this, arguments);
};
}
function add(a, b) {
return a + b;
}
const wrapped = logDecorator(add);
console.log(wrapped(1, 2));

function decorator

Class decoratorโ€‹

A Class Decorator is declared just before a class declaration. The class decorator is applied to the constructor of the class and can be used to observe, modify, or replace a class definition.

function logDecorator(target) {
return function (...args) {
console.log(`Target is ${target} and args are ${args}`);
return new Target(...args);
};
}
@logDecorator
class Operator {
constructor(a, b) {
this.a = a;
this.b = b;
}
}
const op = new Operator(1, 2);
tip

You can run code in jsfiddle.net, select the babel + jax in the editor.

class decorator

Class method decoratorโ€‹

Class method decorators are a little different. Let's declare a decorator:

function log(target, name, descriptor) {
const original = descriptor.value;
descriptor.value = function () {
console.log(`call ${name} and params is ${[...arguments]}`);
return original.apply(this, arguments);
};
return descriptor;
}

Now you can use it to decorate a class methods with @ + decoratorName:

class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
@log
getInfo() {
console.log(`${this.name} is a ${this.age} years old`);
}
}

const p = new Person("jstyro", 18);
p.getInfo();