JavaScript表达式[1 [{}]]的解析过程是怎样的?

6

Can you explain how the JavaScript expression:

[1 [{}]]

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

在Firefox中:

[1 [{}]].toSource()

生成

[(void 0)]

用其他JavaScript值替换1似乎会产生相同的结果。
更新:我现在明白了。codeka、Adrian和CMS澄清了事情。就标准而言,我试图浏览ECMAScript 5。
1 [{}]是一个属性访问器,因此它在§11.2.1中得到了覆盖。
baseReference是评估1的结果,因此仍为1。
baseValue = GetValue(baseReference) == 1。
在GetValue(§8.7.1)中,Type(1)不是Reference(已解析的名称绑定),因此返回1。 propertyNameReference是评估{}的结果,因此为空对象。 propertyNameValue = GetValue(propertyNameReference) == {}
在CheckObjectCoercible(§9.10)中,我们返回(数字可强制转换为对象)。 propertyNameString = ToString(propertyNameValue)
在ToString(§9.8)中,返回ToString(ToPrimitive({},hint String))的结果。
在ToPrimitive(§9.1)中,返回对象的[[DefaultValue]]的结果,传递PreferredType(字符串)。
在[[DefaultValue]](§8.12.8)中,让toString成为具有参数toString的[[Get]]的结果。
这在§15.2.4.2中被定义为返回“[object”+[[Class]]+"]",其中[[Class]]是默认对象原型的“Object”。
由于有一个可调用的toString,我们使用参数this为{}调用它。
返回类型为引用的值,其基本值为BaseValue(1),其引用名称为propertyNameString(“[object Object]”)。
然后我们转到数组初始化程序(§11.1.4),并使用结果构造单个元素数组。

1
我不确定为什么这会是有效的JavaScript代码...所以你会得到引擎尝试处理它的不可预测结果...对我来说似乎很正常。 - Nick Craver
@Nick,我也怀疑这是否是有效的JS,并且我愿意接受它只是未定义行为的可能性。然而,所有4个引擎(它们有不同的实现)以相同的方式解析它至少是有趣的事实。 - Matthew Flaschen
1
@Matthew - Adrian的回答对这4个浏览器中的行为做出了相当好的解释,但我仍然认为[object]不是一个有效的访问器...所以每个引擎如何处理这种情况仍然取决于它自己。虽然这是一个边缘案例,但我在3.1规范中找不到任何关于应该如何处理它的内容。 - Nick Craver
@Nick,至少在ECMAScript 5中似乎是有效的。我尝试在上面走过它。 - Matthew Flaschen
1
@Nick:[object] 是有效的,但 object 将被转换为字符串。 - Matthew Crumley
显示剩余3条评论
3个回答

15

根据阅读OP和Nick的评论,我认为可以更详细地解释Adrian的回答以使其更清晰。

这是完全合法的JavaScript代码。

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

方括号表示法(属性访问器) (MemberExpression [ 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`

8
由于您试图获取对象1的属性{},然后将其放置在一个数组中。由于1没有属性{},所以1[{}]undefined
如果您用一个数组替换1,您会看到它是如何工作的。使用1作为[5]{}作为0,它是[[5][0]]
另外,请记住obj['property']obj.property是相同的。

7
如果我们稍微拆分一下,你会看到:

如果我们稍微拆分一下,你会看到:

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

[baz];

我认为这是有效的JavaScript代码,但我不是专家...


我认为你已经有了。我可能没有看到这个,因为在JavaScript对象中使用数字是不寻常的,而空对象是一个不寻常的键。你对[(void 0)]部分有什么想法吗? - Matthew Flaschen
2
@Matthew:我猜测由于1[{}]是未定义的,(void 0)只是解释器表示“未定义”的“规范”形式。 - Dean Harding

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接