decorator 装饰器

js 目前也有类似于 Java 和 Python 的装饰器概念, 主要写法如下

1
2
3
4
5
6
7
8
9
@frozen
class Foo {
  @configurable(false)
  @enumerable(true)
  method() {}

  @throttle(500)
  expensiveMethod() {}
}

目前在 Node.js 中还无法使用这个特性, 那么他是怎么实现的呢? 关键点在于 Object.defineProperty 都是用这个方法实现的

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Person {
  name() {
    return 'old name';
  }
}

Object.defineProperty(Person.prototype, 'name', {
  value() {
    return 'new name';
  },
  enumerable: false,
  configurable: true,
  writable: true,
}); // 相当于重新定于了Person的name方法

const p = new Person();
console.log(p.name());

这个方式完全重新定义了 name 方法, 如果我的需求是 在原有的方法上做一点扩展, 那该怎样实现呢?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Person {
  constructor() {
    this.age = 17;
  }
  getAge() {
    return this.age;
  }
}

function createAgeDecorator(target, name) {
  const func = target[name]; // 先保存旧的方法
  const ageDescroptor = {
    value() {
      const age = func.apply(this); // 调用旧的方法
      if (age < 18) {
        console.log('这个人还没有成年!');
      }
      return age;
    },
    enumerable: false,
    configurable: true,
    writable: true,
  };
  Object.defineProperty(target, name, ageDescroptor); // 在类上新定义方法
}

createAgeDecorator(Person.prototype, 'getAge'); // Person 类的getAge上添加装饰器

const p = new Person();
console.log(p.getAge());

在 Person 类的 getAge 方法上增加了装饰器, 如果年龄不满 18 岁会有提示

参考链接: Javascript 中的装饰器