Unterklassen von nativen Objekten: Instanceof funktioniert nicht richtig
Ich versuche, die native JS zu unterordnenError
Objekt in CoffeeScript, um spezialisierte Fehlertypen zu erhalten, aber ich fand, dass dieinstanceof
funktioniert nicht richtig, wenn ich keinen Konstruktor in den Unterklassen definiere:
class SimpleError extends Error
class EmptyConstructorError extends Error
constructor: ->
class SuperConstructorError extends Error
constructor: ->
super
new SimpleError instanceof SimpleError # -> false
new EmptyConstructorError instanceof EmptyConstructorError # -> true
new SuperConstructorError instanceof SuperConstructorError # -> true
Das Problem scheint dadurch verursacht zu werden, wie diegeneriert JS Konstruktorfunktionen sind definiert. Wenn ichnicht Definieren Sie einen Konstruktor in CoffeeScript:
SimpleError = (function(_super) {
__extends(SimpleError, _super);
function SimpleError() {
return SimpleError.__super__.constructor.apply(this, arguments);
}
return SimpleError;
})(Error);
Und wenn ichtun Definieren Sie einen Konstruktor in CoffeeScript:
SuperConstructorError = (function(_super) {
__extends(SuperConstructorError, _super);
function SuperConstructorError() {
SuperConstructorError.__super__.constructor.apply(this, arguments);
}
return SuperConstructorError;
})(Error);
Wie Sie sehen, ist der Unterschied einfachreturn
im ersten Fall. Ich verstehe nicht, warum das einen Unterschied machtinstanceof
Verhalten jedoch, da der Superkonstruktor nur auf die angewendet wirdthis
object (d. h. der Superkonstruktor wird nicht mit aufgerufennew
), aber andererseits verstehe ich nicht viel darüber, wie JS-Konstruktoren arbeiten = P
Und das Seltsame ist, dass dieses Verhalten anscheinend nur auftritt, wenn native JS-Objekte unterklassifiziert werden. Wenn ich CoffeeScript-Klassen untergeordnet habe, funktioniert alles wie erwartet.
Irgendeine Idee, warum dies passieren könnte und wie ich vermeiden könnte, Dummy - Konstruktoren nur für das zu schreibeninstanceof
Betreiber richtig arbeiten?
Vielen Dank!
AktualisierenAlso der User matyrantwortete mit einem Link zu dem Commit, in dem dieses Verhalten eingeführt wurde, aber es erklärt nicht ganz, was hier passiert, also werde ich versuchen, dies ein wenig zu erklären, falls sich jemand fragt, warum dies so funktioniert.
Das Hauptproblem ist dieses böse "Feature", das von JavaScript geerbt wurde und mit dem wir eine Konstruktorfunktion definieren können, die ein anderes Objekt als das zu erstellende zurückgibt:
function Foo() {
return {'LOL': 'You fool!'};
}
new Foo() instanceof Foo // -> false
Und es gibt auch die Tatsache, dass einige einheimische Konstrukteure mögenError
, Array
, String
und womit nicht gerufen werden mussnew
: Sie geben nur dann ein neues Objekt des entsprechenden Typs zurück, wenn Sie es vergessen haben.
Am Ende addieren Sie diese beiden hässlichen Dinge und das Ergebnis ist, dass Sie daran denken sollten, zu schreibenclass MyError extends Error then constructor: -> super
statt der intuitiverenclass MyError extends Error
wenn du das willstinstanceof
Betreiber, um richtig mit zu arbeitenMyError
. Das liegt daran, dass der implizite Konstruktor von CoffeeScript nur das zurückgibt, was der übergeordnete Konstruktor zurückgibt, und in diesem Fall auchreturn Error.apply(this, arguments)
das wird nur ein shinny neues Fehlerobjekt anstelle des Objekts zurückgeben, das Sie als das übergebenethis
Streit. Yay!
Dieses Problemwurde in CoffeeScript 1.5.0 behoben! = D
Das Erweitern nativer Objekte funktioniert nun wie erwartet:
class MyError extends Error
new MyError instanceof MyError # -> true :)
Update 3 (4. März 2013)Aaund es ist auf 1.6.0 = P gegangen