在上篇博文CoffeeScript實現Python裝潢器中,筆者利用CoffeeScript支持的高階函數,以及方法調用可省略括符的特性,實現了一個類似Python裝潢器的日志Demo。這只是一種偽實現,JavaScript實現裝潢器,我們需要等到ECMAScript7才行,在ES7特性中帶來了Decorators,它就是我們所需要的裝潢器特性。雖然它是ES7的特性,但在Babel大勢流行的今天,我們可以利用Babel來使用它。關於Babel的推薦文章,請參見另一篇文章Babel-現在開始使用 ES6。
下面我們仍然和上節CoffeeScript實現Python裝潢器一樣,實現一個ES7 Decorators版的日志攔截示例。我們希望得到的代碼效果如下:
class MyClass {
@log('MyClass add')
add(a, b){
return a + b;
}
@log('MyClass product')
product(a, b){
return a * b;
}
@log('MyClass error')
error(){
throw 'Something is wrong!';
}
}
在ES7中Decorators,也是一個函數,我們只需要在它前面加上@符號,並將它標注在特定的目標,如class、method等,則可以實現方法的包裹攔截。它的傳入參數有:target, name, descriptor。它們分別標記目標,標記目標名稱,以及目標描述信息。在descriptor中,包括configurable、enumerable、writable,value四個屬性。它們分別可以控制目標的讀寫、枚舉,以及目標值。
所以我們可以如下實現:
let log = (type) => {
const logger = new Logger('#console');
return (target, name, descriptor) => {
const method = descriptor.value;
descriptor.value = (...args) => {
logger.info(`(${type}) before function execute: ${name}(${args}) = ?`);
let ret;
try {
ret = method.apply(target, args);
logger.info(`(${type})after function execute success: ${name}(${args}) => ${ret}`);
} catch (error) {
logger.error(`(${type}) function execute error: ${name}(${args}) => ${error}`);
} finally {
logger.info(`(${type}) function execute done: ${name}(${args}) => ${ret}`);
}
return ret;
}
}
}
首先我們將原來的方法體緩存起來,直到方法調用時,才會被調用以實現方法調用前后的日志攔截,打印相關信息。示例的效果如下:
整個demo示例,你也可以在codepen上細細把玩:
See the Pen ES7 Decorators by green (@greengerong) on CodePen.