Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do elements created under a `new Document` contain the wrong prototype?

When creating a div it is an instance of HTMLDivElement:

var d = document.createElement('div');
d instanceof HTMLDivElement; // true
d instanceof Element; // true

This also holds true when obtaining an external document and window:

var frame = document.createElement('iframe');
document.body.appendChild(frame);
var doc2 = frame.contentWindow.document;
var d2 = doc2.createElement('div');
d2 instanceof frame.contentWindow.HTMLDivElement; // true
d2 instanceof Element; // false, different realm/dom

I've tried creating a document with the Document constructor to process an external HTML document:

var doc = new Document();
var d = doc.createElement('div');
d instanceof Element; // true

So, it creates Elements and the elements are in the same realm as the one we're in. However to my surprise it does not type its elements:

d instanceof HTMLDivElement; // false
d.constructor.name; // "Element"

Why is that and why does the current document create typed elements while a new document creates only Element?

like image 642
Benjamin Gruenbaum Avatar asked Apr 23 '19 13:04

Benjamin Gruenbaum


2 Answers

The Document constructor is not specific to HTML (as there are XML documents), you need to construct an HTMLDocument, but its constructor is uncallable.

As the comments mention, the correct way to create a document is via the DOMImplementation#createHTMLDocument method.

var doc = document.implementation.createHTMLDocument();
var d = doc.createElement('div');
d instanceof Element; // true;
d instanceof HTMLDivElement; // true
d.constructor.name; // "HTMLDivElement"

From what I can gather, there has been a separation at some point from a general-purpose document (which was shared for HTML and XML) into two distinct constructors. At the same opportunity, they made the new constructors uncallable, and added the .createDocument() (for XML) and .createHTMLDocument() (for HTML) methods.

like image 192
Madara's Ghost Avatar answered Nov 10 '22 20:11

Madara's Ghost


Because you have an instance of Document and not HTMLDocument, it'll create an Element, not an HTMLElement. Document and Element are basic interfaces to shared by all document types. EG an HTMLDocument will create an HTMLElement.

From MDN,

The Document interface describes the common properties and methods for any kind of document. Depending on the document's type (e.g. HTML, XML, SVG, …), a larger API is available: HTML documents, served with the "text/html" content type, also implement the HTMLDocument interface, whereas XML and SVG documents implement the XMLDocument interface.

Element is the most general base class from which all objects in a Document inherit. It only has methods and properties common to all kinds of elements. More specific classes inherit from Element. For example, the HTMLElement interface is the base interface for HTML elements, while the SVGElement interface is the basis for all SVG elements. Most functionality is specified further down the class hierarchy.

You probably want to use DOMImplementation.createHTMLDocument() to create a HTML Document.

like image 5
ShrekOverflow Avatar answered Nov 10 '22 20:11

ShrekOverflow