【问题标题】:How exactly does the JavaScript expression [1 [{}]] parse?JavaScript 表达式 [1 [{}]] 究竟是如何解析的?
【发布时间】:2010-06-21 00:20:19
【问题描述】:

你能解释一下JavaScript的表达方式吗:

[1 [{}]]

解析/评估?在 Firefox、Chrome、Konqueror 和 rhino 中,它似乎创建了一个包含单个元素 undefined 的数组。但是,我不明白为什么。

在 Firefox 中:

[1 [{}]].toSource()

生产

[(void 0)]

将 1 替换为其他 JavaScript 值似乎会产生相同的结果。

更新:我想我现在明白了。 codeka、Adrian 和 CMS 澄清了事情。至于标准,我尝试过 ECMAScript 5。

  1. 1 [{}] 是一个属性访问器,因此在第 11.2.1 节中进行了介绍。
  2. baseReference 是评估1 的结果,所以还是1
  3. baseValue = GetValue(baseReference) == 1
  4. GetValue (§8.7.1),Type(1) 不是 Reference(已解析的名称绑定),因此返回 1。
  5. propertyNameReference 是评估 {} 的结果,因此是一个空对象。
  6. propertyNameValue = GetValue(propertyNameReference) == {}
  7. CheckObjectCoercible(baseValue)(§9.10),我们返回(数字是对象强制的)。
  8. propertyNameString = ToString(propertyNameValue)
  9. ToString(§9.8),返回ToString(ToPrimitive({}, hint String))
  10. ToPrimitive(§9.1),返回对象[[DefaultValue]]的结果,传递PreferredType(字符串)。
  11. [[DefaultValue]](第 8.12.8 节)处,让 toString 为 [[Get]] 的结果,参数为 toString
  12. 在§15.2.4.2 中定义返回"[object " + [[Class]] + "]",其中[[Class]] 是默认对象原型的“对象”。
  13. 由于有一个可调用的toString,我们调用它时参数this{}
  14. 返回一个Reference 类型的值,其基值为BaseValue (1),其引用名称为propertyNameString ("[object Object]")。

然后我们转到数组初始化器(第 11.1.4 节),并用结果构造一个单元素数组。

【问题讨论】:

  • 我不确定为什么这会是有效的 JavaScript...所以您会得到引擎 尝试 处理它的不可预测的结果...对我来说似乎状态正常。
  • @Nick,我也怀疑它是有效的 JS,我愿意接受它只是未定义行为的可能性。然而,所有 4 个引擎(具有单独的实现)以相同的方式解析它的事实至少很有趣。
  • @Matthew - Adrian 的回答很好地解释了这 4 个浏览器中的行为,但我仍然认为 [object] 不是有效的访问器......所以它仍然取决于每个引擎将如何处理这种情况。不过,这是一个极端情况,我在 3.1 规范中找不到任何说明应该如何准确处理的内容。
  • @Nick,它似乎至少对 ECMAScript 5 有效。我试着在上面走过。
  • @Nick: [object] 有效,但object 将被转换为字符串。

标签: javascript parsing literals


【解决方案1】:

阅读OP and Nick comments,我想我可以将Adrian's answer 扩展一点,使其更清晰。

这是完全有效的 JavaScript。

JavaScript 将对象属性名称作为字符串处理,对象不能包含其他类型或其他对象作为 keys,它们只是字符串。

括号符号property accessor (MemberExpression [ Expression ]) 隐式地将括号之间的表达式转换为字符串,因此:

var obj = {};
obj[{}] = "foo";
alert(obj["[object Object]"]); // foo

在上面的示例中,您可以看到我为{} 属性分配了一个值,而{}.toString()(或{}+'')生成了字符串"[object Object](通过Object.prototype.toString)。

表达式1 [{}] 将 1 Number 原语隐式转换为对象(这是由属性访问器创建的)并查找名为 "[object Object]" 的属性,属性查找是在 Number.prototype 和 @ 987654336@个对象,例如:

1['toString'] === Number.prototype.toString; // true

最后,1 [{}] 表达式本身被括在括号中([1 [{}]]),这实际上是一个数组字面量。

总之,解析器如何评估表达式:

 [1 [{}]];
 //   ^ The accessor expression is evaluated and converted to string

 [1 ["[object Object]"]];
 // ^ A property lookup is made on an Number object 
 //   trying to access a property named "[object Object]"

 [undefined];
 //   ^ the property is obviously not found

   [undefined];
 //^         ^
 // An array literal is created with an element `0` which its value is `undefined`

【讨论】:

    【解决方案2】:

    这是因为您试图获取对象1 的属性{},然后将其放入数组中。 1 没有{} 属性,所以1[{}]undefined

    如果您将1 替换为数组,您将看到它是如何工作的。 1[5]{}0,则为[[5][0]]

    另外,请记住 obj['property']obj.property 相同。

    【讨论】:

      【解决方案3】:

      如果我们把它分解一下,你会看到:

      var foo = 1;
      var bar = {};
      var baz = foo[bar];
      
      [baz];
      

      我相信它是有效的 JavaScript,但我不是专家...

      【讨论】:

      • 我想你有它。我可能没有看到这一点,因为将数字用作 JavaScript 对象是不寻常的,而空对象是不寻常的键。您对[(void 0)] 部分有什么想法吗?
      • @Matthew:我的猜测是,由于1[{}] 是未定义的,(void 0) 只是解释器表示“未定义”的“规范”形式。
      猜你喜欢
      • 2012-08-03
      • 2011-10-04
      • 2013-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-08
      相关资源
      最近更新 更多