English 中文(简体)
Javascript: array.forEach() sometimes not working
原标题:

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.

最佳回答

JavaScript arrays only support indexing by number. When you write

ct["me"]= {"name" : "Jakub"};
ct["you"]= {"name" : "stack"};

you are adding ad-hoc properties me and you to the array; you are not adding elements to the array. (Also using the new Array() constructor is kind of weird. If you want an array, use the [] literal.)

It sounds like you should use a JavaScript object, not an array, but be mindful that they only support string indices.

var ct = {};
ct[ me ] = {name:  Jakub };
ct[ you ] = {name:  stack };

for (var k in ct) {
    document.getElementById( tmp , appendChild(document.createTextNode(ct[k]));
}

Edit: If you want to treat the horizontal axis as time, you really don t need to do much more work. There s a good basic example here; view the page source to see the code. The trick here is that, while the data really is an array (of objects), the x-coordinate is stated explicitly as a property rather than as the index in the data array. Each element in the array looks something like this:

>>> data[0]
    {x: /* some JavaScript date object */, y: /* some number */ }

Sources:


Edit 2: You still seem mixed up about arrays versus objects.

Regarding your "BTW": when you write for(key in tlk) ... you re iterating over the keys that are already in the array. That s treating the array as an object, and that s not what you want! You see contains because you re iterating over properties of an array, and contains is a function attached to every array (are you using prototype, or another similar library?).

The basic problem, however, is that you re indexing into an array (tlk) using a Date. That s a big no-no; even if tlk is an object, because you can only index objects using strings. I really don t get what you re doing with tlk, but I don t think you need it at all. What s the form of your input data? If you can give me a small example of the input, I can probably show you what to do with it.

Also, you should really use array and object literals rather than the Array and Object constructors. For example, use var tlk = [] rather than var tlk = new Array();, and var d = {}; rather than var d = new Object();.

问题回答

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:

The Array.prototype.forEach method traverses the array on its numeric indexes.

Arrays are not associative , if you want to have named properties with values you should use a simple object, and use the for-in statement to enumerate the existing properties:

var ct = {};
ct["me"]= {"name" : "Jakub"};
ct["you"]= {"name" : "stack"};

for (var prop in ct) {
  if (ct.hasOwnProperty(prop)) {
    alert(ct[prop]);
  }
}

The hasOwnProperty method is called because the for-in statement traverse properties that are inherited, in that way it will enumerate only the properties that physically exist on the object (own properties).

You can use if (Object.prototype.hasOwnProperty.call(ct, prop)) instead of if (ct.hasOwnProperty(prop)) for extra safety, because if the object has a property named "hasOwnProperty", will not be the method you want to execute.





相关问题
selected text in iframe

How to get a selected text inside a iframe. I my page i m having a iframe which is editable true. So how can i get the selected text in that iframe.

How to fire event handlers on the link using javascript

I would like to click a link in my page using javascript. I would like to Fire event handlers on the link without navigating. How can this be done? This has to work both in firefox and Internet ...

How to Add script codes before the </body> tag ASP.NET

Heres the problem, In Masterpage, the google analytics code were pasted before the end of body tag. In ASPX page, I need to generate a script (google addItem tracker) using codebehind ClientScript ...

Clipboard access using Javascript - sans Flash?

Is there a reliable way to access the client machine s clipboard using Javascript? I continue to run into permissions issues when attempting to do this. How does Google Docs do this? Do they use ...

javascript debugging question

I have a large javascript which I didn t write but I need to use it and I m slowely going trough it trying to figure out what does it do and how, I m using alert to print out what it does but now I ...

Parsing date like twitter

I ve made a little forum and I want parse the date on newest posts like twitter, you know "posted 40 minutes ago ","posted 1 hour ago"... What s the best way ? Thanx.

热门标签