Decorators are the way of wrapping one piece of code with another or apply a wrapper around a function in JavaScript. Decorators are the design pattern that allows behavior to be added to an individual object, either statically or dynamically without affecting the behavior of other objects from the same class. They are used to enhance the functionality of the function without modifying the underlying function. They are just modifying the behavior of the function or method passed to it by returning a new function. Decorators have already been used in languages like Python and C#, now it is used in JavaScript also.
What are decorators?
Decorators are a design pattern in JavaScript that enables the modification of an object’s behavior by adding new functionality to it, without altering its original code. They are functions that take in an object, modify it, and return the modified version, which can have additional features or improved behavior
Decorators are often used to add additional functionality to objects, such as logging or security checks, without changing the underlying code. This makes them a powerful tool for extending the functionality of objects without the need to make significant changes to the original code.
Overall, decorators are a useful tool for adding new behavior to existing objects in JavaScript. They allow you to add additional functionality without modifying the original code and can be applied to a variety of different types of objects.
How do you use decorators in JavaScript?
In JavaScript, a decorator is a higher-order function that modifies the behavior of a function, method, or class. Decorators are used to extending the functionality of a function, method, or class without modifying its code.
- Syntax:
let variable=function(object) { object.property='characteristic'; } // Use as decorator @variable class GFG { } console.log(GFG.property);
- Example: This example implements the work of decorators using a lower version of JavaScript. In this example, the function add takes the print function as a parameter. Here print function works as a decorator. It helps to concatenate the “is best” string to the passed string “GFG”. Here we use the “add” function for extending and executing the “print” function by concatenating the string.
Javascript
<script> // Working of decorators in javascript // "add" function takes the function as // a parameter for wrapping function // "print" is wrapped function add(fn) { return function (s) { var gg = s + ' is Best' ; // By concatenating we extend // the function "add" fn(gg); } } // Decorated function function print(s) { document.write(s); } // Calling "add" var g = add(print); g( 'GFG' ); </script> |
- Output:
GFG is Best
Procedure to run: To run decorators, it requires transpiler support in browsers but at present no browsers are supported.
- Step 1: We use BabelJS and then we can run decorators on browsers. Here we will use jsfiddle to run the code.
- Step 2: Under jsfiddle select the option Babel+JSX, otherwise the program will not run, and only JavaScript will show error @.
The below example illustrates the decorators in JavaScript:
- Example 1:
Javascript
let variable = function (target) { target.property = 'GFG is best' ; } // Decorator @variable class GFG { } // Print in the console console.log(GFG.property); |
- Output:
GFG is best
- Example 2:
Javascript
let variable = function (color) { return function (target) { target.property = color; } }; // The value is passed in the decorator @variable( 'GFG is Green' ) class GFG { } console.log(GFG.property); |
- Output:
GFG is Green
Why Use Decorators?
We can decorate a code using decorators but this decorating is difficult to apply also applying the same techniques to other pieces of code or wrapping one piece of code with another or apply a wrapper around a function is difficult. In ES6, decorators can resolve these difficulties. Decorators allow an efficient and understandable way of wrapping a piece of code with another function or another code. Also, decorators provide a clear syntax for applying these wrappers. JavaScript decorators are not directly supported but in the future may be decorators’ support will be added to javascript.
Types of Decorators: Decorators are called by the appropriate details of the item which will be decorated. Decorators are actually functions that return another function. There are two types of decorators are supported now:
- Class member decorators
- Members of classes
Class member decorators: These decorators are applied to a single member of a class. This decorator has properties, methods, getters, and setters. This decorator accepts 3 parameters:
- target: The class to which the member belongs to.
- name: Name of the class member.
- descriptor: Description of the member which is the object that is passed to Object.defineProperty.
Example 1: In this example, we are passing two arguments, and here the decorator function checks if the descriptor is a function or not, and then it prints the arguments and the addition of them. The function add is decorated here using another function gfg.
Javascript
// Decorator function function gfg(target, name, descriptor) { var fn = descriptor.value; // Checks if "descriptor.value" // is a function or not if ( typeof fn == 'function' ) { descriptor.value = function (...args) { // Document.write(`parameters: ${args}`+"<br>"); console.log(`parameters: ${args}`); var result = fn.apply( this , args); // Document.write(`addition: ${result}`); // Print the addition of passed arguments console.log(`addition: ${result}`); return result; } } return descriptor; } class geek { @gfg add(a, b) { return a + b; } } var e = new geek(); e.add(100, 200); |
- Output:
parameters: 100, 200 addition: 300
- Example 2:
Javascript
let readonly = function (target, key, descriptor) { descriptor.writable = false ; return descriptor; } class car { constructor(color) { this .color = color; } // Decorator @readonly getColor() { return this .color; } } const rCar = new car( 'car is Black' ); // When descriptor.writable = false; rCar.getColor = function () { // When descriptor.writable = true; return 'car is not Black' } console.log(rCar.getColor()); |
- Output:
car is Black
Members of classes: These decorators are applied to the entire class. These functions are called with a single parameter which is to be decorated. This function is a constructor function. These decorators are not applied to each instance of the class, it only applies to the constructor function. These decorators are less useful than class member decorators. Because we can use a simple function to do everything which can be done by these decorators.
- Example:
Javascript
function log() // Decorator function { return function decorator() { // "arrow" function return (...args) => { console.log(`Parameters : args`); return new Class(...args); }; } } // Decorators @log class gfg { constructor(name, category) {} } const e = new gfg( 'geek' , 'code' ); // Arguments for Demo: args console.log(e); |
- Output:
(...args) => { console.log(`Parameters : args`); return new Class(...args); }
Benefits and drawbacks of using decorators
Some benefits of using decorators include:
- Decorators allow you to add new functionality to an object without modifying its code. This can be useful for adding behavior such as logging, error handling, or security checks, without changing the core functionality of the object.
- Decorators can make your code more modular and easier to maintain, as you can add or remove behavior independently of the core functionality of the object.
- Decorators can be easily composed, meaning that you can apply multiple decorators to the same object to achieve a desired behavior.
Some potential drawbacks of using decorators include:
- Decorators can make your code more complex, as they add an additional layer of abstraction to your code.
- Decorators can make your code harder to understand, especially if you are using multiple decorators on the same object.
- Decorators are a relatively new feature of JavaScript, and they are not supported in all environments.
- Overall, decorators are a useful tool that can help you add new behavior to your code in a flexible and modular way. However, it’s important to consider the potential complexity and readability trade-offs when using decorators in your code.
Conclusion
In conclusion, decorators are a design pattern in JavaScript that allows for the modification of an object’s behavior without changing its original code. They are functions that take in an object, modify it, and return the modified version with additional features or improved behavior. They are commonly used to add additional functionality such as logging or security checks to objects. To use decorators in JavaScript, they need to be wrapped around a function, method, or class using the “@” symbol. They can be run on browsers using transpiler support such as BabelJS and jsfiddle. Decorators are a useful tool for extending the functionality of existing objects in JavaScript and can be applied to a variety of different types of objects.