子类化原生对象:instanceof 无法正常工作 [英] Subclassing native objects: instanceof not working properly

查看:16
本文介绍了子类化原生对象:instanceof 无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图子类化 CoffeeScript 中的原生 JS Error 对象以获得专门的错误类型,但我发现如果我不这样做,instanceof 将无法正常工作't 在子类中定义构造函数:

I'm trying to subclass the native JS Error object in CoffeeScript to get specialized error types, but i found that the instanceof does not work correctly if i don't define a constructor in the subclasses:

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 中定义构造函数时:

The problem seems to be caused by how the generated JS constructor functions are defined. When i don't define a constructor in CoffeeScript:

SimpleError = (function(_super) {

  __extends(SimpleError, _super);

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

  return SimpleError;

})(Error);

当我 在 CoffeeScript 中定义一个构造函数时:

And when i do define a constructor in CoffeeScript:

SuperConstructorError = (function(_super) {

  __extends(SuperConstructorError, _super);

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

  return SuperConstructorError;

})(Error);

如您所见,区别在于第一种情况下的简单return.我不明白为什么这会对 instanceof 行为产生任何影响,因为超级构造函数只是被应用于 this 对象(即超级构造函数不是用 new 调用),但我还是不明白 JS 构造函数的工作原理 =P

As you can see, the difference is a simple return in the first case. I don't understand why this makes any difference in the instanceof behavior though, as the super constructor is just being applied to the this object (i.e. the super constructor is not being called with new), but then again i don't understand a whole lot of how JS constructors work =P

奇怪的是,这种行为似乎只在继承原生 JS 对象时才会发生.如果我继承 CoffeeScript 类,一切都会按预期工作.

And the weird thing is that this behavior seems to only happen when subclassing native JS objects. If i subclass CoffeeScript classes everything works as expected.

知道为什么会发生这种情况,以及如何避免编写虚拟构造函数以使 instanceof 运算符正常工作?

Any idea of why this might be happening and how could i avoid writing dummy constructors just for the instanceof operator to work correctly?

谢谢!

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

So the user matyr answered with a link to the commit where this behavior was introduced, but it doesn't quite explain what is happening here, so i'll try to explain that a little bit in case anyone else wonders why this works this way.

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

The main problem is this inherited nasty "feature" from JavaScript which let us define a constructor function that returns an object other than the one being constructed:

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

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

And there is also the fact that some native constructors, like Error, Array, String and whatnot don't need to be called with new: they will just return a new object of the corresponding type if you happen to forget it.

最后,把这两个丑陋的东西加在一起,结果是你应该记得写 class MyError extends Error then constructor: ->如果您希望 instanceof 运算符与 MyError 一起正常工作,则使用 super 而不是更直观的 class MyError extends Error.这是因为 CoffeeScript 的隐式构造函数只会返回父构造函数返回的任何内容,在这种情况下会执行 return Error.apply(this, arguments) 只会返回一个新的错误对象而不是你的对象作为 this 参数传递.耶!

In the end, add these two ugly things together and the result is that you should remember to write class MyError extends Error then constructor: -> super instead of the more intuitive class MyError extends Error if you want the instanceof operator to work properly with MyError. That's because CoffeeScript's implicit constructor will just return whatever the parent constructor returns, and in this case will do return Error.apply(this, arguments) which will just return a shinny new error object instead of the object you passed as the this argument. Yay!

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

现在扩展原生对象可以按预期工作:

Now extending native objects works as expected:

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

更新 3(2013 年 3 月 4 日)

Aaand 1.6.0 已经更新了 =P

Update 3 (Mar 04 2013)

Aaand it's gone on 1.6.0 =P

推荐答案

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

For better or worse, the return was added on 1.3.1 to fix #1966 (and #2111).

这篇关于子类化原生对象:instanceof 无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆