Search code examples
javascriptreturn-valueassociative-arraydynamic-arrays

Javascript associative array returns empty/undefined despite being populated inside function


I am working on a Javascript function which takes an XML document and creates a multidimensional (as needed) associative array. Inside the function, the array builds properly however upon returning the Array object, it returns an empty array.

Interesting to note, if I use the push method, and push a literal Array in the form {"index": index, "value":value} rather than using the assignment operator (array[index]=value) it works just fine

For testing I am using the following XML node object (Level_1_node):

<Level_1>
    <Level_2>VALUE</Level_2>
</Level_1>

Here is the function:

function get_array_from_XML(XML_node){
    var XML_array = new Array();
    var child_node;

    for(var i=0; i<XML_node.childNodes.length; i++){
        child_node = XML_node.childNodes[i];
        if(child_node.childNodes[0]){
            if (child_node.childNodes[0].nodeType == 3){
                XML_array[child_node.nodeName] = child_node.childNodes[0].nodeValue;
            } else {                
                XML_array[child_node.nodeName] = get_array_from_XML(child_node);
            }
        }
    }

    dump(XML_array);  //for my debugging, alerts "LEVEL_2 => VALUE", so everything seems fine

    return XML_array;
}

The follow method works, however the return format is undesirable:

function get_array_from_XML_using_push(XML_node){
    var XML_array = new Array();
    var child_node;

    for(var i=0; i<XML_node.childNodes.length; i++){
        child_node = XML_node.childNodes[i];
        if(child_node.childNodes[0]){
            if (child_node.childNodes[0].nodeType == 3){
                XML_array.push({
                    "index" : child_node.nodeName,
                    "value" : child_node.childNodes[0].nodeValue
                });
            } else {                
                XML_array.push({
                    "index" : child_node.nodeName,
                    "value" : get_array_from_XML_using_push(child_node)
                });
            }
        }
    }

    dump(XML_array);  //shows the fully populated array

    return XML_array;
}

Now when I run get_array_from_XML(Level_1_node) it returns an empty array, but get_array_from_XML_using_push(Level_1_node) returns

{0 => {"index" => "Level_2", "value" => "VALUE"}}

Very frustrating. Any insight is welcome.


Solution

  • Change new Array() to new Object(). The Array constructor is not for associative arrays; it's for numerically indexed arrays only. Objects themselves double as associative arrays in JavaScript.

    function get_array_from_XML(XML_node){
        var XML_array = new Object();
        // -------------------^
        var child_node;
    
        for(var i=0; i<XML_node.childNodes.length; i++){
            child_node = XML_node.childNodes[i];
            if(child_node.childNodes[0]){
                if (child_node.childNodes[0].nodeType == 3){
                    XML_array[child_node.nodeName] = child_node.childNodes[0].nodeValue;
                } else {                
                    XML_array[child_node.nodeName] = get_array_from_XML(child_node);
                }
            }
        }
    
        dump(XML_array);  //for my debugging, alerts "LEVEL_2 => VALUE", so everything seems fine
    
        return XML_array;
    }
    

    Using Objects as Associative Arrays

    Have a look at the following example:

    var colors = new Object();
    colors['red'] = '#f00';
    colors['green'] = '#0f0';
    colors['blue'] = '#00f';
    colors['black'] = '#000';
    colors['white'] = '#fff';
    
    conosle.log(colors['red']); // => #f00
    conosle.log(colors['green']); // => #0f0
    conosle.log(colors['white']); // => #fff
    
    // Use for..in or Object.keys to iterate over an object
    for (var key in colors) {
        console.log(key, colors[key]);
    }
    // Logs all colors and their corresponding code
    
    Object.keys(colors).forEach(function(key) {
        console.log(key, colors[key]);
    });
    // Also logs all colors and their corresponding code
    

    Note that colors['red'] = '#f00'; is identical to colors.red = '#f00';. The square bracket notation is only really needed when you want to use a string which is an invalid identifier or when you want to use the value of a variable as a property name.