为什么不赞成修改JavaScript对象的原型?

时间:2011-06-03 05:49:22

标签: javascript monkeypatching

我在这里和那里发现了一些关于如何修改JavaScript对象原型的不满意的评论?我个人不知道这可能是一个什么问题。例如,扩展Array对象以获得map和include方法或创建更强大的Date方法?

5 个答案:

答案 0 :(得分:23)

问题是可以在几个地方修改原型。例如,一个库会将map方法添加到Array的原型中,并且您自己的代码将添加相同的但具有其他目的。因此,一个实现将被打破。

答案 1 :(得分:10)

主要是因为命名空间冲突。我知道Prototype框架在保持其名称与本机包含的名称不同时存在许多问题。

为人们提供公用事业有两种主要方法..

原型

向Object的原型添加函数。 MooTools和Prototype就是这样做的。

优点:

  1. 超级轻松访问。
  2. 缺点:

    1. 可以使用大量的系统内存。虽然现代浏览器只是从构造函数中获取属性的实例,但是一些较旧的浏览器为构造函数的每个实例存储每个属性的单独实例。
    2. 不一定总是可用。
    3. 我的意思是“不可用”是这样的:

      想象一下,你有一个来自document.getElementsByTagName的NodeList,你想要迭代它们。你做不到..

      document.getElementsByTagName('p').map(function () { ... });
      

      ..因为它是NodeList,而不是Array。以上内容会给您一个错误:Uncaught TypeError: [object NodeList] doesn't have method 'map'

      我应该注意到有很简单的方法可以转换NodeList和其他类似Array的方法 将对象转换为实数。

      采集

      在其上创建全新的全局变量和库存堆积实用程序。 jQuery和Dojo就是这样做的。

      优点:

      1. 永远在那里。
      2. 内存使用率低。
      3. 缺点:

        1. 不是很好。
        2. 有时使用会感到尴尬。
        3. 使用这种方法你仍然无法做到..

          document.getElementsByTagName('p').map(function () { ... });
          

          ..但你可以做..

          jQuery.map(document.getElementsByTagName('p'), function () { ... });
          

          ..但正如Matt所指出的那样,在通常的使用中,你会用..来实现上述目标。

          jQuery('p').map(function () { ... });
          

          哪个更好?

          归根结底,这取决于你。如果您有被覆盖/覆盖的风险,那么我强烈建议进行原型设计。这是我喜欢的风格,我觉得风险值得结果。如果你对我不太满意,那么收藏也是一种很好的风格。它们都有优点和缺点,但总的来说,它们通常产生相同的最终结果。

答案 2 :(得分:6)

正如bjornd指出的那样,monkey-patching只有在涉及多个库时才会出现问题。因此,如果您正在编写可重用的库,那么这不是一个好的做法。但是,在javascript中使用主机对象时,它仍然是解决跨浏览器兼容性问题的最佳技术。

当prototype.js和json2.js一起使用时,请查看this link的真实事故。

答案 3 :(得分:1)

来自Nicholas C. Zakas的一篇优秀文章解释了为什么这种做法不是团队或客户项目中任何程序员的想法(也许你可以做一些教育目的的调整,但不是一般的项目使用)。

可维护的JavaScript:不要修改您不拥有的对象: https://www.nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/

答案 4 :(得分:0)

除了其他答案外,修改内置对象可能引起的一个更永久的问题是,如果非标准更改在足够的站点上使用,则将来的ECMAScript版本将无法使用以下方法定义原型方法:同名。参见here

  

这正是Array.prototype.flattenArray.prototype.contains发生的情况。简而言之,规范是针对这些方法编写的,他们的建议到达了stage 3,然后浏览器开始发布它。但是,在这两种情况下,都发现存在一些古老的库,它们用自己的方法与新方法同名修补内置Array对象,并且行为不同;结果,网站崩溃了,浏览器不得不退出对新方法的实现,并且必须对规范进行编辑。 (方法已重命名。)

例如,当前有一个针对String.prototype.replaceAll的提案。如果您提供了一个被广泛使用的库,并且该库在String.prototype.replaceAll上使用了 custom 非标准方法,则replaceAll名称将不再适用于规范-作家在浏览器实现之前,必须先对其进行更改。