31

For example for this.parentNode I would like to just write this.p or instead of document.getElementById('someid') just write document.g('someid'). Of course that are simple examples, I just want to know what is the correct way to do it.

(I know I can use jQuery or Prototype, but I'd like to learn how it is really done in JS)

rsk82
  • 28,217
  • 50
  • 150
  • 240

5 Answers5

43

Although you can prototype on the HTMLElement in many browsers - Internet Explorer (6,7,8) is NOT one of them. AFAIK, IE9 does support this (though I haven't tested it).

For browsers that do handle it, you can do:

HTMLElement.prototype.doHello = function(thing){
  console.log(this + ' says: ' + thing)
}

document.body.doHello('hello')
vsync
  • 118,978
  • 58
  • 307
  • 400
scunliffe
  • 62,582
  • 25
  • 126
  • 161
  • 3
    @Flash Thunder - I indicated that in the answer... IE6,7,8 were definitely off the 'support' table. – scunliffe Nov 21 '14 at 12:23
  • 1
    yes, but you can simply use `Object` instead of `HTMLElement` – Flash Thunder Nov 21 '14 at 13:38
  • But the OP wanted to bind methods on the HTML elements themselves - using an external object would defeat that purpose... at which point something like jQuery would be better (since they've solved this and much more) – scunliffe Nov 21 '14 at 15:14
  • 2
    But with `HTMLElement.prototype.…` you can't have targeted element with `this` of `self` (like when for example `String.prototype.…`) :( – iiic Aug 23 '18 at 11:48
14

I would strongly suggest not attempting to do this, for a few reasons:

  • Browser compatibility. While it is possible in several browsers, it isn't possible in IE <= 8.
  • DOM elements are host objects. Host objects (i.e. those provided by the environment that aren't native JavaScript objects) have no obligation to play by the same rules as native JavaScript objects and other than specified DOM behaviour can essentially do what they like. So, even if some browsers provide an HTMLElement prototype and allow you to augment it, there's no guarantee that it will work as you expect.
  • Compatibility with other code in your page. If any other code in your page (such as Prototype) messes with the HTMLElement prototype, you risk naming collisions and hard-to-detect bugs.

Instead, I would suggest creating wrapper objects around DOM nodes as jQuery, YUI and other libraries do.

Kangax has written a good article on DOM extensibility, covering all these points and more.

Owen McAlack
  • 399
  • 10
  • 28
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • Are you sure about jQuery? As far as I understand it, jQuery is extending DOM elements and other elements when [`.data()`](https://api.jquery.com/data/) is used. - https://github.com/jquery/jquery/blob/master/src/data/Data.js – JojOatXGME Mar 30 '17 at 12:48
  • 2
    @JojOatXGME: Yes, in the specific case of `data()`, jQuery does store an "expando" property (but not a method) on the DOM element. I suspect it may also use expandos for tracking event listeners and possibly other stuff. However, the overall point stands: jQuery's API provides extended DOM functionality via wrapper objects rather than by extending the DOM itself. The extension that it does to the DOM is used internally only. – Tim Down Mar 31 '17 at 15:07
3

In a word, don't. It is best not to modify objects you don't own.

This is particularly true for HTMLElement, which you cannot modify in some browsers.

lonesomeday
  • 233,373
  • 50
  • 316
  • 318
3

This article from perfectionkills.com will probably give you some insight into how it's done, and why you shouldn't do it.

(By the way, jQuery doesn't extend DOM elements. They use DOM wrappers instead.)

user113716
  • 318,772
  • 63
  • 451
  • 440
2

This might not be what you are looking for if you want to wrap a global object like document, but you can get a similar effect with custom-elements [1] [2] to create your own HTMLElement-like nodes.

  1. create custom-element
  2. add method to custom-element class
  3. you can call the method
export class CustomElementInput extends HTMLElement {

  log(){
    alert("log")
  }

  // you can even overwrite methods like so
  remove(){
    alert("removing this node")
    super.remove()
  }
}

customElements.define("custom-element-input", CustomElementInput)

// somewhere else...
// in your HTML something like:
// <custom-element-input></custom-element-input> 

const el = document.querySelector("custom-element-input")
el.log() // creates alert()
Jose V
  • 1,655
  • 1
  • 17
  • 31
  • 2
    This is what I was looking for. vanilla custom elements under-used IMO – Llama D'Attore May 17 '23 at 01:55
  • 2
    @LlamaD'Attore right? Vanilla custom elements are so flexible, very powerful, a great way to modularize all the javascript that goes with the HTML, and it will never go out of fashion, no matter how many new JS frameworks come out. – Jose V Jun 26 '23 at 12:59