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 "htmlcode">// 类 @log class Person{ // 函数 @log say(){} // 属性 @log name = 'tec'; } // 同样适用于对象字面量的方法、属性 const tec = { @log name:'tec', @log walk(){} };Decorator 实践
在JS中,Decorator 是一个新概念,对于多数没有接触过诸如python、C#的开发者而言,很难理解实际应用场景。幸运的是github已经有人封装了常用Decorator。笔者分析该库,总结如下几种定义模式:
通过 descriptor 的 value 值修改:
function decorate(target, key, descriptor) { const fn = descriptor.value; return { ...descriptor, value() { return fn.apply(this, arguments); } } }通过 descriptor 的 get、set 函数修改:
function decorate(target, key, descriptor) { let value = descriptor.value; return { ...descriptor, get() { return value; } set(v) { value=v; } } }通过 descriptor 的 writable、enumerable 等属性修改:
function readonly(target, key, descriptor) { return { ...descriptor, writable:false } }针对 class ,返回包裹函数
function log(target){ let initTimes=0; return (...arg)=>{ console.log(++initTimes); target.call(this,...arg); }; }在实际开发中,还需要注意以下事项:
- Decorator 的目标是在原有功能基础上,添加功能,切忌覆盖原有功能
- Decorator 不是管道模式,decorator之间不存在交互,所以必须注意保持decorator独立性、透明性
- Decorator 更适用于非业务功能需求
- 确定 decorator 的用途后,切记执行判断参数类型
- decorator 针对每个装饰目标,仅执行一次
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
P70系列延期,华为新旗舰将在下月发布
3月20日消息,近期博主@数码闲聊站 透露,原定三月份发布的华为新旗舰P70系列延期发布,预计4月份上市。
而博主@定焦数码 爆料,华为的P70系列在定位上已经超过了Mate60,成为了重要的旗舰系列之一。它肩负着重返影像领域顶尖的使命。那么这次P70会带来哪些令人惊艳的创新呢?
根据目前爆料的消息来看,华为P70系列将推出三个版本,其中P70和P70 Pro采用了三角形的摄像头模组设计,而P70 Art则采用了与上一代P60 Art相似的不规则形状设计。这样的外观是否好看见仁见智,但辨识度绝对拉满。
更新日志
- 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]