ECMAScript6(18):Decorator润饰器

润饰器

润饰器是 ES7 提出的一个提案,用来修正类的行动。现在须要 babel 才能够运用。它最大的特点是:能够在编译期运转代码!其实质也就是在编译器实行的函数。其实行花样以下:

@decorator    //decorator 是润饰器名,即函数名
class A{}
//相当于
class A{}
A = decorator(A) || A;

润饰器函数接收3个参数,依次是目的函数、属性名(可疏忽)、该属性的形貌对象(可疏忽)。

function test(target){
  target.isTestable = true;               //应用润饰器给类增加静态属性
  target.prototype.isTestable = true;     //应用润饰器给类增加动态属性
}

@test
class A{}

console.log(A.isTestable);       //true
console.log(new A().isTestable);   //true

比方之前的 mixin 能够用润饰器完成一个简朴的版本:

function mixins(...list){
  return function(target){
    Object.assign(target.prototype, ...list);
  }
}
var Foo = {
  foo(){console.log("foo");}
};
@mixins(Foo)
class Cla{}
let obj = new Cla();
obj.foo();     //"foo"

润饰器不单单议能够润饰类,还能够润饰类的属性和要领:

function readonly(target, name, descriptor){
  descriptor.writable = false;
  return descriptor;
}

class Person{
  constructor(name, age, tel){
    this.name = name;
    this.id = id;
  }
  @readonly
  id(){return this.id};
}

固然也能够同时挪用2个润饰器:

function readonly(target, name, descriptor){
  descriptor.writable = false;
  return descriptor;
}
function nonenumerable(target, name, descriptor){
  descriptor.enumerable = false;
  return descriptor;
}

class Person{
  constructor(name, age, tel){
    this.name = name;
    this.id = id;
  }
  @readonly
  @nonenumerable
  id(){return this.id};
}

运用润饰器应当注重:虽然类实质是个函数,但润饰器不能用于函数,由于函数具有声明提拔。

core-decroators.js

这是个三方模块,运用import {function Namelist} from 'core-decroators';引入。它供应了几个罕见的润饰器:

  • @autobind

是对象中的 this 一直绑定原始对象:

class Person{
  @autobind
  whoami(){
    return this;
  }
}
let person = new Person();
let getPerson = person.getPerson;

getPerson() === person;    //true
  • @readonly

使得属性要领只读

class Person{
  @readonly
  id = gen();     //gen 是一个计数器
}
var p = new Person()
p.id = 123;   //Cannot assign to read only property 'id' of [object Object]
  • @override

搜检子类要领是不是准确的掩盖了父类的同名要领,假如不准确会报错

class Person{
  work(){console.log("I am working");}
}
class Coder extends Person{
  @override
  work(){console.log("I am coding");}   //假如不准确会在这里报错
}
  • @deprecate(也作: @deprecated)

在控制台显现一条 warning,示意该要领不久后将被取销,接收一个可选的参数作为正告内容, 接收第二个参数(对象)示意更多信息

class Person{
  @deprecate
  facepalm(){}

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

  @deprecate('We stopped facepalming', {url:'http://balabala.com'})
  facepalmHarder(){}
}
  • @suppressWarnings

抑止 deprecate 润饰器致使挪用 console.warn(), 但异步代码发出的除外。

class Person{
  @deprecate
  facepalm(){}

  @supressWarnings
  facepalmWithoutWarning(){
    this.facepalm();
  }
}
let p = new Person();
p.facepalm();    //控制台显现正告
p.facepalmWithoutWarning();    //没有正告

别的第三方润饰器

另外另有一些库供应一些其他功用,比方 Postal.js(Github)中的 @publish, 能够在函数挪用时宣布一个事宜:

import publish from "../to/decorators/publish";

class FooComponent{
  @publish("foo.some.message", "component")
  someMethod(){}

  @publish("foo.some.other", "")
  anotherMethod(){}
}

再比方 Trait(Github), 和 mixin 功用相似,供应了更壮大的功用:防备同名争执,消除混入某些要领,为混入要领起别号等

import {traits} from 'traits-decorator'

class TFoo{
  foo(){console.log("foo1")}
}
class TBar{
  bar(){console.log("bar")}
  foo(){console.log("foo2")}
}

@traits(TFoo, TBar)       //会报错,由于这两个类中有同名要领
class MyClass{}

let obj = new MyClass();
//假如没有第八行的同名要领,输出以下
obj.foo();   //"foo1"
obj.bar();   //"bar"

然则我们能够修正上面第11行消除这个 foo,让它能够被掩盖:

@traits(TFoo, TBar::excludes('foo'))
class MyClass{}

也可重命名同名要领:

@traits(TFoo, TBar::alias(foo:'aliasFoo'))
class MyClass{}

固然绑定运算符能够链式挪用:

//假定另有个同名的 baz 要领
@traits(TFoo, TBar::excludes('foo')::alias(baz:'aliasBaz'))
class MyClass{}

//另一种写法
@traits(TFoo, TBar::as({excludes: ['foo'], alias: {baz:'aliasBaz'}}))
class MyClass{}
    原文作者:Faremax
    原文地址: https://segmentfault.com/a/1190000016286350
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞