ECMAScript Decorators---装饰器
Decorators是什么
Decorators可以改变类方法和类实例字段的属性和行为,使我们可以灵活地使用更简单的语法动态实现这些内容,是非侵入式的。---举例,你给手机添加一个外壳罢了,并不影响手机原有的通话、充电等功能
应用场景
Decorators的经典的应用是AOP编程,比如“日志系统”,日志系统的作用是记录系统的行为操作,它在不影响原有系统的功能的基础上增加记录环节 更加抽象的理解,可以理解为给数据流做一层filter,因此 AOP 的典型应用包括安全检查、缓存、调试、持久化等等。
原理
Decorators的本质是利用了ES5的Object.defineProperty属性,这三个参数其实是和Object.defineProperty参数一致的,因此不能更改 object 必需。要在其上添加或修改属性的对象 这可能是一个本机JavaScript对象(即用户定义的对象或内置对象)或 DOM 对象。 propertyname必需。一个包含属性名称的字符串 descriptor 必需。 属性描述符。它可以针对数据属性或访问器属性。 举例说明
var myObj = {myPropOne: 1,myPropTwo: 2
};
// modify property descriptor
Object.defineProperty( myObj, 'myPropOne' , {writable: false , // 是否允许该属性值更改enumerable: false , // 是否允许key被枚举,话句话说for in 或者Object.keys() 不会输出keyconfigurable: false // 目标属性是否可以被删除或是否可以再次修改特性
} );
应用举例
类方法 @readonly
class User {constructor( firstname, lastName ) {this.firstname = firstname;this.lastName = lastName;}@readonly getFullName () {return this.firstname ' ' this.lastName;}
}
// create instance
let user = new User( 'John' , 'Doe' );
console.log( user.getFullName() );// 某天我不小心重写了这个方法
User.prototype.getFullName = function () {return 'HACKED!' ;
}// 输出 HACKED! 与预期不符,怎么避免此类情况发生// 方法1 这是最好的解决方案么?修饰器登场
Object.defineProperty( User.prototype, 'getFullName' , {writable: false
});// 将此方法添加到修饰方法getFullName上
function readonly ( target, property, descriptor ) {descriptor.writable = false ;return descriptor;
}
类方法 @log日志打印
function log ( log Message ) {// return decorator function return function ( target, property, descriptor ) {// save original value, which is method (function )let originalMethod = descriptor.value;// replace method implementationdescriptor.value = function ( ...args ) {console.log( '[LOG]' , log Message );// here, call original method// `this` points to the instancereturn originalMethod.call( this, ...args );};return descriptor;}
}
class User {constructor( firstname, lastName ) {this.firstname = firstname;this.lastName = lastName;}@log ('calling getFullName method on User class' )getFullName () {return this.firstname ' ' this.lastName;}
}
var user = new User( 'John' , 'Doe' );
console.log( user.getFullName() );
类的属性 大小写转换
// 解释:descriptor.initializer函数由Babel内部使用来创建对象属性的属性描述符的值
function toCase( CASE = 'lower' ) {return function ( target, name, descriptor ) {let initValue = descriptor.initializer();descriptor.initializer = function (){return ( CASE == 'lower' ) ? initValue.toLowerCase() : initValue.toUpperCase();}return descriptor;}
}
class User {@toCase( 'upper' )firstName = 'default_first_name' ;lastName = 'default_last_name' ;constructor( firstName, lastName ) {if ( firstName ) this.firstName = firstName;if ( lastName ) this.lastName = lastName;}getFullName () {return this.firstName ' ' this.lastName;}
}
console.log( new User() );
类装饰器
function withLoginStatus( UserRef ) {return class extends UserRef {constructor( ...args ) {super( ...args );this.isLoggedIn = false ;}setLoggedIn () {this.isLoggedIn = true ;}}
}
@withLoginStatus
class User {constructor( firstName, lastName ) {this.firstName = firstName;this.lastName = lastName;}
}
let user = new User( 'John' , 'Doe' );
console.log( 'Before ===> ' , user );
// set logged in
user.setLoggedIn();
console.log( 'After ===> ' , user );
babel 装换
在线转换链接(如无法打开网页需翻墙) 构建babel装换
1、创建项目文件
2、命令行进入该项目目录 npm init
3、npm install babel-core babel-plugin-transform-decorators
4、安装 npm install babel-plugin-transform-decorators-legacy --save-dev
5、.babelrc添加
{ "plugins" : [ "transform-decorators-legacy" ]
}
参考链接
ECMAScript Decorators---装饰器 ES7 Decorator 装饰者模式 阮一峰---修饰器