In Java, annotations are the salt of the oil. In JavaScript, annotations are the spice of medieval Europe

Decorators and annotations

Decorators and annotations were not clear about their specific concept before, thinking that they are based on metaprogramming implementation, annotations is one of the decorative pattern.

  • Annotations: Provide additional metadata support and do not perform any operations. Additional scanners are required to perform operations based on the metadata.

  • Decorators: Only provide definition hijacking. You can modify the class, its methods, its properties, and the incoming parameters of its methods. Metadata support is not provided.

The connection between annotations and decorators:

Add metadata through annotations, and then obtain the metadata in the decorator to complete the modification of the class, class method, etc. Add metadata support in the decorator, such as in the decorator factory function and the decorator function.

The difference between annotations and decorators

Although grammatically similar, different concepts may be used in different languages:

  • Languages that use annotations: AtScript, Java, C# (called attributes).

  • Languages that use decorators: Python, JavaScript/ECMAScript.

Conceptually, it’s clear that annotations and decorators have nothing in common semantically!

Annotations and decorators can mimic each other and are not equivalent. Decorators can naturally run at runtime, and annotations can also be reflected (without the type itself).

Inheritance patterns are an important way to enrich the “connotation” of child elements, whether they inherit from an interface or a subclass from a base class. The decorator mode, on the premise of not changing the inheritance relationship, can package the previous modules, enrich their connotation, and will not affect the original function. Compared with inheritance, it is more flexible.

One of the most powerful features of decorators is their ability to reflect metada.

Why do you need reflection in JavaScript?

Reflection is used to describe code that can examine other code in the same system (or itself).

JavaScript applications are getting larger, so tools such as inversion of control containers and features such as run-time type assertions are needed to manage this increasing complexity.

The powerful reflection API should allow us to examine an unknown object at run time and find out all about it. We should be able to find something like this:

  1. The name of the entity.

  2. The type of entity.

  3. Which interfaces are implemented by entities.

  4. The name and type of the entity attribute.

  5. The name and type of the constructor parameters for the entity

In JavaScript, we can use the Object. GetOwnPropertyDescriptor () or Object. The keys () function to find some information about the entity, but we need to look to achieve greater development tools.

Things are about to change, however, as TypeScript begins to support some Reflection features. But they’re really just JavaScript functions that help you comment out your code or modify its behavior — a practice commonly referred to as metaprogramming.

TypeScript decorator

Decorators are great at abstracting code, and they are best used to wrap logic that might be reused in multiple places.

Five ways to decorator

  • Class declaration

  • attribute

  • methods

  • parameter

  • accessor

Class Decorator

Class decorators enable developers to intercept class constructor.

Note: Decorators are called when we declare a class, not when the class is instantiated.

When you decorate a class, decorators do not apply to subclasses of that class. Let’s freeze a class to prevent other programmers from accidentally forgetting this feature.

@Frozen class IceCream {} function Frozen(constructor: Function) { Object.freeze(constructor); Object.freeze(constructor.prototype); } console.log(Object.isFrozen(IceCream)); // True class FroYo extends IceCream {Copy the code

When a decorator function directly decorates a class, it takes a unique argument, constructor, which is the class itself to be decorated.

In addition, when decorating a class, if a decorator function returns a value, the return value redefines the class. That is, when a decorator function returns a value, it generates a new class defined by its return value.

Method Decorator

Method decorators to override a method, change its execution, and run extra code before and after it executes.

The following example will pop up a confirmation box before executing the actual code. If the user clicks cancel, the method is skipped. Notice that here we decorate a method twice, and the two decorators execute from top to bottom.

function log(target, key, descriptor) {} class P { @log foo() { console.log('Do something'); }}Copy the code

The decorator function for a class function accepts, in turn, the following parameters:

  • Target: If you are decorating an instance function of the class, target is the prototype of the class. If you are decorating a static function of the class, then target is the class itself.

  • Key: specifies the function name.

  • Descriptor: specifies the description property of the function, such as a different, value, or Enumerable.

Property Decorator

Property decorators are extremely useful because they can listen for changes in an object’s state.

To fully understand the following example, it is recommended that you familiarize yourself with JavaScript property descriptors.

function foo(target,name){}
class P{
   @foo
   name = 'Jony'
}
Copy the code

Here the decorator function for a property of the class takes two arguments,

  • The first argument:

  • In the case of static properties, it is the class itself

  • For instance properties, it’s the prototype of the class,

  • Second parameter: the name of the property referred to.

Decorator for class function arguments

Parameter decorators for class functions can modify parameters in the constructor of the class, as well as parameters in other ordinary functions of the class. This decorator is executed when a method of the class is called.

function foo(target,key,index){}
class P{
   test(@foo a){
   }
}
Copy the code

A decorator function that takes a class function argument takes three arguments

  • Target: the class itself

  • Key: specifies the name of the function to which this parameter belongs

  • Index: the index of this parameter in the function argument list

Decorators can be used to separate complex logic and are extremely easy to use. Compared to inheritance, it is also more flexible, and can be armed with “teeth” from the decorator class to the parameters of the decorator function.

Metadata operations in Typescript

You can use the reflect-Metadata package to manipulate metadata. Let’s start with reflect-metadata by defining functions that use metadata:

const formatMetadataKey = Symbol("format");

function format(formatString: string) {
    return Reflect.metadata(formatMetadataKey, formatString);
}

function getFormat(target: any, propertyKey: string) {
    return Reflect.getMetadata(formatMetadataKey, target, propertyKey);
}
Copy the code

Here format can be used as a factory function for the decorator function, since format returns a decorator function. The above method defines the metadata Sysmbol(“format”). The reason for using Sysmbol is to prevent duplicate fields in the metadata. Format defines the ability to fetch the corresponding fields in the metadata.

Next, let’s use the corresponding metadata in the class:

class Greeter {
    @format("Hello, %s")
    name: string;

    constructor(name: string) {
        this.name = message;
    }
    sayHello() {
        let formatString = getFormat(this, "name");
        return formatString.replace("%s", this.name);
    }
}

const g = new Greeter("Jony");
console.log(g.sayHello());
Copy the code

In the preceding example, we execute @format(“Hello, %s”) in the name property’s decorator factory function, returning a decorator function that modifies the name property of the Greeter class, writing the value of the “name” property to “Hello, %s”.

GetFormat (this,”name”) getFormat(this,”name”) getString “Hello,%s”

Reference list:

Decorators in the TypeScript & metadata reflection: four zhuanlan.zhihu.com/p/42220487 from novice to expert

Understand the TypeScript decorator zhuanlan.zhihu.com/p/65764702

Annotations and serious face 】 【 decorator zhuanlan.zhihu.com/p/22277764 dribs and drabs

Design patterns in Typescript: Decorators github.com/fortheallli…

Reprint the home station article from Java annotations to ramble to typescript decorator, annotations and decorators, please indicate the source: www.zhoulujun.cn/html/webfro…