最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

html - Can we overwrite Javascript DOM object prototype properties? - Stack Overflow

programmeradmin4浏览0评论

I have been looking for a way to permanently change the HTMLFormElement Javascript object's 'onsubmit' behavior. Let's suppose that one of my Javascript would contain the following code:

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

The idea would be to simply prevent double submits on all forms of the document. I wasn't able to figure out how to do this since the above example is not working.

Is there a way to achieve this without looping through all existing HTMLElements after the document is loaded? A way which would be patible with some older browser and also persist the behavior if you create new form elements using other scripts. (Vanilla JS only please)

I have been looking for a way to permanently change the HTMLFormElement Javascript object's 'onsubmit' behavior. Let's suppose that one of my Javascript would contain the following code:

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

The idea would be to simply prevent double submits on all forms of the document. I wasn't able to figure out how to do this since the above example is not working.

Is there a way to achieve this without looping through all existing HTMLElements after the document is loaded? A way which would be patible with some older browser and also persist the behavior if you create new form elements using other scripts. (Vanilla JS only please)

Share Improve this question edited Dec 19, 2015 at 23:52 Tomáš Zato 53.5k63 gold badges310 silver badges828 bronze badges asked Dec 19, 2015 at 23:21 Nicolas BouvretteNicolas Bouvrette 4,8332 gold badges44 silver badges66 bronze badges 10
  • 7 Wouldn't it be easier to just write code that doesn't submit your forms twice, instead of changing native prototypes ? – adeneo Commented Dec 19, 2015 at 23:24
  • 1 I tried and even multiple .submit() or clicking a submit button multiple times only submitted the form once. – Oriol Commented Dec 19, 2015 at 23:26
  • 2 document.addEventListener("submit", function(e){ var el=e.target; if(el.spent) return e.preventDefault(); el.spent=true; }) – dandavis Commented Dec 19, 2015 at 23:27
  • 2 @dandavis Don't return false in an event listener, that's only for event handlers. Use e.preventDefault(). – Oriol Commented Dec 19, 2015 at 23:28
  • 1 How older is "patible with some older browser"? Why do you have [ES6] tag if you want patibility with older browsers? Are you trying to prevent form submission done by the user (through submit button or implicit submission), or done by you (through .submit())? Are you using target in your form? – Oriol Commented Dec 19, 2015 at 23:44
 |  Show 5 more ments

4 Answers 4

Reset to default 6

Can we overwrite Javascript DOM object prototype properties?

Although the javascript spec cuts host objects a lot of slack in violating normal javascript behavior Object.defineProperty(HTMLFormElement.prototype, "onsubmit", {get: () => {return false;}}) does work. "Work" as in setting a getter on the prototype.

But it's not actually what you want. That's just replacing the getter/setter functionality. There is no guarantee that the browser goes through the javascript inheritance chain to retrieve the handler for the current form.

Either because it bypasses javascript by directly looking at some underlying native properties or because it doesn't have to look at the prototype at all and looks at an instance property of the form itself.

Messing with prototypes is rarely a good idea if you don't know how and when individual properties are actually used by the target class.

Another thing: the getter/setter actually is on HTMLElement.prototype, not HTMLFormElement.prototype. At least that's where it is in Firefox. You should at least inspect the inheritance chain before trying to mess with it ;)

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

Instead of messing with prototypes you can simply install a capturing event listener on the document.

capturing because it happens earlier and is less likely to be intercepted via stopPropagation without canceling the default action, which would be the form submission this case.

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

How about this?

[].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: Nope, do as @Louy says, it's correct. DOM was designed to be looped through, no worries.


Yeah, you can overwrite HTMLElement properties and it's same for HTMLElement descendants. But specifically for some properties, like event callbacks, you're not allowed to do that, because they are not normal properties but getters and setters. I get the following error for your code, which is probably what you meant by "doesn't work":

Even if you achieved to do that, I'm not sure if the resulting behavior is defined by standards. I think this would definitely not lead to anything patible between browsers.

My experience also shows that globally changing some API because you need it for specific functions is not a good idea - soon your request might change and you will be changing whole API in general.

Yes, you can overwrite JavaScript DOM object prototype properties. However, you should never ever ever ever... EVER do this! That is, unless you're writing a 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!

For your specific use case, you can easily achieve the desired effect by using event.preventDefault() on every click of the submit button except for the first click :

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);
发布评论

评论列表(0)

  1. 暂无评论