增强DOM元素节点的原型?

12

我知道如何为每个对象添加新方法 - 通过扩展Object的原型:

Object.prototype.foo = function() {  }; 

但是,是否可以仅为DOM元素节点定义新方法? DOM元素节点对象是否具有原型?或者可能存在用于DOM节点总体的原型吗?

还是原型对象仅存在于内置对象中?

3个回答

30

可以,但不是所有浏览器都支持。Internet Explorer 8(在一定程度上)以及Firefox、Chrome、Opera和Safari都支持DOM prototypes。

HTMLElement.prototype.toggle = function () { 
    this.style.display = this.style.display == 'none' ? '' : 'none';
}

许多人认为通过修改DOM对象的原型是不良做法。Kangax在这个问题上有一篇很棒的文章:http://perfectionkills.com/whats-wrong-with-extending-the-dom/。然而,DOM原型允许我们在不支持标准方法的环境中实现基于标准的方法,就像ECMAScript 5版方法的垫片(shims)一样。


那确实是一篇很棒的文章。我会去看看并回报。 - Šime Vidas
4
示例原型不隐藏该元素。它是可切换的。 - jscripter
为什么只有HTMLDivElement?为什么不向所有HTML元素添加一个原型呢? - vsync
@vsync 我...不...知道...!我们在谈论我六年前写的一个答案,所以我不知道为什么我选择了HTMLDivElement作为示例。当然,整个示例现在相当无用,因为浏览器后来实现了“hidden”属性/属性。如果有什么需要,你可能想要填充它。 - Andy E
1
如果您更新您的答案并提供一个新的示例,那就太好了。 - vsync

4
在某些浏览器中,DOM元素确实会暴露原型对象,该对象也可能继承自Object.prototype,但这并非普遍适用(例如,IE不支持)。通常,像DOM元素这样的宿主对象没有义务执行此操作;事实上,宿主对象不受适用于本机JavaScript对象的许多规则的约束,因此您永远不应依赖DOM元素来支持此类操作。
我建议阅读kangax关于此主题的优秀文章

@Tim,我问这个问题是因为我想让你的选择函数更加方便。例如,如果我可以将selec对象添加到HTML元素节点中,那么我就可以像这样使用你的函数:input.selec.get(); input.selec.set(5,8); - Šime Vidas
1
@Šime:啊,对了。如果你正在使用jQuery,你可以通过增强$.fn来实现类似的功能,就像插件一样。否则,在IE中没有某种元素包装对象(例如jQuery的)是不可能的。 - Tim Down
幸运的是,IE终于朝着正确的方向发展 - IE 9的DOM对象继承自Object.prototype。@Šime包装几乎肯定是目前的最佳选择。 - Andy E
@Andy 等一下,在IE8中,DOM对象不继承自Object.prototype吗??真是太糟糕了。 - Šime Vidas
@Šime:没错。IE 8的DOM原型是半吊子的努力。 - Andy E
@Tim Yea,我想我最终还是会使用jQuery。目前为止,我将你的函数封装在一个名为selec的全局对象中 - http://vidasp.net/js/selection.js - 这样我就可以这样使用它:selec.get(input); selec.set(input, 3, 4);。我以后会扩展这个想法。 - Šime Vidas

2
那正是prototype.js所做的事情,但现在被认为是极其不好的做法。更好的方法是使用包装器/处理程序。请注意,扩展任何本机对象,特别是Object对象,都是不好的做法。
阅读: 扩展DOM的问题
禁止使用Object.prototype 补充:
虽然在小型项目中扩展本机对象可能被认为是安全的,但它实际上会成为一种极其糟糕的习惯。这只比在全局范围内散布函数和变量稍微好一些。不仅发生名称冲突,还发生实现冲突。这将在您混合使用更多库时变得更加明显。
将您的实现保留在自己的对象上是避免任何冲突(名称、实现或其他)的唯一方法。
话虽如此,您有权按照自己的意愿做事,但我不会推荐任何被广泛认为是纯粹的不良做法。我坚持我的建议。

@BGerrissen您能解释一下prototype.js具体是做什么的吗?我对这个库不熟悉。另外,您能详细说明一下如何使用包装器/处理器吗-您指的是什么?此外,您说“增强任何本地对象,特别是Object对象”-但我没有增强它,而是增强它的原型对象。 - Šime Vidas
6
在我看来,建议不要增强任何本地对象是危言耸听。String.prototype扩展非常有用,例如,唯一的潜在缺点是未来可能出现命名冲突。 - Andy E
a) 这是面向对象编程的精髓。 b) JS 是彻底的面向对象的。从什么时候开始算“现在”呢? - Free Consulting
@Sime Vidas和AndyE,扩展本地对象是完全合法的,而且很有可能你会顺利完成它。毕竟,PrototypeJS一直是一个相当成功的js工具包。只是不建议出于许多人的原因。/耸耸肩,避免使用它同样容易。 - BGerrissen
2
@BGerrissen 是的,但是使用jQuery的包装器比使用本地API或原型链慢(即性能)。例如,this.parentNode.id$(this).parent().attr("id")快几十倍。这就是为什么我想避免在简单任务中使用包装器的原因。 - Šime Vidas
显示剩余12条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接