我正在尝试将CoffeeScript中的本机JS Error
对象子类化以获取专门的错误类型,但是如果我没有在中定义构造函数,我发现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
问题似乎是由generated JS构造函数的定义方式引起的。当我不在CoffeeScript中定义构造函数时:
SimpleError = (function(_super) {
__extends(SimpleError, _super);
function SimpleError() {
return SimpleError.__super__.constructor.apply(this, arguments);
}
return SimpleError;
})(Error);
当我做在CoffeeScript中定义构造函数时:
SuperConstructorError = (function(_super) {
__extends(SuperConstructorError, _super);
function SuperConstructorError() {
SuperConstructorError.__super__.constructor.apply(this, arguments);
}
return SuperConstructorError;
})(Error);
正如您所看到的,在第一种情况下差异很简单return
。我不明白为什么这会对instanceof
行为产生任何影响,因为超级构造函数只是应用于this
对象(即超级构造函数未被{{1}调用但是,我再也不了解JS构造函数的工作原理= P
奇怪的是,这种行为似乎只在子类化本机JS对象时才会发生。如果我将CoffeeScript类子类化,一切都按预期工作。
知道为什么会发生这种情况,我怎么能避免只为new
运算符编写虚拟构造函数才能正常工作?
谢谢!
所以用户matyr answered带有引用此行为的提交的链接,但它并没有完全解释这里发生了什么,所以我会尝试解释一下,以防万一其他人想知道为什么这样做。
主要的问题是来自JavaScript的这个继承的令人讨厌的“特性”,它让我们定义一个构造函数,它返回一个不同于正在构造的对象的对象:
instanceof
还有一些本地构造函数,例如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
。这是因为CoffeeScript的隐式构造函数将返回父构造函数返回的任何内容,在这种情况下将执行MyError
,这将只返回一个新的错误对象,而不是您作为return Error.apply(this, arguments)
参数传递的对象。耶!
这个问题was fixed in CoffeeScript 1.5.0! = d
现在扩展本机对象按预期工作:
this
Aaand已经消失在1.6.0 = P