Подклассы нативных объектов: instanceof не работает должным образом
Я пытаюсь создать подкласс нативного JSError
объект в CoffeeScript, чтобы получить специализированные типы ошибок, но я обнаружил, чтоinstanceof
не работает правильно, если я не определяю конструктор в подклассах:
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
Проблема, кажется, вызвана тем, каксгенерированный JS функции конструктора определены. Когда яdon't определить конструктор в CoffeeScript:
SimpleError = (function(_super) {
__extends(SimpleError, _super);
function SimpleError() {
return SimpleError.__super__.constructor.apply(this, arguments);
}
return SimpleError;
})(Error);
И когда яdo определить конструктор в CoffeeScript:
SuperConstructorError = (function(_super) {
__extends(SuperConstructorError, _super);
function SuperConstructorError() {
SuperConstructorError.__super__.constructor.apply(this, arguments);
}
return SuperConstructorError;
})(Error);
Как видите, разница простаreturn
в первом случае. Я не понимаю, почему это имеет какое-либо значение вinstanceof
поведение, так как супер-конструктор просто применяется кthis
объект (т.е. супер-конструктор не вызывается сnew
), но опять же, я не очень понимаю, как работают конструкторы JS = P
И странная вещь в том, что такое поведение происходит только при создании подклассов собственных объектов JS. Если я подкласс класса CoffeeScript все работает как ожидалось.
Любая идея о том, почему это может происходить и как я могу избежать написания фиктивных конструкторов только дляinstanceof
оператор правильно работает?
Спасибо!
UpdateТак что пользователь Матырответил со ссылкой на коммит, где это поведение было введено, но оно не вполне объясняет, что здесь происходит, поэтому я попытаюсь объяснить это немного на тот случай, если кто-нибудь еще удивится, почему это работает таким образом.
Основной проблемой является эта унаследованная неприятная «особенность» из JavaScript, который позволяет нам определить функцию конструктора, которая возвращает объект, отличный от создаваемого:
function Foo() {
return {'LOL': 'You fool!'};
}
new Foo() instanceof Foo // -> false
И есть еще тот факт, что некоторые нативные конструкторы, такие какError
, Array
, String
и тому, что не нужно вызывать сnew
: они просто вернут новый объект соответствующего типа, если вы забудете его.
В конце сложите эти две уродливые вещи вместе, и в результате вы должны будете написатьclass MyError extends Error then constructor: -> super
вместо более интуитивногоclass MyError extends Error
если вы хотитеinstanceof
оператор правильно работать сMyError
, Это потому, что неявный конструктор CoffeeScript просто возвратит все, что возвращает родительский конструктор, и в этом случаеreturn Error.apply(this, arguments)
который будет просто возвращать новый ошибочный объект вместо объекта, который вы передали какthis
аргумент. Ура!
Эта проблемабыло исправлено в CoffeeScript 1.5.0! = D
Теперь расширение нативных объектов работает как положено:
class MyError extends Error
new MyError instanceof MyError # -> true :)
Update 3 (Mar 04 2013)
А он ушел на 1.6.0 = P