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

}

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.


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 ] )

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.) .


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


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 .


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

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


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]-->

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

1

Com o Underscore.js

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.