Trait

Trait 也是一种装饰器,效果与 Mixin 类似,但是提供更多功能,比如防止同名方法的冲突、排除混入某些方法、为混入的方法起别名等等。

下面采用traits-decorator这个第三方模块作为例子。这个模块提供的traits装饰器,不仅可以接受对象,还可以接受 ES6 类作为参数。

  1. import { traits } from 'traits-decorator';
  2. class TFoo {
  3. foo() { console.log('foo') }
  4. }
  5. const TBar = {
  6. bar() { console.log('bar') }
  7. };
  8. @traits(TFoo, TBar)
  9. class MyClass { }
  10. let obj = new MyClass();
  11. obj.foo() // foo
  12. obj.bar() // bar

上面代码中,通过traits装饰器,在MyClass类上面“混入”了TFoo类的foo方法和TBar对象的bar方法。

Trait 不允许“混入”同名方法。

  1. import { traits } from 'traits-decorator';
  2. class TFoo {
  3. foo() { console.log('foo') }
  4. }
  5. const TBar = {
  6. bar() { console.log('bar') },
  7. foo() { console.log('foo') }
  8. };
  9. @traits(TFoo, TBar)
  10. class MyClass { }
  11. // 报错
  12. // throw new Error('Method named: ' + methodName + ' is defined twice.');
  13. // ^
  14. // Error: Method named: foo is defined twice.

上面代码中,TFooTBar都有foo方法,结果traits装饰器报错。

一种解决方法是排除TBarfoo方法。

  1. import { traits, excludes } from 'traits-decorator';
  2. class TFoo {
  3. foo() { console.log('foo') }
  4. }
  5. const TBar = {
  6. bar() { console.log('bar') },
  7. foo() { console.log('foo') }
  8. };
  9. @traits(TFoo, TBar::excludes('foo'))
  10. class MyClass { }
  11. let obj = new MyClass();
  12. obj.foo() // foo
  13. obj.bar() // bar

上面代码使用绑定运算符(::)在TBar上排除foo方法,混入时就不会报错了。

另一种方法是为TBarfoo方法起一个别名。

  1. import { traits, alias } from 'traits-decorator';
  2. class TFoo {
  3. foo() { console.log('foo') }
  4. }
  5. const TBar = {
  6. bar() { console.log('bar') },
  7. foo() { console.log('foo') }
  8. };
  9. @traits(TFoo, TBar::alias({foo: 'aliasFoo'}))
  10. class MyClass { }
  11. let obj = new MyClass();
  12. obj.foo() // foo
  13. obj.aliasFoo() // foo
  14. obj.bar() // bar

上面代码为TBarfoo方法起了别名aliasFoo,于是MyClass也可以混入TBarfoo方法了。

aliasexcludes方法,可以结合起来使用。

  1. @traits(TExample::excludes('foo','bar')::alias({baz:'exampleBaz'}))
  2. class MyClass {}

上面代码排除了TExamplefoo方法和bar方法,为baz方法起了别名exampleBaz

as方法则为上面的代码提供了另一种写法。

  1. @traits(TExample::as({excludes:['foo', 'bar'], alias: {baz: 'exampleBaz'}}))
  2. class MyClass {}