Разница между (i в массиве) и для (var я = 0; я <array.length; я ++)
Это будет очень простой вопрос для всех вас, javascript/jquery.
Я программировал javascript за последние 2 года, и сегодня у меня возникла странная проблема.
Я извлекаю JSONarray из моего C# Webmethod
и называя его jQuery.ajax()
Когда я делаю
for (i in JSONRaw) {
Index = Index + 1;
$('#bottomGridDashboard').append('<tr> <td>' + Index + '</td> <td>' + JSONRaw[i].DisplayName + '</td> <td>' + JSONRaw[i].SpeedInKPH + '</td> <td><img src="' + JSONRaw[i].ImageURL + '" height="20px" alt="" /></td> <td>' + JSONRaw[i].DepotID + '</td> <td>' + JSONRaw[i].RouteID + '/' + JSONRaw[i].ScheduleID + '/' + JSONRaw[i].TripID + '</td> <td>' + JSONRaw[i].Direction + '</td> <td>' + JSONRaw[i].LastStop + '</td> <td> ' + JSONRaw[i].ETAMinutes + ' </td> </tr>');
}
добавленная таблица добавляет две дополнительные строки, которые помещают каждое поле как "undefined". Посмотрите это изображение
Однако, если я заменил цикл на
for (var i = 0; i < JSONRaw.length;i++ ) {
Index = Index + 1;
$('#bottomGridDashboard').append('<tr> <td>' + Index + '</td> <td>' + JSONRaw[i].DisplayName + '</td> <td>' + JSONRaw[i].SpeedInKPH + '</td> <td><img src="' + JSONRaw[i].ImageURL + '" height="20px" alt="" /></td> <td>' + JSONRaw[i].DepotID + '</td> <td>' + JSONRaw[i].RouteID + '/' + JSONRaw[i].ScheduleID + '/' + JSONRaw[i].TripID + '</td> <td>' + JSONRaw[i].Direction + '</td> <td>' + JSONRaw[i].LastStop + '</td> <td> ' + JSONRaw[i].ETAMinutes + ' </td> </tr>');
}
строки undefined исчезают.. Смотрите изображение
Я извиняюсь за свою глупость, но раньше я никогда не сталкивался с такой проблемой.
В чем может быть причина?
EDIT:
Массив отлично. И в нем нет дыр.
Другое замечание состоит в том, что свойства undefined появляются только в нижней части моей сетки. Я думаю, что он обрабатывает два дополнительных индекса больше, чем длина массива.
РЕДАКТИРОВАТЬ-2
Мой console.log показал мне следующие элементы в моем массиве.
http://i.imgur.com/rI5TjdK.jpg
Я объявил прототипы на моей главной странице.
Array.prototype.inArray = function (comparer) {
for (var i = 0; i < this.length; i++) {
if (comparer(this[i])) return true;
}
return false;
};
Array.prototype.pushIfNotExist = function (element, comparer) {
if (!this.inArray(comparer)) {
this.unshift(element);
}
};
Увеличивает ли длина массива.?
Ответы
Ответ 1
Есть несколько способов, которыми эти две петли отличаются.
(1) Первый должен быть for (var i in JSONRaw)
. Установка свойства i
на window
может иметь неочевидные последствия.
(2) JSONRaw
не является массивом, а объектом, который имеет плохо определенное свойство length
.
(3) На JSONRaw
появились другие свойства, которые появляются в первом цикле.
(4) Массив может иметь "дыры". Например, массив ниже имеет отверстие с индексом 1
.
var a = [];
a[0] = 0;
a[2] = 2;
Первый способ опустить 1
. Второй способ будет включать индекс 1
(при a[1]
будет undefined
).
Аналогичная ситуация может произойти следующим образом:
var a = [0, 1];
a.length = 3;
Лично я подозреваю (3).
Выполнение console.log
в первом цикле может выявить проблему.
EDIT: Из вашего отладочного вывода кажется, что (3) был виновником. inArray
и pushIfNotExist
являются ключами на всех массивах, поэтому первый цикл for
повторяется над ними.
Если вы собираетесь использовать первый цикл, у вас есть три варианта:
(1) Не добавляйте эти функции на Array.prototype
. Добавление к встроенным прототипам обычно обескураживается.
(2) Используйте Object.defineProperty
(не будет работать в IE8):
Object.defineProperty(Array.prototype, 'inArray', {
enumerable: false, //this makes it not show up in the for loop
value: function (comparer) {
for (var i = 0; i < this.length; i++) {
if (comparer(this[i])) return true;
}
return false;
}
});
(3) Проверьте, был ли ключ определен на прототипе.
for(var i in JSONRaw) {
if(JSONRaw.hasOwnProperty(i)) {
//do something
}
}
Хотя большинство людей просто используют второй цикл из-за потенциальных ошибок (и более быстрой работы).
Ответ 2
JavaScript for-in
и С# foreach
- совсем другие вещи. Не используйте for-in
для циклического перемещения массивов, если вы не используете соответствующие меры предосторожности, а не то, для чего это необходимо. Он перебирает перечислимые свойства объектов, а не индексы или записи массива.
Используйте либо необходимые меры предосторожности, либо используйте общий for
, как ваш второй пример, или (если вы можете положиться на его использование) используйте Array#forEach
.
Подробнее в this SO answer и в моем блоге.
Отдельно: убедитесь, что вы объявляете i
где-то (вы, кажется, не в первом примере). Если вы этого не сделаете, вы становитесь жертвой Ужас неявных глобалов.
Я объявил прототипы на моей главной странице.
Array.prototype.inArray = function ...
Вот почему вы не используете for-in
для циклического перемещения массивов без каких-либо гарантий. Опять же, см. Ссылки выше. Ваш цикл for-in
будет проходить через свойства индекса массива ("0"
, "1"
и т.д. - да, это действительно строки), а также имена функций, которые вы добавили в Array.prototype
(inArray
и т.д.).
Ответ 3
В нескольких словах цикл for ... in
выполняет итерацию через keys
из object
, а цикл c-like for
выполняет итерацию через индексы массива. JS не так сильно набирается, поэтому он позволяет вам получить оба пути, НО правильные способы для массива - это только второй или "метод forEach". Вы можете прочитать больше в MDN.