Implementation of Minix and decorator in JS

Minix and trimmer

Mixin

Mixin is a common design pattern in object-oriented language, which is usually called composition. An intermediate inheritance object is usually used in js.

Object a has function a, and Object C needs to inherit from object a and add x function,

Solution 1: we can use C to inherit from A, and then define x function on C. However, if type D needs to inherit from type B and also needs the X function, we can only rewrite the function once.

Solution 2: encapsulate the X function into a Mixin function. The Mixin function accepts type A as a parameter, and then create a new type temp in the Mixin function. Temp inherits a and adds the X function. In this way, C only needs to inherit the new temp to have both a and X functions. This method takes type A as a parameter. Similarly, if a subclass of type B wants to add this x function, it only needs to pass B as a parameter into the Mixin function, and then inherit the return value of the function.

Simple code implementation

class A {                // For ordinary type A, it can only print its x attribute, but cannot print its y and z attributes
    constructor(x, y, z){
        this.x = x
        this.y = y
        this.z = z
        this.showX = () => {console.log(this.x)}
    }
}

function MixinShowY (SupCls){  // Function that can print y attribute function and accept a parameter of type
    class Tempcls extends SupCls{
        constructor(...args){
            super(...args)
            this.showY = () => {console.log(this.y)}
        }
    } 
    return Tempcls    // The return value is a class 
}

class C extends MixinShowY(A){}  
// The return value of MixinShowB(A) is A class that can be inherited by C. After inheritance, it has the functions of MixinShowB and A at the same time

In MixinShowB function, take a class as a parameter to create a new type and add function showB. Any type can be passed in, and then return the new type and add function. The reuse of this function is realized.

Mixin stack
The z attribute in the above cannot be printed. We can continue to define the Minix function and add this function

function MixinShowZ (SupCls){  // Add a function that can print y attribute and accept a parameter of type
    class Tempcls extends SupCls{
        constructor(...args){
            super(...args)
            this.showZ = () => {console.log(this.Z)}
        } 
    }
    return Tempcls    // The return value is a class 
}

class D extends MixinShowY(C){}
// perhaps
class D extends MixinShowZ(MixinShowZ(A)){}

obj = new D(1,2,3)
obj.showX()
obj.showY()

The above two writing methods have the same effect. The second one uses Mixin for two consecutive times on the basis of A. Two functions of ShowY and ShowZ are obtained;

At this time, if you want to define A class B, you need to add ShowZ method on the basis of A instead of ShowY, just

class B extends MixinShowZ(A){}

You can use the Mixin function corresponding to this function to mix in any function you need.

Decorator

The definition of decorator syntax in ES7 is a syntax sugar, which depends on the object of ES5 The defineproperty method, because it is the syntax in ES7, needs to use babel to translate the code into that before ES5. You can translate a small amount of code online on babel's official website or build an offline translation environment on the machine. You can view the blogger's JS modular management and babel offline environment construction

Decorator, as its name suggests, is a wrapper that can add some functions to an object. At present, only classes defined by class can use decorators in JS

Continuing with the above example, we add a ShowY function for class A

function addShowY(cls){  // Decorator function
    class Temp extends cls{
        constructor(...args){
            super(...args)
            this.showY = () => {console.log(this.y)}
        }
    }
    return Temp
}

@addShowY  // Equivalent to A = addshowY(A). After decoration, the A identifier has pointed to the return value of addShowY, A new class
class A {
    constructor(x, y, z){
        this.x = x
        this.y = y
        this.z = z
        this.showX = () => {console.log(this.x)}
    }
}

a = new A(1,2,3)
a.showY()    // Call succeeded

Anyone who needs this function class can use this decorator for decoration

@addShowY
class B{
    constructor(a, b, c, d){
        this.a = a
        this.b = b
        this.c = c
        this.d = d
    }
}

Decorative device with reference

We can also use the decorator with parameters, which requires some changes to the object decorator function. Imagine the future use of the decorator function with parameters as follows.

@addname("root")   // Add a family attribute to the class, which can be specified by yourself. Equivalent to C = addname(root)(C)
class C(){}        // In this way, class C will have a specified famliy attribute

From the usage, we can see that this addname function will be called. The return value after calling is a function that accepts a class, and then the return value is a class, that is

function addname(family){
    
    function func(cls){     // 
        class Temp extends cls{
            constructor(...args){
                super(...args)
                this.family = family
            }
        }
        return Temp  // func() function call to return a new class
    }
    return func    // addname returns a function after calling, which executes func(cls)
}

@addname("root")
class C(){
    constructor(x,y){
        this.x = x
        this.y = y
    }
}

let obj = new C(1,2)

console.log(obj.family)

Similarly, this decorator can be used for any class, and the parameters passed in for a long time are different, and the attribute values decorated in the class are different. Through this technology, we can abstract some general functions into a decorator function, and use the decorator injection function for the class that needs to use this function, so as to avoid repeatedly implementing the same code in different classes, so that the code is more concise and readable.

Tags: Front-end

Posted by dinosoup on Wed, 11 May 2022 12:38:44 +0300