裝飾器簡介
個人理解,某些場景需要在不改變原有類和屬性的基礎上擴展一些功能,所以裝飾器就出現了。
裝飾器的寫法是在類或類屬性之前,加個方法名。學過java
的同學應該比較熟悉這種寫法,Spring
中鋪天蓋地都是註解。具體細節到處都是,就不贅述了。
不過截止到今天(2019年8月),遺憾的是nodejs
還未原生支持,仍然需要babel
編譯。
使用場景
突然想到用裝飾器,當然是有業務需要。寫了一個api
類,所有暴露的函數都需要進行一步初始化操作。但初始化代碼又不歸我控制,且是異步接口請求,不能立即執行,這就導致每個函數都要調用一遍這個init
方法。因爲加了緩存,每個都要判斷有沒有緩存,比較噁心。
常用例子
一般用這個日誌模塊來舉例,不過它是同步的
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);
修改爲異步
let init = 0;
class Maths {
@log
add (a, b) {
return a + b + init;
}
}
function log (target, name, descriptor) {
let oldValue = descriptor.value;
descriptor.value = function () {
console.log(`Calling "${name}" with`, arguments);
let args = arguments;
return new Promise((resolve) => {
setTimeout(function () {
// args = [...args, 100];
init = 100;
resolve(oldValue.apply(null, args));
}, 100);
});
};
return descriptor;
}
const math = new Maths();
(async () => {
let a = await math.add(2, 4);
console.log(a);
})();
在具體函數前加了裝飾器後,會先執行log
方法,這樣緩存的變量就修改了。雖然結果變成異步的,但也滿足我的需要了。