17

我正在尝试对ErrorCoffeeScript 中的本机 JS 对象进行子类化以获得专门的错误类型,但我发现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构造函数的定义方式引起的。当我没有在 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回答了一个指向引入此行为的提交的链接,但它并不能完全解释这里发生了什么,所以我会尝试解释一下,以防其他人想知道为什么会这样.

主要问题是这个从 JavaScript 继承的讨厌的“特性”,它让我们定义了一个构造函数,它返回一个对象,而不是正在构造的对象:

function Foo() {
    return {'LOL': 'You fool!'};
}
new Foo() instanceof Foo // -> false

还有一个事实是,一些本地构造函数,如,Error和诸如此类的构造函数不需要用 调用:如果你碰巧忘记了它们,它们只会返回相应类型的新对象。ArrayStringnew

最后,把这两个丑陋的东西加在一起,结果是如果你想让操作符正常工作,你应该记住写class MyError extends Error then constructor: -> super而不是更直观。这是因为 CoffeeScript 的隐式构造函数将只返回父构造函数返回的任何内容,在这种情况下,它将只返回一个新的错误对象,而不是作为参数传递的对象。耶!class MyError extends ErrorinstanceofMyErrorreturn Error.apply(this, arguments)this

更新 2(2013 年 2 月 25 日)

此问题已在 CoffeeScript 1.5.0 中修复!=D

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

class MyError extends Error
new MyError instanceof MyError # -> true :)

更新 3(2013 年 3 月 4 日)

Aaand 它已经在 1.6.0 =P

4

1 回答 1

5

无论好坏,在 1.3.1return添加了以修复#1966(和#2111)。

于 2012-05-29T22:58:11.970 回答