混入

Table of contents

介绍

混入示例

理解示例

介绍

↥ 回到顶端

除了传统的面向对象继承方式,还流行一种通过可重用组件创建类的方式,就是联合另一个简单类的代码。 你可能在Scala等语言里对mixins及其特性已经很熟悉了,但它在JavaScript中也是很流行的。

混入示例

↥ 回到顶端

下面的代码演示了如何在TypeScript里使用混入。 后面我们还会解释这段代码是怎么工作的。

  1. // Disposable Mixin
  2. class Disposable {
  3. isDisposed: boolean;
  4. dispose() {
  5. this.isDisposed = true;
  6. }
  7. }
  8. // Activatable Mixin
  9. class Activatable {
  10. isActive: boolean;
  11. activate() {
  12. this.isActive = true;
  13. }
  14. deactivate() {
  15. this.isActive = false;
  16. }
  17. }
  18. class SmartObject {
  19. constructor() {
  20. setInterval(() => console.log(this.isActive + " : " + this.isDisposed), 500);
  21. }
  22. interact() {
  23. this.activate();
  24. }
  25. }
  26. interface SmartObject extends Disposable, Activatable {}
  27. applyMixins(SmartObject, [Disposable, Activatable]);
  28. let smartObj = new SmartObject();
  29. setTimeout(() => smartObj.interact(), 1000);
  30. ////////////////////////////////////////
  31. // In your runtime library somewhere
  32. ////////////////////////////////////////
  33. function applyMixins(derivedCtor: any, baseCtors: any[]) {
  34. baseCtors.forEach(baseCtor => {
  35. Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
  36. Object.defineProperty(derivedCtor.prototype, name, Object.getOwnPropertyDescriptor(baseCtor.prototype, name));
  37. });
  38. });
  39. }

理解示例

↥ 回到顶端

代码里首先定义了两个类,它们将做为mixins。 可以看到每个类都只定义了一个特定的行为或功能。 稍后我们使用它们来创建一个新类,同时具有这两种功能。

  1. // Disposable Mixin
  2. class Disposable {
  3. isDisposed: boolean;
  4. dispose() {
  5. this.isDisposed = true;
  6. }
  7. }
  8. // Activatable Mixin
  9. class Activatable {
  10. isActive: boolean;
  11. activate() {
  12. this.isActive = true;
  13. }
  14. deactivate() {
  15. this.isActive = false;
  16. }
  17. }

下面创建一个类,结合了这两个mixins。 下面来看一下具体是怎么操作的:

  1. class SmartObject {
  2. ...
  3. }
  4. interface SmartObject extends Disposable, Activatable {}

首先注意到的是,我们没有在SmartObject类里面继承DisposableActivatable,而是在SmartObject接口里面继承的。由于声明合并的存在,SmartObject接口会被混入到SmartObject类里面。

它将类视为接口,且只会混入Disposable和Activatable背后的类型到SmartObject类型里,不会混入实现。也就是说,我们要在类里面去实现。 这正是我们想要在混入时避免的行为。

最后,我们将混入融入到了类的实现中去。

  1. // Disposable
  2. isDisposed: boolean = false;
  3. dispose: () => void;
  4. // Activatable
  5. isActive: boolean = false;
  6. activate: () => void;
  7. deactivate: () => void;

最后,把mixins混入定义的类,完成全部实现部分。

  1. applyMixins(SmartObject, [Disposable, Activatable]);

最后,创建这个帮助函数,帮我们做混入操作。 它会遍历mixins上的所有属性,并复制到目标上去,把之前的占位属性替换成真正的实现代码。

  1. function applyMixins(derivedCtor: any, baseCtors: any[]) {
  2. baseCtors.forEach(baseCtor => {
  3. Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
  4. Object.defineProperty(derivedCtor.prototype, name, Object.getOwnPropertyDescriptor(baseCtor.prototype, name));
  5. })
  6. });
  7. }