Coffeescript 子类化本机对象:instanceof无法正常工作

Coffeescript 子类化本机对象:instanceof无法正常工作,coffeescript,Coffeescript,我试图在CoffeeScript中对本机JSError对象进行子类化,以获得专门的错误类型,但我发现如果在子类中未定义构造函数,instanceof无法正常工作: class SimpleError extends Error class EmptyConstructorError extends Error constructor: -> class SuperConstructorError extends Error constructor: -> super

我试图在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
这个问题似乎是由如何定义构造函数引起的。当我没有在CoffeeScript中定义构造函数时:

SimpleError = (function(_super) {

  __extends(SimpleError, _super);

  function SimpleError() {
    return SimpleError.__super__.constructor.apply(this, arguments);
  }

  return SimpleError;

})(Error);
SuperConstructorError = (function(_super) {

  __extends(SuperConstructorError, _super);

  function SuperConstructorError() {
    SuperConstructorError.__super__.constructor.apply(this, arguments);
  }

  return SuperConstructorError;

})(Error);
当我在CoffeeScript中定义构造函数时:

SimpleError = (function(_super) {

  __extends(SimpleError, _super);

  function SimpleError() {
    return SimpleError.__super__.constructor.apply(this, arguments);
  }

  return SimpleError;

})(Error);
SuperConstructorError = (function(_super) {

  __extends(SuperConstructorError, _super);

  function SuperConstructorError() {
    SuperConstructorError.__super__.constructor.apply(this, arguments);
  }

  return SuperConstructorError;

})(Error);
如您所见,在第一种情况下,区别在于一个简单的
返回。我不明白为什么这会对
instanceof
行为产生任何影响,因为超级构造函数只是应用于
这个
对象(也就是说,超级构造函数不是用
new
调用的),但我还是不明白JS构造函数是如何工作的

奇怪的是,这种行为似乎只有在对本机JS对象进行子类化时才会发生。如果我将CoffeeScript类划分为子类,那么一切都会按预期进行

知道为什么会发生这种情况吗?我如何避免只为
instanceof
操作符的正确工作而编写虚拟构造函数

谢谢

更新 因此,用户matyr提供了一个指向提交的链接,其中引入了这种行为,但它并不能完全解释这里发生了什么,所以我将尝试解释一下,以防其他人想知道为什么会这样

主要问题是继承了JavaScript的这一令人讨厌的“特性”,它允许我们定义一个构造函数,该构造函数返回一个与正在构造的对象不同的对象:

function Foo() {
    return {'LOL': 'You fool!'};
}
new Foo() instanceof Foo // -> false
还有一个事实是,一些本机构造函数,如
Error
Array
String
等等,不需要用
new
调用:如果您碰巧忘记了它,它们只会返回相应类型的新对象

最后,将这两个丑陋的东西加在一起,结果是,如果您希望
instanceof
操作符与
MyError
一起正常工作,您应该记住编写
类MyError extends Error然后编写构造函数:->super
,而不是更直观的
类MyError extends Error
。这是因为CoffeeScript的隐式构造函数将只返回父构造函数返回的任何内容,在本例中,将执行
返回错误。apply(this,arguments)
将只返回一个新的错误对象,而不是作为
this
参数传递的对象。耶

更新2(2013年2月25日) 这个问题=D

现在,扩展本机对象可以按预期工作:

class MyError extends Error
new MyError instanceof MyError # -> true :)
更新3(2013年3月4日)
aa而且它是在1.6.0=p上运行的

不管是好是坏,
返回的
是在1.3.1上修复的(和)。

奇怪的是,你的第一块代码在Chrome、Canary、Safari和Firefox中对我有效。我遗漏了什么吗?所谓的工作,我的意思是它们都像预期的那样返回true。@Sandro这很奇怪:s。在这个链接中,它也适用于我,但奇怪的是JSFIDLE生成的代码似乎与Try CoffeeScript生成的代码不同。查看启用开发人员工具以查看代码的情况,然后。现在这变得更加令人困惑:SMy最初猜测JSFIDLE使用的是旧版本的CoffeeScript,而最新版本破坏了这一功能。这个更新的JSFIDLE也使用了最新的CoffeeScript JS文件。CoffeeScript changelog表示对
super
工作方式的一些更改,因此可能与此相关。如果您访问irc.freenode.net#coffeescript并在那里提及此内容,可能会更容易一些?谢谢您的链接!我想我现在明白了这种改变的动机。但我认为这些JS的肮脏通过CS泄露是有点不幸的。我真的希望,如果
类MyError扩展了Error
,那么
MyError的新MyError实例
。必须将其定义为
类MyError扩展了错误,然后构造函数:->super
似乎非常不合适。我真的不知道为什么有人想要/需要从JS或CS:S中的构造函数返回一个不同的对象(即,我不理解在CS中实现这两个问题所要求的东西的必要性)。如果你感兴趣,我在:D中对此展开了一个问题/讨论