美文网首页JavaScript Rocks
使用 ECMAScript 中的 Decorators

使用 ECMAScript 中的 Decorators

作者: FantasyShao | 来源:发表于2016-09-07 10:59 被阅读42次

    原文地址:http://blog.fantasy.codes/javascript/2016/09/05/use-js-decorators/ 转载请注明出处。

    Decorators 亦即「装饰器」,最早接触到这个概念是在学生时代学习 Python 的时候。

    查阅 ECMA262 的资料可以发现,ECMAScript 提案中的 decorator 分为好几种类型:

    • Class and Property decorators
    • Method Parameter decorators
    • Function Expression decorators

    其中第一种已经处于 stage-2,而下面两种仍处于 stage-0 -- 也就是说我们可能在不远的将来就能使用到原生的 "Class and Property decorators"。当然,不同类型的装饰器的装饰对象不同,应用场景也不同 -- 本文将挑选一些场景来主要讲述如何使用和编写不同的函数装饰器。

    本来想把标题写成「使用 ES7 Decorators」,后来意识到 Decorators 还不一定在哪个版本的 ECMAScript 中出现,索性把题目改成了「使用 ECMAScript 的 Decorators」

    先来看看一个简单的使用装饰器的例子:

    function log (target, key, descriptor) {
      console.log(`Invoking method ${key}`);
      return descriptor;
    }
    
    class Foo {
      @log
      bar () {
        console.log('baaaaar');
      }
    }
    
    let foo = new Foo();
    foo.bar();
    
    // Console:
    // "Invoking method bar"
    // "baaaaar"
    

    可以看到 @log 装饰器用来修饰方法,输出一个 Invoking method ${key} log

    装饰器的实现方法

    通过上文的案例可以看到,装饰器实际上也是一个函数,通过固定的参数可以实现对被装饰的类或函数进行「装饰」。

    再来看看刚才编写的 @log 装饰器:

    function log (target, key, descriptor) {
      console.log(`Invoking method ${key}`);
      return descriptor;
    }
    

    对于这个函数,我们传递了三个参数,target, keydescriptor:

    • target: 装饰器的目标对象
    • key: 目标的名称
    • descriptor: 对应 Object.defineProperty 方法中的 descriptor,即对对象的一些描述,如 configurable, enumerable, writable

    接下来看看一个修改对象描述符 (descriptor) 的装饰器方法:

    function rewritable (target, key, descriptor) {
      descriptor.writable = false;
      return descriptor;
    }
    
    class Foo {
      @rewritable
      bar () {
        console.log('baaaaar');
      }
    }
    
    let foo = new Foo();
    foo.bar();
    foo.bar = () => { console.log('2333333'); };
    foo.bar();
    
    // Console:
    // 'baaaaar'
    // '2333333'
    

    这个例子中,@rewritable 装饰器改写了对象上的方法使得 foo.bar 方法在运行时被改写(对象的 writable 属性默认值为 false)。

    带参数的装饰器

    接下来看看如何实现、使用带参数的装饰器。例如我们可以实现一个装饰器,通过给装饰器传入参数来决定改对象是否为 writalbe

    function writable (value) {
      return function (target, value, descriptor) {
        descriptor.writable = value;
        return descriptor;
      }
    }
    
    class Foo {
      @writable(true)
      bar () {
        console.log('baaaaar');
      }
    }
    

    此处的 @writable 接受一个 value 参数,按需处理了之后返回一个普通的装饰器函数。当然,你可以给装饰器传入多个参数,来实现更多的功能。

    总结

    本文中,我们主要学习了 ES 中的装饰器概念、实现方式和调用方法。

    装饰器的原理虽然简单,但是可以通过更为优雅的语法来实现类似 Python 装饰器乃至 Java 中注解的功能。之后将研究一些更为实用的装饰器实现和使用方法,当然这一切现在仍需要借助 Babel

    参考资料

    相关文章

      网友评论

        本文标题:使用 ECMAScript 中的 Decorators

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