本教程操作环境:windows7系统、ECMAScript 6版、Dell G3电脑。
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
ES6 装饰器
在 ES6 中,装饰器(Decorator)是一种与类相关的语法,用来注释或修改类和类方法。
装饰器其实就是一个函数,通常放在类和类方法的前面。
装饰器对类的行为的改变,是代码编译时发生的,而不是在运行时;装饰器的本质就是编译时执行的函数
装饰器可以用来装饰整个类
@decorateClass class Example { @decorateMethods method(){} }
在上面的代码中使用了两个装饰器,其中 @decorateClass()
装饰器用在类本身,用于增加或修改类的功能;@decorateMethods()
装饰器用在类的方法,用于注释或修改类方法。
两种类型装饰器
装饰器只能用于类和类的方法,下面我们分别看下两种类型的装饰器的使用
1、类装饰器
类装饰器用来装饰整个类
类装饰器的参数
target: 类本身,也相当于是 类的构造函数:Class.prototype.constructor。
@decorateClass class 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 {}
2、类方法装饰器
类方法装饰器用来装饰类的方法
类方法装饰器的参数
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 now math.add(2, 4);
【相关推荐:javascript视频教程、web前端】
以上就是es6中什么是装饰器的详细内容,更多请关注Work网其它相关文章!