0

如果有人想Array.prototype.filter为旧浏览器实现一个功能(例如),哪种方法更好?为什么?各有什么优缺点?

if (!Array.prototype.filter) {
  Array.prototype.filter = function() {
    //implementation
  }
}

或者

function myFilter(e,i,f) {
    if (!Array.prototype.filter) {
        //implementation
    } else {
        return Array.prototype.filter(e,i,f);
    }
}
4

3 回答 3

2

就个人而言,我大部分时间都使用第一种方法(添加Array.prototype.filter),但有时我不使用。在为旧浏览器编写大型框架时,我不使用第一种方法,它需要与 Internet 上的任何其他脚本(包括坏脚本)配合使用。

以下是需要考虑的事项。假设您Array.prototype.filter使用您描述的方法进行填充,然后向您的网站添加一个 3rd 方脚本,该脚本执行以下操作:

var someArray = [ 'a', 'b', 'c' ];
console.log('The first three letters of the alphabet are: ');
for (var i in someArray)
    console.log(someArray[i]);

结果?

The first three letters of the alphabet are: 
a
b
c
function () { ... }

您的过滤器功能被打印出来!现在,在技术层面上,没有人应该使用循环来迭代数组for...in,但是您无法控制 3rd 方脚本可能会做什么。这是主要的缺点,当您编写一个在整个 Internet 上使用的大型库时,值得考虑。

这可以防止您在Object.prototype句号中添加任何内容(使用简单的 Object.prototype.method = function() { ... } assignment), becausefor...in is good to use on other types of objects, and this kind of shimming breaksfor...in`。

但是,如果您只是编写要在您自己的网站上使用的代码,并且您知道您将包含的脚本质量很高,并且不会犯这样的错误,那么这是一种很好的技术。

此外,如果您的代码仅适用于兼容 ECMAScript 5 的浏览器,您可以将 shim 定义为不可枚举,这将防止它们出现在for...in循环中。我目前正在开发一个项目,以在 ES5 浏览器中使用 ECMAScript 6 方法填充,因为它只打算在 ES5 浏览器中运行,所以我可以摆脱:

Object.defineProperty(Array.prototype, 'contains', {
    value: function(value) {
        // Implementation
    },
    enumerable: false,
    writable: true,
    configurable: true
});

以这种方式定义 shim 可以防止它出现在for...in循环中,因此在 上使用它甚至是安全的Object.prototype前提是您的实现准确地遵循 spec/draft

这带来了第二点。如果您不确定是否可以按照规范准确实现该方法,最好不要填充它。这可能会破坏检查内置并在可用时使用它的库,但会退回到某些东西否则,如果不是。最好让他们一无所有,而不是使用损坏的实现。

正是出于这个原因,我从不尝试部分实现 shim。例如,Object.create不能在 ES3 浏览器中完全实现,所以我永远不会填充这个。我只是使用我自己的myLibrary.create函数,它的功能可能类似,但至少任何可以检查是否存在的代码Object.create都不会被误导相信它有一个完整的工作版本。

故事的寓意:如果您要进行 shim,请查看 MDN 上一些非常棒的、符合规范的 shim,并学习编写类似的代码:Array.prototype.filter


最后一点:许多库不在方法中填充的原因Array.prototype可能部分是出于这些考虑,但在许多情况下也有历史原因。像 jQuery 这样的库之前 正在开发,filter是一种标准的内置方法。Prototype.js 采取了添加非标准方法的方法,这比上面讨论的缺点更多。jQuery 决定不向内置原型添加非标准方法,这就是它们具有$.filter.

于 2012-11-12T04:02:57.613 回答
1

第二种方法更常见;它被 jQuery 和 Underscore.js 等流行的 shim JS 库所使用。

也就是说,扩展本机对象远不如扩展宿主对象危险(后者是典型的“第 22 条规则”:您扩展它们以在不能很好地处理宿主对象扩展的浏览器中提供额外的功能)。这篇文章总结了一下:

不要忘记编写正确、合规的垫片很难。如有疑问,请使用独立对象。当您正在填充的方法是未完成规范的一部分时,请使用独立对象。只有当您确定方法合规性并且方法是已完成的、面向未来的规范的一部分时,直接填充原生对象才是安全的。

于 2012-11-07T17:14:05.990 回答
0

对于新的标准 js 函数和类,最佳实践是shiming,如果在旧浏览器上找不到该函数,则扩展类。

但是,如果该函数没有成为标准,最佳实践是创建新函数并且不要更改标准类,因为如果您使用将来可能以不同行为使用的函数名称,它将破坏您的应用程序。

于 2013-01-31T05:06:49.370 回答