TypeScriptは、ES5のトランスパイル出力で `_super`を呼び出す前に` this`に割り当てる必要がありますか?

ローマM.コス

抽象クラスを拡張するすべての子クラスに依存性注入を使用します。

抽象コンストラクタークラスで、必要に応じて子でオーバーライドする予定のメソッドを起動するという問題。

スーパーから起動されたオーバーライドクラスに、注入された依存関係が表示されないという問題が発生しました。

コードの例を次に示します。

abstract class Base {

    constructor(view: string) {
        this._assemble();
    }

    protected _assemble(): void {
        console.log("abstract assembling for all base classes");
    }

}

class Example extends Base {

    constructor(view: string, private helper: Function) {
        super(view);
        console.log(this.helper);
    }

    public tryMe(): void {
        this._assemble();
    }

    protected _assemble(): void {
        super._assemble();
        // at first run this.helper will be undefined!
        console.log("example assembling", this.helper);
    }

}

let e = new Example("hoho", function () { return; })
console.log("So now i will try to reassemble...");
e.tryMe();

したがって、問題の核心は、typescriptがExampleクラスを次のようにコード化することです。

function Example(view, helper) {
    _super.call(this, view);
    this.helper = helper;
    console.log(this.helper);
}

これの代わりに:

function Example(view, helper) {
    this.helper = helper;
    _super.call(this, view);
    console.log(this.helper);
}

ご覧のとおり、this.helper_superにJavaScriptで配置this.helperすると常にで表示され_assembleます。関数superを呼び出す場合でも_assemble

ただし、デフォルトでは、これへの割り当ては_super呼び出しです。したがって、superクラスがアセンブルを呼び出す場合_assemble例のオーバーライドされたメソッドでは、最初は表示されません

だから私の質問は...

バグですか?

または

何がわからないの?

今のところ_assemblesuperクラスから削除常に子から呼び出すという問題を修正しましたしかし、これはただ間違っていると感じます。

Nota Bene:コンパイルされたJavaScriptコードと修正されたJavaScriptコードのデモは次のとおりです。

TypeScriptの通常の出力:

var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var Base = (function () {
    function Base(view) {
        this._assemble();
    }
    Base.prototype._assemble = function () {
        document.write("<p>abstract assembling for all base classes</p>");
    };
    return Base;
}());
var Example = (function (_super) {
    __extends(Example, _super);
    function Example(view, helper) {
        _super.call(this, view);
        this.helper = helper;
        console.log(this.helper);
    }
    Example.prototype.tryMe = function () {
        this._assemble();
    };
    Example.prototype._assemble = function () {
        _super.prototype._assemble.call(this);
        // at first run this.helper will be undefined!
        document.write("<p>example assembling <b/>" + (this.helper) + "</b></p>");
    };
    return Example;
}(Base));
var e = new Example("test", function () { return "needle"; });
document.write("<p><i>So now i will try to reassemble...</i></p>");
e.tryMe();

TypeScriptはjavascriptの出力を修正しました:

var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var Base = (function () {
    function Base(view) {
        this._assemble();
    }
    Base.prototype._assemble = function () {
        document.write("<p>abstract assembling for all base classes</p>");
    };
    return Base;
}());
var Example = (function (_super) {
    __extends(Example, _super);
    function Example(view, helper) {
        /**
         * Slight change, compiled assigning to this BEFORE _super.
         */
        this.helper = helper;
        _super.call(this, view);
        console.log(this.helper);
    }
    Example.prototype.tryMe = function () {
        this._assemble();
    };
    Example.prototype._assemble = function () {
        _super.prototype._assemble.call(this);
        // at first run this.helper will be undefined!
        document.write("<p>example assembling <b/>" + (this.helper) + "</b></p>");
    };
    return Example;
}(Base));
var e = new Example("test", function () { return "Needle"; });
document.write("<p><i>So now i will try to reassemble...</i></p>");
e.tryMe();

ローマM.コス

親の「存在」の前に子供を産むことはできません。

Javaおよびその他のOOP言語では現在のオブジェクトをインスタンス化する前にsuper()を呼び出す必要があります。

これは論理的ですchild cannot be born before parentなぜなら

TypeScript 2superは、を使用していない場合、のステートメントを含めることができるようになりましたthis

これは、this夕食前に使用できない理由の一部でした


コンストラクターで使用される子オーバーライドメソッドは、純粋に「親」リソースに存在する必要があります。

質問が触れる次の部分は、この子がまったくインスタンス化されていないときに、parentオブジェクトが実際にその子によるオーバーライドを呼び出すことassembleです。

子がインスタンス化されていないため、奇妙に思えますが、親コンストラクターがchildrenメソッドを呼び出します...そして、胎児が「お父さん」と言うように不自然に見えます。

この問題については、同様の投稿を参照してください。

しかし、これはこのように考えるのは間違った方法です。コンストラクターで使用される子からのオーバーライドは、子がインスタンス化される方法を変更するために純粋に存在します。

親コンストラクターで使用されるメソッドオーバーライドは、インスタンスの作成方法を指示する必要があります。親が利用できるが、存在しないインスタンスが持っているリソースからは利用できないリソースから。


ダックタイピングのプロトタイプと継承...

プロトタイプの継承は通常、extendこのような機能備えた新しいプロトタイプを合成することによって実現されます。

var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};

この観点からすると、「子供」や「親」というものはありませんが、「セット」というものはあります。セットは、それがすでに存在する場合にのみ、別のセットによって拡張できます。これにより、次のことが可能になります。

トップダウンとボトムアップのデザイン。

プロトタイプとダックタイピングはボトムアップ設計で機能します。トップダウン設計のOOP。


この場合、この奇妙な状況を回避するにはどうすればよいですか?

しないでください!それらを学び、実装することにより、OOPアイデアの力を活用してください!ここで成功する方法:

  • 継承よりも構成、コード設計を再考してください。基本クラスをインターフェースとクラスに分割します。そのインスタンスを「子」クラスのコンストラクターに渡すことができ、宣言されたインターフェースを実装することで目的のインスタンスを作成します。
  • staticを使用しますが、この変更はオブジェクトのすべてのインスタンスで同じになることに注意してください。

    これを依存性注入にのみ使用する場合は問題ありません

  • スマートオーバーライド。

    兄弟(「子」)インスタンスからの追加のリソースを使用せず、コンストラクターから呼び出される独自の追加のメソッドを作成します。

    以下の例(__assembledコンストラクターで一度だけ設定されるため、これはLSPに違反しないことに注意してください):

    abstract class Base {
    
        constructor(view: string) {
            this._assemble();
        }
    
        protected _assemble(): void {
            console.log("abstract assembling for all base classes");
        }
    
    }
    
    class Example extends Base {
    
        private __assembled: boolean = false;
    
        constructor(view: string, private helper: Function) {
            super(view);
            this._assemble_helper();
            this.__assembled = true;
        }
    
        public tryMe(): void {
            this._assemble();
        }
    
        protected _assemble(): void {
            super._assemble();
            // removed from here all extra resources
            // but run them when u need to assemble them again.
            if (this.__assembled) {
                this._assemble_helper();
            }
        }
    
        protected _assemble_helper(): void {
            // at first run this.helper will be undefined!
            console.log("example assembling", this.helper);
        }
    
    }
    
    let e = new Example("hoho", function () { return; })
    console.log("So now i will try to reassemble...");
    e.tryMe();
    

トランスパイルされたES5の結果は次のとおりです。

var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var Base = (function () {
    function Base(view) {
        this._assemble();
    }
    Base.prototype._assemble = function () {
        console.log("abstract assembling for all base classes");
    };
    return Base;
}());
var Example = (function (_super) {
    __extends(Example, _super);
    function Example(view, helper) {
        var _this = _super.call(this, view) || this;
        _this.helper = helper;
        _this.__assembled = false;
        _this._assemble_helper();
        _this.__assembled = true;
        return _this;
    }
    Example.prototype.tryMe = function () {
        this._assemble();
    };
    Example.prototype._assemble = function () {
        _super.prototype._assemble.call(this);
        // removed from here all extra resources
        // but run them when u need to assemble them again.
        if (this.__assembled) {
            this._assemble_helper();
        }
    };
    Example.prototype._assemble_helper = function () {
        // at first run this.helper will be undefined!
        console.log("example assembling", this.helper);
    };
    return Example;
}(Base));
var e = new Example("hoho", function () { return; });
console.log("So now i will try to reassemble...");
e.tryMe();

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

Related 関連記事

ホットタグ

アーカイブ