web-dev-qa-db-ja.com

TypeScript-クラスを継承してラムダメソッドをオーバーライドする方法

継承されたクラスがあり、親には仮想メソッドが必要です。仮想メソッドは子クラスでオーバーライドされます。このメソッドは基本コンストラクターから呼び出され、インスタンスプロパティにアクセスする必要があるため、ラムダ関数である必要があるため、「this」は「_this」です。問題は、ラムダメソッドのオーバーライドが、非ラムダメソッドのオーバーライドのように機能しないことです。これは可能ですか?そうでない場合は、その理由を理解したいと思います。

また、メソッドがコンストラクターからのみ呼び出される場合、「this」は常に「_this」と同じになりますか?

class Base {
    protected prop = null;
    constructor() {
        this.init();
        this.initLambda();
    }
    init() {
        console.log("Base init");
    }
    initLambda = () => {
        console.log("Base initLambda");
    }
}
class Derived extends Base {
    constructor() {
        super();
    }
    init() {
        console.log("Derived init");
    }
    initLambda = () => {
        //let x = this.prop;
        console.log("Derived initLambda");
    }
}

出力:
導出されたinit
ベースinitLambda

9
user210757

まあ、それはありません。
未解決の問題 がありますが、「意図的に」クローズされました。

通常の方法を使用する必要があります。

_class Base {
    protected prop = null;

    constructor() {
        this.init();
        this.initLambda();
    }

    init() {
        console.log("Base init");
    }

    initLambda() {
        console.log("Base initLambda");
    }
}

class Derived extends Base {
    constructor() {
        super();
    }

    init() {
        console.log("Derived init");
    }

    initLambda() {
        console.log("Derived initLambda");
    }
}
_

そして、それはうまくいきます。

正しいthisを維持することに関しては、常にメソッドへの呼び出しを矢印関数として渡すことができます:

_doit() {
    setTimeout(() => this.init(), 1);
}
_

または Function.prototype.bind 関数を使用します。

_setTimeout(this.init.bind(this));
_

また、TypeScriptコンパイラが生成する__this_は、ES5の矢印関数をポリフィルするためのハックにすぎませんが、ターゲットをES6に変更すると、使用されなくなります。


編集:

バインドされたメソッドをメンバーとして保存できます。

_class Base {
    ...
    public boundInit: () => void;

    constructor() {
        ...
        this.boundInit = this.initLambda.bind(this);
        setTimeout(this.boundInit, 500);
    }

...
_

これで、new Derived()を実行すると、次のようになります。

派生init
派生initLambda // 200ミリ秒後

12
Nitzan Tomer

問題は、ラムダがプロパティであることです。

JavaScriptにコンパイルすると、Baseclassは次のようになります

_var Base = (function () {
    function Base() {
        this.prop = null;
        this.initLambda = function () {
            console.log("Base initLambda");
        };
        this.init();
        this.initLambda();
    }
    Base.prototype.init = function () {
        console.log("Base init");
    };
    return Base;
}());
_

ご覧のとおり、initLambdaBaseのコンストラクターinsideで定義されているため、オーバーライドする方法はありません。 。

super()を呼び出すと、Baseのコードで_this.initLambda_を定義するBaseコンストラクターが呼び出され、実行されます。したがって、あなたの結果。

playground で表示

2
Bruno Grieder