最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

parsing - How exactly does the JavaScript expression [1 [{}]] parse? - Stack Overflow

programmeradmin2浏览0评论

Can you explain how the JavaScript expression:

[1 [{}]]

parses/evaluates? In Firefox, Chrome, Konqueror, and rhino, it seems to create an array with a single element, undefined. However, I don't understand why.

In Firefox:

[1 [{}]].toSource()

produces

[(void 0)]

Replacing 1 with other JavaScript values seems to yield the same result.

Update: I think I understand now. codeka, Adrian, and CMS clarified things. As far as the standard, I tried to walk through ECMAScript 5.

  1. 1 [{}] is a Property Accessor, so it's covered in §11.2.1.
  2. baseReference is the result of evaluating 1, so still 1.
  3. baseValue = GetValue(baseReference) == 1.
  4. At GetValue (§8.7.1), Type(1) is not Reference (a resolved name binding), so return 1.
  5. propertyNameReference is result of evaluating {}, so an empty object.
  6. propertyNameValue = GetValue(propertyNameReference) == {}
  7. At CheckObjectCoercible(baseValue) (§9.10), we return (Number is object-coercible).
  8. propertyNameString = ToString(propertyNameValue)
  9. At ToString (§9.8), return ToString(ToPrimitive({}, hint String))
  10. At ToPrimitive (§9.1), return result of object's [[DefaultValue]], passing PreferredType (string).
  11. At [[DefaultValue]] (§8.12.8), let toString be result of [[Get]] with argument toString.
  12. This is defined at §15.2.4.2 to return "[object " + [[Class]] + "]", where [[Class]] is "Object" for the default object prototype.
  13. Since there is a callable toString, we call it with argument this being {}.
  14. Return a value of type Reference, whose base value is BaseValue (1) and whose referenced name is propertyNameString ("[object Object]").

We then go to Array initializer (§11.1.4), and construct a single element array with the result.

Can you explain how the JavaScript expression:

[1 [{}]]

parses/evaluates? In Firefox, Chrome, Konqueror, and rhino, it seems to create an array with a single element, undefined. However, I don't understand why.

In Firefox:

[1 [{}]].toSource()

produces

[(void 0)]

Replacing 1 with other JavaScript values seems to yield the same result.

Update: I think I understand now. codeka, Adrian, and CMS clarified things. As far as the standard, I tried to walk through ECMAScript 5.

  1. 1 [{}] is a Property Accessor, so it's covered in §11.2.1.
  2. baseReference is the result of evaluating 1, so still 1.
  3. baseValue = GetValue(baseReference) == 1.
  4. At GetValue (§8.7.1), Type(1) is not Reference (a resolved name binding), so return 1.
  5. propertyNameReference is result of evaluating {}, so an empty object.
  6. propertyNameValue = GetValue(propertyNameReference) == {}
  7. At CheckObjectCoercible(baseValue) (§9.10), we return (Number is object-coercible).
  8. propertyNameString = ToString(propertyNameValue)
  9. At ToString (§9.8), return ToString(ToPrimitive({}, hint String))
  10. At ToPrimitive (§9.1), return result of object's [[DefaultValue]], passing PreferredType (string).
  11. At [[DefaultValue]] (§8.12.8), let toString be result of [[Get]] with argument toString.
  12. This is defined at §15.2.4.2 to return "[object " + [[Class]] + "]", where [[Class]] is "Object" for the default object prototype.
  13. Since there is a callable toString, we call it with argument this being {}.
  14. Return a value of type Reference, whose base value is BaseValue (1) and whose referenced name is propertyNameString ("[object Object]").

We then go to Array initializer (§11.1.4), and construct a single element array with the result.

Share Improve this question edited Jun 21, 2010 at 2:58 Jason S 190k174 gold badges632 silver badges1k bronze badges asked Jun 21, 2010 at 0:20 Matthew FlaschenMatthew Flaschen 285k53 gold badges521 silver badges552 bronze badges 8
  • 1 I'm not sure why this would be valid JavaScript...so you get unpredictable results of the engine trying to handle it...seems status normal to me. – Nick Craver Commented Jun 21, 2010 at 0:24
  • @Nick, I'm also skeptical that it's valid JS, and I'm willing to accept the possibility it's simply undefined behavior. However, the fact that all 4 engines (which have separate implementations) parse it the same way is at least interesting. – Matthew Flaschen Commented Jun 21, 2010 at 0:31
  • 1 @Matthew - Adrian's answer is a pretty good explanation of the behavior in those 4 browsers, I still don't think [object] is a valid accessor though...so it would still be up to each engine on how it would handle this case. This is an edge case though, and I can't find anything in the 3.1 spec that says how it should be handled exactly. – Nick Craver Commented Jun 21, 2010 at 0:55
  • @Nick, it seems to be valid for ECMAScript 5 at least. I tried to walk through it above. – Matthew Flaschen Commented Jun 21, 2010 at 1:29
  • 1 @Nick: [object] is valid, but object will be converted to a string. – Matthew Crumley Commented Jun 21, 2010 at 1:34
 |  Show 3 more comments

3 Answers 3

Reset to default 15

Reading the OP and Nick comments, I think I can expand a little bit more the Adrian's answer to make it clearer.

It's perfectly valid JavaScript.

JavaScript handles object property names as strings, objects cannot contain other types or other objects as keys, they are just strings.

The bracket notation property accessor (MemberExpression [ Expression ]) implicitly converts the expression between brackets into a string, so:

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

In the above example you can see that I assign a value to the {} property, and {}.toString() (or {}+'') produces the string "[object Object] (via Object.prototype.toString).

The expression 1 [{}] implicitly converts the 1 Number primitive to an object (this is made by the property accessor) and it lookups a property named "[object Object]" the property lookup is made on the Number.prototype and the Object.prototype objects, for example:

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

Finally, the 1 [{}] expression is itself enclosed in brackets ([1 [{}]]), this is actually an Array literal.

In conclusion here is how the parser evaluates the expression:

 [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`

It is because you are trying to get the property {} of the object 1 and then place it in an array. 1 doesn't have the property {}, so 1[{}] is undefined.

If you replace the 1 with an array, you will see how it is working. With 1 as [5] and {} as 0, it is [[5][0]].

Also, keep in mind that obj['property'] is the same as obj.property.

If we break it up a bit, you'll see:

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

[baz];

I believe it's valid JavaScript, but I'm not an expert...

发布评论

评论列表(0)

  1. 暂无评论