JavaScript isDOM — How do you check if a JavaScript Object is a DOM Object?

JavaScript isDOM — How do you check if a JavaScript Object is a DOM Object?

I’m trying to get:
document.createElement(‘div’) //=> true
{tagName: ‘foobar something’} //=> false

In my own scripts, I used to just use this since I never needed tagName as a property:
if (!object.tagName) throw …;

So for the second object, I came up with the following as a quick solution — which mostly works. 😉
The problem is, it depends on browsers enforcing read-only properties, which not all do.
function isDOM(obj) {
var tag = obj.tagName;
try {
obj.tagName = ”; // Read-only for DOM, should throw exception
obj.tagName = tag; // Restore for normal objects
return false;
} catch (e) {
return true;
}
}

Is there a good substitute?

Solutions/Answers:

Solution 1:

This might be of interest:

function isElement(obj) {
  try {
    //Using W3 DOM2 (works for FF, Opera and Chrome)
    return obj instanceof HTMLElement;
  }
  catch(e){
    //Browsers not supporting W3 DOM2 don't have HTMLElement and
    //an exception is thrown and we end up here. Testing some
    //properties that all elements have (works on IE7)
    return (typeof obj==="object") &&
      (obj.nodeType===1) && (typeof obj.style === "object") &&
      (typeof obj.ownerDocument ==="object");
  }
}

It’s part of the DOM, Level2.

Related:  Can a proxy (like fiddler) be used with Node.js's ClientRequest

Update 2: This is how I implemented it in my own library:
(the previous code didn’t work in Chrome, because Node and HTMLElement are functions instead of the expected object. This code is tested in FF3, IE7, Chrome 1 and Opera 9).

//Returns true if it is a DOM node
function isNode(o){
  return (
    typeof Node === "object" ? o instanceof Node : 
    o && typeof o === "object" && typeof o.nodeType === "number" && typeof o.nodeName==="string"
  );
}

//Returns true if it is a DOM element    
function isElement(o){
  return (
    typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2
    o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName==="string"
);
}

Solution 2:

The following IE8 compatible, super-simple code works perfectly.

The accepted answer does not detect all types of HTML elements. For example, SVG elements are not supported. In contrast, this answer works for HTML well as SVG.

See it in action here: https://jsfiddle.net/eLuhbu6r/

function isElement(element) {
    return element instanceof Element || element instanceof HTMLDocument;  
}

Solution 3:

All solutions above and below (my solution including) suffer from possibility of being incorrect, especially on IE — it is quite possible to (re)define some objects/methods/properties to mimic a DOM node rendering the test invalid.

Related:  Can I mark a field invalid from javascript?

So usually I use the duck-typing-style testing: I test specifically for things I use. For example, if I want to clone a node I test it like this:

if(typeof node == "object" && "nodeType" in node &&
   node.nodeType === 1 && node.cloneNode){
  // most probably this is a DOM node, we can clone it safely
  clonedNode = node.cloneNode(false);
}

Basically it is a little sanity check + the direct test for a method (or a property) I am planning to use.

Incidentally the test above is a good test for DOM nodes on all browsers. But if you want to be on the safe side always check the presence of methods and properties and verify their types.

EDIT: IE uses ActiveX objects to represent nodes, so their properties do not behave as true JavaScript object, for example:

console.log(typeof node.cloneNode);              // object
console.log(node.cloneNode instanceof Function); // false

while it should return “function” and true respectively. The only way to test methods is to see if the are defined.

Related:  Is it possible to pass a component as props and use it in a child Component in Vue?

Solution 4:

You could try appending it to a real DOM node…

function isDom(obj)
{
    var elm = document.createElement('div');
    try
    {
        elm.appendChild(obj);
    }
    catch (e)
    {
        return false;
    }

    return true;
}

Solution 5:

How about Lo-Dash’s _.isElement?

$ npm install lodash.iselement

And in the code:

var isElement = require("lodash.iselement");
isElement(document.body);

Solution 6:

This is from the lovely JavaScript library MooTools:

if (obj.nodeName){
    switch (obj.nodeType){
    case 1: return 'element';
    case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
    }
}