Почему indexOf не работает с массивом IE8?

294

Приведенная ниже функция отлично работает на Opera, Firefox и Chrome. Однако в IE8 он не работает наif ( allowed.indexOf(ext[1]) == -1) стороны.

Кто-нибудь знает почему? Есть ли очевидная ошибка?

function CheckMe() {
    var allowed = new Array('docx','xls','xlsx', 'mp3', 'mp4', '3gp', 'sis', 'sisx', 'mp3', 'wav', 'mid', 'amr', 'jpg', 'gif', 'png', 'jpeg', 'txt', 'pdf', 'doc', 'rtf', 'thm', 'rar', 'zip', 'htm', 'html', 'css', 'swf', 'jar', 'nth', 'aac', 'cab', 'wgz');
    var fileinput=document.getElementById('f');
    var ext = fileinput.value.toLowerCase().split('.');
    if ( allowed.indexOf(ext[1]) == -1) 
    {
        document.getElementById('uploadsec').innerHTML = document.getElementById('uploadsec').innerHTML;
        alert('This file type is not allowed!');
    }
}
СДЛ
источник
5
Отличный вопрос, отличный ответ. Спасибо, что дали мне именно то, что мне было нужно.
Hardwareguy

Ответы:

488

Версии IE до IE9 не имеют .indexOf()функции для Array, чтобы определить точную версию спецификации , запустите ее, прежде чем пытаться ее использовать:

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

Это версия от MDN , используемая в Firefox / SpiderMonkey. В других случаях, таких как IE, он будет добавлен .indexOf()в случае, если он отсутствует ... в основном IE8 или ниже в этой точке.

Ник Крейвер
источник
2
Обратите внимание на предостережение о том, что если вы (или библиотеки, которые вы используете) используете синтаксис for / in для перечисления массивов (например, for (idx в arrayname) stmt;), этот метод будет также перечислен. Это связано с тем, что встроенные свойства не перечислены в for / in, а определены пользователем.
Поезд Испании
5
@Mike - это другая проблема ... вы не должны использовать for...inцикл для итерации массива, он должен использоваться только для перечисления .
Ник Крейвер
3
@Mike - Вы перебираете массив по нескольким причинам для этого ... например, вы получаете результаты в правильном порядке в разных браузерах. Использование for..inв массиве вызовет только проблемы, это не просто соглашение ... это непреднамеренное использование и неправильное. Порядок и ключи не полностью определены, они зависят от реализации ... например, IE будет перечислять элементы массива в порядке их добавления , а не по их индексу. Однако вы можете выполнять итерацию правильно, получая доступ по индексу.
Ник Крейвер
1
И это иллюстрирует разницу между перечислением элементов и использованием индекса для итерации. Вот почему у нас есть обе концепции. Вы можете перечислить значения в связанном списке, или вы можете сканировать связанный список и возвращать значения от одного к следующему. Один - математическая концепция, другой - процедурная инструкция.
Jcolebrand
1
@ Да, да! И так как многие ищут "Почему indexOf не работает в массиве IE8?" может быть на более низком уровне сложности WRT до js, может быть полезно указать это как следствие к ответу. Если бы все уже имели глубокое понимание спецификации и различий между реализациями, таких потоков не было бы. @Nick Вы делаете сильные предположения о правильности. Есть много операций, для которых порядок не имеет значения (например, установить разницу.) Кроме того, в исходном комментарии не упоминалось перечисление в индексной последовательности, только то, что для / in включает пользовательские def fn.
Поезд Испании
152

Если вы используете jQuery, вы можете использовать вместо него $ .inArray () .

tiegz
источник
7
Я согласен, что это более полезно. Это одна из основных причин использования JQuery - он много делает для облегчения кросс-браузерной несовместимости.
cw24
17

Если вы используете jQuery и хотите продолжать использовать indexOf, не беспокоясь о проблемах совместимости, вы можете сделать это:

if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(val) {
        return jQuery.inArray(val, this);
    };
}

Это полезно, если вы хотите продолжать использовать, indexOfно обеспечите запасной вариант, когда он недоступен.

Mehdiway
источник
Да, вероятно, потому что он не включил jQuery ¯_ (ツ) _ / ¯ Это правильный синтаксис.
5

Пожалуйста, будьте осторожны с $ .inArray, если хотите его использовать. Я только что узнал, что $ .inArray работает только с "Array", а не со String. Вот почему эта функция не будет работать в IE8!

JQuery API создает путаницу

Метод $ .inArray () похож на нативный метод JavaScript .indexOf () в том смысле, что он возвращает -1, если не находит соответствия. Если первый элемент в массиве соответствует значению, $ .inArray () возвращает 0

-> Они не должны говорить это «похоже». Так как indexOf поддержки "String" также!

ptgamr
источник
16
Это называется inArray. Кажется, что это вполне применимо только к массивам. Вот почему он «похож на», а не «идентичен».
tandrewnichols
Хорошая заметка. Забавный факт indexOfв том, что объект String полностью найден в IE, в то время как indexOfв Array прототип не найден в IE <= 8.
adi518
Вы привязываете его к прототипу массива, чтобы он не влиял на строки.
kagronick
3

Эта проблема

IE <= 8 просто не имеет indexOf()метода для массивов.


Решение

Если вам нужно indexOfв IE <= 8, вам следует рассмотреть возможность использования следующего полизаполнения , которое рекомендуется в MDN :

if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(searchElement, fromIndex) {
        var k;
        if (this == null) {
            throw new TypeError('"this" is null or not defined');
        }
        var o = Object(this);
        var len = o.length >>> 0;
        if (len === 0) {
            return -1;
        }
        var n = +fromIndex || 0;
        if (Math.abs(n) === Infinity) {
            n = 0;
        }
        if (n >= len) {
            return -1;
        }
        k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
        while (k < len) {
            if (k in o && o[k] === searchElement) {
                return k;
            }
            k++;
        }
        return -1;
    };
}

Минимизировано:

Array.prototype.indexOf||(Array.prototype.indexOf=function(r,t){var n;if(null==this)throw new TypeError('"this" is null or not defined');var e=Object(this),i=e.length>>>0;if(0===i)return-1;var a=+t||0;if(Math.abs(a)===1/0&&(a=0),a>=i)return-1;for(n=Math.max(a>=0?a:i-Math.abs(a),0);i>n;){if(n in e&&e[n]===r)return n;n++}return-1});
Джон Слегерс
источник
1

Вы можете использовать это для замены функции, если она не существует:

<script>
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;
    };
}
</script>
Роберт Кадмир
источник