Esto es lo que descubrí:
var isHTMLElement = (function () {
if ("HTMLElement" in window) {
// Voilà. Quick and easy. And reliable.
return function (el) {return el instanceof HTMLElement;};
} else if ((document.createElement("a")).constructor) {
// We can access an element's constructor. So, this is not IE7
var ElementConstructors = {}, nodeName;
return function (el) {
return el && typeof el.nodeName === "string" &&
(el instanceof ((nodeName = el.nodeName.toLowerCase()) in ElementConstructors
? ElementConstructors[nodeName]
: (ElementConstructors[nodeName] = (document.createElement(nodeName)).constructor)))
}
} else {
// Not that reliable, but we don't seem to have another choice. Probably IE7
return function (el) {
return typeof el === "object" && el.nodeType === 1 && typeof el.nodeName === "string";
}
}
})();
Para mejorar el rendimiento, creé una función de invocación automática que prueba las capacidades del navegador solo una vez y asigna la función adecuada en consecuencia.
La primera prueba debería funcionar en la mayoría de los navegadores modernos y ya se discutió aquí. Simplemente prueba si el elemento es una instancia de HTMLElement
. Muy sencillo
El segundo es el más interesante. Esta es su funcionalidad principal:
return el instanceof (document.createElement(el.nodeName)).constructor
Comprueba si el es una instancia de la construcción que pretende ser. Para hacer eso, necesitamos acceso al constructor de un elemento. Es por eso que estamos probando esto en la declaración if. IE7 por ejemplo falla esto, porque (document.createElement("a")).constructor
está undefined
en IE7.
El problema con este enfoque es que document.createElement
realmente no es la función más rápida y podría ralentizar fácilmente su aplicación si está probando muchos elementos con ella. Para resolver esto, decidí almacenar en caché los constructores. El objeto ElementConstructors
tiene nodeNames como claves con sus constructores correspondientes como valores. Si un constructor ya está almacenado en caché, lo usa desde el caché; de lo contrario, crea el Elemento, almacena en caché a su constructor para acceso futuro y luego lo prueba.
La tercera prueba es el retroceso desagradable. Comprueba si el es un object
, tiene una nodeType
propiedad establecida en 1
y una cadena como nodeName
. Por supuesto, esto no es muy confiable, sin embargo, la gran mayoría de los usuarios ni siquiera deberían retroceder hasta ahora.
Este es el enfoque más confiable que se me ocurrió mientras mantengo el rendimiento lo más alto posible.