Реализация массива indexOf для Internet Explorer

Существует множество решений о том, как включить реализацию indexOf в прототип Array, чтобы он работал в Internet Explorer, однако я наткнулся на проблему, которая, похоже, нигде не решена.

Используя довольно хорошо согласованную реализацию в MDC, я следующий код, который сейчас вызывает проблемы:

// indexOf support for IE (from MDC)
if (!Array.prototype.indexOf)
{
    Array.prototype.indexOf = function(elt /*, from*/)   
    {
        var len = this.length >>> 0;

        var from = Number(arguments[1]) || 0;
        from = (from < 0) ? Math.ceil(from) : Math.floor(from);
        if (from < 0)
            from += len;

        for (; from < len; from++)
        {
            if (from in this && this[from] === elt)  
                return from;
        }
        return -1;
    };
}

var i = [1,2,3,4];

for (j in i)
{
    alert(i[j]);
}

Я ожидаю получить 4 предупреждения, каждое из которых содержит один из элементов массива. В Firefox и Chrome это именно то, что я вижу, однако в IE8 я получаю дополнительное предупреждение, содержащее код функции indexOf.

Что можно сделать, чтобы этого избежать?


person Daemon    schedule 19.05.2010    source источник


Ответы (3)


Это потому, что вы редактируете Array.prototype, и, таким образом, любой созданный массив наследует специально созданный метод VISIBLE indexOf, который может видеть команда "in".

Конструкция for..in в JavaScript работает не так, как, например, PHP foreach - она ​​не просто выполняет итерацию всех элементов в массиве, но также выполняет итерацию всех методов и свойств, которые может иметь массив OBJECT (массивы в JavaScript на самом деле являются «замаскированными» объектами) . Собственные методы невидимы для конструкции for..in, но не все пользовательские дополнения.

В вашем примере любой массив будет выглядеть так:

Array:
- [0] value
- [1] value
- [2] value
- ..
- [N] value
- [IndexOf] value

Чтобы избежать нежелательных унаследованных методов и свойств, вы можете использовать метод hasOwnProperty():

for (j in j){
    if(i.hasOwnProperty(j){
        alert(i[j])
    }
}

hasOwnProperty проверяет, не унаследован ли ключ и не принадлежит ли он фактическому объекту. Таким образом проходят только необходимые значения.

person Andris    schedule 19.05.2010
comment
Соглашение заключается в использовании for..in для объектов (перечисление) и простого for для массивов (итерация). См. Ответ CMS - person Justin Johnson; 19.05.2010
comment
for..in на самом деле не самая подходящая конструкция для итерации массивов, особенно с учетом того, что порядок итерации не гарантируется, но иногда он действительно существует - person Andris; 20.05.2010
comment
Спасибо за информацию. Я просто хочу, чтобы IE справлялся с такими вещами, как FF и Chrome. И переписывание циклов for ... in to for на самом деле не вариант, устаревший код может быть проблемой. - person Daemon; 20.05.2010

Это происходит потому, что в IE, поскольку метод не существует, он добавляется к Array.prototype и остается перечисляемым.

Для работы с массивами (и, как правило, с любыми объектами, подобными массиву), я не рекомендую использовать оператор for...in.

Почему?

  • Оператор for...in предназначен для перечисления свойств объекта.
  • Как вы заметили, оператор for...in просматривает цепочку прототипов.
  • Порядок итерации может быть произвольным, итерация по массиву может не посещать элементы в числовом порядке.

Самый простой подход, простой цикл for:

for (var j = 0; j < i.length; j++) {
    alert(i[j]);
}

Смотрите также:

person Christian C. Salvadó    schedule 19.05.2010
comment
Спасибо за информацию. Я просто хочу, чтобы IE справлялся с такими вещами, как FF и Chrome. И переписывание циклов for ... in to for на самом деле не вариант, устаревший код может быть проблемой. - person Daemon; 20.05.2010

Вы можете попробовать добавить:

for (j in i) {
    if (i.hasOwnProperty(j)) { 
        alert(j); 
    }
}
person Scott    schedule 19.05.2010