我们可以覆盖 Javascript DOM 对象原型属性吗?

Can we overwrite Javascript DOM object prototype properties?

我一直在寻找一种方法来永久更改 HTMLFormElement Javascript 对象的 'onsubmit' 行为。假设我的 Javascript 之一包含以下代码:

HTMLFormElement.prototype.onsubmit = function () {
    this.submit();
    // Make sure that you can only submit once.
    this.onsubmit = function () {
        return false;
    };
    return false;
};

我们的想法是简单地防止对所有形式的文档进行双重提交。我无法弄清楚如何执行此操作,因为上面的示例不起作用。

有没有一种方法可以在加载文档后不循环遍历所有现有的 HTMLElements 来实现这一点?一种与某些旧浏览器兼容的方式,并且如果您使用其他脚本创建新的表单元素,也会保留该行为。 (请只使用 Vanilla JS)

这个怎么样?

[].forEach.call(document.getElementsByTagName('form'), function(form) {
  form.onsubmit = function () {
    // Make sure that you can only submit once.
    this.onsubmit = function () {
      return false;
    };
    return true;
  };
});

tl;dr: 不,按照@Louy 说的做,这是正确的。 DOM 设计为可循环,不用担心。


是的,您可以覆盖 HTMLElement 个属性,HTMLElement 个后代也是如此。但特别是对于一些属性,比如事件回调,你是不允许这样做的,因为它们不是普通属性而是 getterssetters。我收到您的代码的以下错误,这可能是您所说的“不起作用”的意思:

即使您做到了这一点,我也不确定由此产生的行为是否由标准定义。我认为这绝对不会导致浏览器之间的任何兼容。

我的经验还表明,因为特定功能需要它而全局更改某些 API 并不是一个好主意 - 很快您的请求可能会更改,并且您通常会更改整个 API。

Can we overwrite Javascript DOM object prototype properties?

尽管 javascript 规范在违反正常 javascript 行为方面大大减少了主机对象 Object.defineProperty(HTMLFormElement.prototype, "onsubmit", {get: () => {return false;}}) 确实有效。 "Work" 就像在原型上设置 getter。

但这实际上不是你想要的。这只是替换 getter/setter 功能。无法保证浏览器通过 javascript 继承链检索当前表单的处理程序。

要么是因为它通过直接查看某些底层本机属性绕过 javascript,要么是因为它根本不必查看原型而是查看表单本身的实例 属性 .

如果您不知道目标实际使用各个属性的方式和时间,那么乱用原型很少是个好主意 class。

另一件事:getter/setter 实际上是在 HTMLElement.prototype 上,而不是 HTMLFormElement.prototype。至少在 Firefox 中是这样。在试图弄乱它之前,您至少应该检查一下继承链 ;)

The idea would be to simply prevent double submits on all forms of the document.

您可以简单地在文档上安装捕获事件侦听器,而不是弄乱原型。

正在捕获,因为它发生得较早并且不太可能被 stopPropagation without canceling the default action 拦截,在这种情况下就是表单提交。

document.addEventListener("submit", (e) => {e.preventDefault();}, true);

是的,您可以覆盖 JavaScript DOM 对象原型属性。但是,您永远不应该……永远不要这样做!也就是说,除非您正在编写 polyfill that is supposed to add standard behavior so browsers that don't support it. Unless you're in that very specific and fairly rare situation, you're not supposed to ever modify objects you don’t own!

对于您的特定用例,您可以通过在每次单击提交按钮时使用 event.preventDefault()(第一次单击除外)轻松实现所需的效果:

var alreadySubmitted = false;

document.getElementById("submitbutton").addEventListener("click", function(event){
    if(!alreadySubmitted) {
        // The first time the button is clicked
        alreadySubmitted = true;
    } else {
        // All subsequent times the button is clicked
        event.preventDefault();
    }
}, false);