Subclassificando objetos nativos: instanceof não funcionando corretamente
Eu estou tentando subclasse o JS nativoError
objeto no CoffeeScript para obter tipos de erros especializados, mas eu achei que oinstanceof
não funciona corretamente se eu não definir um construtor nas subclasses:
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
O problema parece ser causado por como oJS gerado funções construtoras são definidas. Quando eunão faça define um construtor no CoffeeScript:
SimpleError = (function(_super) {
__extends(SimpleError, _super);
function SimpleError() {
return SimpleError.__super__.constructor.apply(this, arguments);
}
return SimpleError;
})(Error);
E quando euFaz define um construtor no CoffeeScript:
SuperConstructorError = (function(_super) {
__extends(SuperConstructorError, _super);
function SuperConstructorError() {
SuperConstructorError.__super__.constructor.apply(this, arguments);
}
return SuperConstructorError;
})(Error);
Como você pode ver, a diferença é simplesreturn
no primeiro caso. Eu não entendo porque isso faz alguma diferença noinstanceof
comportamento, porém, como o super construtor está apenas sendo aplicado aothis
objeto (ou seja, o super construtor não está sendo chamado comnew
), mas, novamente, eu não entendo muito como os construtores JS trabalham = P
E o mais estranho é que esse comportamento parece acontecer apenas ao criar subclasses de objetos JS nativos. Se eu subclasse classes CoffeeScript, tudo funciona como esperado.
Alguma idéia de por que isso pode estar acontecendo e como eu poderia evitar escrever construtores falsos apenas para oinstanceof
operador para funcionar corretamente?
Obrigado!
AtualizarEntão o usuário matyrrespondidas com um link para o commit onde este comportamento foi introduzido, mas isso não explica exatamente o que está acontecendo aqui, então eu tentarei explicar isso um pouco caso alguém mais se pergunte por que isso funciona dessa maneira.
O principal problema é esse "recurso" desagradável herdado do JavaScript que nos permite definir uma função construtora que retorna um objeto diferente daquele que está sendo construído:
function Foo() {
return {'LOL': 'You fool!'};
}
new Foo() instanceof Foo // -> false
E há também o fato de que alguns construtores nativos, comoError
, Array
, String
e não precisa ser chamado comnew
: eles apenas retornarão um novo objeto do tipo correspondente se você o esquecer.
No final, adicione essas duas coisas feias juntas e o resultado é que você deve se lembrar de escreverclass MyError extends Error then constructor: -> super
em vez do mais intuitivoclass MyError extends Error
se você quiserinstanceof
operador para trabalhar corretamente comMyError
. Isso porque o construtor implícito do CoffeeScript retornará apenas o que o construtor pai devolver e, nesse caso, faráreturn Error.apply(this, arguments)
que apenas retornará um novo objeto de erro em vez do objeto que você passou como othis
argumento. Yay!
Este problemafoi corrigido no CoffeeScript 1.5.0! = D
Agora, estender objetos nativos funciona conforme o esperado:
class MyError extends Error
new MyError instanceof MyError # -> true :)
Atualização 3 (04 de março de 2013)Aaand ele foi em 1.6.0 = P