• Mixins
  • 介绍
  • 混入示例
  • 理解这个例子

    Mixins

    介绍

    除了传统的面向对象继承方式,还流行一种通过可重用组件创建类的方式,就是联合另一个简单类的代码。 你可能在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 implements Disposable, Activatable {
    19. constructor() {
    20. setInterval(() => console.log(this.isActive + " : " + this.isDisposed), 500);
    21. }
    22. interact() {
    23. this.activate();
    24. }
    25. // Disposable
    26. isDisposed: boolean = false;
    27. dispose: () => void;
    28. // Activatable
    29. isActive: boolean = false;
    30. activate: () => void;
    31. deactivate: () => void;
    32. }
    33. applyMixins(SmartObject, [Disposable, Activatable]);
    34. let smartObj = new SmartObject();
    35. setTimeout(() => smartObj.interact(), 1000);
    36. ////////////////////////////////////////
    37. // In your runtime library somewhere
    38. ////////////////////////////////////////
    39. function applyMixins(derivedCtor: any, baseCtors: any[]) {
    40. baseCtors.forEach(baseCtor => {
    41. Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
    42. derivedCtor.prototype[name] = baseCtor.prototype[name];
    43. });
    44. });
    45. }

    理解这个例子

    代码里首先定义了两个类,它们将做为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 implements Disposable, Activatable {

    首先应该注意到的是,没使用extends而是使用implements。 把类当成了接口,仅使用Disposable和Activatable的类型而非其实现。 这意味着我们需要在类里面实现接口。 但是这是我们在用mixin时想避免的。

    我们可以这么做来达到目的,为将要mixin进来的属性方法创建出占位属性。 这告诉编译器这些成员在运行时是可用的。 这样就能使用mixin带来的便利,虽说需要提前定义一些占位属性。

    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. derivedCtor.prototype[name] = baseCtor.prototype[name];
    5. })
    6. });
    7. }