簡體   English   中英

在 typescript 中使用 mixins 來模擬 super 有什么好處嗎?

[英]Is there a wasy to emulate super with mixins in typescript?

我通過 Mixins 使用多重繼承(使用替代模式)。 有沒有辦法用這種模式獲得類似於“超級”的東西? 考慮這里的例子

abstract class Activatable{
    private activated: boolean = false;
    constructor(){}
    public activate(): void {
        this.activated = true;
        console.log('Activatable activated')
  }
}

class SomethingElse{};

interface ThingParent extends Activatable{}

class ThingParent extends SomethingElse{
    public activate(): void {
        (this as Activatable).activate();
        let addSomeValueHere = true;
        console.log('Thing parent activated')
    }
}

applyMixins(ThingParent, [Activatable]);

class Thing extends ThingParent {
    constructor(){
        super()
    }
    public activate(): void {
        super.activate();
        
        console.log('Thing activated');
    }
}

let thing = new Thing();
thing.activate();



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)
      );
    });
  });
}

Thing 擴展了 ThingParent,它通過 mixins 擴展了一個名為 Activatable 的類。 當我在 Thing 上調用 activate 時,我也想在 ThingParent 和 Activatable 上調用 activate,但它只在 Activatable 上調用。

如果我更改 ThingParent 上的函數名稱,我可以直接調用該函數,但 ThingParent 無法通過 super 訪問 Activatable(因為它擴展了 SomethingElse)。 然后我必須從 thing.activate() 調用 super.activate() 和 this.thingParentActivate() 所以這是我想盡可能避免的模式。

有替代方案嗎?

(Link to code on typescript playground: https://www.typescriptlang.org/play?#code/IYIwzgLgTsDGEAJYBthjAggvAlgN2AlGQFMBvAWACgFaEAHKfQkhOCZiEgEwC4EQAe0GlgAOwQBeBADNgyMCQDc1OkkFjIUAK7xBUABQBKMgF9VdetpDIcsNrgJdj-PIJzcElGmroQAFjhgAHTsnDxSCNDayha+6poiJMHIggDmBgDk2BxOxKxhTjyZRhbmVOXUKGgYAMqCALYkAThiaQCiCuSmKlTUrVxQcrCsACqBbQAKwFAkYogkAB5cYtwYOZz5ZtRVqOgI461p07PzCEsrawj1TS1tnYrealY2dg65LC4Ibh5ecb4GFoYNBYRyEfJGUJg5xGXrxWikRDAbjcG4kABq8hiAAkSLNItFYj54rANGAkil0llDm0GDM5kjocVSsSEOVKlRqvsaWlzss5lceScGX9WaTNNE9IYTP81GBtPQ8cZ-uVntZbPZCp8jK53J4nvD5YqoFCPjC4fDZXRxeTSJSMpkee9wtwShbaOydlRgPR6MgAJ4AWRwi1aYAMQvp8wANAgANobPI2EgAXVhXuoiKiE150jEJAA7gcc8Zenc0qbwqWM30qDJtGJcBo2L6A8HQ5oDNw8fgeABhCD6fjif2xm2SwdQMDDsT+uNp0W0cc6KUhGT6dpwfwGAwgNAkAf6IxSAB8i7oAHkQAArEjwYJpZoXgtiSZQQTGiD+gBywCa4b3RRDxNRhBEHL9FUhdcoE3WBtwMMQ-xIY9JDPA01CvW9727GRWhIN8PzxL8DCtWhuyYPB+0nYJQPA-1FWjUiEEQppGNZDCbzvCAHyfF8CM-f0ABESDAWAmHoSdd33YCaPfOiGOYpDjwAH2UpjaEwrjgjEkhPjEbRkGQFl4nTVlTFMj1TNMIA )

如您所知,JavaScript 類不支持多重繼承,因此如果您想獲得這種效果,您需要做一些事情來模擬它。 Mixin是實現此目的的一種方法,但它們並不真正支持沖突的方法名稱。 如果您有沖突的方法名稱,那么 mixins 最終會破壞除其中一個之外的所有方法,這不是您想要的。

如果您想在“子類”的實例上調用特定的“超類”方法,您可以直接使用Function.prototype.call()來執行this操作,並將實例作為 t​​his arg。 而不是Activatable::activate() ,您調用Activatable.prototype.activate.call(this); .

讓我們試一試:

interface ThingParent extends Activatable { }
class ThingParent extends SomethingElse {
    public activate(): void {
        Activatable.prototype.activate.call(this);
        let addSomeValueHere = true;
        console.log('Thing parent activated')
    }
}

class Thing extends ThingParent {
    constructor() {
        super()
    }
    public activate(): void {
        ThingParent.prototype.activate.call(this);
        console.log('Thing activated');
    }
}

let thing = new Thing();
thing.activate();
// [LOG]: "Activatable activated" 
// [LOG]: "Thing parent activated" 
// [LOG]: "Thing activated" 

這可以編譯並產生您期望的輸出。


在更復雜的場景中,您可能會決定需要組合使用 mixins 和直接方法call 或者其他一些方法。

Playground 代碼鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM