Comment réparer Array indexOf () dans JavaScript pour les navigateurs Internet Explorer


295

Si vous avez longuement travaillé avec JavaScript, vous savez qu'Internet Explorer n'implémente pas la fonction ECMAScript pour Array.prototype.indexOf () [y compris Internet Explorer 8]. Ce n'est pas un gros problème, car vous pouvez étendre les fonctionnalités de votre page avec le code suivant.

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

Quand dois-je mettre cela en œuvre?

Dois-je l'envelopper sur toutes mes pages avec la vérification suivante, qui vérifie si la fonction prototype existe et sinon, continuez et étendez le prototype Array?

if (!Array.prototype.indexOf) {

    // Implement function here

}

Ou le navigateur vérifie-t-il et s'il s'agit d'Internet Explorer, il suffit de l'implémenter?

//Pseudo-code

if (browser == IE Style Browser) {

     // Implement function here

}

En Array.prototype.indexOffait, ne fait pas partie de l'ECMA-262 / ECMAScript. Voir ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf Peut-être que vous pensez String.prototype.indexOf...
Crescent Fresh

5
C'est une extension qui ne fait pas partie de la norme d'origine. Il devrait cependant être implémenté dans le cadre de Javascript 1.6 (ce que IE ne fait pas) developer.mozilla.org/en/New_in_JavaScript_1.6
Josh Stodola

1
@Josh: faisait juste référence à "IE n'implémente pas la fonction ECMAScript ..."
Crescent Fresh

4
Votre implémentation de Array.indexOfne prend pas en compte les indices de départ négatifs. Voir l'implémentation de l'interruption de la suggestion de Mozilla ici: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
nickf

3
J'ai mis à jour la question pour utiliser "===", car je crains que les gens ne la copient avec le "==" et ce serait faux - à part ça, ça va. Voir la réponse d'Eli Grey.
joshcomley

Réponses:


213

Fais-le comme ça...

if (!Array.prototype.indexOf) {

}

Comme la compatibilité recommandée par MDC .

En général, le code de détection du navigateur est un gros no-no.


Je n'ai pas assez de représentant pour modifier la question, mais n'hésitez pas à supprimer le jargon ECMAScript et à le remplacer par le libellé approprié. Merci encore
Bobby Borszich

12
Soyez prudent si vous utilisez ce type de détection. Une autre bibliothèque pourrait implémenter cette fonction avant de la tester, et elle pourrait ne pas être conforme aux normes (le prototype l'a fait il y a un certain temps). Si je travaillais dans un environnement hostile (beaucoup d'autres codeurs utilisant beaucoup de bibliothèques distinctes), je ne ferais confiance à aucun de ceux-ci ...
Pablo Cabrera

La colonne "Linked" ---> est vraiment pratique! J'adore la réponse ici: stackoverflow.com/questions/1744310/…
gordon

Doit-il être enveloppé dans chaque fichier js?
rd22

Qui est MDC exactement?
Ferrybig

141

Alternativement, vous pouvez utiliser la fonction jQuery 1.2 inArray , qui devrait fonctionner sur tous les navigateurs:

jQuery.inArray( value, array [, fromIndex ] )

'IndexOf' est du code natif (à droite), donc le jQuery 'inArray ()' sera-t-il aussi rapide, comme utiliser natif lorsqu'il est disponible et poly-fill quand ce n'est pas le cas?
Jeach

10
Ok donc pour répondre à mon propre commentaire (ci-dessus), je viens de l'implémenter et sur Chrome c'est aussi rapide que lorsque j'utilisais 'indexOf ()', mais dans IE 8 c'est très, très lent ... donc au moins on sait que 'inArray ()' utilise natif quand il le peut.
Jeach

78

Le code complet serait alors le suivant:

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

Pour obtenir une réponse et un code vraiment approfondis, ainsi que d'autres fonctions de tableau, consultez la question Stack Overflow Fixing JavaScript Array dans Internet Explorer (indexOf, forEach, etc.) .


2
merci d'avoir juste le truc complet. Je visite cette page fréquemment chaque fois que j'ai besoin d'un index multi-plateforme dans un nouveau projet, et votre extrait est le seul à avoir un code complet. :) Ces quelques secondes s'additionnent vraiment quand on fréquente cette page.
dylnmc


10

Vous devez vérifier s'il n'est pas défini à l'aide de if (!Array.prototype.indexOf).

En outre, votre implémentation de indexOfn'est pas correcte. Vous devez utiliser à la ===place de ==dans votre if (this[i] == obj)relevé, sinon[4,"5"].indexOf(5) serait 1 selon votre implémentation, ce qui est incorrect.

Je vous recommande d'utiliser l'implémentation sur MDC .


9

Il existe une solution officielle 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;
        };
    }
})();

1
Être pédant, mais MDN n'est pas seulement Mozilla. Il s'agit d'un projet mené par la communauté qui comprend du personnel de Mozilla mais aussi des bénévoles, n'importe qui peut se joindre et contribuer.
ste2425

5

Je recommanderais ceci à tous ceux qui recherchent des fonctionnalités manquantes:

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

Il apporte la plupart des fonctionnalités ecma5 manquantes aux anciens navigateurs :)


** Bien que je note que j'ai eu des problèmes avec IE7 avec cette lib.
Josh Mc

2

C'était ma mise en œuvre. Essentiellement, ajoutez ceci avant tout autre script sur la page. c'est-à-dire dans votre master pour une solution globale pour Internet Explorer 8. J'ai également ajouté dans la fonction trim qui semble être utilisée dans de nombreux frameworks.

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

ça marche pour moi.

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

Avec le Underscore.js

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.