我正在寻找一个明确的答案,以说明为什么扩展内置原型在JS开发人员社区中受到如此严重的抨击。我使用Prototype JS框架已有一段时间了,对我来说[1,2,3].each(doStuff)
似乎比做的要优雅得多$.each([1,2,3], doStuff)
。我知道它会造成“名称空间污染”,但我仍然不明白为什么将其视为一件坏事。扩展内置原型是否还会导致实际性能下降?谢谢!
我正在寻找一个明确的答案,以说明为什么扩展内置原型在JS开发人员社区中受到如此严重的抨击。我使用Prototype JS框架已有一段时间了,对我来说[1,2,3].each(doStuff)
似乎比做的要优雅得多$.each([1,2,3], doStuff)
。我知道它会造成“名称空间污染”,但我仍然不明白为什么将其视为一件坏事。扩展内置原型是否还会导致实际性能下降?谢谢!
Answers:
我建议您阅读这篇文章,我认为这很好地解释了为什么扩展对象对于原型也不是一个好主意。
综上所述:
缺乏规格
暴露“原型对象”不是任何规范的一部分。为了使实现完全符合DOM级别2,不需要公开那些全局Node,Element,HTMLElement等对象。
主机对象没有规则
DOM对象是宿主对象。宿主对象可以通过任何依赖实现的行为来实现这些内部方法,或者宿主对象可能仅实现某些内部方法,而没有实现其他方法。
[...]内部方法的行为取决于实现。[...]根据定义,您正在使用某些行为,这些行为可能会以无法预测的方式出现且完全不稳定。
碰撞的机会
考虑到当今正在使用的大量环境,无法判断某些属性是否还不是某些DOM的一部分。[...]
每个命名的表单控件都隐藏了通过原型链继承的属性。表单元素发生碰撞和意外错误的可能性更高。
采用某种前缀策略可以缓解此问题。但是可能还会带来额外的噪音。
性能开销
不支持元素扩展的浏览器(例如IE 6、7,Safari 2.x等)需要手动对象扩展。问题在于手动扩展很慢,不便且无法扩展。
[...]一旦开始扩展元素,库API很可能需要在任何地方返回扩展元素。结果,像$$这样的查询方法最终可能会扩展查询中的每个元素。
IE DOM一团糟
如上一节所示,手动DOM扩展是一团糟。但是,IE中的手动DOM扩展甚至更糟[...]
奖励:浏览器错误
另一个原因是代码的可读性/可维护性。如果另一个开发人员(尤其是新手)正在阅读我的代码并看到[0, 1, 2].foo(...)
,他们可能不知道foo方法是什么,或者在哪里可以找到其文档/源代码。foo是对prototype.js,正在使用的另一个库或在另一个文件中我的代码的其他部分所添加的语言的扩展,还是它们不知道的本机JavaScript方法?他们需要寻找它,可能不会立即找到它(或者,如果有冲突,他们可能找不到合适的一个)。
如果使用jQuery方法,则可以看到$.foo(...)
foo方法的名称空间,如果您不知道它的作用,那么可以很明显地在哪里找到其定义/文档。
这是一个基本的问题:如果您有两个工具以不兼容的方式扩展原型,或者以导致产生不同结果的方式扩展了常用的方法(这for...in
在JavaScript中是一个特殊问题),从而导致代码依赖打破常规行为?
基本上,这是滥用全局变量时遇到的相同问题。就其本身而言,也许没有坏事发生。但是,当两个表面上分开的代码突然相互踩踏时,这会给您带来麻烦(并且在调试时很难进行调试)。
当然,prototype.js是众所周知的,大多数工具都围绕它的工作进行工作。同样,我确信在某些情况下扩展基本原型是正确的选择。但是,要谨慎处理。
不知道这是否真的仍然是一个问题,但是我对Internet Explorer早期版本的经验是,有时甚至无法扩展某些内置类型。
这里有两个独立的问题。第一个是内置原型的一般扩展,另一个是专门扩展DOM原型的扩展。反对扩展内置原型的论点:
Array.prototype
或Object.prototype
会产生连锁反应,例如添加for...in
循环中枚举的扩展方法至于扩展DOM原型,上面的潜在冲突参数仍然适用。此外,DOM节点是宿主对象,因此不受本地JavaScript对象的任何正常规则约束。他们本质上可以做自己喜欢的事情,并且没有义务提供合理的原型对象,甚至没有额外的(“扩展”)属性。IE尤其行使此权利,即在IE 9之前不提供DOM对象的原型,并且对各种DOM对象上的属性有各种怪异的想法(尽管通常情况下,您可以将属性分配给元素,只要没有设置document.expando
为即可false
。)
for(var ... in ...)
由于也传递了原型函数,因此导致循环混乱。