JS的 decorator
已经到了Stage 2 Draft
的阶段。并且在 Babel 7
中得到支持。
修饰器其实在其他的语言中已经得到很完善的实现了,比如 Python
。修饰器主要的功能是将辅助性的功能和核心功能分开。例如,核心功能可以是主营业务,辅助功能可以是身份验证,信息缓存或者日记功能。这些辅助功能大部分是可以共享的,并且和主要功能没有什么联系,所以解耦和重用是修饰器很重要的功能。
相关信息
不同类型修饰器的应用和分析
类修饰器
使用场景:为类添加静态属性或者方法。
修饰器的参数:
- 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是不一样的。
例子:
- 存储描述符: 给属性添加监听器
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
- 数据描述符: 将属性设置为只读
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 '#<Medium>'
Desugar
说到底JS中的修饰器只是一种语法糖,最终还是由解释器翻译成一般的JS语法。JS的修饰器主要依赖于 Object.defineProperty
功能,当解释器遇到了 @decorator
的语法时,就会调用这个修饰器函数对属性(方法)的描述符(descriptor)进行操作,然后将修饰过的 descriptor
重新定义属性。
具体的转义可以查看:https://github.com/wycats/javascript-decorators#desugaring
网友评论