Javascript: array.forEach() sometimes not working

Jakub picture Jakub · Aug 23, 2010 · Viewed 9.7k times · Source

this is my code snippet, where the program doesn't enter the foreach loop:

var ct = new Array();
ct["me"]= {"name" : "Jakub"};
ct["you"]= {"name" : "stack"};
ct.forEach(function (c){
    document.getElementById("tmp").appendChild(document.createTextNode(c));
});

When I change the array indices from strings ("me", "you") to integers, it works:

var ct = new Array();
ct[0]= {"name" : "Jakub"};
ct[1]= {"name" : "stack"};
ct.forEach(function (c){
    document.getElementById("tmp").appendChild(document.createTextNode(c));
});

Can you help me to implement the solution to iterate over the arrays with all kinds of indices? My aim is to store the values for given date objects.


I use the data for the Protovis library and AFAIK it needs an array as input.

The data structure I use in the protovis example is more complicated than this one shown above.

In my project I send via JavaBean the set of some objects. Those object contain among other things the date. My aim is to show those objects on the graph like this, presented on protovis website http:// vis.stanford.edu / protovis/ex/area.html.

I will use the horizontal axis for the time, and the vertical axis for number of objects for a given time. This is why I want to have the array sorted by the date, since AFAIK protovis only allows arrays as the data input for their diagrams in the default mode - function chaining.

edit: For now I changed the method. Instead of storing strings as array keys I do following: hereby is my original code snippet:
edit2: I added some original input: var result2 = {"h": { 10 "documents": [ 11 { 12 "biographicalCategories": [ 13 ], 14 "body": "Greece's conservative Government has ordered an investigation into a 1955 agreement between the C.I.A. and the Greek military for the establishment of a guerrilla network to fight invading Warsaw Pact forces in the event of a war.", 15 "descriptors": [ 16 ], 17 "generalOnlineDescriptors": [ 18 ], 19 "guid": 0, 20 "headline": "Greece to Investigate Plan for Guerrilla War", 21 "locations": [ 22 "GREECE" 23 ], 24 "names": [ 25 ], 26 "onlineDescriptors": [ 27 ], 28 "onlineLocations": [ 29 ], 30 "onlineOrganizations": [ 31 ], 32 "onlinePeople": [ 33 ], 34 "onlineTitles": [ 35 ], 36 "organizations": [ 37 ], 38 "people": [ 39 ], 40 "publicationDate": "1990-11-21 00:00:00.0 CET", 41 "sourceFile": "0402635.xml", 42 "taxonomicClassifiers": [ 43 ], 44 "titles": [ 45 ], 46 "typesOfMaterial": [ 47 ], 48 "score": 0.80242133 49 },


var resultTmp = new Array();
var i = 0;
var averageScore = 0; 

var startDate = new Date();
var endDate = new Date(1700, 01, 01);
var docDate;
var actDate;

var tlk = new Array();
var av = 0;
var d = new Object();

result2.h.documents.forEach(function(c) {
    averageScore += c.score;
  if(typeof(c.publicationDate) != "undefined"){
    docDate = c.publicationDate.split("-");
    actDate = new Date(docDate[0], docDate[1]-1, docDate[2].split(" ")[0]);
    if(actDate  endDate){
        endDate = actDate;
    }
    if(defined(tlk[actDate])){
        av = tlk[actDate];
        resultTmp[av].docs.push(c);
    }
    else {
        d = new Object();
        d.date = actDate;
        d.docs = new Array();
        d.docs.push(c);
        resultTmp[i] = d;
        tlk[actDate] = i;
        i++;
    }
  }
});

i = 0;
var dates = [];
for(key in tlk){
    if(key )
        d = new Date(key);
    if(isValidDate(d)){
    dates[i] = new Date(key);
    i++;        
    }
}
dates.sort(function (a, b) {
    return a > b;
});

var ii = 0;
i = 0;
var ddocs;
var result = new Array();
for(i=0; i maxDocsPerDate){
            maxDocsPerDate = d.docs.length;
        } 
        result[i] = d;
}


edit3 the code above is working now:

In a nutshell: I use the tlk array to reflect the date to the index. For one index in the resultTmp array I store the date and the set of objects related to that date. The next part of code I use to sort the dates from the oldest to the newest and analogously sort the resultTemp. The sorted version of resultTemp is in the result Array.

I present data in protovis in following way:


vis.add(pv.Line)
    .data(result)
    .lineWidth(2)
    .left(function(a) x(a.date))
    .bottom(function(a) y(a.docs.length))
    .add(pv.Dot)
    .lineWidth(function(a) a.docs.length - (a.docs.length-1)/3)
    .radius(function(a) a.docs.length * (a.docs.length/1.2))
    .fillStyle(function(a) color(a.docs.length))
    .event("click", function(a) Popup.show(a.docs))
    .anchor("top").add(pv.Label)
    .text(function(a) a.docs.length)
    .textBaseline("bottom");

vis.render();

The exemplary result looks like: i.imgur.com / WODYA.png
I didn't include the code for printing the x and y axes as well as for scaling from the date to the graph width. You can find examples on the protovis examples page.

BTW: I'm confused why in the part:

for(key in tlk){
    dates[i] = new Date(key);
    i++;
}

As the last key I get "contains"? Tried to find answer on Internet, without success. Bears explained in his comment that the reason I get this probelm is because I'm iterating over the properties of the array.

Answer

Andy E picture Andy E · Aug 23, 2010

JavaScript doesn't have associative arrays, par se. Objects have named properties, though, which is similar. forEach() will only iterate over indexed properties. A for...in loop will help you here, although in general you would avoid using for...in on arrays because it iterates over named properties too.

for (var c in ct) {
    if (ct.hasOwnProperty(c)) {
        // do something
    }
}

See also: