TypeScript应该在ES5的编译输出中的_super调用之前分配给this?

Rom*_*oss 3 javascript transpiler typescript

我对所有扩展抽象类的子类使用依赖项注入。

在抽象构造函数类中,如果需要的话,我启动了一个计划在其子级中覆盖的方法。

我陷入了一个问题,即从super启动的重写类中看不到注入的依赖项。

这是代码示例:

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();
Run Code Online (Sandbox Code Playgroud)

因此,问题的核心是打字稿将Example类转换为如下代码:

function Example(view, helper) {
    _super.call(this, view);
    this.helper = helper;
    console.log(this.helper);
}
Run Code Online (Sandbox Code Playgroud)

代替这个:

function Example(view, helper) {
    this.helper = helper;
    _super.call(this, view);
    console.log(this.helper);
}
Run Code Online (Sandbox Code Playgroud)

如您所见,如果我在JavaScript中放在this.helper前面_superthis.helper则始终会在中显示_assemble。即使super会调用该_assemble函数。

但是作为默认分配是在_super调用之后。因此,如果superclass将调用assemble。_assemble第一次在“示例” 中的覆盖方法中将不可见。

所以我的问题是

是虫子吗?

要么

我不知道什么

现在,我解决了我的问题,只是_assemblesuper课堂上删除,并始终从孩子那里调用它。但这感觉不对。

Nota Bene:这是已编译的JavaScript代码与固定的JavaScript代码演示:

TypeScript通常的输出:

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();
Run Code Online (Sandbox Code Playgroud)

TypeScript固定的javascript输出:

function Example(view, helper) {
    _super.call(this, view);
    this.helper = helper;
    console.log(this.helper);
}
Run Code Online (Sandbox Code Playgroud)

Rom*_*oss 5

孩子不能在父母“存在”之前出生。

在Java和其他OOP语言中,必须在实例化当前对象之前调用super()。

这是合乎逻辑的,因为child cannot be born before parent

TypeScript 2现在可以使用以前的语句super(如果它们不习惯于)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 __());
};
Run Code Online (Sandbox Code Playgroud)

从这个角度来看,没有这样的“孩子”和“父母”,但有某种“集合”。集只能在已经存在的情况下才能被另一个集扩展。这使我们能够:

自上而下和自下而上的设计。

原型和鸭子打字在自下而上的设计中起作用。自顶向下设计中的OOP。


在这种情况下如何解决这种奇怪的情况?

只是不要!通过学习和实施OOP想法的力量!这里是如何成功的:

  • 组成重于继承,重新思考代码设计。将基类拆分为接口和一个类,您可以将其实例传递给“子”类的构造函数,并通过实现声明的接口来组成所需的实例。
  • 使用static,但是请注意,此更改对于您对象的所有实例都是相同的。

    如果仅将其用于依赖项注入,则可以

  • 智能覆盖。

    不要使用同级(“子级”)实例中的额外资源,而要创建自己的额外方法,该方法将从构造函数中调用。

    下面的示例(请注意,这不会违反LSP,因为__assembled在构造函数中仅设置了一次):

    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();
    
    Run Code Online (Sandbox Code Playgroud)

这是转译的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 __());
};
Run Code Online (Sandbox Code Playgroud)