ECMAScript Decorators---装饰器

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() 不会输出key
    configurable: false// 目标属性是否可以被删除或是否可以再次修改特性
} );

复制代码

应用举例

  1. 类方法 @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;
}
复制代码
  1. 类方法 @log日志打印
function log( logMessage ) {
    // return decorator function
    return function ( target, property, descriptor ) {
        // save original value, which is method (function)
        let originalMethod = descriptor.value;
        // replace method implementation
        descriptor.value = function( ...args ) {
            console.log( '[LOG]', logMessage );
            // here, call original method
            // `this` points to the instance
            return 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() );
复制代码
  1. 类的属性 大小写转换
// 解释: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() );
复制代码
  1. 类装饰器
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 装换

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"
  ]
}
复制代码

参考链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值