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 */ }

Источники:


Редактировать 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", не будет методом, который вы хотите выполнить.

Другие вопросы по тегам