2010-06-21 26 views
6

你能解释JavaScript表达式如何:JavaScript表达式[1 [{}]]究竟如何解析?

[1 [{}]] 

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

在Firefox:

[1 [{}]].toSource() 

产生

[(void 0)] 

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

更新:我想我现在明白了。 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),我们返回(Number是对象强制的)。
  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]]是默认对象原型的“Object”。
  13. 由于有一个可召集的toString,我们称它为this{}
  14. 返回类型为Reference的值,其基值为BaseValue(1),其参考名称为propertyNameString"[object Object]")。

然后,我们转到数组初始值设定项(第11.1.4节),并用结果构造单个元素数组。

+1

我不知道为什么,这将是有效的JavaScript ...所以你得到发动机*试图*处理它的不可预知的结果。 ..似乎对我来说很正常。 – 2010-06-21 00:24:12

+0

@尼克,我也怀疑它是有效的JS,并且我愿意接受它可能只是未定义的行为。但是,所有4个引擎(它们都有独立的实现)以相同的方式解析它的事实至少是有趣的。 – 2010-06-21 00:31:44

+1

@Matthew - Adrian的回答是对这4个浏览器中行为的一个很好的解释,但我仍然不认为'[object]'是一个有效的访问器,尽管...所以它仍然取决于每个引擎如何会处理这种情况。尽管这是一个边缘案例,我无法在3.1规范中找到任何说明它应该如何处理的内容。 – 2010-06-21 00:55:17

回答

7

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

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

[baz]; 

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

+0

我认为你有它。我可能没有看到这个,因为使用一个数字作为JavaScript对象并不常见,而空对象是一个不寻常的关键。你对'[(void 0)]'部分有任何想法吗? – 2010-06-21 00:55:40

+2

@Matthew:我的猜测是由于'1 [{}]'是未定义的,'(void 0)'仅仅是解释器用于表示“未定义”的“规范”形式。 – 2010-06-21 01:15:48

8

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

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

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

15

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

这是完全有效的JavaScript。

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

的括号记号property accessorMemberExpression [ Expression ])括号内的表达式隐式转换成一个字符串,所以:

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

在上面的例子可以看出,我分配一个值到{}属性,和{}.toString()(或{}+'')产生字符串"[object Object](通过Object.prototype.toString)。

表达1 [{}]隐式转换的1 Number原语的一个对象(这是由属性访问制造),它查找命名"[object Object]"属性查找是对Number.prototypeObject.prototype对象所做的属性,例如:

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`