Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”

Decorator pattern means without changing the original structure and function under the premise of adding new functionality for the object model, such as buy a semifinished product room to decorate, then can add some cool on interior lighting, plus some smart devices, in this process, we will not modify the original structure and function of the house and It’s just a little decoration on top of what we wanted

A decorator

Decorator mode is a common usage scenario in JS, and decorators are already supported in JS

A Decorator is a class-related syntax for annotating or modifying classes and class methods. Many object-oriented languages have this capability, and there is currently a proposal to introduce it into ECMAScript.

The adornment of the class

Decorators can be used to decorate entire classes

function decoratorAnimal(target) {
    target.prototype.name = "animal"; // Add instance attributes
    target.prototype.eat = function () { // Add instance methods
        console.log("Eat something...");
    };
}

@decoratorAnimal
class Animal {
    constructor(){}}const animal = new Animal();
console.log(animal.name); // animal
animal.eat(); // Eat something ~ ~ ~
Copy the code

The target argument to decoratorAnimal is the constructor itself. Adding properties and methods to prototype adds properties and methods to Animal

Note that the decorator changes the behavior of the class at compile time, not run time. This means that the decorator can run the code at compile time. That is, decorators are essentially functions that are executed at compile time.

Decoration of instance properties and methods

Decorators can decorate not only classes but also class properties.

function decoratorSleep(target, key, descriptor) {
    descriptor.enumerable = true
    return descriptor
}

function decoratorName(target, key) {
    descriptor.protoName = 'protoName';
}

class Animal {
    @decoratorSleep
    sleep() {}

    @decoratorName
    name = "nordon";
}
Copy the code

The function’s decoratorSleep takes three arguments

Targe: equivalent to animal. prototype, the prototype object of the current decorator class

Key: Equivalent to sleep, represents the name of the property to be decorated

Descriptor: Represents the property description object of the second parameter, which is as follows

{
    value: specifiedFunction,
    enumerable: false.configurable: true.writable: true
}
Copy the code

Therefore, the above decorator is equivalent to

decoratorSleep(Animal.prototype, 'sleep', {
    value: specifiedFunction,
    enumerable: false.configurable: true.writable: true
})
Copy the code

In fact, one of the most frequently used parameters is descriptor, which is what we call attribute descriptor objects, which is object.defineProperty

So the above code can also be expressed as:

Object.defineProperty(Animal.prototype, 'sleep', {
    value: specifiedFunction,
    enumerable: false.configurable: true.writable: true
});
Copy the code

Instance attributes: when adornment descriptor. ProtoName assignment is equivalent to Animal. The prototype. ProtoName assignment

Decoration of static properties and methods

function decoratorEat(target, key, descriptor) {}function decoratorName(target, key) {
    descriptor.staticName = 'staticName';
}

class Animal {
    @decoratorName
    static name = "nordon";

    @decoratorEat
    eat(){}}Copy the code

Target: Points to the constructor of the current decoration class, unlike instance decoration

The meanings of key and descriptor are the same

Realize the readonly

Use a decorator to modify the properties of a class so that the properties of the class are read-only and cannot be modified

function readonly(target, key) {
    Object.defineProperty(target, key, {
        writable: false})}class Animal {
    @readonly
    age = 12;
}

const animal = new Animal();
console.log(animal.age);
animal.age = 18;
Copy the code

The output of the above code can be printed normally on the console, but when you try to change its value to 18, you will find that the change fails because writable is set to false

Using decorators can help us do a lot of extra things during development, and good libraries are used, such as Mobx, etc