javascriptarraysdynamicweakly-typed

How are JavaScript arrays represented in physical memory?


It is my understanding that I can store mixed data in a JavaScript array, as well as change any element in the array to some other type. How does the interpreter keep track of what place in physical memory any element is at. Also how is the overwriting of the data in the next element prevented if I change an element to a larger data type.

I assume that arrays only store references to actual objects, and primitives are wrapped behind the scenes when placed in arrays.

Assuming this is the case, If I have a different handle on the primitive variable and change the value stored in the array is synchronicity maintained?

I know I probably already answered my own question, but I don't know for sure and I can't find any information on the matter.


Solution

  • Normally, arrays allocate a contiguous block of memory of fixed length. However, in Javascript, arrays are Object types with special constructors and accessor methods.

    Which means, a statement like:

    var arr = new Array(100000);
    

    does not allocate any memory! In fact, it simply sets the value of the length property in the array. When you construct an array, you don't need to declare a size as they grow automatically. So, you should use this instead:

    var arr = [];
    

    Arrays in Javascript are sparse which means not all the elements in the array may contain data. In other words, only the elements that actually contain data exist in the array. This reduces the amount of memory used by the array. The values are located by a key and not by an offset. They're simply a method of convenience and not intended to be used for complex numerical analysis.

    Arrays in Javascript are not typed so the value of an element can be an object, string, number, boolean, function or an array. The main difference between an array and an object is the length property which has a value greater than the largest integer key in the array.

    For example:

    You could have an create an empty array and add two elements at index 0 and index 99. The length would be 100, but the number of elements in the array would be 2.

    var arr = [];
    arr[0] = 0;
    arr[99] = {name: "John"};
    console.log(arr.length); // prints 100
    arr; // prints something like [0, undefined × 98, Object { name: "John"}]
    

    To answer your questions directly:

    Q. It is my understanding that I can store mixed data in a JavaScript array, as well as change any element in the array to some other type. How does the interpreter keep track of what place in physical memory any element is at? Also, how is the overwriting of the data in the next element prevented if I change an element to a larger data type?

    A. You probably know this by now if you've read my comments above. In Javascript, an array is a Hashtable Object type so the interpreter doesn't need to keep track of physical memory and changing the value of an element doesn't affect other elements as they're not stored in a contiguous block of memory.

    --

    Q. I assume that arrays only store references to actual objects, and primitives are wrapped behind the scenes when placed in arrays. Assuming this is the case, if I have a different handle on the primitive variable and change the value stored in the array is synchronicity maintained?

    A. No, primitives are not wrapped. Changing a primitive that was assigned to an array will not change the value in the array as they're stored by value. Objects on the other hand are stored by reference, so changing the objects value will reflect that change in that array.

    Here's an example you can try:

    var arr = [];
    var obj = { name: "John" };
    var isBool = true;
    
    arr.push(obj);
    arr[1] = isBool;
    
    console.log(arr[0]); // print obj.name
    console.log(arr[1]); // print true
    
    obj.age = 40;        // add age to obj
    isBool = false;      // change value for isBool
    
    console.log(arr[0]); // value here will contain age
    console.log(arr[1]); // value here will still be true
    

    Also, note that when you initialize an array in the following two ways, it has a different behavior:

    var arr = new Array(100);
    console.log(arr.length);        // prints 100
    console.log(arr);               // prints []
    
    var arr2 = new Array(100, 200);
    console.log(arr2.length);       // prints 2
    console.log(arr2);              // prints [100, 200]
    

    If you want to use Javascript Arrays as contiguous blocks of memory, you should look into using TypedArray. TypedArray's allow you to allocate a block of memory as a byte array and access the raw binary data more efficiently.

    You can learn more about the intricacies of Javascript by reading the ECMA-262 spec (ver 5.1).