• ES6 |修饰器Decorator


    修饰器(Decorator)是一个函数,用来修改类的行为。修饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。这意味着,修饰器能在编译阶段运行代码

    在这里插入图片描述

    类的修饰

    //修饰器函数1:为类加上静态属性isTestable
    //修饰器函数的第一个参数,就是所要修饰的目标类
    function testable(target) {
      target.isTestable = true;
    }
    
    //修饰类的行为。写在类上方,表示修饰器的目标是这整个类
    @testable
    class MyTestableClass {}
    
    console.log(MyTestableClass.isTestable) // true
    
    //修饰器函数2:添加实例属性
    function testable(target) {
      target.prototype.isTestable = true;
    }
    
    @testable
    class MyTestableClass {}
    
    let obj = new MyTestableClass();
    obj.isTestable // true
    

    修饰器的实际行为

    @decorator
    class A {}
    
    // 等同于
    class A {}
    A = decorator(A) || A;
    

    类的方法的修饰

    class Person {
      @readonly
      name() { return `${this.first} ${this.last}` }
    }
    

    修饰器的参数

    修饰器函数一共可以接受三个参数:

    • 所要修饰的目标对象
    • 所要修饰的属性名
    • 该属性的描述对象
    function nonenumerable(target, name, descriptor) {
      descriptor.enumerable = false; //修改了描述对象的属性enumerable,使得不可遍历
      return descriptor;
    }
    
    class Person {
      @nonenumerable //修饰该属性
      get kidCount() { return this.children.length; }
    }
    

    @log修饰器例子:输出日志

    function log(target, name, descriptor) {
      var oldValue = descriptor.value;
      descriptor.value = function() {
        console.log(`Calling "${name}" with`, arguments);
        return oldValue.apply(null, arguments);
      };
      return descriptor;
    }
    
    class Math {
      @log
      add(a, b) {
        return a + b;
      }
    }
    
    
    const math = new Math();
    // passed parameters should get logged now
    math.add(2, 4);
    

    修饰器有注释作用

    @testable
    class Person {
      @readonly
      @nonenumerable
      name() { return `${this.first} ${this.last}` }
    }
    //可看出Person类是可测试的,而name方法是只读和不可枚举的
    

    core-decorators.js

    core-decorators.js是一个第三方模块,提供了几个常见的修饰器,通过它可以更好地理解修饰器

    • @autobind:使得方法中的this对象,绑定原始对象

      import { autobind } from 'core-decorators';
      
      class Person {
        @autobind
        getPerson() {
          return this;
        }
      }
      
      let person = new Person(); 
      let getPerson = person.getPerson;
      
      getPerson() === person; 	// true
      
    • @readonly:使得属性或方法不可写

      import { readonly } from 'core-decorators';
      
      class Meal {
        @readonly
        entree = 'steak';
      }
      
      var dinner = new Meal();
      dinner.entree = 'salmon';
      // Cannot assign to read only property 'entree' of [object Object]
      
    • @override:检查子类的方法是否正确覆盖了父类的同名方法,如果不正确会报错

      import { override } from 'core-decorators';
      
      class Parent {
        speak(first, second) {}
      }
      
      class Child extends Parent {
        @override
        speak() {}// SyntaxError: Child#speak() does not properly override Parent#speak(first, second)
      }
      
    • @deprecate (别名@deprecated):在控制台显示一条警告,表示该方法将废除

      import { deprecate } from 'core-decorators';
      
      class Person {
        @deprecate
        facepalm() {}
      
        @deprecate('We stopped facepalming')
        facepalmHard() {}
      
        @deprecate('We stopped facepalming', { url: 'http://knowyourmeme.com/memes/facepalm' })
        facepalmHarder() {}
      }
      
      let person = new Person();
      
      person.facepalm();
      // DEPRECATION Person#facepalm: This function will be removed in future versions.
      
      person.facepalmHard();
      // DEPRECATION Person#facepalmHard: We stopped facepalming
      
      person.facepalmHarder();
      // DEPRECATION Person#facepalmHarder: We stopped facepalming
      //
      //     See http://knowyourmeme.com/memes/facepalm for more details.
      //
      

    Mixin

    在修饰器的基础上,可以实现Mixin模式。所谓Mixin模式,就是对象继承的一种替代方案,中文译为“混入”(mixin),意为在一个对象之中混入另外一个对象的方法

    以往写法:

    //一个对象,里面有个foo方法
    const Foo = {
      foo() { console.log('foo') }
    };
    
    //一个类
    class MyClass {}
    
    //通过Object.assign在类的原型对象上添加Foo对象上的方法添加进去,
    Object.assign(MyClass.prototype, Foo);
    
    let obj = new MyClass();
    obj.foo() // 'foo'
    

    现在:部署一个通用脚本mixins.js,将mixin写成一个修饰器

    export function mixins(...list) {
      return function (target) {
        Object.assign(target.prototype, ...list);
      };
    }
    //原理:传入参数(这里是对象类型),然后将该参数中的方法添加在类的原型对象中
    

    使用

    import { mixins } from './mixins';
    
    const Foo = {
      foo() { console.log('foo') }
    };
    
    @mixins(Foo) //传入Foo对象,把Foo对象中foo方法的添加在MyClass的原型对象中
    class MyClass {}
    
    let obj = new MyClass();
    obj.foo() // "foo"
    

    Trait修饰器

    效果与Mixin类似,但是提供更多功能,比如防止同名方法的冲突、排除混入某些方法、为混入的方法起别名等等

    下面采用traits-decorator这个第三方模块作为例子。这个模块提供的traits修饰器,不仅可以接受对象,还可以接受ES6类作为参数

    import { traits } from 'traits-decorator';
    
    //TFoo类中有foo方法
    class TFoo {
      foo() { console.log('foo') }
    }
    
    //TBar对象中有bar方法
    const TBar = {
      bar() { console.log('bar') }
    };
    
    //把TFoo类中有foo方法和TBar对象中有bar方法加进MyClass类的原型对象中
    @traits(TFoo, TBar)
    class MyClass { }
    
    let obj = new MyClass();
    obj.foo() // foo
    obj.bar() // bar
    

    另外,Trait不允许“混入”同名方法

    Babel转码器的支持

    目前,Babel转码器已经支持Decorator。

    首先,安装babel-corebabel-plugin-transform-decorators。由于后者包括在babel-preset-stage-0之中,所以改为安装babel-preset-stage-0亦可

    $ npm install babel-core babel-plugin-transform-decorators
    

    然后,设置配置文件.babelrc

    {
      "plugins": ["transform-decorators"]
    }
    

    这时,Babel就可以对Decorator转码了

    脚本中打开的命令如下

    babel.transform("code", {plugins: ["transform-decorators"]})
    
  • 相关阅读:
    Linux命令记录-Tomcat(七)
    Linux命令记录-PostgreSql(六)
    Linux命令记录-Mysql(五)
    Linux Crontab实现定时任务
    Linux命令记录-Java环境(四)
    Linux命令记录-防火墙(三)
    Linux命令记录-服务相关(二)
    Linux命令记录-环境准备(一)
    Linux 系统安装,磁盘分区要点
    java之Collection类
  • 原文地址:https://www.cnblogs.com/sanhuamao/p/13595816.html
Copyright © 2020-2023  润新知