TypeScript 应该在 ES5 的转译输出中调用 _super 之前分配给 this 吗?
TypeScript should assign to `this` before `_super` call in transpiled output for ES5?
我对所有扩展抽象 class.
的 child classes 使用依赖注入
抽象构造函数 class 中的问题我启动了一个方法,我计划在其 children 中重写,如有必要。
我遇到了一个问题,即我注入的依赖项在从 super 启动的覆盖 class 中不可见。
这是一个代码示例:
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();
所以问题的核心是打字稿将示例class转译为如下代码:
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
将始终在 _assemble
中可见。即使super
会调用_assemble
函数。
但默认分配给它是在 _super
调用之后。所以如果super
class 就会调用assemble。首次在示例中重写的 _assemble
方法中将不可见。
所以我的问题是...
这是一个错误吗?
或
我不知道什么?
现在我解决了我的问题,只是从 super
class 中删除 _assemble
,并始终从 child 中调用它。但这就是感觉不对。
诺塔贝内:
这是编译的 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之前出生 "existence".
在 Java 和其他 OOP 语言中,super() 必须在 之前被调用 当前 object 被实例化。
这是合乎逻辑的,因为child cannot be born before parent
。
TypeScript 2 now can have statements before super
, if they are not using to this
.
这是为什么 this
不能在晚饭前使用的答案的一部分。
Child 构造函数中使用的覆盖方法应该纯粹存在于 "parent" 资源上。
下一个问题涉及的部分是,parent
object 实际上在 child 的同时调用其 children assemble
的覆盖] 根本没有实例化。
这看起来很奇怪,因为 children 没有被实例化,但是 parent 构造函数调用了 children 方法......并且看起来像未出生的人一样不自然 child说 "dad".
See similar post about this issue.
但这样想是错误的。将在构造函数中使用的 children 的重写,纯粹是为了改变 child 的实例化方式。
parent 构造函数中使用的方法覆盖必须告诉您的实例应该如何制作。 来自那些可用于 parent 的资源,但是不是来自您的 non-existing 实例拥有的资源。
Duck typing 原型和继承...
原型中的继承通常通过合成具有 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 __());
};
从这个角度来看,没有 "children" 和 "parents" 本身,但有 "sets" 之类的。只有当一个集合已经存在时,它才能被另一个集合扩展。这将我们带到:
Top-down and bottom-up design.
原型和鸭子打字在 bottom-up 设计中起作用。自上而下设计中的 OOP。
在这种情况下如何解决这种奇怪的情况?
只是不要!通过学习和实施 OOP 思想的力量!如何成功:
- Composition over inheritance,重新思考代码设计。将基础 class 拆分为接口和一个 class,您可以将其实例传递给 "child" class 的构造函数,并通过实现已声明的接口来组合所需的实例。
Use static,但请注意,此更改对于您的 object 的所有实例都是相同的。
如果你只将它用于依赖注入就没问题
智能覆盖。
不要使用兄弟 ("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();
我对所有扩展抽象 class.
的 child classes 使用依赖注入抽象构造函数 class 中的问题我启动了一个方法,我计划在其 children 中重写,如有必要。
我遇到了一个问题,即我注入的依赖项在从 super 启动的覆盖 class 中不可见。
这是一个代码示例:
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();
所以问题的核心是打字稿将示例class转译为如下代码:
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
将始终在 _assemble
中可见。即使super
会调用_assemble
函数。
但默认分配给它是在 _super
调用之后。所以如果super
class 就会调用assemble。首次在示例中重写的 _assemble
方法中将不可见。
所以我的问题是...
这是一个错误吗?
或
我不知道什么?
现在我解决了我的问题,只是从 super
class 中删除 _assemble
,并始终从 child 中调用它。但这就是感觉不对。
诺塔贝内: 这是编译的 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之前出生 "existence".
在 Java 和其他 OOP 语言中,super() 必须在 之前被调用 当前 object 被实例化。
这是合乎逻辑的,因为child cannot be born before parent
。
TypeScript 2 now can have statements before super
, if they are not using to this
.
这是为什么 this
不能在晚饭前使用的答案的一部分。
Child 构造函数中使用的覆盖方法应该纯粹存在于 "parent" 资源上。
下一个问题涉及的部分是,parent
object 实际上在 child 的同时调用其 children assemble
的覆盖] 根本没有实例化。
这看起来很奇怪,因为 children 没有被实例化,但是 parent 构造函数调用了 children 方法......并且看起来像未出生的人一样不自然 child说 "dad".
See similar post about this issue.
但这样想是错误的。将在构造函数中使用的 children 的重写,纯粹是为了改变 child 的实例化方式。
parent 构造函数中使用的方法覆盖必须告诉您的实例应该如何制作。 来自那些可用于 parent 的资源,但是不是来自您的 non-existing 实例拥有的资源。
Duck typing 原型和继承...
原型中的继承通常通过合成具有 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 __());
};
从这个角度来看,没有 "children" 和 "parents" 本身,但有 "sets" 之类的。只有当一个集合已经存在时,它才能被另一个集合扩展。这将我们带到:
Top-down and bottom-up design.
原型和鸭子打字在 bottom-up 设计中起作用。自上而下设计中的 OOP。
在这种情况下如何解决这种奇怪的情况?
只是不要!通过学习和实施 OOP 思想的力量!如何成功:
- Composition over inheritance,重新思考代码设计。将基础 class 拆分为接口和一个 class,您可以将其实例传递给 "child" class 的构造函数,并通过实现已声明的接口来组合所需的实例。
Use static,但请注意,此更改对于您的 object 的所有实例都是相同的。
如果你只将它用于依赖注入就没问题
智能覆盖。
不要使用兄弟 ("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();