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?
No need for hacks, you can just ask if an element is an instance of the Element:
Each DOMElement.constructor returns function HTML...Element() or [Object HTML...Element] so...
In Firefox, you can use the
instanceof Node
. ThatNode
is defined in DOM1.But that is not that easy in IE.
You can only ensure it is DOM element by using DOM function and catch if any exception. However, it may have side effect (e.g. change object internal state/performance/memory leak)
differentiate a raw js object from a HTMLElement
use:
// OR
use:
o={}; o.is("HTML") // false o=document.body; o.is("HTML") // true
I think prototyping is not a very good solution but maybe this is the fastest one: Define this code block;
than check your objects isDomElement property:
I hope this helps.
This is what I figured out:
To improve performance I created a self-invoking function that tests the browser's capabilities only once and assigns the appropriate function accordingly.
The first test should work in most modern browsers and was already discussed here. It just tests if the element is an instance of
HTMLElement
. Very straightforward.The second one is the most interesting one. This is its core-functionality:
It tests whether el is an instance of the construcor it pretends to be. To do that, we need access to an element's contructor. That's why we're testing this in the if-Statement. IE7 for example fails this, because
(document.createElement("a")).constructor
isundefined
in IE7.The problem with this approach is that
document.createElement
is really not the fastest function and could easily slow down your application if you're testing a lot of elements with it. To solve this, I decided to cache the constructors. The objectElementConstructors
has nodeNames as keys with its corresponding constructors as values. If a constructor is already cached, it uses it from the cache, otherwise it creates the Element, caches its constructor for future access and then tests against it.The third test is the unpleasant fallback. It tests whether el is an
object
, has anodeType
property set to1
and a string asnodeName
. This is not very reliable of course, yet the vast majority of users shouldn't even fall back so far.This is the most reliable approach I came up with while still keeping performance as high as possible.