Javascript Decorator

JS的 decorator 已经到了Stage 2 Draft的阶段。并且在 Babel 7 中得到支持。

修饰器其实在其他的语言中已经得到很完善的实现了,比如 Python。修饰器主要的功能是将辅助性的功能和核心功能分开。例如,核心功能可以是主营业务,辅助功能可以是身份验证,信息缓存或者日记功能。这些辅助功能大部分是可以共享的,并且和主要功能没有什么联系,所以解耦和重用是修饰器很重要的功能。

相关信息

  • Babel 7
  • tc39 proposal
  • original implementation

不同类型修饰器的应用和分析

类修饰器

使用场景:为类添加静态属性或者方法。
修饰器的参数:

  • target: 类本身

例子:

function language(value) {
    return function(target) {
        target.language = value;
    }
}

@language('English')
class Country {}

console.log(Country.language);
# output: English
实例方法修饰器

应用场景:输出日志,性能计算,权限验证。
修饰器的参数:

  • target:类的prototype。
  • name:要修饰的方法名称。
  • descriptor:该方法的修饰器。

例子:

function beforeFunc(target, name, descriptor) {
    const func = descriptor.value;
    const newFunc = function() {
        console.log(`Before calling: ${name}`);
        const result = func.apply(this, arguments);
        return result;
    }
    return {
        ...descriptor,
        value: newFunc
    }
}

function afterFunc(target, name, descriptor) {
    const func = descriptor.value;
    const newFunc = function() {
        const result = func.apply(this, arguments);
        console.log(`After calling: ${name}`);
        return result;
    }
    return {
        ...descriptor,
        value: newFunc
    }
}

class Medium {
    constructor() {
        this.base = 10;
    }

    @afterFunc
    @beforeFunc
    add(a, b){
        console.log(`Calculating...`);
        return a + b + this.base;
    }
}

// console.log(Country.language);

const m = new Medium();
console.log('Sum: ', m.add(1, 4));
# Output:
# Before calling: add
# Calculating...
# After calling: add
# Sum:  15
实例属性修饰器

使用场景:修改property的属性(writable,enumerable,configurable等),监听属性的变化(watcher)。
修饰器的参数:

  • target:类的prototype。
  • name:要修饰的方法名称。
  • descriptor:该方法的修饰器。

Note: 使用数据描述符和存储描述符定义的属性,它们的descriptor是不一样的。

例子:

  1. 存储描述符: 给属性添加监听器
function observable(target, name, descriptor) {
    const setter = descriptor.set;
    return {
        ...descriptor,
        get: function() {
            console.log(`Before getting '${name}'. '${name}' is ${this.base}`);
            return this.base;
        },
        set: function(value) {
            console.log(`Before setting '${name}'. '${name}' is ${this.base}`);
            setter.call(this, value);
            return true;
        }
    };
}

class Medium {
    @observable
    get count () {
        return this.base;
    };
    set count (value) {
        this.base = value;
    };

    constructor() {
        this.base = 10;
    }
}

const m = new Medium();
m.count += 20;
console.log('Count: ', m.count);
# Output:
# Before getting 'count'. 'count' is 10
# Before setting 'count'. 'count' is 10
# Before getting 'count'. 'count' is 30
# Count:  30
  1. 数据描述符: 将属性设置为只读
function readonly(target, name, descriptor) {
    descriptor.writable = false;
    return descriptor;
}
class Medium {
    @readonly
    age = 18;
}
const m = new Medium();
m.age = 28;

# throw an error: 
# TypeError: Cannot assign to read only property 'age' of object '#'

Desugar

说到底JS中的修饰器只是一种语法糖,最终还是由解释器翻译成一般的JS语法。JS的修饰器主要依赖于 Object.defineProperty 功能,当解释器遇到了 @decorator 的语法时,就会调用这个修饰器函数对属性(方法)的描述符(descriptor)进行操作,然后将修饰过的 descriptor 重新定义属性。
具体的转义可以查看:https://github.com/wycats/javascript-decorators#desugaring

你可能感兴趣的:(Javascript Decorator)