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

}
Bobby Borszich
la source
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.

Josh Stodola
la source
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 ] )
Moses Lee
la source
'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.) .

Luis Perez
la source
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
16

La bibliothèque underscore.js possède une fonction indexOf que vous pouvez utiliser à la place:

_.indexOf([1, 2, 3], 2)
scotta7exander
la source
4
Cette réponse évite de jouer avec le prototype de tableau , et elle délègue à l'indexOf natif lorsqu'il est disponible. Je l'aime.
Brad Koch
Semble être le moyen le plus simple si vous pouvez inclure un trait de soulignement ou un lodash
ChrisRich
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 .

Eli Grey
la source
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;
        };
    }
})();
Will V King
la source
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 :)

Josh Mc
la source
** 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]-->
Glennweb
la source
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;
  };
}
Allen Wong
la source
1

Avec le Underscore.js

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

sri_bb
la source