在es6中,修饰器用来注释或修改类和类的方法,依赖于es5的“object.defineproperty”方法,写法为“@函数名”;修饰器其实就是一个函数,通常放在类和类方法的前面。修饰器可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。
本教程操作环境:windows7系统、ecmascript 6版、dell g3电脑。
修饰器模式(decorator pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
es6 装饰器(修饰器)在 es6 中,装饰器(decorator)是一种与类相关的语法,用来注释或修改类和类方法。
装饰器其实就是一个函数,通常放在类和类方法的前面。
@decorateclassclass example { @decoratemethods method(){}}
在上面的代码中使用了两个装饰器,其中 @decorateclass() 装饰器用在类本身,用于增加或修改类的功能;@decoratemethods() 装饰器用在类的方法,用于注释或修改类方法。
两种类型装饰器(修饰器)装饰器只能用于类和类的方法,不能用于函数,因为存在函数提升。
装饰器只能用于类和类的方法,下面我们分别看下两种类型的装饰器的使用
类装饰器类装饰器用来装饰整个类
类装饰器的参数target: 类本身,也相当于是 类的构造函数:class.prototype.constructor。
@decorateclassclass example { //...}function decorateclass(target) { target.istestclass = true}
如上面代码中,装饰器 @decorateclass 修改了 example 整个类的行为,为 example 类添加了静态属性 istestclass。装饰器就是一个函数,decorateclass 函数中的参数 target 就是 example 类本身,也相当于是类的构造函数 example.prototype.constructor.
装饰器传参上面实现的装饰器在使用时是不能传入参数的,如果想要在使用装饰器是传入参数,可以在装饰器外面再封装一层函数
@decorateclass(true)class example { //...}function decorateclass(istestclass) { return function(target) { target.istestclass = istestclass }}
上面代码中实现的装饰器在使用时可以传递参数,这样就可以根据不同的场景来修改装饰器的行为。
实际开发中,react 与 redux 库结合使用时,常常需要写成下面这样。
class myreactcomponent extends react.component {}export default connect(mapstatetoprops, mapdispatchtoprops)(myreactcomponent);
有了装饰器,就可以改写上面的代码。
@connect(mapstatetoprops, mapdispatchtoprops)export default class myreactcomponent extends react.component {}
类方法装饰器类方法装饰器用来装饰类的方法
类方法装饰器的参数target:
装饰器修饰的类方法是静态方法:target 为类的构造函数
装饰器修饰的类方法是实例方法:target 为类的原型对象
method:被修饰的类方法的名称
descriptor:被修饰成员的属性描述符
// descriptor对象原来的值如下{ value: specifiedfunction, enumerable: false, configurable: true, writable: true};
class example { @log instancemethod() { } @log static staticmethod() { }}function log(target, methodname, descriptor) { const oldvalue = descriptor.value; descriptor.value = function() { console.log(`calling ${name} with`, arguments); return oldvalue.apply(this, arguments); }; return descriptor;}
如上面代码中,装饰器 @log 分别装饰了实例方法 instancemethod 和 静态方法 staticmethod。@log 装饰器的作用是在执行原始的操作之前,执行 console.log 来输出日志。
类方法装饰器传参上面实现的装饰器在使用时是不能传入参数的,如果想要在使用装饰器是传入参数,可以在装饰器外面再封装一层函数
class example { @log(1) instancemethod() { } @log(2) static staticmethod() { }}function log(id) { return (target, methodname, descriptor) => { const oldvalue = descriptor.value; descriptor.value = function() { console.log(`calling ${name} with`, arguments, `this id is ${id}`); return oldvalue.apply(this, arguments); }; return descriptor; }}
上面代码中实现的装饰器在使用时可以传递参数,这样就可以根据不同的场景来修改装饰器的行为。
类装饰器与类方法装饰器的执行顺序如果在一个类中,同时使用装饰器修饰类和类的方法,那么装饰器的执行顺序是:先执行类方法的装饰器,再执行类装饰器。
如果同一个类或同一个类方法有多个装饰器,会像剥洋葱一样,先从外到内进入,然后由内到外执行。
// 类装饰器function decoratorclass(id){ console.log('decoratorclass evaluated', id); return (target) => { // target 类的构造函数 console.log('target 类的构造函数:',target) console.log('decoratorclass executed', id); }}// 方法装饰器function decoratormethods(id){ console.log('decoratormethods evaluated', id); return (target, property, descriptor) => { // target 代表 // process.nexttick((() => { target.abc = 123 console.log('method target',target) // })) console.log('decoratormethods executed', id); }}@decoratorclass(1)@decoratorclass(2)class example { @decoratormethods(1) @decoratormethods(2) method(){}}/** 输入日志 **/// decoratormethods evaluated 1// decoratormethods evaluated 2// method target example { abc: 123 }// decoratormethods executed 2// method target example { abc: 123 }// decoratormethods executed 1// decoratorclass evaluated 1// decoratorclass evaluated 2// target 类的构造函数: [function: example]// decoratorclass executed 2// target 类的构造函数: [function: example]// decoratorclass executed 1
如上面代码中,会先执行类方法的装饰器 @decoratormethods(1) 和 @decoratormethods(2),执行完后再执行类装饰器 @decoratorclass(1) 和 @decoratorclass(2)
上面代码中的类方法装饰器中,外层装饰器 @decoratormethods(1) 先进入,但是内层装饰器 @decoratormethods(2) 先执行。类装饰器同理。
利用装饰器实现aop切面编程function log(target, name, descriptor) { var oldvalue = descriptor.value; descriptor.value = function () { console.log(`calling "${name}" with`, arguments); return oldvalue.apply(null, arguments); } return descriptor;}// 日志应用class maths { @log add(a, b) { return a + b; }}const math = new maths();// passed parameters should get logged nowmath.add(2, 4);
【相关推荐:javascript视频教程、web前端】
以上就是es6 修饰器是干什么用的详细内容。