Pourquoi indexOf ne fonctionne-t-il pas sur un tableau IE8?

294

La fonction ci-dessous fonctionne correctement sur Opera, Firefox et Chrome. Cependant, dans IE8, il échoue de la if ( allowed.indexOf(ext[1]) == -1)part.

Quelqu'un sait-il pourquoi? Y a-t-il une erreur évidente?

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
la source
5
Grande question, excellente réponse. Merci de m'avoir donné exactement ce dont j'avais besoin.
Hardwareguy

Réponses:

488

Les versions d'IE avant IE9 n'ont pas de .indexOf()fonction pour Array, pour définir la version exacte des spécifications , exécutez ceci avant d'essayer de l'utiliser:

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

Il s'agit de la version de MDN , utilisée dans Firefox / SpiderMonkey. Dans d'autres cas comme IE, cela ajoutera .indexOf()dans le cas où il manque ... essentiellement IE8 ou inférieur à ce stade.

Nick Craver
la source
2
Notez que si vous (ou les bibliothèques que vous utilisez) utilisez la syntaxe for / in pour énumérer les tableaux (par exemple, pour (idx dans le nom de tableau) stmt;) que cette méthode sera également énumérée. En effet, les propriétés intégrées ne sont pas énumérées par for / in, mais celles définies par l'utilisateur le sont.
Espagne Train
5
@Mike - C'est un problème différent ... vous ne devriez pas utiliser une for...inboucle pour itérer un tableau, il ne doit être utilisé que pour l' énumération .
Nick Craver
3
@Mike - Vous parcourez un tableau pour plus de raisons ... comme obtenir vos résultats dans le bon ordre sur tous les navigateurs. L'utilisation for..insur un tableau ne causera que des problèmes, ce n'est pas seulement une convention ... c'est une utilisation imprévue et incorrecte. L'ordre et les clés ne sont pas tous les deux complètement spécifiés, ils dépendent de l'implémentation ... par exemple, IE énumérera les éléments du tableau dans l'ordre où ils ont été ajoutés , et non par leur index. Cependant, vous pouvez itérer correctement en accédant par index.
Nick Craver
1
Et cela illustre la différence entre l'énumération des éléments et l'utilisation d'un index pour itérer. C'est pourquoi nous avons les deux concepts. Vous pouvez énumérer les valeurs dans une liste liée, ou vous pouvez analyser la liste liée et renvoyer les valeurs de l'une à la suivante. L'un est un concept mathématique, l'autre est une instruction procédurale.
jcolebrand
1
@Pointy Oui! Et comme beaucoup recherchent "Pourquoi indexOf ne fonctionne-t-il pas sur un tableau IE8?" peut être à un niveau de sophistication inférieur WRT à js, il peut être utile de le signaler comme corollaire à la réponse. Si tout le monde avait déjà une compréhension approfondie des spécifications et des différences entre les implémentations, de tels threads n'existeraient pas. @Nick Vous faites de fortes hypothèses sur l'exactitude. Il existe de nombreuses opérations pour lesquelles l'ordre n'a pas d'importance (par exemple, définir la différence.) De plus, le commentaire d'origine ne faisait aucune mention de l'énumération dans la séquence d'index, juste que pour / in inclut les définitions de l'utilisateur fn.
Espagne Train
152

Si vous utilisez jQuery, vous pouvez utiliser $ .inArray () à la place.

tiegz
la source
7
Je suis d'accord que c'est plus utile. C'est l'une des principales raisons d'utiliser JQuery - il fait beaucoup pour atténuer les incompatibilités entre les navigateurs.
cw24
17

Si vous utilisez jQuery et souhaitez continuer à utiliser indexOf sans vous soucier des problèmes de compatibilité, vous pouvez le faire:

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

Ceci est utile lorsque vous souhaitez continuer à utiliser, indexOfmais fournit une solution de rechange lorsqu'elle n'est pas disponible.

Mehdiway
la source
Oui, probablement parce qu'il n'a pas inclus jQuery ¯_ (ツ) _ / ¯ C'est une syntaxe valide.
5

Veuillez faire attention à $ .inArray si vous souhaitez l'utiliser. Je viens de découvrir que $ .inArray ne fonctionne qu'avec "Array", pas avec String. C'est pourquoi cette fonction ne fonctionnera pas dans IE8!

L'API jQuery crée de la confusion

La méthode $ .inArray () est similaire à la méthode native .indexOf () de JavaScript car elle renvoie -1 lorsqu'elle ne trouve pas de correspondance. Si le premier élément du tableau correspond à la valeur, $ .inArray () renvoie 0

-> Ils ne devraient pas dire "similaire". Depuis indexOf supporte également "String"!

ptgamr
la source
16
Ça s'appelle inArray. Cela semble s'appliquer définitivement aux tableaux uniquement. C'est pourquoi il est "similaire à" et non "identique à".
tandrewnichols
Bonne note. Le fait amusant est indexOfqu'un objet String est entièrement trouvé dans IE tandis que indexOfdans Array, le prototype n'est pas trouvé dans IE <= 8.
adi518
Vous le liez au prototype de la baie afin que cela n'affecte pas les chaînes.
kagronick
3

Le problème

IE <= 8 n'a tout simplement pas de indexOf()méthode pour les tableaux.


La solution

Si vous avez besoin indexOfdans IE <= 8, vous devriez envisager d'utiliser le polyfill suivant , qui est recommandé au 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;
    };
}

Minifié:

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
la source
1

Vous pouvez l'utiliser pour remplacer la fonction si elle n'existe pas:

<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
la source