21

The difference between a JavaScript Array, and Object is not very big. In fact it seems Array mainly adds the length field, so you can use both Arrays and Objects as numeric arrays:

var ar = new Array();
ar[0] = "foo";
ar["bar"] = "foo";

var ob = new Object();
ob[0] = "foo";
ob["bar"] = "foo";

assert(ar[0] == ob[0] == ar["0"] == ob["0"] == ar.bar == ob.bar); // Should be true.

So my questions is, in popular JavaScript engines (V8, JavaScriptCore, SpiderMonkey, etc.), how is this handled? Obviously we do not want our arrays to be actually stored as hash maps with key values! How can we be reasonably sure our data is stored as an actual array?

As far as I can see there are a few approaches engines could take:

  1. Array is implemented exactly the same way as Object - as an associative array with string keys.
  2. Array is a special case, with a std::vector-like array backing the numeric keys, and some density heuristic to prevent insane memory use if you do ar[100000000] = 0;
  3. Array is the same as Object, and all objects get a heuristic to see if using an array would make more sense.
  4. Something insanely complicated that I haven't thought of.

Really this would be simpler if there were a proper array type (cough WebGL typed arrays cough).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Timmmm
  • 88,195
  • 71
  • 364
  • 509
  • 2
    This [article](http://news.qooxdoo.org/javascript-array-performance-oddities-characteristics) is a little old, and it doesn't explicitly explain implementation. However, it does detailed performance measurements, and infers the likely implementations. – Matthew Flaschen Feb 10 '12 at 19:57
  • 2
    Array isn't _just_ a map with a `length` property tacked on. If it were, then shifting or unshifting would break the indexing (i.e. shift a value off an array, and it still starts at index 0, not 1). So there's at least a little more going on. (Not that this necessarily says anything about the implementation, of course) – Flambino Feb 10 '12 at 20:00
  • 1
    Why would you expect `r[0] == ob[0] == ar["0"] == ob["0"] == ar.bar == ob.bar` to be true? `'a' == 'a' == 'a'` is false because it evaluates to `true == 'a'` which evaluates to `false`. – Mike Samuel Feb 10 '12 at 20:15
  • 4
    @Flambino, that is not true. [`shift`](http://es5.github.com/#x15.4.4.9) is implemented as a generic method, not array specific. It will work perfectly well with a regular object. Shifting works because it grabs the first value, then loops over all values assigning left and finally deletes the last element and sets length. – Mike Samuel Feb 10 '12 at 20:17
  • 1
    @Flambino, try running `var a = { 0: 0, 1: 1, length: 2 }; Array.prototype.shift.apply(a); alert(JSON.stringify(a))`. You should reliably get `{"0":1,"length":1}`. – Mike Samuel Feb 10 '12 at 20:19
  • @MikeSamuel Sir, I stand corrected. I never thought to try it on a non-Array object. Should have occurred to me, though, since I've used `slice` often enough on `arguments` objects. Interesting – Flambino Feb 10 '12 at 20:27

2 Answers2

15

In SpiderMonkey, arrays are implemented basically as C arrays of jsvals. These are referred to as "dense arrays". However, if you start doing un-array-like things to them -- like treating them like objects -- their implementation is changed to something which very much resembles objects.

Moral of the story: when you want an array, use an array. When you want an object, use an object.

Oh, a jsval is a sort of variadic type which can represent any possible JavaScript value in a 64 bit C type.

Wes
  • 950
  • 5
  • 12
8

In V8 and Carakan (and presumably Chakra), all (non-host) objects (both those that are arrays and those that aren't) with properties whose names are array indexes (as defined in ES5) are stored as either a dense array (a C array containing some value wrapper) or a sparse array (which is implemented as a binary search tree).

The unified object representation shows through in that it affects enumeration order: with an object, SpiderMonkey and SquirrelFish both give all properties in insertion order; and with an array, they in general (there are special cases in SM at least!) array indexes first then all other properties in insertion order. V8, Carakan, and Chakra always give array indexes first then all other properties in insertion order, regardless of object type.

gsnedders
  • 5,532
  • 2
  • 30
  • 41