Javascript: array.forEach() иногда не работает
Это мой фрагмент кода, где программа не входит в цикл foreach:
var ct = new Array();
ct["me"]= {"name" : "Jakub"};
ct["you"]= {"name" : "stack"};
ct.forEach(function (c){
document.getElementById("tmp").appendChild(document.createTextNode(c));
});
Когда я изменяю индексы массива со строк ("я", "ты") на целые числа, это работает:
var ct = new Array();
ct[0]= {"name" : "Jakub"};
ct[1]= {"name" : "stack"};
ct.forEach(function (c){
document.getElementById("tmp").appendChild(document.createTextNode(c));
});
Можете ли вы помочь мне реализовать решение для перебора массивов со всеми видами индексов? Моя цель - сохранить значения для заданных объектов даты.
Я использую данные для библиотеки Protovis и AFAIK это требует массива в качестве входных данных.
Структура данных, которую я использую в примере с Protovis, более сложна, чем та, что показана выше.
В моем проекте я посылаю через JavaBean набор некоторых объектов. Эти объекты содержат среди прочего дату. Моя цель состоит в том, чтобы показать эти объекты на графике, как это представлено на веб-сайте Protovis http:// vis.stanford.edu / protovis/ex/area.html.
Я буду использовать горизонтальную ось для времени и вертикальную ось для количества объектов в данный момент времени. Вот почему я хочу отсортировать массив по дате, так как AFAIK protovis разрешает массивы только в качестве ввода данных для своих диаграмм в режиме по умолчанию - цепочке функций.
редактировать: сейчас я изменил метод. Вместо того, чтобы хранить строки как ключи массива, я делаю следующее: здесь мой оригинальный фрагмент кода:
edit2: я добавил некоторые исходные данные:
var result2 = {"h": {
10 "documents": [
11 {
12 "biographicCategories": [
13 ],
14 "body": "Консервативное правительство Греции приказало провести расследование 1955 года Соглашение между ЦРУ и греческими военными о создании партизанской сети для борьбы с вторжениями сил Варшавского договора в случае войны.",
15 " дескрипторов ": [
16 ],
17 "generalOnlineDescriptors": [
18 ],
19 "guid": 0,
20 "headline": " Греция расследует план партизанской войны ",
21 " локация ": [
22 " ГРЕЦИЯ "
23 ],
24 " имена ": [
25 ],
26 "onlineDescriptors": [
27 ],
28 "onlineLocations": [
29 ],
30 "onlineOrganizations": [
31 ],
32 "onlinePeople": [
33 ],
34 "onlineTitles": [
35 ],
36 "организаций": [
37 ],
38 "людей": [
39 ],
40 "publishingDate": "1990-11-21 00:00:00.0 CET",
41 "sourceFile": "0402635.xml",
42 "taxonomicClassifiers": [
43 ],
44 "title": [
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 код выше работает сейчас:
В двух словах: я использую массив tlk для отображения даты в индексе. Для одного индекса в массиве resultTmp я храню дату и набор объектов, связанных с этой датой. Следующая часть кода, которую я использую, чтобы отсортировать даты от самых старых до самых новых и аналогично отсортировать resultTemp. Сортированная версия resultTemp находится в массиве результатов.
Я представляю данные в протоколе следующим образом:
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();
Примерный результат выглядит так:
i.imgur.com / WODYA.png
Я не включил код для печати осей X и Y, а также для масштабирования от даты до ширины графика. Вы можете найти примеры на странице примеров protovis.
Кстати: я запутался, почему в части:
for(key in tlk){
dates[i] = new Date(key);
i++;
}
Как последний ключ, который я получаю "содержит"? Пытался найти ответ в интернете, но безуспешно. В своем комментарии Медведс объяснил, что причина, по которой я получаю эту проблему, заключается в том, что я перебираю свойства массива.
3 ответа
Массивы JavaScript поддерживают индексацию только по номеру. Когда ты пишешь
ct["me"]= {"name" : "Jakub"};
ct["you"]= {"name" : "stack"};
вы добавляете специальные свойства me
а также you
в массив; Вы не добавляете элементы в массив. (Также используя new Array()
конструктор немного странно Если вы хотите массив, используйте []
буквальный.)
Похоже, вы должны использовать объект JavaScript, а не массив, но помните, что они поддерживают только строковые индексы.
var ct = {};
ct['me'] = {name: 'Jakub'};
ct['you'] = {name: 'stack'};
for (var k in ct) {
document.getElementById('tmp', appendChild(document.createTextNode(ct[k]));
}
Изменить: Если вы хотите обрабатывать горизонтальную ось как время, вам действительно не нужно делать намного больше работы. Здесь есть хороший базовый пример; просмотреть исходный код страницы, чтобы увидеть код. Хитрость здесь в том, что, хотя данные действительно являются массивом (объектов), x-координата явно указывается как свойство, а не как индекс в массиве данных. Каждый элемент в массиве выглядит примерно так:
>>> data[0]
{x: /* some JavaScript date object */, y: /* some number */ }
Источники:
- http://www.google.com/search?q=protovis+x-axis+time
- http://groups.google.com/group/protovis/browse_thread/thread/75ec1518692c2de5
- http://graphics.stanford.edu/~mbostock/dates/dates.html
Редактировать 2: Вы все еще, кажется, запутались в массивах против объектов.
Относительно вашего "BTW": когда вы пишете for(key in tlk) ...
вы перебираете ключи, которые уже есть в массиве. Это рассматривает массив как объект, и это не то, что вы хотите! Ты видишь contains
потому что вы перебираете свойства массива, и contains
функция прикреплена к каждому массиву (вы используете прототип или другую подобную библиотеку?).
Основная проблема, однако, заключается в том, что вы индексируете в массив (tlk
) с использованием даты. Это большое нет-нет; даже если tlk
является объектом, потому что вы можете только индексировать объекты, используя строки. Я действительно не понимаю, что вы делаете с tlk
Но я не думаю, что тебе это нужно вообще. Какова форма ваших входных данных? Если вы можете дать мне небольшой пример ввода, я, вероятно, покажу вам, что с ним делать.
Кроме того, вы должны действительно использовать литералы массива и объекта, а не Array
а также Object
Конструкторы. Например, используйте var tlk = []
скорее, чем var tlk = new Array();
, а также var d = {};
скорее, чем var d = new Object();
,
У JavaScript нет ассоциативных массивов, как таковых. Однако объекты имеют именованные свойства, что аналогично. forEach () будет перебирать только индексированные свойства. for...in
петля поможет вам здесь, хотя в целом вы бы избегали использования for...in
на массивах, потому что он также перебирает именованные свойства.
for (var c in ct) {
if (ct.hasOwnProperty(c)) {
// do something
}
}
Смотрите также:
Array.prototype.forEach
Метод обходит массив по его числовым индексам.
Массивы не являются "ассоциативными", если вы хотите иметь именованные свойства со значениями, вы должны использовать простой объект и использовать for-in
Заявление для перечисления существующих свойств:
var ct = {};
ct["me"]= {"name" : "Jakub"};
ct["you"]= {"name" : "stack"};
for (var prop in ct) {
if (ct.hasOwnProperty(prop)) {
alert(ct[prop]);
}
}
hasOwnProperty
метод вызывается, потому что for-in
Свойства обхода оператора, которые наследуются, таким образом, он будет перечислять только те свойства, которые физически существуют в объекте (собственные свойства).
Ты можешь использовать if (Object.prototype.hasOwnProperty.call(ct, prop))
вместо if (ct.hasOwnProperty(prop))
для дополнительной безопасности, потому что, если объект имеет свойство с именем "hasOwnProperty
", не будет методом, который вы хотите выполнить.