【问题标题】:Subclassing native objects: instanceof not working properly子类化原生对象:instanceof 无法正常工作
【发布时间】:2012-06-04 00:38:56
【问题描述】:

我试图在 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

还有一个事实是,一些原生构造函数,如ErrorArrayString 等不需要用new 调用:它们只会返回相应的新对象如果您碰巧忘记了,请输入。

最后,将这两个丑陋的东西加在一起,结果是如果你想让instanceof 运算符与MyError 正常工作,你应该记得写class MyError extends Error then constructor: -> super 而不是更直观的class MyError extends Error。这是因为 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 日)

Aaand 1.6.0 已经更新了 =P

【问题讨论】:

  • 奇怪的是,您在第一个代码块中的代码在 Chrome、Canary、Safari 和 Firefox 中适用于我。 jsfiddle.net/WpkgS我错过了什么吗?
  • 通过作品,我的意思是它们都按预期返回 true。
  • @Sandro 这很奇怪:S。它在那个链接中也适用于我,但奇怪的是 jsfiddle 生成的代码似乎与 Try CoffeeScript 生成的不同。查看your fiddle,启用开发人员工具以查看代码,然后查看what Try CoffeeScript generates。现在这变得更加混乱:S
  • 我最初的猜测是 JSFiddle 使用的是旧版本的 CoffeeScript,而最新版本破坏了这个功能。这个更新的 JSFiddle 也使用了最新的 CoffeeScript JS 文件中断。 jsfiddle.net/WpkgS/2
  • CoffeeScript 变更日志表明 super 的工作方式发生了一些变化,因此这可能是相关的。如果您前往 irc.freenode.net #coffeescript 并在那里提及这一点可能会更容易?

标签: coffeescript


【解决方案1】:

无论好坏,return 是 1.3.1 上的 added 以修复 #1966(和 #2111)。

【讨论】:

  • 感谢您的链接!我想我现在明白这种改变的动机了。但我认为这些 JS 肮脏通过 CS 泄漏是一种不幸。我真的希望如果class MyError extends Error 然后new MyError instanceof MyError。必须将其定义为class MyError extends Error then constructor: -> super 似乎很不合适。而且我真的不知道为什么有人想要/需要从 JS 或 CS 中的构造函数返回不同的对象:S(即我不明白需要在 CS 中实现这两个问题的要求:S)。
  • 如果您有兴趣,我在jashkenas/coffee-script 中打开了一个关于此的问题/讨论:D
猜你喜欢
  • 2016-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-04
  • 2012-12-09
  • 1970-01-01
相关资源
最近更新 更多