【问题标题】:a instanceof b returns false even though b is in a's prototype chain即使 b 在 a 的原型链中,a instanceof b 返回 false
【发布时间】:2016-07-12 16:27:33
【问题描述】:

又一个instanceof 问题。 我正在使用来自 antlr4 解析器的一些自动生成的代码。解析器工作正常,我将它与 ace 连接在一起,语法高亮工作,......到目前为止一切都很好。但是现在发生了一件非常奇怪的事情。我写了自己的parserTreeListener,但由于instanceof 调用返回错误结果而失败。

将问题分解为一个小程序是可行的。但就像魔术一样,即使使用相同的代码(解析器、词法分析器、侦听器......),一切都很好。

不足为奇,在 chrome devtools 中调试问题,显示对象 t 原型链 (__proto__) 确实是 TerminalNode 的一个实例,但调用 t instanceof TerminalNode 仍然返回 false

不幸的是,我无法发布主项目的代码,它失败了(至少现在还没有)。也许有人知道为什么以及何时会出现此类问题。

一些可能的解释(尽管我怀疑)

  • 脚本加载了两次,TerminalNode 不等于 proto 的 TerminalNode
  • 与工作线程中加载的同一个库发生冲突

antlr4 中的这段代码失败了:

ParseTreeWalker.prototype.walk = function(listener, t) {
var errorNode = t instanceof ErrorNode ||
        (t.isErrorNode !== undefined && t.isErrorNode());
if (errorNode) {
    listener.visitErrorNode(t);
} else if (t instanceof TerminalNode) { /*here t fails on first TerminalNode*/
    listener.visitTerminal(t);
} else {
    this.enterRule(listener, t);
    for (var i = 0; i < t.getChildCount(); i++) {
        var child = t.getChild(i);
        this.walk(listener, child);
    }
    this.exitRule(listener, t);
}
};

一些调试信息

当我键入时,两个脚本在断点处返回相同的结果:

$ var obj = t; while(obj) console.log(obj = Object.getPrototypeOf(obj));
TerminalNode {}
ParseTree {}
SyntaxTree {}
Tree {}
Object {}
Object {}

【问题讨论】:

  • t.prototype === TerminalNode.prototype 说什么?
  • instanceof.isPrototypeOf 不一样!编辑:好的,只有你的问题标题令人困惑。
  • false 在这两种情况下:t instanceof TerminalNode true t.prototype === TerminalNode.prototype false 即使在它工作的示例中,也可以,因为tTerminalNodeImpl 的一个实例
  • 你找到这个问题的答案了吗?
  • @Nayan 正如下面的答案所述......脚本被多次加载,覆盖了原始定义,从而导致了这个混乱。

标签: javascript antlr4 instanceof


【解决方案1】:

a instanceof b 检查 a 是否继承自 b.prototype,而不是继承自 b

如果要测试b本身是否出现在a的原型链中,可以使用

b.isPrototypeOf(a);

一些例子:

[] instanceof Array;                           // true
Array.isPrototypeOf([]);                       // false
Object.getPrototypeOf([]) === Array;           // false

[] instanceof Array.prototype;                 // TypeError
Array.prototype.isPrototypeOf([]);             // true
Object.getPrototypeOf([]) === Array.prototype; // true

【讨论】:

  • Object.getPrototypeOf(t) 返回TerminalNode {} TerminalNode.isPrototypeOf(t) 返回false t instanceof TerminalNode 应该返回trueTerminalNode.prototype.isPrototypeOf(t) 在失败的脚本中返回 false,在有效的脚本中返回 true。问题仍然没有答案
  • @SeDav 试试var obj = t; while(obj) console.log(obj = Object.getPrototypeOf(obj));,你会看到所有的原型链。
  • 我做到了并将其添加到问题中
  • 这似乎是一个奇怪的并发问题,禁用 ace 语法突出显示(访问同一个库)然后一切正常......奇怪......我将进一步研究这个问题。也许它与 UMD browserify 方法有关(我浏览了 antlr4 lib + 解析器)
【解决方案2】:

即使我没有解释,这种奇怪的行为是如何发生的。双重包含的脚本是错误的根本原因。当我使用 Polymer 和 Webcomponents 时,多个组件包含相同的脚本。

通过将特定的&lt;script ..&gt;标签从组件中移到主文档中,这些问题不再发生。

也许还有人有线索,为什么会导致这样的错误?

【讨论】:

  • 好吧,如果脚本被执行多次,就会有多个类看起来相似(同名,相同成员)等,但并不相同。在TerminalNode 被第二次执行覆盖之前创建的第一个类的实例不是第二个类的实例。
  • 我有点希望你在问这个问题之前已经检查过了,因为你已经提到这是一个可能的原因......
  • @Bergi 我确实检查了它,但包含有点隐藏(意味着它不明显)。我什至在使用同一个库的工作线程中取消了一个 importScript-Statement 的注释 - 但当然,这不是问题,因为工作线程无论如何都是从另一个环境沙箱化的。我通常总是在不得不在这里提问之前解决问题,但这对我来说似乎很奇怪,我认为这对面临类似问题的其他人可能会有所帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-20
  • 2021-11-28
  • 1970-01-01
  • 1970-01-01
  • 2014-03-29
  • 2021-10-06
  • 1970-01-01
相关资源
最近更新 更多