【问题标题】:Odd behaviour of comparison of object literals对象文字比较的奇怪行为
【发布时间】:2018-12-02 00:12:48
【问题描述】:

我已经搜索过,但在 JavaScript 中找不到后面的逻辑。

当我在 Chrome 控制台中输入时:

{} == null 

返回

Uncaught SyntaxError: Unexpected token ==

但是

{} == {}

{} == function(){} 

返回假

为什么?

【问题讨论】:

  • 仅供参考,null == {}({} == null) 都可以。
  • 我的第一个猜测是对象字面量被解释为一个块
  • @MoritzRoessler 那么为什么{} == {} 不会产生错误?
  • 你可以在es5.github.io查看这个
  • @MoritzRoessler 能否具体说明文章编号?

标签: javascript google-chrome


【解决方案1】:

我假设你明白为什么 {} == null 会抛出 SyntaxError。长话短说,这是因为 { 在开头的块语句不是对象文字。你可以检查答案here

至于为什么{} == {} 有效。

如果您检查在控制台中计算表达式的铬代码。您可以找到以下内容 (code)

if (/^\s*\{/.test(text) && /\}\s*$/.test(text))
    text = '(' + text + ')';
executionContext.evaluate(text, "console", !!useCommandLineAPI, false, false, true, printResult);

这段代码用括号包裹{} == {} 代码,使其成为比较两个空对象字面量的有效表达式({} == {})。计算结果为false,因为对象是通过引用进行比较的。

节点 repl 具有相同的行为 src

if (/^\s*\{/.test(code) && /\}\s*$/.test(code)) {
  // It's confusing for `{ a : 1 }` to be interpreted as a block
  // statement rather than an object literal.  So, we first try
  // to wrap it in parentheses, so that it will be interpreted as
  // an expression.
  code = `(${code.trim()})\n`;
  wrappedCmd = true;
}

【讨论】:

  • {} == function(){} 也返回 false 呢
  • @dhaker 此代码与条件相同的逻辑。它以{ 开头,以} 结尾
  • 这很高兴知道,但我会注意到这是一个答案关于 Chrome(显然是节点)。我提到这一点只是因为问题假设这是关于 Javascript 作为一种语言。
  • @MarkAdelsberger 谢谢。我添加了 chrome 标签以突出显示“当我在 Chrome 控制台中键入时:”
【解决方案2】:

您可以在声明(第 12 条)下的规范中找到这一点

12 - 声明

声明:
堵塞。 变量语句
空语句
表达式语句
.
.
.

第一个适用的规则是块或表达式语句。所以我们需要看看12.4。

在 12.4 中,规范明确规定表达式语句不能以 { 开头。

虽然我还没有找到使示例 2 成为表达式的原因,但可能是特定于实现的

12.4 表达式语句

语法 表达式语句: [lookahead ∉ {{, function}] 表达式;

注意 ExpressionStatement 不能以左大括号开头,因为这可能会使它与 Block 产生歧义。此外,ExpressionStatement 不能以 function 关键字开头,因为这可能会使其与 FunctionDeclaration 产生歧义。

语义 产生 ExpressionStatement : [lookahead ∉ {{, function}]Expression;评估如下:

设 exprRef 为 Expression 求值的结果。 返回(正常,GetValue(exprRef),空)。

【讨论】:

    【解决方案3】:

    我会说这是一个解析问题,而不是一个逻辑问题。

    在 Chrome 中,我得到了观察到的行为。

    在 IE 中,每当我将 {}(或者,似乎是任何对象文字)放在 == 的 LHS 上时,都会出现语法错误。

    在这两种浏览器中,将() 放在表达式周围可以解决问题。或者先将对象赋值给一个变量

    var x = {}
    x == null
    

    我会说这在我看来像是解析中的错误。这在学术意义上是否属实需要深入研究规范和语法;实际的答案是,有足够简单的解决方法,最好不要这样做。

    【讨论】:

    • 那么为什么解析{} == {}没有问题
    • 正如我所说,这可能是一个错误(在这种情况下,试图推理“为什么”是没有意义的),如果不是,那么鉴于不同的浏览器行为不同(IE 确实,事实上,解析{} == {}有问题,它必须属于未定义行为的类别(在这种情况下,试图推理“为什么”是没有意义的)。我不认为这很重要为什么。观察到它会发生,并且有一些简单的方法可以解决它
    • 从 Yury 的回答中添加信息作为上下文,我会稍微澄清一下。 Chrome 中 not 抛出错误的行为要么是故意设计的偏离规范(无论其意图是否良性,这都是一个错误),要么是规范提供了足够的灵活性做或不做 Chrome 选择做的事情(本质上是未定义的行为)。它使行为看起来不太一致且更难预测的事实是我不同意它的原因,也不会故意编写利用它的 JS 代码。
    【解决方案4】:

    这是因为 JavaScript 很烂 它不起作用的原因是因为 JavaScript 采用比较从第一个对象中采用的类型。

    例如

    3+”1” = 4 
    

    但是

    “3”+1 = 31
    

    第一个示例将操作作为数字进行,因为第一个对象是数字 第二个示例将字符串视为第一个对象,并将操作视为字符串的串联。

    以你的为例 {} 是一个对象,但 null 不能转换为对象

    它以另一种方式工作,因为 {} 可以表示为空对象。

    【讨论】:

    • “对于您的示例 {} 是一个对象,但 null 无法转换为对象”以及运行时语义如何导致 SyntaxError
    • 呃...不,这与观察到的行为无关。如果是 ({} == null) 也会有同样的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-24
    • 2014-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-13
    相关资源
    最近更新 更多