Andre's Blog
Perfection is when there is nothing left to take away
JavaScript string accessed C-style

A couple of days ago I came across JavaScript code in which a developer replaced an array object with a string and forgot to change the subscripting operator to a charAt() call, so the code looked like this:

var s = new String("0123456789");
var c = s[4];

Much to my surprise, the code appeared to work just fine when compiled in ASP and it also worked in FireFox, Opera, Chrome and Safari, although failed in Internet Explorer.

Curious about the reasons this syntax didn't cause any errors, I sat down and read the ECMA Script specification for about an hour. There was nothing in the specification that would allow this syntax, even though the section 8.4 described string characters as UTF-16 code points stored in a sequence, which hinted towards C-style strings.

I downloaded JavaScript reference implementation, which also interpreted this syntax without a hitch. It took me a few minutes to realize that this was a reference implementation of the next edition of JavaScript and that this syntax is a part of the next JavaScript release. I searched ECMAScript 4th Edition Language Overview, and there it was, page 34:

String indexing

A character can be fetched from a string using bracket syntax, as for Array, no longer requiring an explicit call to the charAt method:

   "ecmascript"[3]       // evaluates to "a"

Whew! It was driving me crazy! It turned out that all of the mentioned browsers just went for an early adoption of this syntax.

Now I was curious whether accessing JavaScript strings was faster than calling charAt(), so I ran this code in FireFox and Opera:

<script type="text/javascript">
   var stime;
   var s = new String("0123456789");
   var c; 
   stime = new Date().getTime();
   for(var i = 0; i < 1000000; i++)
      c = s[4];
   document.write("oper []: " + 
                    (new Date().getTime() - stime) + " ms\n");

   stime = new Date().getTime();
   for(var i = 0; i < 1000000; i++)
      c = s.charAt(4);
   document.write("charAt : " + 
                    (new Date().getTime() - stime) + " ms\n");

The first loop took 0.4 seconds to complete, while the second took 1.4 seconds in FireFox. Other browsers produced similar results. What a difference!

When I ran an equivalent test in ASP, the ratio was similar. However, soon I realized that it wasn't because Microsoft adopted something from the upcoming standard, but merely because the code wasn't doing much when evaluating the subscripting operator. That is, ASP evaluated the expression "0123456789"[4] as "0123456789".4, which yields undefined because JavaScript string instances do not have a property named 4 and ASP JavaScript isn't smart enough to detect a bad property identifier, which has to start with a non-digit character, and report a syntax error.

Interestingly enough, JavaScript ASP.Net interpreted this syntax correctly, but showed no difference in performance between the subscripting operator and charAt(). What did surprise me was that it took ASP.Net 2.3 seconds to run each of the loops above. Isn't .Net supposed to compile JavaScript to native code? This poor performance, however, is no match to classic ASP's performance. It took it whopping 15 seconds to run the second loop. It almost makes sense to replace ASP with one of the browsers running within IIS!