我尝试在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
对象(即超级构造函数不是用new
调用的),但话又说回来,我不太理解JS构造函数是如何工作的=P
奇怪的是,这种行为似乎只在本机JS对象的子类化时发生。如果我子类化CoffeeScript类,一切都像预期的那样工作。
你知道为什么会发生这种情况吗?为了让instanceof
操作符正常工作,我该如何避免编写伪构造函数呢?
谢谢!
更新
用户matyr answered带有一个链接,指向引入此行为的提交,但它不能完全解释这里发生的事情,所以我将尝试解释一下,以防其他人想知道为什么会这样。
主要的问题是从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
参数传递的对象。耶!
更新2(2013年2月25日)
这个问题was fixed in CoffeeScript 1.5.0!=D
现在,扩展本机对象的工作方式与预期一致:
class MyError extends Error
new MyError instanceof MyError # -> true :)
更新3(2013年3月4日)
它在1.6.0 =P上消失了
https://stackoverflow.com/questions/10805084
复制相似问题