¿Cómo se comprueba si un objeto JavaScript es un objeto DOM?
Estoy intentando conseguir:
document.createElement('div') //=> true
{tagName: 'foobar something'} //=> false
En mis propios scripts, solía usar esto ya que nunca lo necesité tagName
como propiedad:
if (!object.tagName) throw ...;
Entonces, para el segundo objeto, se me ocurrió lo siguiente como una solución rápida, que en su mayoría funciona. ;)
El problema es que depende de que los navegadores apliquen propiedades de solo lectura, algo que no todos hacen.
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;
}
}
¿Existe un buen sustituto?
Esto puede ser de interés:
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");
}
}
Es parte del DOM, Nivel2 .
Actualización 2 : así es como lo implementé en mi propia biblioteca: (el código anterior no funcionó en Chrome, porque Node y HTMLElement son funciones en lugar del objeto esperado. Este código se prueba en FF3, IE7, Chrome 1 y 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"
);
}
La respuesta aceptada es un poco complicada y no detecta todos los tipos de elementos HTML. Por ejemplo, los elementos SVG no son compatibles. Por el contrario, esta respuesta funciona tanto para HTML como para SVG, etc.
Véalo en acción aquí: https://jsfiddle.net/eLuhbu6r/
function isElement(element) {
return element instanceof Element || element instanceof HTMLDocument;
}
Cereza en la parte superior: el código anterior es compatible con IE8.
No hay necesidad de hacks, simplemente puedes preguntar si un elemento es una instancia del elemento DOM :
const isDOM = el => el instanceof Element
Todas las soluciones anteriores y siguientes (incluida mi solución) tienen la posibilidad de ser incorrectas, especialmente en IE: es muy posible (re)definir algunos objetos/métodos/propiedades para imitar un nodo DOM que invalida la prueba.
Por eso, normalmente uso las pruebas de tipo pato: pruebo específicamente las cosas que uso. Por ejemplo, si quiero clonar un nodo, lo pruebo así:
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);
}
Básicamente es una pequeña verificación de cordura + la prueba directa de un método (o propiedad) que planeo usar.
Por cierto, la prueba anterior es una buena prueba para los nodos DOM en todos los navegadores. Pero si quiere estar seguro, compruebe siempre la presencia de métodos y propiedades y verifique sus tipos.
EDITAR: IE usa objetos ActiveX para representar nodos, por lo que sus propiedades no se comportan como un verdadero objeto JavaScript, por ejemplo:
console.log(typeof node.cloneNode); // object
console.log(node.cloneNode instanceof Function); // false
mientras que debería devolver "función" y true
respectivamente. La única forma de probar métodos es ver si están definidos.
Una forma sencilla de probar si una variable es un elemento DOM (sintaxis detallada, pero más tradicional :-)
function isDomEntity(entity) {
if(typeof entity === 'object' && entity.nodeType !== undefined){
return true;
}
else{
return false;
}
}
O como sugirió HTMLGuy (sintaxis breve y limpia):
const isDomEntity = entity =>
typeof entity === 'object' && entity.nodeType !== undefined