TypeScript Mixins 概念介绍
Mixins
除了傳統的 OO 層次結構,另一種從可重用組件構建類的流行方法是通過組合更簡單的部分類來構建它們。 您可能熟悉 Scala 等語言的 mixin 或特征的想法,并且該模式在 JavaScript 社區中也很流行。
模式依賴于使用具有類繼承的泛型來擴展基類。 TypeScript 最好的 mixin 支持是通過類表達式模式完成的。
看一個例子:
class Sprite {name = "";x = 0;y = 0;constructor(name: string) {this.name = name;} }type Constructor = new (...args: any[]) => {};// This mixin adds a scale property, with getters and setters // for changing it with an encapsulated private property:function Scale<TBase extends Constructor>(Base: TBase) {return class Scaling extends Base {// Mixins may not declare private/protected properties// however, you can use ES2020 private fields_scale = 1;setScale(scale: number) {this._scale = scale;}get scale(): number {return this._scale;}}; }const EightBitSprite = Scale(Sprite);const flappySprite = new EightBitSprite("Bird"); flappySprite.setScale(0.8); console.log('Ethan:' ,flappySprite.scale);本例子和我之前的文章TypeScript 類裝飾器的一個例子和使用單步調試搞清楚其運行原理其實很類似,只是沒有使用裝飾器語法罷了。
使用Scale 對 Sprite 進行裝配,傳入的是 Class Sprite 的定義:
返回的是一個新的函數,但只要不使用該函數去實例化新的類實例,函數體就不會執行。
現在準備使用 Scale 裝飾過后的 Sprite 的擴展類去進行實例化操作了:
即將進入 mixin 內部:
首先執行基類的字段初始化邏輯:
然后才是子類字段的初始化邏輯:
Constrained Mixins
我們可以對上述 Mixins 做一些改造和增強。
在上面的形式中,mixin 沒有類的基礎知識,這會使創建你想要的設計變得困難。
比如,使用上面的 mixin,我們可以給任意的 Class 添加 _scale 屬性。
如果我們想對此做進一步限制,比如限制 Scale 只能裝飾某些特定類型的 Class.
為了對此建模,我們修改原始構造函數類型以接受泛型參數。
// This was our previous constructor: type Constructor = new (...args: any[]) => {}; // Now we use a generic version which can apply a constraint on // the class which this mixin is applied to type GConstructor<T = {}> = new (...args: any[]) => T;現在,使用這個類型構造器,必須傳入一個基類的類型作為類型參數:
type Spritable = GConstructor<Sprite>;現在,Scale 裝飾器只能修飾 Sprite 及其子類了:
現在,如果傳入一個并非 Sprite 及其子類的方法進入 Scale 裝飾器,會引起語法錯誤:
另一種通過 Object.defineProperty 實現的 Mixin
// Each mixin is a traditional ES class class Jumpable {jump() {} }class Duckable {duck() {} }// Including the base class Sprite {x = 0;y = 0; }// Then you create an interface which merges // the expected mixins with the same name as your base interface Sprite extends Jumpable, Duckable {} // Apply the mixins into the base class via // the JS at runtime applyMixins(Sprite, [Jumpable, Duckable]);let player = new Sprite(); player.jump(); console.log(player.x, player.y);// This can live anywhere in your codebase: function applyMixins(derivedCtor: any, constructors: any[]) {constructors.forEach((baseCtor) => {Object.getOwnPropertyNames(baseCtor.prototype).forEach((name) => {Object.defineProperty(derivedCtor.prototype,name,Object.getOwnPropertyDescriptor(baseCtor.prototype, name) ||Object.create(null));});}); }把 Jumpable 和 Duckable 的屬性通過 Object.defineProperty 賦給 Sprite:
最后的運行時效果:
interface Sprite,可以使用 Duckable 和 Jumpable 類里定義的方法了。
更多Jerry的原創文章,盡在:“汪子熙”:
總結
以上是生活随笔為你收集整理的TypeScript Mixins 概念介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: adc转换原理
- 下一篇: 空间计量的基本模型学习笔记