The short answer:
In your code the arr.length
is the major bottleneck. Simply because of the differences between the various implementations of JavaScript. Not only the implementations differ, but also what the engines actually do prior to executing your code.
Why do I think this: simple:
for([[expr evaluated at start of loop]];
[[expr re-evaluated on each iteration + 1(end of loop)]];
[[expr evaluated for each iteration +1(end of loop)]]
)
The cases that are fastest on IE7 are those where the conditional expression in the for-loop is either missing or is simply comparing the values of 2 variables.
The long answer, without focussing on arr.length
, but keep in mind that here, you're getting a property of an object, that is, sort-of, inherited from the prototype.
The reason why is simply because of how Chrome's V8 compiles the code, and how the Object[[GetProperty]]
is implemented. Since JS arrays are just augmented objects (Array instanceof Object
is true
), getting a value from an array is, essentially the same as someObj.someProp
.
Most JS implementations use either a HashMap or HashTable for the objects. Chrome's V8 engine, is a bit of an odd one out, in a couple of crucial ways.
FF's SpiderMonkey/*Monkey engines compile JS code to intermediate byte-code, that runs on a virtual machine.
Their Rhino engine compiles JS to Java, which is also a VM environment. Cf the hybrid model in the img below
JS "engines" of old didn't even go that far, they were just parse-and-execute things. They did no or very little optimization or reflection on the code they were asked to parse.
V8 does things a bit different: it parses, optimizes and compiles the resulting AST (Abstract Syntax Tree) straight into machine-executable code. No byte-code virtual-machine stuff to hold you back:
So, Chrome's V8 compiles to machine code, which cuts down overall execution time (in most cases). In addition to that, the V8 engine does not use a HashTable for object properties. It creates classes:
To reduce the time required to access JavaScript properties, V8 does not use dynamic lookup to access properties. Instead, V8 dynamically creates hidden classes behind the scenes.
What does this mean for arr.length
:
//V8:
arr = [];//creates class, that has length property, value 0
arr.push(123);//arr points to class with property 0 = 123, length = 1
That means that, arr.length
or arr[0]
both are simple, atomic operations. In terms of time-complexity, they are as close as makes no difference both: O(1). Now, I'm not familiar with the internals of IE's JScript engine, but I'm prepared to take a punt on how arr.length
works:
arr.length;//->arr @instancelevel->search(length)
//
==>arr.prototype->search(length)
//
==> magic property, probably does something like:
return max(@instance.keys) +1
Now, this may range anywhere from pretty accurate to down-right absurd, but the principle stands: getting the length property from an array on engines that don't create classes for instances, is not atomic, and therefore slower.
Sadly, because of MS's software being closed source, I can't tell you what kind of AST the parser churns out, nor what the engine then does with that AST. You'll have to get friendly with someone working in Redmond, or send a very polite email, requesting more info (don't expect an answer, though :-P).
So, V8 compiles the AST directly to machine-executable code, and creates classes to speedup property. In theory, accessing a property in JS, running on V8 should be almost as fast as C++ code. In theory, that is :P.
Internet Explorer's JScript engine, especially IE7, is quite dated. It doesn't do optimization very well. It doesn't compile JS as well as modern day engines do.
I can't find the resource ATM, but I also seem to remember that IE's JScript implementation of objects was, in fact, rather lacking, too. I seem to recall it didn't even use a full-blown HashTable for its objects, which would explain why someArray.length
takes ages (since it requires a prototype lookup).
Read more here.
for (var el, y = 0; el = arr[y]; y++) { el++; }
\$\endgroup\$