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))
新闻热点
疑难解答
图片精选