Перш за все, ніколи не використовуйте 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)