2013-11-23 3 views
10

Это будет очень простой вопрос для всех вас, javascript/jquery.Разница между for (i в массиве) и для (var i = 0; i <array.length; i ++)

Я программировал 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>'); 
} 

прилагаемой таблице добавляет две дополнительные строки кладя каждое поле, как «не определено». See this Image

Однако, если я заменить петлю с

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>'); 
} 

неопределенные строки исчезают .. See the image

Прошу прощения за мою глупость, но я никогда не сталкивался с какой-либо такой проблемой раньше. В чем может быть причина?

EDIT:

Массив прекрасно. И в нем нет дыр. Другое наблюдение заключается в том, что неопределенные свойства появляются только в нижней части моей сетки. Я думаю, что он обрабатывает два дополнительных индекса больше, чем длина массива.

EDIT-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

Поместите полное содержание своего вопроса * в свой вопрос *, не связывайтесь с сайтом. Вы можете отправлять изображения, но с выходом 'console.log' лучше всего включать его в текст. –

+0

Я позабочусь об этом в будущем .. :) – writeToBhuwan

ответ

2

Есть несколько способов, которыми эти две петли отличаются.

(1) Первый должен быть for (var i in JSONRaw). Установка свойства i на window может иметь неочевидные последствия.

(2) JSONRaw не представляет собой массив, а объект, который имеет плохо определенное свойство length.

(3) Были другие свойства, установленные на JSONRaw, которые появляются в первом цикле.

(4) Массив может иметь «дыры». Например, приведенный ниже массив имеет отверстие с индексом 1.

var a = []; 
a[0] = 0; 
a[2] = 2; 

Первый способ - опустить 1. Второй способ будет включать индекс 1a[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 
    } 
} 

Хотя большинство людей просто используют второй цикл из-за потенциальных подводных камней (и более высокой производительности).

+0

Спасибо, Пол. BUt Я не вижу никакого другого объявления «i» в качестве глобального объекта или не вижу никаких дыр в моем массиве JSON. Console.log массива показал мне правильный массив без каких-либо неопределенных свойств. – writeToBhuwan

+0

@writeToBhuwan, я, возможно, был неясен ... Я имел в виду 'console.log' * внутри * первый цикл (так что вы будете несколько значений). –

+0

См. Редактирование в моем вопросе .... Мой журнал консоли (массив [i]) в моем цикле – writeToBhuwan

7

JavaScript for-in и C# foreach - совсем другие вещи. Не используйте for-in для перебора массивов, если вы не используете соответствующие меры предосторожности, это не то, для чего это необходимо. Он перебирает перечислимые свойства объектов, а не индексы или записи массива.

Используйте либо необходимые меры предосторожности, либо используйте общий for, как ваш второй пример, или (если вы можете положиться на его использование) используйте Array#forEach.

Подробнее в this SO answer и on my blog.


Отдельно: Убедитесь, что вы объявляя i где-то (вам не кажется, что в первом примере). Если вы этого не сделаете, вы становитесь жертвой The Horror of Implicit Globals.


Я объявил прототипы в моей главной странице.

Array.prototype.inArray = function ...

Вот почему вы не используете for-in для шлейфовых массивов без гарантий. Опять же, см. Ссылки выше. Ваш for-in цикл будет перебрать свойство индекса массива ("0", "1", и так далее - да, они действительно струнные) и также имен функций, которые вы добавили к Array.prototype (inArray и таким).

+0

Нет такой глобальной переменной. Я могу опубликовать весь свой javascript, если вы хотите, чтобы я – writeToBhuwan

+0

Я долгое время использовал i (без объявления), и он всегда работал нормально. (Не пытайтесь оскорбить, просто ожидая некоторой ясности) – writeToBhuwan

+0

@writeToBhuwan: Если вы не объявляете «я» где-то, используя его так, как вы делаете * неявно * создает глобальный. Подробнее см. Ссылку. Это означает, что если вы делаете это в двух функциях, а один вызывает другой, они будут мешать друг другу. –

2

В нескольких словах, for ... in цикл перебирает keys из object, в то время как с-for цикл перебирает индексы массива. JS не так сильно набирается, поэтому он позволяет вам получить оба пути, НО правильные способы для массива - это только второй или «метод forEach». Вы можете прочитать больше on MDN.

+0

* «НО правильный способ для массива - только второй» * Совсем нет. 'Array # forEach' - еще один правильный способ; и есть соответствующие применения для 'for-in' с массивами (особенно редкие массивы), вам просто нужно использовать правильные меры предосторожности. –

+0

Согласовано, forEach совершенно правильно, но я не использую его, потому что иногда я прибивал поддержку IE8, и в этом случае мне нужно написать polyfill. Если вам не нужно поддерживать такой архаичный софт, вы можете безопасно использовать его. Он все еще нуждается в [] .протоптическом трюке для использования с живыми коллекциями, но хорошо, что вы упомянули об этом. Я добавлю это к своему ответу. – Tommi

Смежные вопросы