JavaScriptデコレーション

2673 ワード

前言
  • 多くのオブジェクト向けにdecorator(装飾器)関数があります.例えばpythonではdecorator関数でコードを強化することもできます.decoratorは高次関数に相当し、1つの関数を受信し、1つの装飾された関数を返します.
  • の次のコードの例は、デザイナlogDecoratorを使用して関数をカプセル化し、呼び出されるたびにコンソールに呼び出された関数名と時間が表示されます.
  • import time
        def logDecorator(func):
            def wrapper(*args, **kw):
                print('%s %s():' % ('    ', func.__name__))
                return func(*args, **kw)
            return wrapper
    @logDecorator
    def now():
        print(time.ctime(time.time()))
    if __name__ == '__main__':
        now()
    

    JavaScriptに戻る
  • javascriptにもdecoratorに関する提案がありますが、現在nodeおよび各ブラウザではサポートされていません.babelプラグインをインストールしてコードを変換するしかありません.プラグインの名前はこれ:transform-decorators-legacyです.
  • babel公式サイトのオンライン試用で、transform-decorators-legacyプラグインをインストールすると、エスケープ後のコードが表示されます.以下の
  • //      
    @testable
    class MyTestableClass {
      // ...
    }
    
    @testable
    class MyTestableClass2 {
      // ...
    }
    
    
    function testable(target) {
      target.isTestable = true;
    }
    
    MyTestableClass.isTestable // true
    
  • 転義後:
  • "use strict";
    
    var _class, _class2;
    
    function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
    
    var MyTestableClass = testable(_class = function MyTestableClass() {
      _classCallCheck(this, MyTestableClass);
    }) || _class;
    
    var MyTestableClass2 = testable(_class2 = function MyTestableClass2() {
      _classCallCheck(this, MyTestableClass2);
    }) || _class2;
    
    function testable(target) {
      target.isTestable = true;
    }
    
    MyTestableClass.isTestable; // true
    
  • から分かるように、jsのアクセサリーは、アクセサリー関数を呼び出し、クラスclassをカプセル化することである.アクセラレータ関数に戻り値がある場合は、その値を元のclassに割り当て、戻り値がない場合は元のclassに割り当てます.

  • 装飾類の属性
  • pythonのデコレーションコードが見え、1つの関数をデコレーションしていますが、jsではできません.具体的な原因は、関数宣言の昇格にあるようです.だからclass、またはclassの属性しか装飾できません.
  • function readonly(target, name, descriptor){
      descriptor.writable = false;
      return descriptor;
    }
    class Person {
      @readonly
      name() { return `${this.first} ${this.last}` }
    }
    
  • 上記のコードはclassのname属性を装飾し、このときのdecorator関数は3つのパラメータ:クラスのプロトタイプオブジェクト、装飾された属性、装飾された属性の修飾子オブジェクトを受信する.そしてこれらのパラメータに基づいて装飾します.
  • decorator装飾属性の場合、実際には戻り値を返さなくてもよいし、複数のdecoratorを併用して同一属性を装飾することもサポートされる.
  • class Person {
      @readonly
      @validate
      name() { return `${this.first} ${this.last}` }
    }
    

    小結
  • es 6がclassの概念を提案するにつれて、いくつかのシーンではclassまたはclassの属性のために追加の修飾または注釈が必要になる.decoratorの役割は、class宣言およびclass属性のメタプログラミングであり、注釈でもある.