Correction des fonctions JavaScript Array dans Internet Explorer (indexOf, forEach, etc.) [fermé]

137

Comme indiqué ailleurs , et par ailleurs apparemment bien connu, Internet Explorer ( sans aucun doute la version 7, et dans certains cas, la version 8) ne met pas en œuvre les fonctions clés, notamment sur Array( par exemple forEach, indexOfetc.).

Il existe un certain nombre de solutions de contournement ici et là, mais j'aimerais plier un ensemble approprié et canonique d'implémentations dans notre site plutôt que de copier-coller ou de pirater nos propres implémentations. J'ai trouvé des méthodes js , ce qui semble prometteur, mais j'ai pensé publier ici pour voir si une autre bibliothèque est plus fortement recommandée. Quelques critères divers:

  • La bibliothèque devrait simplement être une non-opération pour les fonctions pour lesquelles un navigateur a déjà des implémentations ( js-methodssemble fonctionner assez bien ici).
  • Non GPL , s'il vous plaît, mais LGPL est acceptable.
cemerick
la source

Réponses:

220

Beaucoup utilisent les implémentations de secours MDC (par exemple pour indexOf ). Ils sont généralement rigoureusement conformes aux normes, même au point de vérifier explicitement les types de tous les arguments.

Malheureusement, s'il est clair que les auteurs considèrent ce code comme trivial et librement utilisable, il ne semble pas y avoir de licence explicite pour le mettre par écrit. Le wiki dans son ensemble est CC Attribution-ShareAlike, si c'est une licence acceptable (bien que CC ne soit pas conçu pour le code en tant que tel).

js-methods semble correct en général, mais n'est pas aussi conforme aux normes sur les bords de la façon dont les fonctions sont supposées être (par exemple, des éléments de liste non définis, des fonctions qui mutent la liste). Il est également plein d'autres méthodes aléatoires non standard, y compris des méthodes douteuses comme le stripTags douteux et le codec UTF-8 incomplet (ce qui est également un peu inutile étant donné l' unescape(encodeURIComponent)astuce).

Pour ce que ça vaut, voici ce que j'utilise (que je publie par la présente dans le domaine public, si on peut dire que c'est sous copyright). C'est un peu plus court que les versions MDC car il n'essaie pas de renifler le type que vous n'avez pas fait quelque chose de stupide comme passer des rappels sans fonction ou des index non entiers, mais à part cela, il tente d'être conforme aux normes. (Faites-moi savoir si j'ai manqué quelque chose. ;-))

'use strict';

// Add ECMA262-5 method binding if not supported natively
//
if (!('bind' in Function.prototype)) {
    Function.prototype.bind= function(owner) {
        var that= this;
        if (arguments.length<=1) {
            return function() {
                return that.apply(owner, arguments);
            };
        } else {
            var args= Array.prototype.slice.call(arguments, 1);
            return function() {
                return that.apply(owner, arguments.length===0? args : args.concat(Array.prototype.slice.call(arguments)));
            };
        }
    };
}

// Add ECMA262-5 string trim if not supported natively
//
if (!('trim' in String.prototype)) {
    String.prototype.trim= function() {
        return this.replace(/^\s+/, '').replace(/\s+$/, '');
    };
}

// Add ECMA262-5 Array methods if not supported natively
//
if (!('indexOf' in Array.prototype)) {
    Array.prototype.indexOf= function(find, i /*opt*/) {
        if (i===undefined) i= 0;
        if (i<0) i+= this.length;
        if (i<0) i= 0;
        for (var n= this.length; i<n; i++)
            if (i in this && this[i]===find)
                return i;
        return -1;
    };
}
if (!('lastIndexOf' in Array.prototype)) {
    Array.prototype.lastIndexOf= function(find, i /*opt*/) {
        if (i===undefined) i= this.length-1;
        if (i<0) i+= this.length;
        if (i>this.length-1) i= this.length-1;
        for (i++; i-->0;) /* i++ because from-argument is sadly inclusive */
            if (i in this && this[i]===find)
                return i;
        return -1;
    };
}
if (!('forEach' in Array.prototype)) {
    Array.prototype.forEach= function(action, that /*opt*/) {
        for (var i= 0, n= this.length; i<n; i++)
            if (i in this)
                action.call(that, this[i], i, this);
    };
}
if (!('map' in Array.prototype)) {
    Array.prototype.map= function(mapper, that /*opt*/) {
        var other= new Array(this.length);
        for (var i= 0, n= this.length; i<n; i++)
            if (i in this)
                other[i]= mapper.call(that, this[i], i, this);
        return other;
    };
}
if (!('filter' in Array.prototype)) {
    Array.prototype.filter= function(filter, that /*opt*/) {
        var other= [], v;
        for (var i=0, n= this.length; i<n; i++)
            if (i in this && filter.call(that, v= this[i], i, this))
                other.push(v);
        return other;
    };
}
if (!('every' in Array.prototype)) {
    Array.prototype.every= function(tester, that /*opt*/) {
        for (var i= 0, n= this.length; i<n; i++)
            if (i in this && !tester.call(that, this[i], i, this))
                return false;
        return true;
    };
}
if (!('some' in Array.prototype)) {
    Array.prototype.some= function(tester, that /*opt*/) {
        for (var i= 0, n= this.length; i<n; i++)
            if (i in this && tester.call(that, this[i], i, this))
                return true;
        return false;
    };
}

D'autres méthodes ECMA262-5 non implémentées ici incluent Array reduce/ reduceRight, les Objectméthodes JSON et les quelques nouvelles méthodes qui peuvent être implémentées de manière fiable en tant que fonctions JS.

bobince
la source
5
Merci pour ce pointeur - les autres liens que j'ai vus dans mozdev où de tels impls pourraient être trouvés étaient périmés. Pour info, le code est sous licence MIT, comme spécifié ici: developer.mozilla.org/Project:Copyrights (à peu près aussi bon que vous pouvez obtenir! :-)
cemerick
1
Fait intéressant, si je référence un fichier js contenant tous les impls MDC ECMA262-5 avant jquery 1.4.2, jquery est cassé - par exemple, tous les sélecteurs échouent, retournant null. Déplacer les impls MDC après jquery conduit au comportement attendu. Très étrange.
cemerick
C'est curieux! Je vais regarder ça (avez-vous un cas de test?) ... Je ne peux pas immédiatement penser pourquoi cela pourrait arriver, bien que ce que jQuery fait à la ligne 72 semble suspect.
bobince
4
REMARQUE: dans la plupart des navigateurs où ces stubs sont nécessaires, si vous faites un "for (index in somearray) {...}", vous devrez utiliser somearray.hasOwnProperty (index) comme contrôle. Le moteur JS d'IE <= 8 inclura les extensions array.prototype dans celui-ci. Le code asynchrone de Google Adwords ne le fait pas. Il est préférable d'utiliser Underscore, ou la fonctionnalité d'une autre bibliothèque qui standardise à ce sujet.
Tracker1
1
C'est l'implémentation d'indexOf () la plus rapide que j'ai pu trouver pour IE 8. Merci!
Alex Denysenko
27

Jetez un œil à Underscore.js .

rfunduk
la source
2
ES5Shim et d'autres stubs (comme ceux de MDC) ont également tendance à avoir d'autres conséquences. Il est préférable d'utiliser le trait de soulignement ou une autre bibliothèque pour ces types de fonctions, qui utiliseront les méthodes internes lorsqu'elles sont disponibles.
Tracker1
Avec le Underscore.js var arr = ['a', 'a1', 'b'] _.filter (arr, function (a) {return a.indexOf ('a')> -1;})
sri_bb
9

Kris Kowal a compilé une petite bibliothèque qui agit comme un shim pour les fonctions ECMAScript 5 qui peuvent manquer dans l'implémentation du navigateur. Certaines des fonctions ont été révisées à plusieurs reprises par d'autres personnes pour être optimisées pour la vitesse et pour contourner les bogues du navigateur. Les fonctions sont écrites pour suivre la spécification aussi étroitement que possible.

es5-shim.js a été publié sous la licence MIT, les extensions Array.prototype sont en haut et vous pouvez couper et supprimer toutes les fonctions dont vous n'avez pas besoin assez facilement. Je vous suggère également de réduire le script car les commentaires le rendent beaucoup plus volumineux que nécessaire.

Andy E
la source
1

Par «ne pas mettre en œuvre les fonctions clés», vous entendez en fait «est conforme à l'ECMA 262 3ème éd», n'est-ce pas? :)

Les méthodes auxquelles vous faites référence font partie de la nouvelle 5ème édition - pour les navigateurs ne prenant pas en charge cela, vous pouvez utiliser le 'shim' suivant qui s'étend de 3'rd à 5'th http://github.com/kriskowal/narwhal- lib / blob / narwhal-lib / lib / global-es5.js .

Sean Kinsey
la source
1
C'est un bon début, mais il y a pas mal d'erreurs dans les implémentations qui ne proviennent pas de MDC. par exemple. beaucoup de méthodes de tableau ne passent pas assez d'arguments à leurs callbacks et n'agissent pas tout à fait correctement dans le cas d'une mutation de tableau dans la fonction de rappel.
bobince
Je vais prendre tout ce que je peux pour faire de js un langage plus sensé / minimalement capable. </snark> :-)
cemerick
1

Ces scripts ne fonctionnent pas bien dans mes tests. Je crée un fichier avec les mêmes fonctions à partir de documents MDN .

Trop de zones de problèmes sont résolues dans Internet Explorer 8. Voir le code dans egermano / ie-fix.js .

Egermano
la source
0

Avec le Underscore.js

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

sri_bb
la source