Corrigindo funções de matriz JavaScript no Internet Explorer (indexOf, forEach, etc.) [fechado]

137

Conforme detalhado em outros lugares , e de outra forma aparentemente bem conhecido, o Internet Explorer (definitivamente versão 7, e em alguns casos, a versão 8) não implementar funções-chave, em particular no Array(tais como forEach, indexOf, etc).

Há várias soluções alternativas aqui e ali, mas eu gostaria de dobrar um conjunto canônico adequado de implementações em nosso site, em vez de copiar e colar ou cortar nossas próprias implementações. Eu encontrei o método js , que parece promissor, mas achei que eu postaria aqui para ver se outra biblioteca é mais recomendada. Alguns critérios diversos:

  • A biblioteca deve ser apenas uma operação inoperante para as funções para as quais um navegador já possui implementações ( js-methodsparece funcionar muito bem aqui).
  • Não GPL , por favor, embora LGPL seja aceitável.
cemerick
fonte

Respostas:

220

Muitos usam as implementações de fallback do MDC (por exemplo, para indexOf ). Geralmente, eles são rigorosamente compatíveis com os padrões, mesmo na verificação explícita dos tipos de todos os argumentos.

Infelizmente, embora esteja claro que os autores consideram esse código trivial e livremente utilizável, não parece haver uma concessão explícita de licença para colocar isso por escrito. O wiki como um todo é CC Attribution-ShareAlike, se for uma licença aceitável (embora o CC não tenha sido projetado para código como tal).

js-methods parece bem em geral, mas não é tão compatível com os padrões nas bordas de como as funções devem ser (por exemplo, itens de lista indefinidos, funções que modificam a lista). Também está cheio de outros métodos não padronizados aleatórios, incluindo alguns questionáveis, como o desagradável stripTags e o codec UTF-8 incompleto (que também é um pouco desnecessário, dado o unescape(encodeURIComponent)truque).

Pelo que vale a pena, aqui está o que eu uso (que por meio deste, libero para o domínio público, se é que se pode dizer que é de propriedade do autor). É um pouco menor do que as versões do MDC, pois não tenta detectar que você não fez algo bobo como passar retornos de chamada sem função ou índices não inteiros, mas, além disso, ele tenta ser compatível com os padrões. (Deixe-me saber se eu perdi alguma coisa. ;-))

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

Outros métodos ECMA262-5 não implementados aqui incluem Matriz reduce/ reduceRight, os Objectmétodos JSON e os poucos métodos novos que podem ser implementados de forma confiável como funções JS.

bobince
fonte
5
Obrigado por esse ponteiro - os outros links que eu vi no mozdev onde esses impls podem ser encontrados estavam obsoletos. FYI, o código é MIT-licenciados, conforme especificado aqui: developer.mozilla.org/Project:Copyrights (quase tão bom quanto você pode obter :-)!
cemerick
1
Curiosamente, se eu fizer referência a um arquivo js contendo todo o MDC ECMA262-5 implementado antes do jquery 1.4.2, o jquery será quebrado - por exemplo, todos os seletores falharão, retornando nulo. Mover o MDC implica após jquery leva ao comportamento esperado. Muito estranho.
Cemerick
Isso é curioso! Vou olhar para isso (você tem um caso de teste?) ... Não consigo pensar imediatamente por que isso pode acontecer, embora o jQuery faça na linha 72 pareça suspeito.
quer
4
NOTA: na maioria dos navegadores em que esses stubs são necessários, se você fizer um "for (index in somearray) {...}", precisará usar somearray.hasOwnProperty (index) como uma verificação. O mecanismo JS do IE <= 8 incluirá as extensões array.prototype. O código assíncrono do Google Adwords não faz isso. É melhor usar o Underscore, ou a funcionalidade de outra biblioteca que padronize isso.
precisa saber é o seguinte
1
Esta é a implementação indexOf () mais rápida para o IE 8 que eu consegui encontrar. Obrigado!
Alex Denysenko #
27

Dê uma olhada no Underscore.js .

rfunduk
fonte
2
O ES5Shim e outros stubs (como o MDC) também tendem a ter outras consequências. É melhor usar sublinhado ou outra biblioteca para esses tipos de funções, que usarão os métodos internos quando disponíveis.
precisa saber é o seguinte
Com o Underscore.js var arr = ['a', 'a1', 'b'] _.filter (arr, função (a) {return a.indexOf ('a')> -1;})
sri_bb
9

Kris Kowal compilou uma pequena biblioteca que funciona como um calço para as funções do ECMAScript 5 que podem estar ausentes na implementação do navegador. Algumas das funções foram revisadas várias vezes por outras pessoas para serem otimizadas quanto à velocidade e contornar os erros do navegador. As funções são escritas para seguir a especificação o mais próximo possível.

O es5-shim.js foi lançado sob a licença MIT, as extensões Array.prototype estão próximas da parte superior e você pode cortar e remover todas as funções desnecessárias com facilidade. Sugiro também que você reduza o script, pois os comentários o tornam muito maior do que precisa.

Andy E
fonte
1

Por 'não implementar funções-chave', você realmente quer dizer 'está em conformidade com a ECMA 262 3ª edição', certo? :)

Os métodos aos quais você está se referindo fazem parte da nova quinta edição - para navegadores que não suportam isso, você pode usar o seguinte 'shim' que se estende de 3º para 5º http://github.com/kriskowal/narwhal- lib / blob / lib-narwhal / lib / global-es5.js .

Sean Kinsey
fonte
1
Esse é um bom começo, mas há alguns erros nas implementações não retiradas do MDC. por exemplo. muitos dos métodos de matriz não transmitem argumentos suficientes para seus retornos de chamada e não agem corretamente no caso de mutação de matriz na função de retorno de chamada.
bobince
Vou levar o que puder para tornar o js uma linguagem mais sã / minimamente capaz. </snark> :-)
cemerick
1

Esses scripts não funcionam bem nos meus testes. Crio um arquivo com as mesmas funções com base nos documentos MDN .

Muitas áreas de problemas são resolvidas no Internet Explorer 8. Consulte o código em egermano / ie-fix.js .

egermano
fonte
0

Com o Underscore.js

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

sri_bb
fonte