今天学习koa过程中用到了babel装饰器,因为对这部分不熟悉,所以做个笔记。 decorator是一个语法糖,可以用来修饰类/方法、对象的描述符。
修饰类
如果装饰类的decorator函数返回值为空,那么yourClassName就是装饰后的类;如果不为空,那么yourClassName就是返回值。
例如: 类B在装饰后,变量B的值就是18。
有必要时,我们可以返回新的类来替换原来的类,但多数情况下我们还是不需要返回值的。
@sayHello
class A {}
function sayHello (target) {
// target就是我们正在装饰的类A
target.prototype.sayHello = () => console.log('hello')
}
// 或者
@setAge(18)
class B {}
function setAge (n) {
return (target) => {
return target.age = n
}
}
/* 对类A的修饰
var _dec, _class;
let A = (_dec = setAge(18), _dec(_class = class A {}) || _class);
function setAge(n) {
return target => {
return target.age = n;
};
}
*/
修饰对象的描述符
修饰方法是对该方法的修饰符对象做修饰
descriptor对象:{ configurable: true, enumerable: false, writable: true, value: fn }
class MyClass {
@readOnly
print () {}
}
// 返回 访问器属性
function readOnly (target, key, descriptor) {
descriptor.writable = false
return descriptor
}
// 或者 返回数据属性
function Decorator(type){
return function (target, name, descriptor){
let v = descriptor.initializer && descriptor.initializer.call(this);
return {
enumerable: true,
configurable: true,
get: function() {
return v;
},
set: function(c) {
v = c;
}
}
}
}
多个修饰器
在此之前我们可以了解
@setAge(18)
, setAge函数会执行,返回_decorator函数(参数为 target、key、descriptor)@myhobby
, 函数本身就是包装器函数
class A {
@decorator(11)
@decorator2(22)
@decorator3
mymethod() {}
}
function decorator (n) {
return function desc1(target, key, descriptor) {
}
}
function decorator2 (n) {
return function desc2 (target, key, descriptor) {
}
}
function decorator3 (t, k, descriptor) => {
}
转化后的代码
// 1. 获取包装器函数
var _dec1 = decorator(11), _dec2 = decorator2(22);
var _class = class A { mymethod() {} }
_applyDecoratedDescriptor(_class.prototype, 'mymethod', [_dec1, _dec2, decorator3], Object.getOwnPropertyDescriptor(_class.prototype, 'mymethod'), _class.prototype);
function _applyDecoratedDescriptor( target, property, decorators,
descriptor, context) {
// 1. desc: 对方法修饰符做浅拷贝
var desc = {}
Object.keys(descriptor).forEach(function(key) {
desc[key] = descriptor[key]
})
desc.enumerable = !!desc.enumerable
desc.configurable = !!desc.configurable
if ('value' in desc || desc.initializer) {
desc.writable = true
}
// 2. decorators对象反序,然后执行里面的函数
// 注意到在这个过程中:
// target是全局的,对target修改可以在下一个_desc获得
// _desc返回值是修饰符,不返回则取上一个_desc,默认是desc。
// 执行得到的就是该方法最终的修饰符对象
desc = decorators.slice().reverse()
.reduce(function(desc, decorator) {
return decorator(target, property, desc) || desc
}, desc)
if (context && desc.initializer !== void 0) {
desc.value = desc.initializer ? desc.initializer.call(context) : void 0
desc.initializer = undefined
}
if (desc.initializer === void 0) {
Object.defineProperty(target, property, desc)
desc = null
}
return desc
}
附上koa配置的.babelrc文件
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
}
]
],
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }]
]
}