javascript - 在 ES5 的转译输出中调用 `this` 之前,TypeScript 应该分配给 `_super` 吗?

标签 javascript typescript transpiler

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

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

我遇到了一个问题,即我注入(inject)的依赖项在从 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();

所以一个问题的核心是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);
}

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

但默认分配给它是在 _super 调用之后。所以如果 super 类将调用汇编。第一次在Example中重写的_assemble方法中是不可见的。

所以我的问题是...

这是一个错误吗?

我不知道什么?

现在我解决了我的问题,只是从 super 类中删除 _assemble,并始终从子类中调用它。但这只是感觉不对。

注意事项: 这是编译后的 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();

最佳答案

child 不能在 parent “存在”之前出生。

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

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

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

这是为什么 this 的答案的一部分。不能在晚饭前使用。


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

问题涉及的下一部分是 parent对象实际上调用了其子项的覆盖 assemble在这个 child 根本没有被实例化的同时。

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

See similar post about this issue.

但这样想是错误的。将在构造函数中使用的子项的覆盖纯粹是为了改变您的子项的实例化方式。

在父构造函数中使用的方法覆盖必须告诉您的实例应该如何制作。从那些对父可用的资源,而不是从您不存在的实例所拥有的资源。


Duck 类型原型(prototype)和继承......

原型(prototype)中的继承通常通过将新原型(prototype)与 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 __());
};

从这个 Angular 来看,没有“ child ”和“ parent ”本身,但有某种“集合”。只有当一个集合已经存在时,它才能被另一个集合扩展。这将我们带到:

Top-down and bottom-up design.

原型(prototype)和鸭子打字在自下而上的设计中工作。自上而下设计中的 OOP。


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

只是不要!通过学习和实现 OOP 思想的力量!如何成功:

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

    如果你只将它用于依赖注入(inject),这没问题

  • 智能覆盖。

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

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

关于javascript - 在 ES5 的转译输出中调用 `this` 之前,TypeScript 应该分配给 `_super` 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41020742/

相关文章:

Javascript 检查对象是否为空或 null 字段和数组

javascript - 如何在 Promise 中仅返回解析类型?

php - 从 $ajax 中的链接检索值失败

javascript - Bootstrap 导航栏不完全打开

javascript - InnerHtml AJAX : Javascript not working

javascript - 使用 Typescript 编译运行 Nodemon?

javascript - ES6 rest 参数不适用于 babel

javascript - 如何编译 require 语句?

javascript - Typescript tsconfig 排除一些源文件

javascript - Angular 不从工厂获取数据