“This is the 16th day of my participation in the First Challenge 2022. For details: First Challenge 2022”


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.

This article will discuss JavaScript decorators in detail to improve your understanding. Rush ~

Introduction to the

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.

Code examples:

@readonly
class Example {
    @log()
    exampleFunction() {}
}
Copy the code

As mentioned earlier, JavaScript decorator support is still in the proposal stage. However, 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 multiply(x, y) { console.log('Total : ' + (x*y)); } function logDecorator(logger) { return function (message) { const result = logger.apply(this, arguments); console.log("Logged at:", new Date().toLocaleString()); return result; } } const wrapperFunction = logDecorator(multiply); WrapperFunction (10, 10)Copy the code

In the example above, wrapperFunction() modifies the multiply() function via logDecorator(), which can be called just like any JavaScript function.

JavaScript function decorators have been around since the introduction of higher-order functions. However, we cannot use the same method for JavaScript classes.

Class decorator

Class decorators are a little different. TypeError will be reported if you try to use the same method:

You can overcome this problem if you have a good understanding of the JavaScript this keyword. But it’s not the easiest way.

The class decorator applies to the entire class. Therefore, any changes we make will affect the entire class. Anything done to the class decorator needs to replace the class constructor by returning a new constructor.

Here’s an example:

function log(name) { return function decorator(Class) { return (... args) => { console.log(`Arguments for ${name}: ${args}`); return new Class(... args); }; } @log('Multiply') class Calculator {constructor (x,y) {}} Calculator = new Calculator(10,10); // Arguments for Multiply: [10, 10] console.log(calculator); // Calculator {}Copy the code

The log() function takes the Calculator class as an argument and returns a new function to replace the Calculator class constructor;

Class member decorator

Class member decorators apply to individual members of a class. These members can be properties, methods, getters, or setters. The decorator function takes three input parameters:

  • Target – The class to which the member belongs.
  • Name – The Name of the class member.
  • Descriptor – Member descriptor.

Code examples:

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

class Example {
  x() {}
  @readonly
  y() {}
}

const myClass = new Example();
myClass.x = 10;
myClass.y = 20;
Copy the code

In the readonly() function, we set the writable property of the descriptor to false. It is then used as a decorator for the function y(). If you try to modify it, you get a TypeError.

In addition, we can create custom decorators and use them as class member decorators, as follows:

function log(name) { return function decorator(t, n, descriptor) { const original = descriptor.value; if (typeof original === 'function') { descriptor.value = function (... args) { console.log("Logged at:", new Date().toLocaleString()); try { const result = original.apply(this, args); console.log(`Result from ${name}: ${result}`); return result; } cach (e) { console.log(`Error from $ {name}: ${e}`); thro e; }}; } return descriptor; }; } class Calculator { @log('Multiply') multiply(x,y){ return x*y; } } calculator = new Calculator(); The calculator. Multiply (10, 10); // Logged at: 1/12/2022, 08:00:00 PM // Result from Multiply: 100Copy the code

The Calculator class has a method called multiply() and is decorated with the log() function. The Log() function takes a single parameter as input, to which we can pass the value when we call the decorator (@log(‘Multiply’)).

summary

The main reason decorators were introduced to JavaScript was to share functionality between JavaScript classes and class attributes.

But that’s not the only advantage decorators offer.

Decorators allow developers to write clean and reusable code. Developers can use decorators to easily separate enhancements from code features.

In addition, the decorator syntax is very simple, allowing you to add new functionality to classes and properties without increasing code complexity.

This makes the code easier to maintain and debug.

The above is the share of ~~~

I’m Nuggets Anthony, output exposure input, technical insight into life, goodbye ~