Decorator 装饰器你了解多少?
前言
你真的了解装饰器吗?相信使用过装饰器的开发者肯定对它的一些特性会爱不释手。无论是react、vue、angular都能通过babel使其支持,当然也有一些封装好的第三方装饰器库,引用后即可实现一些强大的功能。下面我们一起来简单了解一下吧。
什么是装饰器?
装饰器是一种函数,目的是用来修改类及其成员。
Javascript装饰器还处于草案中,目前没有直接支持该语法的环境,但Babel 已支持其语法转换。
在TypeScript里也已做为一项实验性特性予以支持。
在Angular中也进行了大量使用,有很多内置的装饰器。
实际上就是设计模式中常说的装饰者模式的一种实现
装饰者模式,是指在不必改变原类文件或使用继承的情况下,动态地扩展一个对象的功能,
为对象增加额外特性的一种设计模式。
为什么要用装饰器?
装饰器有方便、高效、语义化更强的特性。
合理利用装饰器可以极大的提高开发效率、可以封装提炼非内部函数的逻辑代码、
可以帮助我们快速完成重复性的工作。
Decorator装饰器的使用及实例
case 1: 修饰类 基础用法
给类添加装饰器,自动把类作为第一个参数,传递给装饰器。
case 2: 修饰类 并自定义参数
如果你觉得一个参数不够用,可以在装饰器函数的外层再封装一层函数。不只是装饰器,在Vue
中利用闭包的特性,还可以向computed和getter
等方法中传递指定的参数。
装饰器在装饰类的属性时,会智能的去装饰该原型,其
- 第一参数为要装饰的目标元素,
- 第二个参数为属性名,
- 第三参数为该属性的描述对象
装饰器对类的行为的改变,是在代码编译时发生的,而不是在运行时。
case3 多个装饰器嵌套的应用
如果多个装饰器有传参会按顺序执行所有装饰器的外部函数。执行完毕后再用reduce倒序递归执行得到的内部装饰器函数。
case4 实现类的多继承
在js中class没有直接的语法可以实现多重继承,如果要实现多继承,只能使用mixin的方式或用getOwnPropertyNames遍历等间接的手段。如:
class C extends A, B {} // Error
class C extends A extends B {} // Error
Mixin 方法实现
class A{}
function Mixin ( BaseClass ) {
return class extends BaseClass
{
mixin(){ console.log('这是混合继承的类的方法,继承生成新的表达式类') }
}
}
class C extends Mixin(A){}
new C().mixin() // 这是混合继承的类的方法,继承生成新的表达式类
// getOwnPropertyNames 方式实现
class C extend B {}
for (let key of Object.getOwnPropertyNames(A.prototype)) {
if (key === 'constructor') continue
Object.defineProperty(C.prototype, key, Object.getOwnPropertyDescriptor(A.prototype, key))
}
但有了装饰器,开发人员无需关注上面的具体实现,
可通过@Decorator,能够帮你省去很多繁琐的步骤来用上装饰器
case5 其他常用的简易装饰器
@readonly 装饰器
使属性只读
class Person{
@readonly // 使该属性只读。
age() {
}
}
function readonly(target, name, descriptor){
// descriptor对象原来的值如下
// {
// value: specifiedFunction,
// enumerable: false,
// configurable: true,
// writable: true
// };
descriptor.writable = false;
return descriptor;
}
readonly(Person.prototype, 'name', descriptor)
@getExcuteTime 装饰器,
获取某个函数执行开始时间到结束的时间
以往需要这样
class Person{
something1(){
let start = Date.now()
// do something...
let end = Date.now()
console.log('执行时间:',end-start)
}
something2(){
let start = Date.now()
// do something...
let end = Date.now()
console.log('执行时间:',end-start)
}
}
使用装饰器,使计时和业务分离
class Person{
@getExcuteTime
something1(){
// do something...
}
@getExcuteTime
something2(){
// do something...
}
}
@log 装饰器
我们不希望日志和业务掺和在一起,这样使用修饰器就避免了这个问题
class Person{
@log('开始第一步')
step1() {
// do something...
// 无需在函数中写打印的逻辑
}
@log('开始第二步')
step2() {
// do something...
}
}
function log(value) {
return function (target, name, descriptor) {
// 可以在这里根据参数打印更加详细的信息
console.log(value)
}
}
还有像登陆(不要重复写一些是否登陆的逻辑)、aixos等装饰器,需要我们自身根据具体需求去实现。
其它
vue项目中使用装饰器,其官方提供的组件装饰器
core-decorators.js 提供了一些常用的装饰器方法
总结
总的来说,装饰器简单易用,合理使用装饰器能提高我们的开发效率、能使代码可读性更高、更容易维护、功能更加聚合。
此外,如果大家在阅读中发现不合理或者有误的地方,欢迎留言指正,万分感谢!
如果觉得有帮助,不妨点赞、关注支持一下。再次感谢!
作者:tager
链接:https://juejin.cn/post/7020406094904164383
说明:稀土掘金同步更新
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。