What are decorators and how are they used in JavaScript ?

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.

  • 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 lower version of JavaScript. In this example, the function add takes the print function as parameter. Here print function works as 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 concatenate the string.
    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

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

    chevron_right

    
    

  • Output:
    GFG is Best

Procedure to run: To run decorators, it requires transpiler support in browsers but at present no browsers are supported this.

  • Step1: We use BabelJS and then we can run decorators on browsers. Here we will use jsfiddle for run the code.
  • Step 2: Under jsfiddle select the option Babel+JSX, otherwise the program will not run, only JavaScript will show error @.

Below example illustrates the decorators in JavaScript:

  • Example 1:
    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    let variable = function(target) {
      target.proprty = 'GFG is best';
    }
      
    // Decorator
    @variable  
    class GFG
    { }
       
    // Print in the console
    console.log(GFG.proprty);

    chevron_right

    
    

  • Output:
    GFG is best
  • Example 2:
    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    let variable = function(color) {
        return function (target) {
          target.proprty = color;
      }
    };
       
    // The value is passed in the decorator 
    @variable('GFG is Green'
    class GFG
    { }
        
    console.log(GFG.proprty);

    chevron_right

    
    

  • Output:
    GFG is Green

Why Use Decorators ?
We can decorate a code using decorators but this decorating is difficult to apply and also apply 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 Decorator: 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 decorator 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, setters. This decorator accepts 3 parameters:

  • target: The class in 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 function or not and then it prints the arguments and the addition of them. The function add is decorated here using another function gfg.
    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // 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(`addtion: ${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);

    chevron_right

    
    

  • Output:
    parameters: 100, 200
    addition: 300
  • Example 2:
    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    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());

    chevron_right

    
    

  • 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:
    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    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);

    chevron_right

    
    

  • Output:
    (...args) =>  
        {
          console.log(`Parameters : args`);
          return new Class(...args);
        }

full-stack-img




My Personal Notes arrow_drop_up

3rd year student of Information Technology JADAVPUR UNIVERSITY

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.