@Decorator — ES7的一种新的提案。

@decorator模块学习

我的github学习地址:关于decorator

Decorator简介

修饰器(Decorator)是一个函数,用于修饰类的行为,这是ES7的一个提案,目前已经被babel支持。

在TypeScript中,就是修饰器的概念,比如用于组件传值的 @input @output等等。

一个简单的修饰器的使用如下:

function testAble(target){
    target.isTest = true;
}

@testAble
class A {}

console.log(A.isTest);// true

在一个修饰器中,参数target就是你要修饰的类,这个类也叫做Decorator的修饰目标对象。

上面示例实现的效果就是,给这个类添加了一个静态属性isTest。

那么,我们如何给这个类添加一个实例属性呢?

function testAble(target){
    target.prototype.isTest = 'test';
}

@testAble
class A {};

new A().isTest; // true

通过这样的方式,我们就给这个类添加了一个实例属性。

多参数的修饰器的实现

有这样的一种状态,你觉得你的参数不够用,仅仅一个target无法满足你的要求,这个时候,可以把这个修饰器进行变形。

function testAble(value) {
    return function(target){
        target.prototype.isTrue = value;
    }
}

@testAble(true)
class A {};

new A().isTrue;// true

使用Object.assign来实现class属性批量的添加

在给一个class添加实例属性的时候,修饰器可以通过Object.assign来实现一些东西。

function testAble(...list) {
    return function(target){
        Object.assign(target.prototype, ...list)
    }
}

let options = {
  name: 'mapbar_front',
  age: 123,
  getName: function(){
    console.log(this.name);
  }
}
@testAble(options)
class A {}

new A().getName()
注意:在修饰器进行修饰一个类的时候,不能进行定义name属性,要不会发生错误。

修饰器不仅仅可以修饰class,也可以进行修饰对象的属性

基本的使用方式如下:

function test(target, name, descriptor) {
    descriptor.writable = true;
    return descriptor;
}
class A {
    @test
    name(){
        console.log('my name is mapbar_front!');
    }
}

//表示类A的name方法是可重写的。

修饰器在修饰一个属性的时候,它有三个参数,第一个参数target,表示这个修饰器对应的class。

第二个参数,就是你要修饰的类的属性名。第三个参数是修饰器的属性描述对象。

function testAA(target, name, descriptor) {
  descriptor.writable = false;
  return descriptor;
}
class A {
  @testAA
  name(){
      console.log('my name is mapbar_front!');
  }
}
var obj111 = new A();
obj111.name();

obj111.name = 123;//报错
console.log(obj111.name)

关于属性修饰符descriptor的说明

这个和Object.defineProperty()相关。

let obj = {};
Object.defineProperty(obj, 'name', {
    configurable: true,
    writable: true,
    enumberable: true,
    value: 'mapbar_front',
});
console.log(obj.name);// 'mapbar_front';

以上代码,定义了一个obj的对象,给它添加了一个name属性,这个name属性的value值是’mapbar-front’。

configurable: true。代表了你可以更改name属性的修饰符配置。

enumberable: true。代表了你可以使用for in把这个定义好的name属性遍历出来。

writable: true。代表了name属性是可重写的。也就是说你可以更改name属性的value值。

@log修饰器的实现、@readonly、@enumberable等修饰器的实现。

@log修饰器的需求就是,在我执行函数的时候,打印出参数。

function log(target, name, descriptor){
    var oldValue = descriptor.value;
    descriptor.value = function(){
        console.log(`this prop ${name} 的参数为 ${arguments}`);
        return oldValue.appay(null, arguments);
    }

    return descriptor;
}

class Math {
    @log
    add(a, b){
        return a + b;
    }
}

其他的@readonly、@enumberable等的修饰器的实现,本质上都是对descriptor的实现。

需要注意的是,修饰器不能用于函数

var counter = 0;

var add = function () {
  counter++;
};

@add
function foo() {
}

上面的代码,意图是执行后counter等于1,但是实际上结果是counter等于0。

修饰器不能用于函数的核心原因,就是函数存在函数提升。

core-decorator第三方模块,提供常用的几个修饰器

<1> @autobind

使得方法中的this对象,绑定原始对象。

<2> @readonly

使得class中的属性或者方法不可写。

<3> @override

检查子类的方法,是否正确覆盖了父类的同名方法,如果不正确会报错。

<4> @deprecate (别名@deprecated)

deprecate或deprecated修饰器在控制台显示一条警告,表示该方法将废除。

import { deprecate } from 'core-decorators';

class Person {
  @deprecate
  facepalm() {}

  @deprecate('We stopped facepalming')
  facepalmHard() {}

  @deprecate('We stopped facepalming', { url: 'http://knowyourmeme.com/memes/facepalm' })
  facepalmHarder() {}
}

let person = new Person();

person.facepalm();
// DEPRECATION Person#facepalm: This function will be removed in future versions.

person.facepalmHard();
// DEPRECATION Person#facepalmHard: We stopped facepalming

person.facepalmHarder();
// DEPRECATION Person#facepalmHarder: We stopped facepalming
//
//     See http://knowyourmeme.com/memes/facepalm for more details.
//

<5> @suppressWarnings

suppressWarnings修饰器抑制decorated修饰器导致的console.warn()调用。但是,异步代码发出的调用除外。

Mixin模式——混入模式

在一个对象中混入另外一个对象的属性和方法。

常用的方式,就是使用的Object.assign

class A{}
Object.assign(A.prototype, {
    name: 'mapbar_front',
});

let name = new A().name;
console.log(name);

不过,我们可以使用修饰器的方式,给任何的类进行添加额外的属性和方法

function testAble(...list) {
    return function(target){
        Object.assign(target.prototype, ...list)
    }
}

let options = {
  name: 'mapbar_front',
  age: 123,
  getName: function(){
    console.log(this.name);
  }
}
@testAble(options)
class A {}

new A().getName()

上面是通过修改prototype对象的方式实现Mixin模式,也可以通过extends的方式来实现继承

class A extends B{

}
//如果B中有foo方法,此时的A也会继承foo方法。

也可以通过在A和B之间添加一个混入类来实现。

let myMixin = function(B) {
    return class extends B {
        foo(){
            console.log('foo');
        }
    }
}
class A extends myMixin(B) {}

如果要添加多个Mixin属性。就可以通过多写几个Mixin方法来实现:

class A extends myMixin1(myMixin2(B)) {
    //coding
}

traits-decorator第三方库

1、一个简单的使用示例:

import { traits } from 'traits-decorator';

class TFoo {
    foo(){ console.log('foo') }
}
class TBar {
    bar(){ console.log('bar') }
}
@traits(TFoo, TBar)
class MyClass{}

var obj = new MyClass();
obj.foo();
obj.bar();

这里达到的效果是。MyClass被混入了foo方法以及bar方法。

2、traits不允许混入同名方法

import { traits } from 'traits-decorator';

class TFoo {
    foo(){ console.log('foo') }
    bar(){ console.log('bar') }
}
class TBar {
    bar(){ console.log('bar') }
}
@traits(TFoo::excludes('bar'), TBar);//这里需要修改成这样,如果不改为这样的话,会报错
class MyClass{}

var obj = new MyClass();
obj.foo();
obj.bar();

另外一种方式是给bar方法起一个别名。

@traits(TFoo::alias({bar: aliasBar}), TBar);//这里需要修改成这样,如果不改为这样的话,会报错
class MyClass{}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值