Decorator 提供了一種獨特的抽象邏輯,可在原有代碼基礎上,零侵入添加新功能特性。商業代碼總是多種交織并存的,在日常開發中,除了實現業務功能之外,我們還需要考慮諸如:異常處理、性能分析、日志等額外的需求。未經設計的的開發方法會傾向于將各種需求耦合組成一個功能模塊,比如:
class Math{ static add(num1,num2){ try{ console.time('some label'); log('log for something'); const result= num1+num2; console.timeEnd('some label'); return result; }catch(e){ error('something had broken'); } }}上述簡單的兩數相加功能,在添加各類需求之后,已經變的面目全非。Decorator 語法通過描述,可將功能特性疊加到原有功能中:
class Math{ @log @error @time static add(num1,num2){ return num1+num2; }}Decorator 是什么
Decorator 就是一個的包裹函數,運行時在編譯階段調用該函數,修改目標對象的行為、屬性。我們先來看一個簡單實例:
const log = (target,prop)=>console.log(`Wrap function: '${prop}'`);const tec={ @log say(){ console.log('hello world') }}// => Wrap function 'say'Decorator 函數簽名如下:
// @param target 作用對象// @param prop 作用的屬性名// @param descriptor 屬性描述符// @return descriptor 屬性描述符function decorator(target,prop,descriptor){}參數詳解:
target : 作用的對象,有如下情況: 作用于 class 時,target 為該 class 函數 作用于 class 中的函數、屬性 時,target 為該 class 的 prototype 對象 作用于 對象字面量中的函數、屬性 時,target 為該對象 prop : 描述的屬性名,若decorator作用于class時,該參數為空 descriptor : 屬性原本的描述符,該描述符可通過Object.getOwnPropertyDescriptor() 獲取,若decorator作用于class時,該參數為空 decorator 函數支持返回描述符或 undefined,當返回值為描述符時,運行時會調用Object.defineProperty()修改原有屬性。Decorator 的ES5實現
理解 Decorator 機制,最佳方式是使用ES5實現該過程。
class裝飾器機制比較簡單,僅做一層包裝,偽代碼:
// 調用實例@log class Person{}// 實現代碼const Person = log(Person);屬性裝飾器機制則比較復雜,babel 就此提供了一個參考范例:
// decorator 處理function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) { var desc = {}; Object['ke' + 'ys'](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; } 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['define' + 'Property'](target, property, desc); desc = null; } return desc;}// 調用實例class Person{ @log say(){}}// 實現代碼_applyDecoratedDescriptor( Person.prototype, 'say', [log], Object.getOwnPropertyDescriptor(Person.prototype, 'say'), Person.prototype))
新聞熱點
疑難解答
圖片精選