Por que o indexOf não funciona em uma matriz IE8?

294

A função abaixo funciona bem no Opera, Firefox e Chrome. No entanto, no IE8, ele falha por if ( allowed.indexOf(ext[1]) == -1)parte.

Alguem sabe por quê? Existe algum erro óbvio?

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!');
    }
}
nLL
fonte
5
Ótima pergunta, ótima resposta. Obrigado por me dar exatamente o que eu precisava.
Hardwareguy

Respostas:

488

As versões do IE anteriores ao IE9 não possuem uma .indexOf()função para Array. Para definir a versão exata das especificações , execute isso antes de tentar usá-lo:

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

Esta é a versão do MDN , usada no Firefox / SpiderMonkey. Em outros casos, como o IE, ele adiciona .indexOf()o caso de estar faltando ... basicamente o IE8 ou abaixo neste momento.

Nick Craver
fonte
2
Observe a ressalva de que, se você (ou bibliotecas que você usa) usar a sintaxe for / in para enumerar matrizes (por exemplo, para (idx no nome da matriz) stmt;), esse método também será enumerado. Isso ocorre porque as propriedades internas não são enumeradas por for / in, mas as definidas pelo usuário.
Spain Train
5
@ Mike - Esse é um problema diferente ... você não deve usar um for...inloop para iterar uma matriz, ele deve ser usado apenas para enumeração .
Nick Craver
3
@ Mike - Você itera sobre uma matriz por mais motivos para isso ... como obter os resultados na ordem certa nos navegadores. Usar for..inem uma matriz só causará problemas, não é apenas uma convenção ... é um uso não intencional e incorreto. A ordem e as chaves não são completamente especificadas, elas dependem da implementação ... por exemplo, o IE enumera os itens da matriz na ordem em que foram adicionados , não pelo índice. No entanto, você pode iterar corretamente, acessando por índice.
Nick Craver
1
E isso ilustra a diferença entre enumerar os elementos e usar um índice para iterar. É por isso que temos os dois conceitos. Você pode enumerar os valores em uma lista vinculada ou rastrear a lista vinculada e retornar os valores de um para o outro. Um é um conceito matemático, um é uma instrução processual.
precisa saber é o seguinte
1
@Pointy Yes! E já que muitos pesquisaram "Por que o indexOf não funciona em um array IE8?" Se o WRT estiver em um nível de sofisticação menor para js, pode ser útil apontar isso como um corolário da resposta. Se todos já tivessem um entendimento profundo das especificações e diferenças entre implementações, threads como esses não existiriam. @ Nick Você faz fortes suposições sobre a correção. Existem muitas operações para as quais a ordem não importa (por exemplo, definir diferença.) Além disso, o comentário original não mencionou a enumeração na sequência do índice, apenas que para / in inclui as definições de usuário.
Spain Train
152

Se você estiver usando jQuery, poderá usar $ .inArray () .

tiegz
fonte
7
Eu concordo que isso é mais útil. Essa é uma das principais razões para o uso do JQuery - ele ajuda bastante a aliviar incompatibilidades entre navegadores.
Cw24
17

Se você estiver usando jQuery e quiser continuar usando o indexOf sem se preocupar com problemas de compatibilidade, faça o seguinte:

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

Isso é útil quando você deseja continuar usando, indexOfmas fornece um fallback quando não está disponível.

Mehdiway
fonte
Sim, provavelmente porque ele não incluiu o jQuery ¯_ (ツ) _ / ¯ É uma sintaxe válida.
5

Por favor, tome cuidado com $ .inArray se você quiser usá-lo. Acabei de descobrir que o $ .inArray só funciona com "Array", não com String. É por isso que essa função não funciona no IE8!

A API jQuery cria confusão

O método $ .inArray () é semelhante ao método nativo .indexOf () do JavaScript, pois retorna -1 quando não encontra uma correspondência. Se o primeiro elemento dentro da matriz corresponder ao valor, $ .inArray () retornará 0

-> Eles não deveriam dizer "Similar". Desde indexOf suporte "String" também!

ptgamr
fonte
16
É chamado inArray. Isso parece definitivamente se aplicar apenas a matrizes. É por isso que é "semelhante a" e não "idêntico a".
Tandrewnichols
Boa nota. O fato engraçado é indexOfem um objeto String é totalmente encontrado no IE, enquanto indexOfna matriz protótipo não é encontrado no IE <= 8.
adi518
Você está vinculando-o ao protótipo da matriz, para que isso não afete as strings.
kagronick
3

O problema

O IE <= 8 simplesmente não possui um indexOf()método para matrizes.


A solução

Se você precisar indexOfno IE <= 8, considere usar o seguinte polyfill , recomendado no 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;
    };
}

Minificado:

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});
John Slegers
fonte
1

Você pode usar isso para substituir a função se ela não existir:

<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>
Robert Cadmire
fonte