TypeScript混入Mixins
阿新 • • 發佈:2021-01-20
介紹
除了傳統的面向物件繼承方式,還流行一種通過可重用元件建立類的方式,就是聯合另一個簡單類的程式碼。 你可能在Scala等語言裡對mixins及其特性已經很熟悉了,但它在JavaScript中也是很流行的。
混入示例
下面的程式碼演示瞭如何在TypeScript裡使用混入。 後面我們還會解釋這段程式碼是怎麼工作的。
// Disposable Mixin class Disposable { isDisposed: boolean; dispose() { this.isDisposed = true; } } // Activatable Mixin class Activatable { isActive: boolean; activate() { this.isActive = true; } deactivate() { this.isActive = false; } } class SmartObject implements Disposable, Activatable { constructor() { setInterval(() => console.log(this.isActive + " : " + this.isDisposed), 500); } interact() { this.activate(); } // Disposable isDisposed: boolean = false; dispose: () => void; // Activatable isActive: boolean = false; activate: () => void; deactivate: () => void; } applyMixins(SmartObject, [Disposable, Activatable]); let smartObj = new SmartObject(); setTimeout(() => smartObj.interact(), 1000); //////////////////////////////////////// // In your runtime library somewhere //////////////////////////////////////// function applyMixins(derivedCtor: any, baseCtors: any[]) { baseCtors.forEach(baseCtor => { Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => { derivedCtor.prototype[name] = baseCtor.prototype[name]; }); }); }
理解這個例子
程式碼裡首先定義了兩個類,它們將做為mixins。 可以看到每個類都只定義了一個特定的行為或功能。 稍後我們使用它們來建立一個新類,同時具有這兩種功能。
// Disposable Mixin class Disposable { isDisposed: boolean; dispose() { this.isDisposed = true; } } // Activatable Mixin class Activatable { isActive: boolean; activate() { this.isActive = true; } deactivate() { this.isActive = false; } }
下面建立一個類,結合了這兩個mixins。 下面來看一下具體是怎麼操作的:
class SmartObject implements Disposable, Activatable {
首先應該注意到的是,沒使用extends
而是使用implements
。 把類當成了介面,僅使用Disposable和Activatable的型別而非其實現。 這意味著我們需要在類裡面實現介面。 但是這是我們在用mixin時想避免的。
我們可以這麼做來達到目的,為將要mixin進來的屬性方法創建出佔位屬性。 這告訴編譯器這些成員在執行時是可用的。 這樣就能使用mixin帶來的便利,雖說需要提前定義一些佔位屬性。
// Disposable
isDisposed: boolean = false;
dispose: () => void;
// Activatable
isActive: boolean = false;
activate: () => void;
deactivate: () => void;
最後,把mixins混入定義的類,完成全部實現部分。
applyMixins(SmartObject, [Disposable, Activatable]);
最後,建立這個幫助函式,幫我們做混入操作。 它會遍歷mixins上的所有屬性,並複製到目標上去,把之前的佔位屬性替換成真正的實現程式碼。
function applyMixins(derivedCtor: any, baseCtors: any[]) {
baseCtors.forEach(baseCtor => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
derivedCtor.prototype[name] = baseCtor.prototype[name];
})
});
}