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;
- }
来源: http://www.bubuko.com/infodetail-2770941.html