• JS中的Minix和装饰器实现


    Minix和装饰器

    Mixin

    Mixin 是面向对象语言中一种常用的设计模式,通常称之为组合,在js中通常使用一个中间的继承对象实现。

    A对象有功能a,C对象需要继承自A对象并添加x功能,

    解决办法1:我们可以使用C继承自A,再在C上定义x功能。但是如果D类型需要继承自B类型,同样也需要该x功能,我们就只能重写一遍功能。

    解决方法2:将x功能进行封装到一个Mixin函数中,Mixin函数接受类型A作为参数,然后在这个Mixin函数中创建一个新的类型Temp,Temp继承A并添加该x功能。这样C只需要继承这个新建的Temp就可以同时拥有A和x功能了。这种方式将类型A作为参数。同样的,如果B类型的子类想添加这个x功能,只需要将B作为参数传入这个Mixin函数,然后继承这个函数的返回值。

    代码简单实现

    class A {                // 普通类型A,他只能打印它的x属性,无法打印y和z属性
        constructor(x, y, z){
            this.x = x
            this.y = y
            this.z = z
            this.showX = () => {console.log(this.x)}
        }
    }
    
    function MixinShowY (SupCls){  // 可以打印y属性功能的函数,接受一个类型为参数
        class Tempcls extends SupCls{
            constructor(...args){
                super(...args)
                this.showY = () => {console.log(this.y)}
            }
        } 
        return Tempcls    // 返回值为一个类 
    }
    
    class C extends MixinShowY(A){}  
    // MixinShowB(A) 的返回值为一个类,可以被C继承,继承后同时拥有MixinShowB和A的功能
    

    在MixinShowB函数中,接受一个类作为参数来创建一个新的类型并添加功能showB,任何一个类型都可以被传入,然后返回新的类型并添加功能。便实现了这个函数功能的复用。

    Mixin叠加
    上面中z属性无法被打印,我们可以继续定义Minix函数添加这个功能

    function MixinShowZ (SupCls){  // 增加可以打印y属性功能的函数,接受一个类型为参数
        class Tempcls extends SupCls{
            constructor(...args){
                super(...args)
                this.showZ = () => {console.log(this.Z)}
            } 
        }
        return Tempcls    // 返回值为一个类 
    }
    
    class D extends MixinShowY(C){}
    // 或者
    class D extends MixinShowZ(MixinShowZ(A)){}
    
    obj = new D(1,2,3)
    obj.showX()
    obj.showY()
    

    上面的两种写法效果相同,第二种在A的基础上连续使用两次包装Mixin。获得了ShowY和ShowZ两个功能;

    此时如果想定义一个类B,他需要在A的基础上增加ShowZ方法,而不需要ShowY,只需要

    class B extends MixinShowZ(A){}
    

    需要哪种功能,就使用该功能对应的Mixin函数混入即可。

    装饰器

    装饰器语法在ES7中的定义,它是一个语法糖,依赖于ES5的Object.defineProperty方法,由于是ES7中的语法,需要使用babel将代码转译为ES5以前的,可以在babel官网在线转译少量代码,也可以在本机上搭建离线的转译环境。可以查看博主的JS模块化管理及babel离线环境搭建

    装饰器,顾名思义就是可以为一个对象添加某种功能的包装器,在目前JS中只有使用class定义的类才能使用装饰器

    继续上面的示例,我们为A类添加一个ShowY的功能

    function addShowY(cls){  // 装饰器函数
        class Temp extends cls{
            constructor(...args){
                super(...args)
                this.showY = () => {console.log(this.y)}
            }
        }
        return Temp
    }
    
    @addShowY  // 等价于 A = addshowY(A),装饰后A标识符已经指向了addShowY的返回值,一个新的类
    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()    // 调用成功
    

    任何需要这个功能类,都可以使用这个装饰器进行装饰

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

    带参装饰器

    我们还可以使用带参数的装饰器,这需要对象装饰器函数进行些许的改变,想象一下这个带参装饰器函数未来的使用方式应该是下面这样。

    @addname("root")   // 为类添加一个family属性,这个family可以自己指定。等价于C = addname(root)(C)
    class C(){}        // 这样C 类将会拥有一个指定的famliy属性
    

    从用法乐意看出,这个addname函数将会被调用,调用后的返回值是一个接受类的函数,然后返回值为一个类,即

    function addname(family){
        
        function func(cls){     // 
            class Temp extends cls{
                constructor(...args){
                    super(...args)
                    this.family = family
                }
            }
            return Temp  // func()函数调用,返回新的类
        }
        return func    // addname调用后返回一个函数,这个函数执行 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)
    

    同样的,这个装饰器可以用于任何类,并且很久传入的参数不同,类中被装饰的属性值不同,通过这种技术,我们可以将一些通用的功能抽象到一个装饰器函数中,对需要使用该功能类使用装饰器注入功能,从而避免了反复的在不同的类中实现相同的代码,从而然代码更加简洁可读。

  • 相关阅读:
    Windows 10 WiFi 连接故障 排查及解决
    bash 获取当前运行文件脚本的路径
    Ubuntu 添加左侧栏 快捷启动
    Ubuntu 下 kazam 录屏 没声音解决方案
    Python学习笔记-Day61和Day62-Django模板系统
    Python学习笔记-Day60-装饰器
    Python学习笔记-Day33-进程
    Python学习笔记-Day33-操作系统与进程的基本概念
    Python学习笔记-Day32-socketserver模块实现TCP协议的server与多个client端连接
    Python学习笔记-Day31-黏包的原理及解决办法-struct模块
  • 原文地址:https://www.cnblogs.com/k5210202/p/13819464.html
Copyright © 2020-2023  润新知