views:

366

answers:

3

I want to write some javascript classes which extend DOM nodes (so that I can then insert instances of my class directly into the DOM), but am having difficulty finding out which class/prototype I should inherit from.

eg

function myExtendedElement() {
       this.superclass = ClassA;
       this.superclass();
       delete this.superclass;
}

but what should ClassA be?

A: 

You can simply add new functions to the DOM prototypes, eg.

Element.prototype.myNameSpaceSomeFunction = function(...){...}

Then myNameSpaceSomeFunction will exist on all elements.

olliej
Note that this will not work on any version of IE before IE8.
scunliffe
This isn't what I'm looking for as I want to have several different types of extended element, so can't just lter the prototype for all elements
wheresrhys
A: 

I've found a hack that works... at least, it enables me to access the extended object properties via the DOM element and vice versa. But it's hardly elegant.

var DOMelement = document.getElementById('myID'); // or  $('#myID')[0]; in jQuery
DOMelement.extended = new extensionClass(this);

function extensionClass(element) {
    this.element = element;
    ...
}
wheresrhys
You should actually **avoid adding properties to elements** like that (also known as expandos). Not only is it not safe to augment host objects, chances are you'll accidentally create circular reference between host object and native object, which **leaks** in some versions (<8, IIRC) of IE.
kangax
I am wary of creating circular references and will be testing my app with some ridiculously big instances of it to see if any effect is noticeable.Why is it otherwise not safe to augment host objects?
wheresrhys
+6  A: 

It's not a good idea to do this.

First of all, to inherit from DOM element, you need to have access to that element's prototype. The problem is that not all browsers provide access to prototypes of DOM elements. Newer Gecko and WebKit -based clients, for example, expose some of these prototypes as global objects - HTMLDivElement, HTMLElement, Element, Node, etc.

For example, plain DIV element usually has a prototype chain similar to:

HTMLDivElement.prototype -> HTMLElement.prototype -> Element.prototype 
  -> Node.prototype -> Object.prototype -> null

You can access any of them and extend or inherit from as desired. But again, even though you can, I strongly advise not to.

When browser doesn't expose these prototypes, you're pretty much out of luck. You can try retrieving them by following constructor property of DOM element itself -

document.createElement('div').constructor;

- but then there's no guarantee that element has constructor property (e.g. IE6 doesn't) and even if it does, that this property references "correct" object. If, after all, constructor does reference correct object, there's still no guarantee that this objects is allowed to be augmented at all. The truth is that host objects are allowed to implement completely bizarre behavior and do not even have to follow rules that native JS objects follow (you can find dozens of such examples in real life).

Second reason you want to avoid inheriting from DOM element prototypes is that mechanism of such inheritance is not really specified anywhere; it could be quirky, unpredictable and overall fragile and unreliable.

Yes, you can create a constructor that would initialize objects with proper prototype chain (i.e. having DOM prototype in it):

function MyDivElement(){}
MyDivElement.prototype = HTMLDivElement.prototype;

var myDiv = new MyDivElement();
typeof myDiv.appendChild; // "function"

- but this is as much as it goes, and usefulness of this whole approach becomes limited by having certain methods in prototype and nothing else -

typeof myDivElement.nodeName; // "undefined"
myDivElement.innerHTML = '<span>foo<\/span>';
myDivElement.childNodes; // Error

Until some standard specifies exact mechanism for inheriting from DOM prototypes (and browsers actually implement that mechanism), it's best to leave them alone, and perhaps try alternative approach - e.g. wrapper or decorator patterns rather than prototype one :)

kangax
You might also be interested in http://perfectionkills.com/whats-wrong-with-extending-the-dom/
kangax