Is it possible to subclass a DOM class?

I was wondering if I can subclass HTMLDivElement. Like this.

MyDivElement.prototype.pickColor = function() { return this.picked; } function MyDivElement() { this = new HTMLDivElement(); this.picked = 'unknowd'; } alert(this.picked); // print: 'unkowd' 

Is this (something like) possible? If not, what is the best way to achieve this?

+7
source share
4 answers

new HTMLDivElement(); throws a TypError "Illegal constructor" in Chrome - so this is not possible.

Update: I tested in other current browsers and they generate different types of errors, but they all throw.


Actually, this would work:

 function MyDivElement() { this.picked = 'unknowd'; } MyDivElement.prototype = document.createElement('div'); var mydiv = new MyDivElement(); 

But I'm not sure how you could use this template ...

+2
source

In browsers where __proto__ displayed and modified, you can use subclass DOM elements. It looks like this:

 function CustomEl () { var el = document.createElement('div') el.__proto__ = CustomEl.prototype return el } CustomEl.prototype.__proto__ = HTMLDivElement.prototype 

I also played with it in more detail on jsFiddle . Unfortunately, although IE and Opera do not allow __proto__ access and do not plan in the future, as far as I know.

+6
source

In some browsers you can expand the prototype, in others not. I will let you guess those where you cannot. :-) This is not the same as extending a DOM element, but it allows you to do certain subsets of things for which you might want this object. The fact is that DOM elements are not JavaScript objects; these are just simulacra provided by the runtime system. (Perhaps someday all jsdom work will really succeed.)

Well, I'll tell you about problem browsers: IE doesn't like it at all. However, others do. If you have ever looked at the Prototype library, you will encounter a manifestation of this fact all the time through annoying annoying IE errors only when you forget the Prototype -ize reference to the DOM element.

(IE9 may be different, but I kind of doubt it.)

This is the thing that is easy to check on jsfiddle .

+1
source

I am experimenting with this a bit. The big difficulty is that you need a document context to create an element. You can go with window.document by default, but it's boring.

Here is the POC I'm working on:

 function CustomNode(type, parent) { if (type instanceof Node) { // Decorate a preexisting node appropriately if called that way. if (arguments.length === 2 && type.ownerDocument !== parent) { // Import the node if it not owned by the requested document. type = parent.importNode(type, true); } return Object.assign(type, this.__proto__); } //Normal flow, eg, new CustomNode("div"); var d = document; if (parent) { // Alt document flow, eg, new CustomNode("div", xmlDoc); if (parent.nodeType === 9) { d = parent; } else { // Support for new CustomNode("div", parentElement); // This doesn't append the element, just makes sure // the documents match d = parent.ownerDocument; } } var inst; // Creation flags if (type[0] === '#') { //text inst = d.createTextNode(type.substr(1)); } else if (type[0] === '?') { //Processing instruction type = type.substr(1).split(' '); inst = d.createProcessingInstruction(type.shift(), type.join(' ')); } else if (type[0] === '[') { // CDATA inst = d.createCDATASection(type.substr(1)); } else if (type[0] === '/') { // Comment inst = d.createComment(type.substr(1)); } else { //Everything else gets an element. inst = d.createElement(type); } // DE-COR-ATE Object.assign(inst, this.__proto__); return inst; } // Decorator for customized NodeLists; probably inefficient. Decorates // contents with CustomNode function CustomNodeList(list) { var Self = this.constructor, CNode = this.Node; return Object.assign([].map.call(list, function (node) { return new CNode(node); }), this.__proto__); } CustomNodeList.prototype = { // so we know how to wrap... Node: CustomNode, text: function () { return this[0].textContent; } }; CustomNode.prototype = { // So we know how to decorate NodeLists NodeList: CustomNodeList, // So we know how to decorate Nodes Node: CustomNode, // Easy make-and-attach new: function (type, attach) { var CNode = this.Node; var ret = new CNode(type, this.ownerDocument); if (attach) { this.appendChild(ret); } return ret; }, // NodeLists with ES5 iterators! find: function () { var CNodeList = this.NodeList; return new CNodeList(this.querySelectorAll.apply(this, arguments)); }, kids: function () { var CNodeList = this.NodeList; return new CNodeList(this.childNodes); } }; 

Reason, this is probably a bad idea: all in the same scope of these functions (including the elements themselves) will never receive garbage collection, since GC in most browsers is dead-dumb when it comes to elements referencing objects. I will never use it for production just for this reason: this is a direct memory leak.

+1
source

All Articles