1、javascript中的装饰器
装饰器是对类、方法、属性的修饰,增加额外的行为。装饰器不侵入,所以对原先的内容不会破坏。装饰器可以理解成一种解决问题的通用思路,装饰器模式遇到程序之后诞生了多种多样的表现形式。javascript也引入了装饰器这一实验内容,在typescript中已经有使用的案例。
这篇博客记录方法的装饰器,先梳理下装饰器的思路。比如有一个run方法,原先的run方法只是简单输出I am running。
class Run {
constructor() {
}
run() {
console.log( 'I am running' );
}
}
接着,希望run方法能输出跑步的速度。最直接的方法是修改Run的run方法,输出速度。我们采用另外一种思路,形式上不修改Run。主要是通过Object.getOwnPropertyDescriptor获取类的方法属性,并修改方法,最后使用Object.defineProperty覆盖原先的方法。
function decorateFunc( Cls, funcNm ) {
// 获取需要包装的target
let target = Cls.prototype;
// 获取属性的descriptor
let descriptor = Object.getOwnPropertyDescriptor( target, funcNm );
// 装饰函数
let decoratedFunc = function ( ...args ) {
let speed = 12;
descriptor.value.apply( target, args ); // 执行原来的函数
console.log( `my speed is ${ speed }` ); // 增加新特性
}
// 改写原来的内容
//Object.defineProperty( target, funcNm, {
// ...descriptor,
// value: decoratedFunc
//} );
}
decorateFunc( Run, 'run' );
let target = new Run();
target.run();// I am running my speed is 12
装饰器获取run方法之后执行,并增加了行为,我们还可以再封装一次,可以增加不同的行为。
//target descriptor key
function wrap( decorator ) {
return function ( Cls, funcNm ) {
let target = Cls.prototype;
let descriptor = Object.getOwnPropertyDescriptor( target, funcNm );
decorator( target, funcNm, descriptor )
}
}
let runSpeed = function ( target, funcNm, descriptor ) {
let speed = 12;
descriptor.value.apply(target,[]);
console.log(`my speed is ${speed}`);
}
let runDecorator = wrap( runSpeed );
runDecorator( Run, 'run' );
new Run().run();
wrap的参数是函数,函数是用于装饰的函数,装饰用的函数需要目标对象,装饰的函数名称,装饰函数的descriptor。
2、ES7中的Decorator
------------------------------------未完待续----------------------------------