Cómo arreglar Array indexOf () en JavaScript para los navegadores Internet Explorer

295

Si ha trabajado con JavaScript por algún tiempo, sabe que Internet Explorer no implementa la función ECMAScript para Array.prototype.indexOf () [incluido Internet Explorer 8]. No es un gran problema, porque puede ampliar la funcionalidad de su página con el siguiente 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;
}

¿Cuándo debo implementar esto?

¿Debo envolverlo en todas mis páginas con la siguiente verificación, que verifica si la función del prototipo existe y si no, continúe y extienda el prototipo de matriz?

if (!Array.prototype.indexOf) {

    // Implement function here

}

¿O comprueba el navegador y si es Internet Explorer, simplemente impleméntelo?

//Pseudo-code

if (browser == IE Style Browser) {

     // Implement function here

}
Bobby Borszich
fuente
En realidad Array.prototype.indexOfno es parte de ECMA-262 / ECMAScript. Ver ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf Quizás estés pensando String.prototype.indexOf...
Crescent Fresh el
55
Es una extensión, no parte del estándar original. Sin embargo, debe implementarse como parte de Javascript 1.6 (que IE no puede hacer) developer.mozilla.org/en/New_in_JavaScript_1.6
Josh Stodola
1
@Josh: solo se refería a "IE no implementa la función ECMAScript ..."
Crescent Fresh el
44
Su implementación de Array.indexOfno tiene en cuenta los índices iniciales negativos. Vea la implementación
provisional de
3
He actualizado la pregunta para usar "===", porque me preocupa que la gente la copie con "==" y eso estaría mal, aparte de eso está bien. Ver la respuesta de Eli Grey.
joshcomley

Respuestas:

213

Hazlo asi...

if (!Array.prototype.indexOf) {

}

Según la compatibilidad recomendada por MDC .

En general, el código de detección del navegador es un gran no-no.

Josh Stodola
fuente
No tengo suficiente representante para editar la pregunta, pero siéntase libre de eliminar la jerga de ECMAScript y reemplazarla con la redacción adecuada. Gracias de nuevo
Bobby Borszich
12
Tenga cuidado si usa este tipo de detección. Otra biblioteca podría implementar esta función antes de probarla, y podría no cumplir con los estándares (el prototipo lo ha hecho hace un tiempo). Si estuviera trabajando en un ambiente hostil (un montón de otros codificadores que utilizan una gran cantidad de distintas bibliotecas), yo no confiar en ninguno de estos ...
Pablo Cabrera
La columna "Vinculado" ---> es realmente útil. Me encanta la respuesta aquí: stackoverflow.com/questions/1744310/…
gordon el
¿Tiene que estar envuelto en cada archivo js?
rd22
¿Quién es MDC exactamente?
Ferrybig
141

Alternativamente, puede usar la función jQuery 1.2 inArray , que debería funcionar en todos los navegadores:

jQuery.inArray( value, array [, fromIndex ] )
Moses Lee
fuente
El 'indexOf' es código nativo (derecha), entonces ¿jQuery 'inArray ()' será tan rápido, como usar native cuando esté disponible y poly-fill cuando no?
Jeach
10
Ok, para responder mi propio comentario (arriba), lo acabo de implementar y en Chrome es tan rápido como cuando estaba usando 'indexOf ()', pero en IE 8 es muy, muy lento ... así que al menos sabemos que 'inArray ()' usa nativo cuando puede.
Jeach
78

El código completo sería este:

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 obtener una respuesta y un código realmente completos para esto, así como para otras funciones de matriz, consulte la pregunta sobre desbordamiento de pila. Cómo arreglar las funciones de matriz de JavaScript en Internet Explorer (indexOf, forEach, etc.) .

Luis perez
fuente
2
gracias por tener todo el contenido Visito esta página con frecuencia cada vez que necesito indexOf multiplataforma en un nuevo proyecto, y su fragmento es el único con código completo. :) Esos pocos segundos realmente se suman cuando uno frecuenta esta página.
dylnmc
16

La biblioteca underscore.js tiene una función indexOf que puede usar en su lugar:

_.indexOf([1, 2, 3], 2)
scotta7exander
fuente
44
Esta respuesta evita meterse con el prototipo de matriz y delega al indexOf nativo cuando está disponible. Me gusta.
Brad Koch
Parece ser la forma más fácil si puedes incluir guiones bajos o lodash
ChrisRich
10

Debe verificar si no está definido usando if (!Array.prototype.indexOf).

Además, su implementación de indexOfno es correcta. Debe usar en ===lugar de ==en su if (this[i] == obj)declaración, de lo contrario [4,"5"].indexOf(5)sería 1 de acuerdo con su implementación, lo cual es incorrecto.

Le recomiendo que use la implementación en MDC .

Eli Gray
fuente
9

Hay una solución oficial de 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
fuente
1
Solo siendo pedante, pero MDN no es solo Mozilla. Es un proyecto impulsado por la comunidad que contiene personal de Mozilla pero también voluntarios, cualquiera puede unirse y contribuir.
ste2425
5

Recomendaría esto a cualquiera que busque la funcionalidad faltante:

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

Trae la mayor parte de la funcionalidad ecma5 que falta a los navegadores más antiguos :)

Josh Mc
fuente
** Aunque notaré que he tenido problemas en IE7 con esta lib.
Josh Mc
2

Esta fue mi implementación. Básicamente, agregue esto antes que cualquier otro script en la página. es decir, en su maestro para una solución global para Internet Explorer 8. También agregué la función de recorte que parece usarse en una gran cantidad de marcos.

<!--[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
fuente
2

esto funciona para mi.

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
fuente
1

Con el Underscore.js

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

sri_bb
fuente