扩展类或创建新函数,哪个更好?

时间:2012-11-07 17:09:47

标签: javascript cross-browser ecmascript-5

如果有人想为旧浏览器实现一个函数(例如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);
    }
}

3 个答案:

答案 0 :(得分:2)

就个人而言,我大部分时间都使用第一种方法(添加Array.prototype.filter),但有时我不这样做。在为旧浏览器编写大型框架时,我没有使用第一种方法,这些框架需要与互联网上的任何其他脚本一起使用,包括不良脚本。

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

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循环迭代数组,但是你无法控制第三方脚本可能会做什么。这是主要的缺点,当你编写一个大型图书馆在互联网上使用时,值得考虑。

这可以防止您向Object.prototype期间添加任何内容(使用简单的Object.prototype.method = function(){...} assignment), because ... is good to use on other types of objects, and this kind of shimming breaks为... in`。

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

此外,如果您的代码仅用于兼容ECMAScript 5的浏览器,则可以将填充程序定义为不可枚举,这将阻止它们显示在for...in循环中。我目前正在开发一个项目来为ES5浏览器提供ECMAScript 6方法,并且因为它只打算在ES5浏览器中运行,所以我可以逃脱:

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

以这种方式定义填充程序会阻止它出现在for...in循环中,因此在Object.prototype上使用它甚至是安全的,前提是您的实现准确地遵循规范/草案

这引出了次要观点。如果你不确定你可以按照规范准确地实现这个方法,那么最好也不要将其填入。这可能会破坏检查内置的库并在可用的情况下使用它,但是会回到某些东西否则,如果不是。除了执行不力之外,最好不要留下任何东西。

正因如此,我从未试图部分实施垫片。例如,Object.create无法在ES3浏览器中完全实现,因此我永远不会对此进行整理。我只是使用我自己的myLibrary.create函数,它的功能可能类似,但至少任何可以检查Object.create是否存在的代码都不会被误导,因为它认为它有一个完整的工作版本。< / p>

故事的道德:如果你要去垫片,请查看MDN上一些非常棒的,符合规范的垫片,并学会编写类似的代码:Array.prototype.filter


最后一点:许多图书馆没有在Array.prototype上的方法中进行垫片的原因可能部分是因为其中一些考虑因素,但在许多这些案例中也存在历史原因。在 filter之前,正在开发这样的库是一种标准的内置方法。 Prototype.js采用添加非标准方法的方法,这比上面讨论的方法有更多的缺点。 jQuery决定不向内置原型添加非标准方法,这就是他们$.filter的原因。

答案 1 :(得分:1)

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

说,扩展原生对象远远不如扩展主机对象(后者,它是典型的'catch 22':你扩展它们以提供额外的功能不能很好地处理主机对象扩展的浏览器)。 This article总结了一下:

  

不要忘记编写合适的,兼容的垫片很难。什么时候进去   怀疑,使用独立对象。当你正在填补的方法是一部分   未完成的规范,使用独立对象。只有在你的时候   某些方法合规性和方法是完成的一部分,   面向未来的规范,直接填充本机对象是安全的。

答案 2 :(得分:0)

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

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