¿Por qué indexOf no funciona en una matriz IE8?

294

La siguiente función funciona bien en Opera, Firefox y Chrome. Sin embargo, en IE8 falla por if ( allowed.indexOf(ext[1]) == -1)parte.

¿Alguien sabe por qué? ¿Hay algún error obvio?

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
fuente
55
Gran pregunta, gran respuesta. Gracias por darme exactamente lo que necesitaba.
Hardwareguy

Respuestas:

488

Las versiones de IE antes de IE9 no tienen una .indexOf()función para Array, para definir la versión exacta de especificaciones , ejecute esto antes de intentar usarlo:

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 es la versión de MDN , utilizada en Firefox / SpiderMonkey. En otros casos, como IE, se agregará .indexOf()en caso de que falte ... básicamente IE8 o inferior en este punto.

Nick Craver
fuente
2
Tenga en cuenta la advertencia de que si usted (o las bibliotecas que usa) usa la sintaxis for / in para enumerar matrices (por ejemplo, for (idx in arrayname) stmt;) que este método también se enumerará. Esto se debe a que las propiedades integradas no están enumeradas por for / in, pero sí las definidas por el usuario.
Tren de España el
55
@ Mike - Ese es un problema diferente ... no deberías usar un for...inbucle para iterar una matriz, debería usarse solo para enumeración .
Nick Craver
3
@Mike: itera sobre una matriz por más razones para eso ... como obtener sus resultados en el orden correcto en todos los navegadores. El uso for..inen una matriz solo causará problemas, no es solo una convención ... es un uso involuntario y uno incorrecto. El orden y las claves no están completamente especificados, dependen de la implementación ... por ejemplo, IE enumerará los elementos de la matriz en el orden en que se agregaron , no por su índice. Sin embargo, puede iterar correctamente, accediendo por índice.
Nick Craver
1
Y eso ilustra la diferencia entre enumerar los elementos y usar un índice para iterar. Por eso tenemos ambos conceptos. Puede enumerar los valores en una lista vinculada, o puede rastrear la lista vinculada y devolver los valores de uno a otro. Uno es un concepto matemático, uno es una instrucción de procedimiento.
jcolebrand
1
@Pointy ¡Sí! Y dado que muchos buscan "¿Por qué indexOf no funciona en una matriz IE8?" puede estar en un nivel de sofisticación más bajo WRT a js, puede ser útil señalar esto como un corolario de la respuesta. Si todos ya tuvieran una comprensión profunda de las especificaciones y las diferencias entre las implementaciones, los hilos como estos no existirían. @Nick Hace fuertes suposiciones sobre la corrección. Hay muchas operaciones para las que el orden no importa (p. Ej., Establecer la diferencia). Además, el comentario original no mencionaba la enumeración en la secuencia de índice, solo que for / in incluye la definición del usuario.
Tren de España el
152

Si usa jQuery, puede usar $ .inArray () en su lugar.

tiegz
fuente
77
Estoy de acuerdo en que esto es más útil. Esa es una de las principales razones para usar JQuery: hace mucho para aliviar las incompatibilidades entre navegadores.
cw24
17

Si está usando jQuery y desea seguir usando indexOf sin preocuparse por problemas de compatibilidad, puede hacer esto:

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

Esto es útil cuando desea seguir usando indexOfpero proporciona un respaldo cuando no está disponible.

Mehdiway
fuente
Sí, probablemente porque no incluyó jQuery ¯_ (ツ) _ / ¯ Es una sintaxis válida.
5

Tenga cuidado con $ .inArray si desea usarlo. Me acabo de enterar de que $ .inArray solo funciona con "Array", no con String. ¡Es por eso que esta función no funcionará en IE8!

La API jQuery crea confusión

El método $ .inArray () es similar al método .indexOf () nativo de JavaScript en el sentido de que devuelve -1 cuando no encuentra una coincidencia. Si el primer elemento dentro de la matriz coincide con el valor, $ .inArray () devuelve 0

-> No deberían decirlo "Similar". Desde indexOf soporta "String" también!

ptgamr
fuente
16
Se llama inArray. Parece que definitivamente se aplica solo a matrices. Por eso es "similar a" y no "idéntico a".
tandrewnichols
Buena nota. El hecho curioso es que indexOfun objeto String se encuentra completamente en IE, mientras que indexOfen Array el prototipo no se encuentra en IE <= 8.
adi518
Lo está vinculando al prototipo de matriz para que no afecte las cadenas.
kagronick
3

El problema

IE <= 8 simplemente no tiene un indexOf()método para matrices.


La solución

Si necesita indexOfen IE <= 8, debería considerar usar el siguiente polyfill , que se recomienda en el 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;
    };
}

Minified:

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

Puede usar esto para reemplazar la función si no existe:

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