• 技术文章 >web前端 >前端问答

    es6中什么是装饰器

    青灯夜游青灯夜游2022-03-23 13:58:31原创164

    在es6中,装饰器(Decorator)是一种与类(class)相关的语法,用来注释或修改类和类方法;装饰器其实就是一个编译时执行的函数,语法“@函数名”,通常放在类和类方法的定义前面。装饰器有两种:类装饰器和类方法装饰器。

    本教程操作环境:windows7系统、ECMAScript 6版、Dell G3电脑。

    装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

    这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

    ES6 装饰器

    在 ES6 中,装饰器(Decorator)是一种与类相关的语法,用来注释或修改类和类方法。

    装饰器其实就是一个函数,通常放在类和类方法的前面。

    装饰器对类的行为的改变,是代码编译时发生的,而不是在运行时;装饰器的本质就是编译时执行的函数

    装饰器可以用来装饰整个类

    @decorateClass
    class Example {
        @decorateMethods
        method(){}
    }

    在上面的代码中使用了两个装饰器,其中 @decorateClass() 装饰器用在类本身,用于增加或修改类的功能;@decorateMethods() 装饰器用在类的方法,用于注释或修改类方法。

    两种类型装饰器

    装饰器只能用于类和类的方法,不能用于函数,因为存在函数提升。

    装饰器只能用于类和类的方法,下面我们分别看下两种类型的装饰器的使用

    1、类装饰器

    类装饰器用来装饰整个类

    类装饰器的参数

    target: 类本身,也相当于是 类的构造函数:Class.prototype.constructor。

    @decorateClass
    class Example {
        //...
    }
    
    function decorateClass(target) {
        target.isTestClass = true
    }

    如上面代码中,装饰器 @decorateClass 修改了 Example 整个类的行为,为 Example 类添加了静态属性 isTestClass。装饰器就是一个函数,decorateClass 函数中的参数 target 就是 Example 类本身,也相当于是类的构造函数 Example.prototype.constructor.

    装饰器传参

    上面实现的装饰器在使用时是不能传入参数的,如果想要在使用装饰器是传入参数,可以在装饰器外面再封装一层函数

    @decorateClass(true)
    class Example {
        //...
    }
    
    function decorateClass(isTestClass) {
        return function(target) {
      target.isTestClass = isTestClass
      }
    }

    上面代码中实现的装饰器在使用时可以传递参数,这样就可以根据不同的场景来修改装饰器的行为。

    实际开发中,React 与 Redux 库结合使用时,常常需要写成下面这样。

    class MyReactComponent extends React.Component {}
    export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);

    有了装饰器,就可以改写上面的代码。

    @connect(mapStateToProps, mapDispatchToProps)
    export default class MyReactComponent extends React.Component {}

    2、类方法装饰器

    类方法装饰器用来装饰类的方法

    类方法装饰器的参数

    // descriptor对象原来的值如下
    {
      value: specifiedFunction,
      enumerable: false,
      configurable: true,
      writable: true
    };
    class Example {
        @log
        instanceMethod() { }
    
        @log
        static staticMethod() { }
    }
    
    function log(target, methodName, descriptor) {
      const oldValue = descriptor.value;
    
      descriptor.value = function() {
        console.log(`Calling ${name} with`, arguments);
        return oldValue.apply(this, arguments);
      };
    
      return descriptor;
    }

    如上面代码中,装饰器 @log 分别装饰了实例方法 instanceMethod 和 静态方法 staticMethod。@log 装饰器的作用是在执行原始的操作之前,执行 console.log 来输出日志。

    类方法装饰器传参

    上面实现的装饰器在使用时是不能传入参数的,如果想要在使用装饰器是传入参数,可以在装饰器外面再封装一层函数

    class Example {
        @log(1)
        instanceMethod() { }
    
        @log(2)
        static staticMethod() { }
    }
    
    function log(id) {
        return (target, methodName, descriptor) => {
        const oldValue = descriptor.value;
    
        descriptor.value = function() {
          console.log(`Calling ${name} with`, arguments, `this id is ${id}`);
          return oldValue.apply(this, arguments);
        };
    
        return descriptor;
      }
    }

    上面代码中实现的装饰器在使用时可以传递参数,这样就可以根据不同的场景来修改装饰器的行为。

    类装饰器与类方法装饰器的执行顺序

    如果在一个类中,同时使用装饰器修饰类和类的方法,那么装饰器的执行顺序是:先执行类方法的装饰器,再执行类装饰器。

    如果同一个类或同一个类方法有多个装饰器,会像剥洋葱一样,先从外到内进入,然后由内到外执行。

    // 类装饰器
    function decoratorClass(id){
        console.log('decoratorClass evaluated', id);
    
        return (target) => {
            // target 类的构造函数
            console.log('target 类的构造函数:',target)
            console.log('decoratorClass executed', id);
        }
    }
    // 方法装饰器
    function decoratorMethods(id){
        console.log('decoratorMethods evaluated', id);
        return (target, property, descriptor) => {
            // target 代表
    
            // process.nextTick((() => {
                target.abc = 123
                console.log('method target',target)
            // }))
            console.log('decoratorMethods executed', id);
    
        }
    }
    
    @decoratorClass(1)
    @decoratorClass(2)
    class Example {
        @decoratorMethods(1)
        @decoratorMethods(2)
        method(){}
    }
    
    /** 输入日志 **/
    // decoratorMethods evaluated 1
    // decoratorMethods evaluated 2
    // method target Example { abc: 123 }
    // decoratorMethods executed 2
    // method target Example { abc: 123 }
    // decoratorMethods executed 1
    // decoratorClass evaluated 1
    // decoratorClass evaluated 2
    // target 类的构造函数: [Function: Example]
    // decoratorClass executed 2
    // target 类的构造函数: [Function: Example]
    // decoratorClass executed 1

    如上面代码中,会先执行类方法的装饰器 @decoratorMethods(1) 和 @decoratorMethods(2),执行完后再执行类装饰器 @decoratorClass(1) 和 @decoratorClass(2)

    上面代码中的类方法装饰器中,外层装饰器 @decoratorMethods(1) 先进入,但是内层装饰器 @decoratorMethods(2) 先执行。类装饰器同理。

    利用装饰器实现AOP切面编程

    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 Maths {
        @log
        add(a, b) {
            return a + b;
        }
    }
    const math = new Maths();
    // passed parameters should get logged now
    math.add(2, 4);

    【相关推荐:javascript视频教程web前端

    以上就是es6中什么是装饰器的详细内容,更多请关注php中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    专题推荐:es6 装饰器
    上一篇:es6箭头函数要注意什么 下一篇:typescript跟es6有什么区别
    Web大前端开发直播班

    相关文章推荐

    • es6数组怎么清除所有元素• es6怎么比较2个数组的值是否相等• es6怎么判断数组是否为空• es6中三个点是什么意思• es6深度拷贝的几种实现方法是什么
    新人一分购

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网