我看到一些我无法解释的奇怪行为。
我有一个父类和子类:
class Foo {}
class Bar extends Foo {}
在父构造函数中发生了一些事情,然后它调用了孩子的“setup”类来做更多的事情。我不能把子东西放在它的构造函数中,因为在父构造函数中我有一个条件决定它是否应该发生。
class Foo {
constructor(){
...
this.startup();
}
}
class Bar extends Foo {
public startup(){
...
}
}
现在问题。在子类中,我有一个需要回调的操作,回调是该类的私有成员之一
class Bar extends Foo {
public startup(){ ... }
public something(){
someModule.subscribe("channel", this.onChannel);
}
// As a variable rather than function to support "this"
private onChannel = (msg) => {
console.log(msg);
}
}
不幸的是,这不起作用。当我在订阅之前记录“this”时,onChannel
不存在。经过大量的反复试验,我注意到了更多的东西。
案例1
JSFiddle:https://jsfiddle.net/pjx46kh2/
如果我这样做:
class Bar extends Foo {
public startup(){ ... }
public something(){ ... }
private onChannel = (msg) => { ... }
}
汇编为:
var Bar = (function (_super) {
__extends(Bar, _super);
function Bar() {
_super.apply(this, arguments);
this.onChannel = function (msg) {
console.log(msg);
};
}
...
它不起作用(如上所述)。
案例2
JSFiddle:https://jsfiddle.net/9k6a2my0/1/
如果我这样做:
class Bar extends Foo {
constructor(arg){
super(arg);
}
public startup(){ ... }
public something(){ ... }
private onChannel = (msg) => { ... }
}
汇编为:
var Bar = (function (_super) {
__extends(Bar, _super);
function Bar(arg) {
_super.call(this, arg);
this.onChannel = function (msg) {
console.log(msg);
};
}
它不起作用。
案例3
JSFiddle:https://jsfiddle.net/ao02oru8/2/
如果我这样做:
class Bar extends Foo {
constructor(arg){
super.constructor(arg);
}
public startup(){ ... }
public something(){ ... }
private onChannel = (msg) => { ... }
}
汇编为:
var Bar = (function (_super) {
__extends(Bar, _super);
function Bar(arg) {
this.onChannel = function (msg) {
console.log(msg);
};
_super.prototype.constructor.call(this, arg);
}
它有效......
显然我的代码要复杂得多,实际上它处理的是很多事件和异步内容,所以如果你在小提琴中做一个例子,它可能会运行得很好,但可能没有。
答案 0 :(得分:1)
首先,您不应该编写不能正确传递编译器的代码。打字稿会让很多错误通过,但你不应该利用这个。
你的第一个例子中发生的事情是在调用超级构造函数之后首先定义了Bar :: onChannel:
function Bar()
{
_super.apply(this, arguments);
this.onChannel = function (msg)
{
console.log(msg);
};
}
因此,基类构造函数中的逻辑将失败。
在调用任何构造函数之前,直接在原型上定义方法(与字段不同):
Bar.prototype.startup = function () {
this.something();
};
...这就是为什么你可以访问你的方法,而不是你的字段onChannel。
这适用于您的第一个和第二个示例。
在第三个示例中,当您在派生构造函数中编写代码而不首先调用super()时,首先会导致编译代码定义onChannel,因为这是一个隐含的赋值,应该在您自己的自定义逻辑之前发生。但我认为这实际上编译的是考虑未定义,因为它无论如何都不是有效的打字稿。
如果你想要这种逻辑结构/流程你可以做什么:
abstract class Foo
{
abstract startup():void;
constructor()
{
this.startup();
}
}
class Bar extends Foo
{
public startup()
{
this.something();
}
public something()
{
// Bind this like this instead
someModule.subscribe("channel", (msg:any) => this.onChannel(msg));
}
public onChannel(msg) {
console.log(msg);
}
}
class SomeModule {
public subscribe(channel, callback){
console.log("channel", channel);
console.log("callback", callback);
}
}
var someModule = new SomeModule();
var bar = new Bar();