15

I was looking at some of the AJAX calls that GMail does, and I noticed that sometimes the return value of the calls started with a number. Example: (note that there's is no semi-colon after the first line)

3 
[1, 2];

If I were to enter this into a JavaScript console, I'd get undefined returned back. However, if the second parameter is a number or a string, I'd get the second parameter returned back. Example:

3
4

Returns 4.

My guess is that they're doing this to stop jsonp-type attacks, however, does anyone know what underlying evaluation is being done? In the 2nd case I believe that a semi-colon is "inserted" after the first line, which would make returning 4 make sense. However, I can't think of a reason why the first expression would return undefined.

patorjk
  • 2,164
  • 1
  • 20
  • 30
  • 1
    And in terms of security (and it's possible that Google is aware of this and has put a meaningless last element or something) this is actually a lot worse than a `{"d":}` wrapper - by defining properties on the `Number` prototype, one could determine whether the contents of the last element match a certain value. (So if someone is intending on doing this to fix the Firefox 2- bug... be aware! `=)`) – Ry- Jan 31 '13 at 17:32
  • (Yep, looks like the last number in Gmail is always `0`. Anyways...) – Ry- Jan 31 '13 at 17:35
  • Ah, because the comma operator will return the last element in its set. Very interesting. – patorjk Jan 31 '13 at 17:54

2 Answers2

9

This is because how ASI ( Automatic Semicolon Insertion ) works. The first statement is interpreted as

3[1,2];

so it is undefined. The second one is interpreted by ASI as 3;4; which is 4.

ASI rules are counterintuitive in some cases, for example you might wonder why there is no semicolon between number and bracket? Well, there is a reason for that. Read these resources for more details:

What are the rules for JavaScript's automatic semicolon insertion (ASI)?

http://bclary.com/2004/11/07/#a-7.9.1

Google will probably give you more results. :) That's why we have neverending semicolon-free JavaScript war.

Community
  • 1
  • 1
freakish
  • 54,167
  • 9
  • 132
  • 169
  • 3
    @Bergi Ah, I see, property access :) Gotta love how `{}`, `[]`, and `()` have multiple meanings in JS. – Šime Vidas Jan 31 '13 at 17:05
  • @freakish: Could you please point to the specific ASI rules for that? – Bergi Jan 31 '13 at 17:07
  • `123['foo']` - property access on a *Number* literal. Thanks, Brendan for putting this in. `:P` – Šime Vidas Jan 31 '13 at 17:09
  • +1 Type this in the console : `['a', 'b', 'c'] [1,2]` (with a \n in the middle) : you get 'c'. This confirms freakish 's finding. – Denys Séguret Jan 31 '13 at 17:09
  • 2
    @Bergi From what I remember, semi-colons are only inserted if an offending token is encountered. In this case `[` after `3` is not offending, so the engine won't perform ASI. – Šime Vidas Jan 31 '13 at 17:11
  • @minitech Nice :) I think you should be able to intercept property access with ES6 proxies, so that you don't have write 1000 properties to Number.prototype, but instead have a generic getter. – Šime Vidas Jan 31 '13 at 17:54
  • @ŠimeVidas: Yeah, I tried that a while ago (maybe the standards have changed since? It still doesn't work in V8), but it turns out `Number.prototype` isn't proxyable. Oh well. – Ry- Jan 31 '13 at 17:56
7

This is to prevent the Ajax JSON hack changing the Array constructor. This is an old bug, not relevant in modern browsers, but which has to be handled.

The hack is overriding the Array constructor, thus when the JSON is read, the code will do what the constructor does. More explanation here: http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx

By the way, this is why ASP.NET always sends back objects of this kind: {d: []}.

Florian Margaine
  • 58,730
  • 15
  • 91
  • 116
  • I think the OP knows that, but the actual question was "*why does the first statement return `undefined` while the second doesn't*" – Bergi Jan 31 '13 at 17:04
  • @Bergi Oh, my bad then. I'm leaving the answer as it kind of answers part of his question. – Florian Margaine Jan 31 '13 at 17:05