美文网首页es6
ES7装饰器详解

ES7装饰器详解

作者: zhangAllen | 来源:发表于2019-12-05 20:43 被阅读0次

    本文将从以下几个角度解析装饰器:

    1. 装饰器模式;
    2. 装饰器的基本概念;
    3. 装饰器的类型;
    

    一、什么是装饰器模式:

    要想正确理解设计模式,首先必须明确它是为了解决什么问题而提出来的。

    那装饰器模式到底是为了解决什么问题呢?在我们的开发过程中我们会为了一些通用功能在多个不同的组件、接口或者类中使用,这个时候我们这些功能写到每个组件、接口或者类中,但是这样非常不利于维护。

    装饰器就是为了解决在不修改原本组件、接口或者类的时候为其添加额外的功能。

    从本质上看装饰器模式是一个包装模式((Wrapper Pattern),它是通过封装其他对象达到设计的目的的。

    react的高阶组件本质也是装饰器模式,以后会有一篇文章会专门详解react的高阶组件。

    理解了装饰器的能解决了什么问题,那我们一遍在什么情况下考虑使用装饰器模式呢?我的理解是:

    • 需要扩展一个类,为这个类附加一个方法或者属性的时候;
    • 需要修改一个类的功能,或者重构这个类中的某个方法;

    二、装饰器的基本概念:

    上面我们解释了什么是装饰器模式,下面我们将要ES7的装饰器的一些基本概念:如何定义装饰器、装饰器执行时机、装饰器类型。

    1、如何定义装饰器

    装饰器本质是一个函数,可以分为带参数和不带参数(也叫装饰器工厂),装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。

    @Test()
    class Hello {}
    
    function Test(target:any) {
        console.log("I am decorator.")
    }
    

    2、装饰器执行时机

    修饰器对类的行为的改变,是代码编译时发生的(不是TypeScript编译,而是js在执行机中编译阶段),而不是在运行时。这意味着,修饰器能在编译阶段运行代码。也就是说,修饰器本质就是编译时执行的函数

    3、装饰器的类型

    类装饰器、属性装饰器、方法装饰器、参数装饰器

    三、装饰器类型:

    • 类修饰器

    类装饰器一般主要应用于类构造函数,可以监视、修改、替换类的定义,装饰器用来装饰类的时候。装饰器函数的第一个参数,就是所要装饰的目标类本身。

    a、添加静态属性或方法

    @Test()
    class Hello {}
    
    function Test(target) {
       target.a = 1;
    }
    
    let o = new Hello();
    
    console.log(o.a) ==>1
    

    b、添加实例属性或方法

    @Test()
    class Hello {}
    
    function Test(target) {
       target.prototype.a = 1;
       target.prototype.f = function(){
           console.log("新增加方法")
       };
    
    }
    
    let o = new Hello();
    o.f() ==>"新增加方法"
    console.log(o.a) ==>1
    

    c、装饰器工厂(函数柯里化)

    很多文章说装饰器工厂是闭包,其实不准确,关于高阶函数、闭包、函数柯里化可以参考:
    理解运用JS的闭包、高阶函数、柯里化

    @Test('hello')
    class Hello {}
    
    function Test(str) {
       return function(){
            target.prototype.a = str;
            target.prototype.f = function(){
                console.log(str)
            };
       }
    
    }
    
    let o = new Hello();
    o.f() ==>"hello"
    console.log(o.a) ==>"hello"
    

    d、重载构造函数

    @Test('hello')
    class Hello {
        constructor(){
            this.a= 1
        }
        f(){
             console.log('我是原始方法',this.a)
        }
    
    }
    
    function Test(target) {
      return class extends target{
          f(){
             console.log('我是装饰器方法',this.a)
        }
      }
    
    }
    
    let o = new Hello();
    o.f() ==>"我是装饰器方法",1
    
    • 方法装饰器

    它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义。
    方法装饰会在运行时传入下列3个参数:

    1. target:对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
    2. key: 成员的名字。
    3. descriptor:成员的属性描述符。
    descriptor:
    // {
    //   value: specifiedFunction,
    //   enumerable: false,
    //   configurable: true,
    //   writable: true
    // };
    
    

    方法装饰器最后必须返回descriptor

    function nameDecorator(target, key, descriptor) {
        descriptor.value = () => {
            return 'jake';
        }
        return descriptor;
    }
    
    class Person {
        constructor() {
            this.name = 'jake'
        }
        @nameDecorator
        getName() {
            return this.name;
        }
    }
    
    let p1 = new Person();
    console.log(p1.getName())
    
    
    
    另外一个经典例子
    
    class Math {
      @log
      add(a, b) {
        return a + b;
      }
    }
    
    function log(target, name, descriptor) {
      var oldValue = descriptor.value;
    
      descriptor.value = function(...list) {
        console.log(list);
        console.log(`Calling ${name} with`, ...list);
        return oldValue.call(this, ...list);
      };
    
      return descriptor;
    }
    
    const math = new Math();
    
    // passed parameters should get logged now
    let result = math.add(2, 4);
    
    console.log(result)
    

    相关文章

      网友评论

        本文标题:ES7装饰器详解

        本文链接:https://www.haomeiwen.com/subject/nppjgctx.html