1. 程式人生 > >ES6裝飾器Decorator基本用法

ES6裝飾器Decorator基本用法

alua map white eval 更多 ast https specified 執行順序

1. 基本形式

@decorator
class A {}

// 等同於

class A {}
A = decorator(A);

裝飾器在javascript中僅僅可以修飾類和屬性,不能修飾函數。
裝飾器對類的行為的改變,是代表編譯時發生的,而不是在運行時。
裝飾器能在編譯階段運行代碼。
裝飾器是經典的AOP模式的一種實現方式。

2. 裝飾器的執行順序

同一處的多個裝飾器是按照洋蔥模型,由外到內進入,再由內到外執行

function dec(id){
    console.log(‘evaluated‘, id);
    return (target, property, descriptor) => console.log(‘executed‘, id);
}

class Example {
    @dec(
1) @dec(2) method(){} } // evaluated 1 // evaluated 2 // executed 2 // executed 1

3. 常見的裝飾器的例子

1. 類可測試,添加一個屬性

@testable
class MyTestableClass {
  // ...
}

function testable(target) {
  target.isTestable = true;
}

MyTestableClass.isTestable // true

若要進行更多的配置,可以使用高階函數,增加參數,相當於一個工廠方法,用於生產特定類型的裝飾器,例如:

//
testable是一個Factory function testable(isTestable) { return function(target) { target.isTestable = isTestable; } } @testable(true) class MyTestableClass {} MyTestableClass.isTestable // true @testable(false) class MyClass {} MyClass.isTestable // false

2. 屬性readonly裝飾器

class Person {
  @readonly
  name() { 
return `${this.first} ${this.last}` } } function readonly(target, name, descriptor){ // descriptor對象原來的值如下 // { // value: specifiedFunction, // enumerable: false, // configurable: true, // writable: true // }; descriptor.writable = false; return descriptor; }

3. 日誌裝飾器

class Math {
  @log
  add(a, b) {
    return a + b;
  }
}

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;
}

const math = new Math();

// passed parameters should get logged now
math.add(2, 4);

3. 實現memoize,備用錄模式

class Person {
  @memoize
  get name() { return `${this.first} ${this.last}` }
  set name(val) {
    let [first, last] = val.split(‘ ‘);
    this.first = first;
    this.last = last;
  }
}

let memoized = new WeakMap();
function memoize(target, name, descriptor) {
  let getter = descriptor.get, setter = descriptor.set;

  descriptor.get = function() {
    let table = memoizationFor(this);
    if (name in table) { return table[name]; }
    return table[name] = getter.call(this);
  }

  descriptor.set = function(val) {
    let table = memoizationFor(this);
    setter.call(this, val);
    table[name] = val;
  }
}

function memoizationFor(obj) {
  let table = memoized.get(obj);
  if (!table) { table = Object.create(null); memoized.set(obj, table); }
  return table;
}   

參考:https://www.cnblogs.com/goloving/p/8001530.html
   https://www.cnblogs.com/whitewolf/p/details-of-ES7-JavaScript-Decorators.html

ES6裝飾器Decorator基本用法