修复Internet Explorer中的JavaScript数组函数(indexOf,forEach等)

138

其他地方详细说明的那样,以及其他人显然已经知道的,Internet Explorer(特别是版本7,在一些情况下是版本8)没有实现关键函数,尤其是在Array上(例如forEachindexOf等)。

有许多解决方法,但我想将一个适当的、规范的实现集成到我们的网站中,而不是复制粘贴或对我们自己的实现进行修改。我发现了js-methods,看起来很有前途,但我想在这里发布帖子,看看是否有其他更受推荐的库。还有一些杂项标准:

  • 对于浏览器已经有实现的这些函数,该库应该只是一个无操作(js-methods在这方面表现得很好)。
  • 请勿使用GPL,尽管LGPL是可以接受的。
6个回答

221
许多人使用MDC回退实现(例如indexOf)。它们通常严格遵守标准,甚至明确检查所有参数的类型。不幸的是,尽管作者认为这段代码是微不足道的并且可以自由使用,但似乎没有明确授权将其写下来。如果整个维基百科都是CC Attribution-ShareAlike,那么看起来还可以接受该许可证(尽管CC并不适用于代码)。js-methods总体上看起来还不错,但在函数应该如何工作的边缘方面不太符合标准(例如未定义的列表项,更改列表的函数)。它还充满了其他随机的非标准方法,包括一些可疑的方法,如不良的stripTags和不完整的UTF-8编解码器(考虑到unescape(encodeURIComponent)技巧,这也有点不必要)。就我而言,这是我使用的(如果可以说它是可版权的,我在此将其发布给公共领域)。它比MDC版本短一些,因为它不会尝试对您是否做了愚蠢的事情(例如传递非函数回调或非整数索引)进行类型嗅探,但除此之外,它试图符合标准。(如果我漏掉了什么,请告诉我。;-))
'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;
    };
}

这里没有实现其他ECMA262-5方法,包括Array的reduce/reduceRight,JSON方法和一些新的Object方法,这些方法可以作为JS函数可靠地实现。


5
谢谢你提供的指引 -- 我之前看到的连接指向 mozdev 的实现已经过时。顺便说一下,该代码是根据 MIT 许可证授权的,详见这里:https://developer.mozilla.org/Project:Copyrights (这基本上是最好的!:-) - cemerick
1
有趣的是,如果我在jquery 1.4.2之前引用一个包含所有MDC ECMA262-5实现的js文件,则jquery会出现故障--例如,所有选择器都会失败,返回null。 将MDC实现移动到jquery之后会导致预期的行为。非常奇怪。 - cemerick
4
注意:在大多数需要这些存根的浏览器中,如果您执行“for(index in somearray){...}”,则需要使用somearray.hasOwnProperty(index)进行检查。 IE <= 8的JS引擎将包括此中array.prototype扩展。Google Adwords异步代码不会这样做。最好使用Underscore或其他标准化此操作的库的功能。 - Tracker1
1
这是我能找到的IE 8中最快的indexOf()实现。谢谢! - Alex Denysenko
我注意到影响Array.prototype可能会导致IE中的一些异常。我建议使用Object.defineProperty,就像https://dev59.com/W5Pfa4cB1Zd3GeqPFqCH#35135200中所述。 - Psddp
显示剩余6条评论

27

2
ES5Shim和其他存根(例如来自MDC的存根)往往也会产生其他后果。最好使用underscore或另一个库来处理这些类型的函数,这将在可用的情况下使用内部方法。 - Tracker1
使用 Underscore.js,var arr=['a','a1','b'] _.filter(arr, function(a){ return a.indexOf('a') > -1; }) - srikanth_yarram

9

Kris Kowal编写了一个小型库,作为ECMAScript 5函数的替代品,以弥补浏览器实现中可能缺失的功能。其中一些函数已经被其他人修订多次,以优化速度并解决浏览器错误。这些函数的编写尽可能地遵循规范。

es5-shim.js是在MIT许可下发布的,Array.prototype扩展位于顶部,您可以轻松地剪切和删除任何不需要的函数。我还建议您最小化脚本,因为注释使其比所需的要大得多。


1

1
这是一个不错的开始,但实现中存在许多错误并未参考 MDC。例如,许多数组方法没有向它们的回调函数传递足够的参数,在回调函数中进行数组变异时也不能完全正确地执行。 - bobince
我会尽力让JS成为一个更加理智/最低限度有能力的语言。 </snark> :-) - cemerick

1

这些脚本在我的测试中效果不佳。我根据 MDN 文档创建了一个具有相同功能的文件。

太多问题区域都已经在 Internet Explorer 8 中得到解决。请参见 egermano / ie-fix.js 中的代码。


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接