Прежде всего, никогда не используйте for in
цикл для перечисления по массиву. Никогда. Используйте старый добрый for(var i = 0; i<arr.length; i++)
.
Причина этого заключается в следующем: каждый объект в JavaScript имеет специальное поле с именем prototype
. Все, что вы добавите в это поле, будет доступно для каждого объекта этого типа. Предположим, вы хотите, чтобы у всех массивов была новая классная функция, filter_0
которая будет фильтровать нули.
Array.prototype.filter_0 = function() {
var res = [];
for (var i = 0; i < this.length; i++) {
if (this[i] != 0) {
res.push(this[i]);
}
}
return res;
};
console.log([0, 5, 0, 3, 0, 1, 0].filter_0());
//prints [5,3,1]
Это стандартный способ расширения объектов и добавления новых методов. Многие библиотеки делают это. Однако давайте посмотрим, как for in
работает сейчас:
var listeners = ["a", "b", "c"];
for (o in listeners) {
console.log(o);
}
//prints:
// 0
// 1
// 2
// filter_0
Ты видишь? Он вдруг думает, что filter_0 - это еще один индекс массива. Конечно, это на самом деле не числовой индекс, а for in
перечисление через поля объекта, а не только числовые индексы. Итак, мы сейчас перечисляем все числовые индексы и filter_0
. Но filter_0
это не поле какого-либо конкретного объекта массива, каждый объект массива теперь имеет это свойство.
К счастью, у всех объектов есть hasOwnProperty
метод, который проверяет, действительно ли это поле принадлежит самому объекту или оно просто унаследовано от цепочки прототипов и, следовательно, принадлежит всем объектам этого типа.
for (o in listeners) {
if (listeners.hasOwnProperty(o)) {
console.log(o);
}
}
//prints:
// 0
// 1
// 2
Обратите внимание, что, хотя этот код работает, как и ожидалось, для массивов, вы никогда не должны использовать никогдаfor in
и for each in
для массивов. Помните, что for in
перечисляет поля объекта, а не индексы или значения массива.
var listeners = ["a", "b", "c"];
listeners.happy = "Happy debugging";
for (o in listeners) {
if (listeners.hasOwnProperty(o)) {
console.log(o);
}
}
//prints:
// 0
// 1
// 2
// happy
if (evtListeners.hasOwnProperty(ind))
чтобы ограничить обработку только собственными (не унаследованными) свойствами. Тем не менее, в некоторых случаях вы действительно хотите перебрать все свойства, включая унаследованные. В этом случае JSLint заставляет вас обернуть тело цикла в оператор if, чтобы решить, какие свойства вы действительно хотите. Это сработает и сделает JSlint счастливым:if (evtListeners[ind] !== undefined)