微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

javascript – 在ES5的转换输出中,TypeScript应该在`_super`之前调用`this`?

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

问题是,在抽象构造函数类中,我启动了一个我计划在子代中覆盖的方法,如果有必要的话.

我遇到的问题是我的注入依赖项在我从super启动的override类中不可见.

这是一个代码示例:

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

如您所见,如果我在_super之前将this.helper放在JavaScript中,this.helper将始终在_assemble中可见.即使super会调用_assemble函数.

但是默认情况下,在_super调用之后分配给它.所以如果超级类会调用汇编.第一次在Example中重写_assemble方法时不会显示它.

所以我的问题是……

这是一个错误吗?

要么

我不知道的是什么?

现在我修复了我的问题,只是从超类中删除_assemble,并始终从子进程调用它.但这只是错了.

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

解决方法:

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

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

这是合乎逻辑的,因为孩子不能在父母之前出生.

TypeScript 2 now can have statements before super, if they are not using to this.

这是为什么在晚餐前不能使用这个问题的答案的一部分.

构造函数中使用的子覆盖方法应该纯粹存在于“父”资源上.

接触问题的下一部分是,父对象实际上在其子集未实例化的同时实际调用其子节点的覆盖.

这看起来很奇怪,因为孩子们没有实例化,但是父母构造函数调用了孩子们的方法……而且看起来不自然,就像未出生的孩子说“爸爸”一样.

See similar post about this issue.

但这是一种错误的思考方式.来自将在构造函数中使用的子项的覆盖,纯粹存在以更改子项的实例化方式.

父构造函数中使用的方法覆盖必须告诉您应该如何制作实例.来自那些可用于父级的资源,而不是来自不存在的实例所具有的资源.

鸭子打字原型和继承……

原型中的继承通常通过合成具有这种扩展功能的新原型来实现.

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

从这个角度来看,没有“孩子”和“父母”这样,但有“套”,有点.只有在已存在的情况下,Set才能通过另一个集合进行扩展.这让我们:

Top-down and bottom-up design.

原型和鸭子打字工作采用自下而上的设计. OOP采用自顶向下设计.

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

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

> Composition over inheritance,重新考虑代码设计.将基类拆分为接口和类,可以将其实例传递给“child”类的构造函数,并通过实现声明的接口来组成所需的实例.
> Use static,但请注意,对于对象的所有实例,此更改都是相同的.

如果您仅将此用于依赖注入,则可以
>智能覆盖.

不要使用兄弟(“child”)实例中的额外资源,并创建一个将从构造函数中调用的额外方法.

下面的示例(请注意,这不违反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();

这是转换后的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] 举报,一经查实,本站将立刻删除。

相关推荐