Decorator是ES7中的一个提案, 这个概念是从 Python 借鉴来的,在 Python 里,decorator 实际上是一个 wrapper,它作用于一个目标函数,对这个目标函数做一些额外的操作,然后返回一个新的函数,ES中的Decorator也类似。
简单来说,Decorator是一个包裹函数,可以用来为
类
、属性
或者函数
提供额外的功能。
使用前的准备
虽然Decorator只是一个提案,但可以通过相应的工具来使用它:
Babel:
babel-plugin-syntax-decorators
babel-plugin-transform-decorators-legacy
TypeScript:
以命令行的形式:
|
|
或者修改tsconfig.json:
|
|
代码最终将被编译成ES5,你可以在Babel_REPL上查看到编译后的代码
作用在属性上
以一个logger为例:
|
|
流程是,我们通过log
在add
函数外面进行包裹:通过一个originalMethod
变量来保留原始函数,触发console.log,最后将原始参数传递给原始函数并再次调用。
这里的log
方法可以单独抽取成一个模块,之后在任何需要的地方引入它,即可使用。
Decorator方法(Object.defineProperty)接收3个参数:
target: 需要被操作的目标对象
name: 目标对象需要定义或修改的属性的名称
descriptor: 将被定义或修改的属性的描述符
比较关键的是 descriptor 参数,它其实也是一个对象,其字段决定了 obj 的 prop 属性的一些特性。比如 enumerable 的真假就能决定目标对象是否可枚举(能够在 for…in 循环中遍历到,或者出现在 Object.keys 方法的返回值中), writable 决定目标对象的属性是否可以更改,等等。详情参看MDN 。
作用在类上
Decorator也可以作用在类上,这里我们将使用它来实现工厂模式,传递某些参数到decorator方法来给类附加一些属性,例如:
|
|
我们使用一个项目常用的验证登陆的例子:比如某些交互行为需要先判断用户登录状态,在已登录的情况下往下执行,未登录的的情况下则中断行为,并做相应提示。
代码如下:
|
|
总结
Decorator可以允许我们将行为包装成简单的代码块,以便复用,使代码更加整洁。像常用的权限判断,实现工厂模式等。
Decorator已经被很多框架和代码库所使用,例如Vue的vue-class-component,vue-property-decorator。
参考文献:
https://www.martin-brennan.com/es7-decorators/
Understanding Decorators
Decorators in ES7
JavaScript — Make your Code Cleaner with Decorators