JavaScript:扩展Array.prototype有什么危险?

And*_*kin 56 javascript prototype coding-style

谷歌JavaScript风格指南建议不要扩展Array.prototype.但是,我Array.prototype.filter = Array.prototype.filter || function(...) {...}在浏览器中使用它(和类似方法)的方式不存在.MDN实际上提供了类似的例子.

我知道Object.prototype问题,但Array不是哈希表.

扩展时会出现什么问题,这会让Array.prototypeGoogle提出反对意见?

Jam*_*son 78

大多数人都错过了这一点.在我看来,填充或填充标准功能,Array.prototype.filter以便它在旧浏览器中工作一个好主意.不要听仇恨.Mozilla甚至会向您展示如何在MDN上执行此操作.通常,不扩展Array.prototype或其他原生原型的建议可能归结为以下之一:

  1. for..in 可能无法正常工作
  2. 其他人可能也想要使用相同的函数名扩展Array
  3. 它可能无法在每个浏览器中正常工作,即使使用垫片也是如此.

以下是我的回复:

  1. 您通常不需要for..in在Array上使用.如果你这样做,你可以hasOwnProperty用来确保它是合法的.
  2. 只有当你知道自己是唯一一个这样做的人或者当它是标准的东西时,才会扩展本地人Array.prototype.filter.
  3. 这很烦人,有点咬我.旧IE有时会出现添加此类功能的问题.您只需要根据具体情况查看它是否有效.对我来说,我遇到的问题是添加Object.keys到IE7.它似乎在某些情况下停止工作.你的旅费可能会改变.

看看这些参考文献:

祝好运!

  • "你不需要使用for..in" - 根本不要使用它.即使使用`hasOwnProperty`,你仍然会跳过`length`,这在大多数情况下都没有意义. (10认同)
  • @Malvolio不同意:您无法轻易了解/控制第三方库中的内容.例如,`for..in`在用于Three.js的SEA3D加载器中中断,我添加了`Array.prototype`.事实上,three.js中的大部分都使用`for..in`.真的,请注意.这些不是必须找到的令人愉快的错误. (2认同)
  • @NickWiggill,for .. in不是为数组而设计的,它是为arraylike对象设计的(读取关联数组).你永远不应该使用for .. in for arrays. (2认同)
  • 您可以使用 [`Object.defineProperty()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) 扩展 Array.prototype 对象来避免枚举问题 (2认同)

Jam*_*ers 9

我将从Nicholas Zakas的优秀文章中给出关键句子的要点.可维护的JavaScript:不要修改你不拥有的对象:

  • 可靠性:"简单的解释是企业软件产品需要一致且可靠的执行环境才能维护."
  • 不兼容的实现:"修改您不拥有的对象的另一个危险是命名冲突和不兼容的实现的可能性."
  • 如果每个人都这样做怎么办 :"简单地说:如果团队中的每个人都修改了他们不拥有的对象,那么很快就会遇到命名冲突,不兼容的实现和维护噩梦."

基本上,不要这样做.即使您的项目永远不会被其他任何人使用,并且您永远不会导入第三方代码,也不要这样做.你会建立一种可怕的习惯,当你开始尝试与他人玩耍时,这种习惯很难打破.

  • 事实上这种推理反对OOP (3认同)
  • 如果团队同意,扩展宿主对象以使其符合标准没有任何问题.使用非标准属性扩展主机对象是一个不同的游戏,我同意"不要这样做" (2认同)
  • @jsumners,如果John或Jane已经编写了`VeryUsefulObject`但它仍然缺少`exactWhatINeed`方法怎么办? (2认同)

the*_*dow 5

作为Jamund Ferguson答案的现代更新:

通常,不扩展Array.prototype或其他本机原型的建议可能归结为以下一种:

  1. for..in可能无法正常工作
  2. 其他人可能也想使用相同的函数名称扩展Array
  3. 即使使用填充程序,它也可能无法在所有浏览器中正常工作。

现在可以在ES6中通过使用符号添加方法来减轻第1点和第2点的压力

它使调用结构变得更加笨拙,但是添加了一个不会被迭代且无法轻易复制的属性。

// Any string works but a namespace may make library code easier to debug. 
var myMethod = Symbol('MyNamespace::myMethod');

Array.prototype[ myMethod ] = function(){ /* ... */ };

var arr = [];

// slightly clumsier call syntax
arr[myMethod]();

// Also works for objects
Object.prototype[ myMethod ] = function(){ /* ... */ };
Run Code Online (Sandbox Code Playgroud)

优点:

  • For..in可以正常工作,不会重复符号。
  • 方法名称没有冲突,因为符号是作用域的局部符号,因此会努力进行检索。

缺点: