Como corrigir Array indexOf () no JavaScript para navegadores Internet Explorer

295

Se você já trabalhou com JavaScript, sabe que o Internet Explorer não implementa a função ECMAScript para Array.prototype.indexOf () [incluindo o Internet Explorer 8]. Não é um problema enorme, porque você pode estender a funcionalidade da sua página com o seguinte código.

Array.prototype.indexOf = function(obj, start) {
     for (var i = (start || 0), j = this.length; i < j; i++) {
         if (this[i] === obj) { return i; }
     }
     return -1;
}

Quando devo implementar isso?

Devo envolvê-lo em todas as minhas páginas com a seguinte verificação, que verifica se a função protótipo existe e, caso contrário, vá em frente e estenda o protótipo Array?

if (!Array.prototype.indexOf) {

    // Implement function here

}

Ou verifique o navegador e, se for o Internet Explorer, basta implementá-lo?

//Pseudo-code

if (browser == IE Style Browser) {

     // Implement function here

}
Bobby Borszich
fonte
Na verdade, Array.prototype.indexOfnão faz parte do ECMA-262 / ECMAScript. Veja ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf Talvez você esteja pensando String.prototype.indexOf...
Crescent Fresh
5
É uma extensão, não faz parte do padrão original. Convém, no entanto, ser implementado como parte de Javascript 1.6 (que IE deixa de fazer) developer.mozilla.org/en/New_in_JavaScript_1.6
Josh Stodola
1
@ Josh: estava apenas se referindo a "IE não implementar a função ECMAScript ..."
Crescent Fresh
4
Sua implementação Array.indexOfnão leva em consideração índices iniciais negativos. Veja a implementação da lacuna de sugestões da Mozilla aqui: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
nickf
3
Atualizei a questão para usar "===", porque estou preocupada que as pessoas copiem com o "==" e isso estaria errado - fora isso, tudo bem. Veja a resposta de Eli Grey.
joshcomley

Respostas:

213

Faça isso deste modo...

if (!Array.prototype.indexOf) {

}

Conforme compatibilidade recomendada pelo MDC .

Em geral, o código de detecção do navegador é um grande não-não.

Josh Stodola
fonte
Não tenho representante suficiente para editar a pergunta, mas sinta-se à vontade para remover a linguagem do ECMAScript e substituí-la pela redação apropriada. Obrigado mais uma vez
Bobby Borszich
12
Tenha cuidado se você usar esse tipo de detecção. Outra biblioteca pode implementar essa função antes de testá-la e talvez não seja compatível com os padrões (o protótipo já fez isso há algum tempo). Se eu estivesse trabalhando em um ambiente hostil (lotes de outros programadores que utilizam muitas bibliotecas distintas), eu não confiar em qualquer um destes ...
Pablo Cabrera
A coluna "Vinculada" ---> é realmente útil! Eu amo a resposta aqui: stackoverflow.com/questions/1744310/…
gordon:
Ele precisa ser agrupado em todos os arquivos js?
Rd22
Quem é o MDC exatamente?
Ferrybig 04/07/19
141

Como alternativa, você pode usar a função inArray do jQuery 1.2 , que deve funcionar nos navegadores:

jQuery.inArray( value, array [, fromIndex ] )
Moses Lee
fonte
O 'indexOf' é um código nativo (à direita), então o jQuery 'inArray ()' será tão rápido, como usar o nativo quando disponível e o preenchimento múltiplo quando não?
Jeach
10
Ok, então para responder meu próprio comentário (acima), eu apenas o implementei e no Chrome é tão rápido quanto quando eu estava usando 'indexOf ()', mas no IE 8 é muito, muito lento ... então pelo menos sabemos que 'inArray ()' usa nativo quando pode.
Jeach 7/03/13
78

O código completo seria então:

if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(obj, start) {
         for (var i = (start || 0), j = this.length; i < j; i++) {
             if (this[i] === obj) { return i; }
         }
         return -1;
    }
}

Para obter uma resposta e um código realmente completos, assim como outras funções da matriz, consulte a questão Stack Overflow, Fixando funções da matriz JavaScript no Internet Explorer (indexOf, forEach, etc.) .

Luis Perez
fonte
2
obrigado por ter tudo. Eu visito esta página frequentemente sempre que preciso de indexOf entre plataformas em um novo projeto, e seu snippet é o único com código completo. :) Esses poucos segundos realmente aumentam quando alguém frequenta esta página.
precisa saber é o seguinte
16

A biblioteca underscore.js possui uma função indexOf que você pode usar:

_.indexOf([1, 2, 3], 2)
scotta7exander
fonte
4
Essa resposta evita mexer com o protótipo da matriz e delega para o indexOf nativo quando disponível. Eu gosto disso.
Brad Koch
Parece ser a maneira mais fácil se você é capaz de incluir sublinhado ou lodash
ChrisRich
10

Você deve verificar se não está definido usando if (!Array.prototype.indexOf) .

Além disso, sua implementação de indexOfnão está correta. Você deve usar em ===vez de ==em sua if (this[i] == obj)declaração, caso contrário[4,"5"].indexOf(5) seria 1 de acordo com sua implementação, o que está incorreto.

Eu recomendo que você use a implementação no MDC .

Eli Gray
fonte
9

Existe a solução oficial da Mozilla: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf

(function() {
    /**Array*/
    // Production steps of ECMA-262, Edition 5, 15.4.4.14
    // Reference: http://es5.github.io/#x15.4.4.14
    if (!Array.prototype.indexOf) {
        Array.prototype.indexOf = function(searchElement, fromIndex) {
            var k;
            // 1. Let O be the result of calling ToObject passing
            //    the this value as the argument.
            if (null === this || undefined === this) {
                throw new TypeError('"this" is null or not defined');
            }
            var O = Object(this);
            // 2. Let lenValue be the result of calling the Get
            //    internal method of O with the argument "length".
            // 3. Let len be ToUint32(lenValue).
            var len = O.length >>> 0;
            // 4. If len is 0, return -1.
            if (len === 0) {
                return -1;
            }
            // 5. If argument fromIndex was passed let n be
            //    ToInteger(fromIndex); else let n be 0.
            var n = +fromIndex || 0;
            if (Math.abs(n) === Infinity) {
                n = 0;
            }
            // 6. If n >= len, return -1.
            if (n >= len) {
                return -1;
            }
            // 7. If n >= 0, then Let k be n.
            // 8. Else, n<0, Let k be len - abs(n).
            //    If k is less than 0, then let k be 0.
            k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
            // 9. Repeat, while k < len
            while (k < len) {
                // a. Let Pk be ToString(k).
                //   This is implicit for LHS operands of the in operator
                // b. Let kPresent be the result of calling the
                //    HasProperty internal method of O with argument Pk.
                //   This step can be combined with c
                // c. If kPresent is true, then
                //    i.  Let elementK be the result of calling the Get
                //        internal method of O with the argument ToString(k).
                //   ii.  Let same be the result of applying the
                //        Strict Equality Comparison Algorithm to
                //        searchElement and elementK.
                //  iii.  If same is true, return k.
                if (k in O && O[k] === searchElement) {
                    return k;
                }
                k++;
            }
            return -1;
        };
    }
})();
Will V King
fonte
1
Apenas ser pedante, mas o MDN não é apenas o Mozilla. É um projeto conduzido pela comunidade que contém funcionários da Mozilla, mas também voluntários, qualquer um pode participar e contribuir.
ste2425
5

Eu recomendaria isso para quem procura falta de funcionalidade:

http://code.google.com/p/ddr-ecma5/

Ele traz a maioria das funcionalidades ausentes do ecma5 para os navegadores mais antigos :)

Josh Mc
fonte
** Embora eu observe que tive problemas no IE7 com esta lib.
Josh Mc
2

Esta foi a minha implementação. Essencialmente, adicione isso antes de qualquer outro script na página. ou seja, no seu mestre para uma solução global para o Internet Explorer 8. Também adicionei a função trim que parece ser usada em várias estruturas.

<!--[if lte IE 8]>
<script>
    if (!Array.prototype.indexOf) {
        Array.prototype.indexOf = function(obj, start) {
            for (var i = (start || 0), j = this.length; i < j; i++) {
                if (this[i] === obj) {
                    return i;
                }
            }
            return -1;
        };
    }

    if(typeof String.prototype.trim !== 'function') {
        String.prototype.trim = function() {
            return this.replace(/^\s+|\s+$/g, '');
        };
    };
</script>
<![endif]-->
Glennweb
fonte
2

funciona para mim.

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;
  };
}
Allen Wong
fonte
1

Com o Underscore.js

var arr=['a','a1','b'] _.filter(arr, function(a){ return a.indexOf('a') > -1; })

sri_bb
fonte