En este momento estoy usando isElement by lodash para verificar si es probable que un elemento sea DOM. Quiero deshacerme de esta biblioteca, así que estoy buscando una implementación JS pura de esta función.
Estoy usando esto, pero no sé si es la implementación correcta y si estoy ignorando algún caso extremo:
const isDOMElement = el => el instanceof HTMLElementHe probado ( enlace codepen ) las cuatro implementaciones propuestas, en todos los casos funciona como se esperaba, tal vez la propuesta por @cesare cubre la mayoría de los casos, pero también la propuesta por @peter-seliger es inteligente y funciona con un " pensamiento fuera de la CAJA". Finalmente, tanto @David Thomas como el que uso primero, funcionan para la mayoría de los casos.
Entonces, en conclusión, creo que, como apunta David Thomas It's just a matter of preference .
PD: Las etiquetas utilizadas para la prueba se extraen de la referencia de elementos HTML de MDN
P.S2: No estoy seguro de cómo proceder y qué respuesta aceptar. Tanto cesare como peter tienen un buen punto.
Uno podría intentarlo...
function exposeImplementation(value) { return Object .prototype .toString .call(value); } function getInternalClassName(value) { return (/^\[object\s+(?<className>[^\]]+)\]$/) .exec( exposeImplementation(value) ) ?.groups ?.className; } function isHTMLElement(value) { return !!value && (/^HTML(?:[AZ][A-Za-z]+)?Element$/) .test( String( getInternalClassName(value) ) ); } console.log( getInternalClassName(document.createElement('h1')), isHTMLElement(document.createElement('h1')) ); console.log( getInternalClassName(document.body), isHTMLElement(document.body) ); console.log( getInternalClassName(document), isHTMLElement(document) ); .as-console-wrapper { min-height: 100%!important; top: 0; }Mire la implementación del código fuente de la biblioteca:
Esta es la utilidad de lodash :
function isElement(value) { return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value) } Básicamente, con isObjectLike verifica que el valor pasado sea un objeto no null (ya que null es un objeto en js) y con !isPlainObject que no es un objeto simple (ya que podría ser un objeto que lleva un "nodeType": 1 entrada y porque una instancia de HTMLElement tiene prototipos anidados.
La isPlainObject es esta:
function isPlainObject(value) { if (!isObjectLike(value) || getTag(value) != '[object Object]') { return false } if (Object.getPrototypeOf(value) === null) { return true } let proto = value while (Object.getPrototypeOf(proto) !== null) { proto = Object.getPrototypeOf(proto) } return Object.getPrototypeOf(value) === proto } Como puede ver, la primera verificación es redundante ya que verifica isObjectLike nuevamente, pero la advertencia principal en mi opinión es que no cubre el caso de otros objetos, ya que, por ejemplo, "Arrays" también son objetos, por lo que pasan la verificación:
const arr = [1, 2]; // array arr.nodeType = 1; // add nodeType property to the array object console.log(isElement(arr)); // true LodashInténtalo tú mismo.
Creo que es más seguro verificar si el objeto tiene una propiedad nodeType heredada:
const _isElement = (node) => typeof node === 'object' && node !== null && !node.hasOwnProperty('nodeType') && node.nodeType && node.nodeType === 1 const el = document.createElement('h1'); // node const arr = [1, 2]; // array arr.nodeType = 1; // add nodeType property to the array object console.log(isElement(arr)); // true Lodash console.log(isElement(el)); // true Lodash console.log(_isElement(arr)) // false console.log(_isElement(el)) // trueEn cualquier caso, prefiero usar su control que ya cubre la mayoría de esos controles, ya que cualquier no objeto primitivo no es una instancia de HTMLElement, null no es una instancia de HTMLElement, y una instancia de HTMLElement tiene una propiedad de "tipo de nodo" pero se hereda de proto y no es una propiedad propia, :
const isDOMElement = el => el instanceof HTMLElement //or const isDOMElement = el => el instanceof Node