2016-06-15 13 views
0

Ich sehe ein seltsames Verhalten, das ich nicht erklären kann, so hoffte, dass jemand helfen kann.Typescrit erweitert Klassen, verhält sich nicht logisch

Ich habe eine Elternklasse und Kindklasse:

class Foo {} 

class Bar extends Foo {} 

Es gibt einige Sachen in der Mutter Konstruktor geschehen, und es ruft dann eine „Setup“ Klasse des Kindes etwas mehr Dinge zu tun. Ich kann das Kind-Zeug nicht in seinen Konstruktor einfügen, weil ich im Eltern-Konstruktor eine Bedingung habe, die entscheidet, ob es passieren soll oder nicht.

class Foo { 
    constructor(){ 
     ... 
     this.startup(); 
    } 
} 

class Bar extends Foo { 
    public startup(){ 
     ... 
    } 
} 

Nun zu dem Problem. In untergeordneter Klasse habe ich Aktion, den Rückruf erfolgt, und der Rückruf ist einer der privaten Mitglieder dieser Klasse

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

Leider ist dies nicht funktioniert. Wenn ich "dies" kurz vor dem Abonnieren protokolliere, existiert die onChannel nicht. Nach viel Versuch/Irrtum habe ich mehr Zeug bemerkt.

Fall 1

JSFiddle: https://jsfiddle.net/pjx46kh2/

Wenn ich tun:

class Bar extends Foo { 
    public startup(){ ... } 
    public something(){ ... } 
    private onChannel = (msg) => { ... } 
} 

Es zu kompiliert:

var Bar = (function (_super) { 
    __extends(Bar, _super); 
    function Bar() { 
     _super.apply(this, arguments); 
     this.onChannel = function (msg) { 
      console.log(msg); 
     }; 
    } 
... 

Und es funktioniert nicht (siehe oben).

Fall 2

JSFiddle: https://jsfiddle.net/9k6a2my0/1/

Wenn ich tun:

var Bar = (function (_super) { 
    __extends(Bar, _super); 
    function Bar(arg) { 
     _super.call(this, arg); 
     this.onChannel = function (msg) { 
      console.log(msg); 
     }; 
    } 

Und es funktioniert nicht:

class Bar extends Foo { 
    constructor(arg){ 
     super(arg); 
    } 
    public startup(){ ... } 
    public something(){ ... } 
    private onChannel = (msg) => { ... } 
} 

Es zu kompiliert.

Fall 3

JSFiddle: https://jsfiddle.net/ao02oru8/2/

Wenn ich tun:

class Bar extends Foo { 
    constructor(arg){ 
     super.constructor(arg); 
    } 
    public startup(){ ... } 
    public something(){ ... } 
    private onChannel = (msg) => { ... } 
} 

Es kompiliert:

var Bar = (function (_super) { 
    __extends(Bar, _super); 
    function Bar(arg) { 
     this.onChannel = function (msg) { 
      console.log(msg); 
     }; 
     _super.prototype.constructor.call(this, arg); 
    } 

Und es funktioniert ...

Offensichtlich ist mein Code viel komplizierter und es handelt sich tatsächlich um ziemlich viele Ereignisse und asynchrone Sachen, wenn Sie also ein Beispiel in Geige machen, könnte es gut funktionieren, aber es könnte nicht funktionieren.

Jede gute Seele könnte erklären, was hier vor sich geht?

+0

Ihr letztes Beispiel nicht kompiliert mit [Typoskript Spielplatz] (http://www.typescriptlang.org/play/ index.html), behauptet er, dass der Unterklassenkonstruktor einen Aufruf von 'super()' enthalten muss (was sinnvoll ist). Ich vermute also, dass es * nicht funktioniert, da der gezeigte transpilierte OnChannel nicht mehr an ein bestimmtes "This" gebunden ist als das darüberliegende. –

+0

@ T.J.Crowder tatsächlich auf meinem PC kompiliert es, obwohl mit dem gleichen Fehler, aber am Ende funktioniert es. Es ist die einzige Möglichkeit, das funktioniert, wie ich in der Frage – Tom

+0

* erwähnt habe "auf meinem PC kompiliert es, obwohl mit dem gleichen Fehler" * Das heißt ** nicht kompilieren **. :-) Wenn es überhaupt eine Ausgabe gibt, ist TypeScript schlecht, aber man kann Fehler nicht einfach ignorieren. Re "arbeiten": Der 'onChannel' im letzten transpilierten Block (der, den du gesagt hast" funktioniert ") ist ** identisch mit dem' onChannel' im vorherigen transpilierten Block (der, den du gesagt hast, t "Arbeit"). Also werden sie beide "arbeiten" oder nicht "arbeiten". Es könnte hilfreich sein, wenn Sie definieren, was "funktioniert" bedeutet, aber ehrlich gesagt, ich denke, dies ist nur Beobachtungsfehler und ein Versuch, ein Konstrukt zu verwenden, das nicht dort unterstützt wird, wo Sie es verwenden. –

Antwort

1

Nun, vor allem sollten Sie keinen Code schreiben, der den Compiler nicht richtig übergibt. Typescript wird viele Fehler durchlassen, aber Sie sollten keinen Vorteil daraus ziehen.

Was in Ihrem ersten Beispiel passiert, ist, dass die Bar :: onChannel zuerst nach dem Aufruf definiert wird das Super-Konstruktor passiert:

function Bar() 
{ 
    _super.apply(this, arguments); 
    this.onChannel = function (msg) 
    { 
     console.log(msg); 
    }; 
} 

daher Ihre Logik in dem Konstruktor der Basisklasse wird fehlschlagen.

werden Methoden definiert direkt auf dem Prototyp, bevor Konstrukteure genannt werden (im Gegensatz zu Feldern):

Bar.prototype.startup = function() { 
    this.something(); 
}; 

... so ist dies, warum Sie Ihre Methoden zugreifen können, nicht aber das Feld onChannel.

Dies gilt für Ihr erstes und zweites Beispiel. Wenn Sie im abgeleiteten Konstruktor Code schreiben, ohne zuerst super() aufzurufen, veranlassen Sie den kompilierten Code, zuerst den onChannel zu definieren, da dies eine implizite Zuweisung ist, die vor Ihrer eigenen benutzerdefinierten Logik stattfinden sollte . Aber ich denke, dass das, worüber dieses eigentlich kompiliert, als undefiniert betrachtet wird, da es sowieso kein gültiges Typoskript ist.

Was Sie tun können, wenn Sie diese Art der logischen Struktur/flow wollen:

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