¿Cómo se verifica si un objeto JavaScript es un objeto DOM?


247

Estoy tratando de obtener:

document.createElement('div')  //=> true
{tagName: 'foobar something'}  //=> false

En mis propios scripts, solía usar esto ya que nunca lo necesitaba tagNamecomo propiedad:

if (!object.tagName) throw ...;

Entonces, para el segundo objeto, se me ocurrió lo siguiente como una solución rápida, que funciona principalmente. ;)

El problema es que depende de que los navegadores apliquen propiedades de solo lectura, lo 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;
  }
}

¿Hay un buen sustituto?


3
¿Estoy siendo obtuso al preguntarme si un "Objeto DOM" no debería cubrir no solo los Elementos sino también todos los Nodos (Nodos de Texto, Atributos, etc.)? Todas las respuestas y la forma en que ha planteado la cuestión tienden a sugerir esta pregunta es específicamente acerca de los elementos ...
Mike roedor

Respuestas:


300

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 funcionaba 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"
);
}

11
Vale la pena señalar que esto no funcionará en elementos que pertenecen a otras ventanas / marcos. El método recomendado es la escritura de patos
Andy E

2
Puedes engañarlo con:function Fake() {}; Fake.prototype=document.createElement("div"); alert(new Fake() instanceof HTMLElement);
Kernel James

11
Hecho de WTF: Firefox 5 y versiones anteriores regresan truepara [] instanceof HTMLElement.
Rob W

66
Por cierto, HTMLElementsiempre es un function, así typeofque lo sacará de la pista y ejecutará la segunda parte de la declaración. Puede intentarlo si lo desea instanceof Object, porque la función será una instancia de Object, o simplemente comprobará explícitamente typeof === "function", porque Nodey HTMLElementson funciones de objeto nativas.
Roland

2
Cuando llamas isElement(0), devuelve 0, no falso ... ¿Por qué es eso y cómo puedo evitarlo?
Jessica

68

El siguiente código súper simple compatible con IE8 funciona perfectamente.

La respuesta aceptada 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.

Véalo en acción aquí: https://jsfiddle.net/eLuhbu6r/

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

3
'Elemento' no está definido en IE7
Dan

49
Soy de la opinión de que cualquiera que siga usando IE7 debería dedicar los cinco segundos a descargar un mejor navegador en lugar de ponernos a invertir días o semanas para evitar su negativa a cumplir con los tiempos.
mopsyd

1
Estoy de acuerdo con @mopsyd, pero el autor de la respuesta afirma que funciona en IE7, que podría necesitar actualizarse en aras de la corrección.
Lajos Meszaros

1
Actualizado para decir IE9. No estoy seguro si IE8 lo admite.
Monarca Wadia

1
@MonarchWadia sí, es compatible con IE8. Pero tenga en cuenta que esto no devuelve verdadero para el documentelemento (en todos los navegadores). si lo necesita, debe intentar:x instanceof Element || x instanceof HTMLDocument
S.Serpooshan

11

Todas las soluciones anteriores y posteriores (incluida mi solución) tienen la posibilidad de ser incorrectas, especialmente en IE: es bastante posible (re) definir algunos objetos / métodos / propiedades para imitar un nodo DOM que invalida la prueba.

Por lo general, utilizo la prueba de estilo de escritura de 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 un pequeño control de cordura + la prueba directa para un método (o una propiedad) que planeo usar.

Por cierto, la prueba anterior es una buena prueba para los nodos DOM en todos los navegadores. Pero si desea estar seguro, siempre verifique 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 truerespectivamente. La única forma de probar los métodos es ver si están definidos.


"typeof document.body.cloneNode" devuelve "objeto" en mi IE
Dennis C

Esto parece una respuesta decente. Sin embargo, vea mi respuesta a continuación, stackoverflow.com/a/36894871/1204556
Monarch Wadia

8

Podría intentar agregarlo a un nodo DOM real ...

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

    return true;
}

11
¿Esto funciona? Sigue siendo una solución. Una creativa en eso.
Justin Meyer

3
+1 por la creatividad y certeza que ofrece. Sin embargo, si el nodo ya forma parte del DOM, ¡acaba de eliminarlo! Entonces ... esta respuesta está incompleta sin hacer el trabajo de volver a agregar el elemento al DOM si es necesario.
svidgen

44
Estoy leyendo esto después de casi 5 años, y creo que es uno de los mejores. Solo necesita ser refinado. Puede intentar agregar un clon del nodo a un elemento separado, por ejemplo. Si eso no es un objeto DOM. seguramente algo saldrá mal. Sin embargo, sigue siendo una solución bastante cara.
MaxArt

O en lugar de tratar de anexar el clon del elemento, tratando de clonar que debería ser suficiente: obj.cloneNode(false). Y no tiene efectos secundarios.
mauroc8

1
Esto es realmente costoso e innecesariamente complicado. Vea mi respuesta a continuación, stackoverflow.com/a/36894871/1204556
Monarch Wadia


6

¿Qué hay de Lo-Dash's_.isElement ?

$ npm install lodash.iselement

Y en el código:

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

1
Me gusta esta solución Es simple y funciona en Edge e IE, incluso para elementos en iframes separados, a diferencia de la mayoría de las soluciones más votadas aquí.
Elias Zamaria

Esta respuesta es útil, aunque uno necesitaría Webpack para ejecutar módulos NPM en el navegador.
Edwin Pratt

5

Esto es de la encantadora biblioteca de JavaScript MooTools :

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

12
Este código no afirma que el objeto es un elemento DOM; solo que se parece un poco a uno. Cualquier objeto puede recibir una propiedad nodeName y nodeType y satisfacer este código.
thomasrutter

Esta respuesta no detecta todos los tipos de elementos HTML. Por ejemplo, los elementos SVG no son compatibles. Vea mi respuesta a continuación.
Monarca Wadia

Realmente no funciona en todos los elementos, por ejemplo SVG. Vea mi respuesta a continuación, stackoverflow.com/a/36894871/1204556
Monarch Wadia

4

Al usar la detección de raíz que se encuentra aquí , podemos determinar si, por ejemplo, alert es un miembro de la raíz del objeto, que probablemente sea una ventana:

function isInAnyDOM(o) { 
  return (o !== null) && !!(o.ownerDocument && (o.ownerDocument.defaultView || o.ownerDocument.parentWindow).alert); // true|false
}

Para determinar si el objeto es la ventana actual es aún más simple:

function isInCurrentDOM(o) { 
  return (o !== null) && !!o.ownerDocument && (window === (o.ownerDocument.defaultView || o.ownerDocument.parentWindow)); // true|false
}

Esto parece ser menos costoso que la solución try / catch en el hilo de apertura.

Don P


Lo probé en Chrome y FF más recientes, y también en IE11, y funciona en todas partes, también para nodos de texto y objetos creados a través document.createElement()de DOM, pero no insertados. Asombroso (: Gracias
Geradlus_RU

Esto parece una respuesta decente, aunque la mía hace muchas de las mismas cosas y es menos complicada. stackoverflow.com/a/36894871/1204556
Monarch Wadia

4

hilo antiguo, pero aquí hay una posibilidad actualizada para usuarios de ie8 y ff3.5 :

function isHTMLElement(o) {
    return (o.constructor.toString().search(/\object HTML.+Element/) > -1);
}

4

Sugiero una forma simple de probar si una variable es un elemento DOM

function isDomEntity(entity) {
  if(typeof entity  === 'object' && entity.nodeType !== undefined){
     return true;
  }
  else{
     return false;
  }
}

o como HTMLGuy sugirió:

const isDomEntity = entity => {
  return typeof entity   === 'object' && entity.nodeType !== undefined
}

1
Demasiado detallado. La comparación ya devolverá un valor booleano:return typeof entity === 'object' && typeof entity.nodeType !== undefined;
HTMLGuy

1
¡Muy interesante! A veces, dependiendo de los tipos que tenga en su objectpropiedad y / o propiedad, ¡esto puede ser muy útil! Tx, @Roman
Pedro Ferreira

3
var IsPlainObject = function ( obj ) { return obj instanceof Object && ! ( obj instanceof Function || obj.toString( ) !== '[object Object]' || obj.constructor.name !== 'Object' ); },
    IsDOMObject = function ( obj ) { return obj instanceof EventTarget; },
    IsDOMElement = function ( obj ) { return obj instanceof Node; },
    IsListObject = function ( obj ) { return obj instanceof Array || obj instanceof NodeList; },

// De hecho, es más probable que use estos en línea, pero a veces es bueno tener estos atajos para el código de configuración


obj.constructor.name no funciona en IE, porque en IE, las funciones no tienen la propiedad de nombre. Reemplazar por obj.constructor! = Objeto.
mathheadinclouds

3

Esto podría ser útil: isDOM

//-----------------------------------
// Determines if the @obj parameter is a DOM element
function isDOM (obj) {
    // DOM, Level2
    if ("HTMLElement" in window) {
        return (obj && obj instanceof HTMLElement);
    }
    // Older browsers
    return !!(obj && typeof obj === "object" && obj.nodeType === 1 && obj.nodeName);
}

En el código anterior, usamos el operador de doble negación para obtener el valor booleano del objeto pasado como argumento, de esta manera nos aseguramos de que cada expresión evaluada en la declaración condicional sea booleana, aprovechando la evaluación de cortocircuito , por lo tanto, la función vuelve trueofalse


Cualquier cosa falsa debería cortocircuitar tu booleano. undefined && window.spam("should bork")nunca evalúa la spamfunción falsa , por ejemplo. Así que no hace !!falta, no lo creo. Eso, ¿puede proporcionar un caso límite [no académico] donde su uso es importante?
ruffin

Gracias por tu aclaración. Solía * !! * doble negación para convertir toda expresión de valor booleano, no Truthy o Falsy.
jherax

Bien, pero no hay una razón práctica para hacerlo, no creo, mira aquí . Y ciertamente no es necesario aprovechar la evaluación de Short-Cut aquí. Incluso si no compró el !!argumento "nunca es necesario" ( y si no lo hace, tengo curiosidad por qué no ), puede editar esa línea return !!(obj && typeof obj === "object" && obj.nodeType === 1 && obj.nodeName);y hacer que funcione igual.
Ruffin

Eso fue lo que hice;) más limpio y el mismo efecto. gracias.
jherax

2

Puede ver si el objeto o nodo en cuestión devuelve un tipo de cadena.

typeof (array).innerHTML === "string" => false
typeof (object).innerHTML === "string" => false
typeof (number).innerHTML === "string" => false
typeof (text).innerHTML === "string" => false

//any DOM element will test as true
typeof (HTML object).innerHTML === "string" => true
typeof (document.createElement('anything')).innerHTML === "string" => true

3
typeof ({innerHTML: ""}).innerHTML === "string"
Qtax

¡CALIENTE! Esta respuesta debería ser el ganador del juego. if (typeof obj.innerHTML! == 'string') // no es un elemento dom.
user3751385

1
Inicialmente reaccioné contra la crítica de @Qtax y thomasrutter en una respuesta anterior , pero estoy empezando a comprarlo. Aunque no me he encontrado con perros graznando como patos exactamente así antes, puedo ver a alguien que no comprueba si algo es un nodo, corriendo notANode.innerHTML = "<b>Whoops</b>";, y luego que ese código pase su obj contaminado a este código. Código defensivo === mejor código, todas las demás cosas iguales, y esto finalmente no es defensivo
ruffin


2

Creo que la creación de prototipos no es una muy buena solución, pero tal vez esta sea la más rápida: defina este bloque de código;

Element.prototype.isDomElement = true;
HTMLElement.prototype.isDomElement = true;

que compruebe sus objetos propiedad isDomElement:

if(a.isDomElement){}

Espero que esto ayude.


1
1) cambiar objetos que no son de su propiedad no es aconsejable. 2) esto no detecta elementos que no son parte del mismo documento.
fregante

2

De acuerdo con mdn

Elementes la clase base más general de la que todos los objetos de una Documentherencia. Solo tiene métodos y propiedades comunes a todo tipo de elementos.

Podemos implementar isElementpor prototipo. Aquí está mi consejo:

/**
 * @description detect if obj is an element
 * @param {*} obj
 * @returns {Boolean}
 * @example
 * see below
 */
function isElement(obj) {
  if (typeof obj !== 'object') {
    return false
  }
  let prototypeStr, prototype
  do {
    prototype = Object.getPrototypeOf(obj)
    // to work in iframe
    prototypeStr = Object.prototype.toString.call(prototype)
    // '[object Document]' is used to detect document
    if (
      prototypeStr === '[object Element]' ||
      prototypeStr === '[object Document]'
    ) {
      return true
    }
    obj = prototype
    // null is the terminal of object
  } while (prototype !== null)
  return false
}
console.log(isElement(document)) // true
console.log(isElement(document.documentElement)) // true
console.log(isElement(document.body)) // true
console.log(isElement(document.getElementsByTagName('svg')[0])) // true or false, decided by whether there is svg element
console.log(isElement(document.getElementsByTagName('svg'))) // false
console.log(isElement(document.createDocumentFragment())) // false


1

Creo que lo que tiene que hacer es hacer un control minucioso de algunas propiedades que siempre estarán en un elemento DOM, pero su combinación no más probable estar en otro objeto, de este modo:

var isDom = function (inp) {
    return inp && inp.tagName && inp.nodeName && inp.ownerDocument && inp.removeAttribute;
};

1

En Firefox, puedes usar el instanceof Node. Eso Nodese define en DOM1 .

Pero eso no es tan fácil en IE.

  1. "instanceof ActiveXObject" solo puede decir que es un objeto nativo.
  2. "typeof document.body.appendChild == 'object'" indica que puede ser un objeto DOM, pero también puede ser algo que tenga la misma función.

Solo puede asegurarse de que sea un elemento DOM utilizando la función DOM y capturar si hay alguna excepción. Sin embargo, puede tener efectos secundarios (por ejemplo, cambiar el estado interno del objeto / rendimiento / pérdida de memoria)


1

Tal vez esta es una alternativa? Probado en Opera 11, FireFox 6, Internet Explorer 8, Safari 5 y Google Chrome 16.

function isDOMNode(v) {
  if ( v===null ) return false;
  if ( typeof v!=='object' ) return false;
  if ( !('nodeName' in v) ) return false; 

  var nn = v.nodeName;
  try {
    // DOM node property nodeName is readonly.
    // Most browsers throws an error...
    v.nodeName = 'is readonly?';
  } catch (e) {
    // ... indicating v is a DOM node ...
    return true;
  }
  // ...but others silently ignore the attempt to set the nodeName.
  if ( v.nodeName===nn ) return true;
  // Property nodeName set (and reset) - v is not a DOM node.
  v.nodeName = nn;

  return false;
}

La función no se dejará engañar, por ejemplo, esto

isDOMNode( {'nodeName':'fake'} ); // returns false

2
Buen intento, pero el manejo de excepciones es un costo demasiado costoso si se puede evitar. Además, ES5 le permite definir propiedades de solo lectura para los objetos.
Andy E

1

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")).constructorestá undefineden IE7.

El problema con este enfoque es que document.createElementrealmente 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 ElementConstructorstiene 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 nodeTypepropiedad establecida en 1y 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.


1

Prueba si objhereda del nodo .

if (obj instanceof Node){
    // obj is a DOM Object
}

Node es una interfaz básica de la que heredan HTMLElement y Text.


1

diferenciar un objeto js sin formato de un elemento HTMLE

function isDOM (x){
     return /HTML/.test( {}.toString.call(x) );
 }

utilizar:

isDOM( {a:1} ) // false
isDOM( document.body ) // true

// O

Object.defineProperty(Object.prototype, "is",
    {
        value: function (x) {
            return {}.toString.call(this).indexOf(x) >= 0;
        }
    });

utilizar:

o={}; o.is("HTML") // false o=document.body; o.is("HTML") // true


0

aquí hay un truco usando jQuery

var obj = {};
var element = document.getElementById('myId'); // or simply $("#myId")

$(obj).html() == undefined // true
$(element).html() == undefined // false

poniéndolo en una función:

function isElement(obj){

   return (typeOf obj === 'object' && !($(obj).html() == undefined));

}

2
jQuery lo está haciendo internamente, elem.nodeType === 1¿por qué no guardar la sobrecarga de la llamada y la dependencia de jQuery y hacer que su función isElement lo haga por sí misma?
Joseph Lennox

Es 2016, solo di "no".
Thomas McCabe

0

No para forzar esto o cualquier cosa, sino para los navegadores compatibles con ES5, ¿por qué no simplemente:

function isDOM(e) {
  return (/HTML(?:.*)Element/).test(Object.prototype.toString.call(e).slice(8, -1));
}

No funcionará en TextNodes y no está seguro sobre Shadow DOM o DocumentFragments etc, pero se trabajará en casi todos los elementos de etiquetas HTML.


0

Esto funcionará para casi cualquier navegador. (No hay distinción entre elementos y nodos aquí)

function dom_element_check(element){
    if (typeof element.nodeType !== 'undefined'){
        return true;
    }
    return false;
}

En primer lugar, no necesita devolver verdadero o falso, solo devuelva la instrucción if. En segundo lugar, esto será verdadero para {nodeType: 1}
bluejayke

0

Un método absolutamente correcto, el objetivo de verificación es un código primario de elemento html real :

    (function (scope) {
        if (!scope.window) {//May not run in window scope
            return;
        }
        var HTMLElement = window.HTMLElement || window.Element|| function() {};

        var tempDiv = document.createElement("div");
        var isChildOf = function(target, parent) {

            if (!target) {
                return false;
            }
            if (parent == null) {
                parent = document.body;
            }
            if (target === parent) {
                return true;
            }
            var newParent = target.parentNode || target.parentElement;
            if (!newParent) {
                return false;
            }
            return isChildOf(newParent, parent);
        }
        /**
         * The dom helper
         */
        var Dom = {
            /**
             * Detect if target element is child element of parent
             * @param {} target The target html node
             * @param {} parent The the parent to check
             * @returns {} 
             */
            IsChildOf: function (target, parent) {
                return isChildOf(target, parent);
            },
            /**
             * Detect target is html element
             * @param {} target The target to check
             * @returns {} True if target is html node
             */
            IsHtmlElement: function (target) {
                if (!X.Dom.IsHtmlNode(target)) {
                    return false;
                }
                return target.nodeType === 1;
            },
            /**
             * Detect target is html node
             * @param {} target The target to check
             * @returns {} True if target is html node
             */
            IsHtmlNode:function(target) {
                if (target instanceof HTMLElement) {
                    return true;
                }
                if (target != null) {
                    if (isChildOf(target, document.documentElement)) {
                        return true;
                    }
                    try {
                        tempDiv.appendChild(target.cloneNode(false));
                        if (tempDiv.childNodes.length > 0) {
                            tempDiv.innerHTML = "";
                            return true;
                        }
                    } catch (e) {

                    }
                }
                return false;
            }
        };
        X.Dom = Dom;
    })(this);

Prueba en IE 5


0

Cada DOMElement.constructor devuelve la función HTML ... Element () u [Object HTML ... Element] así que ...

function isDOM(getElem){
    if(getElem===null||typeof getElem==="undefined") return false;
    var c = getElem.constructor.toString();
    var html = c.search("HTML")!==-1;
    var element = c.search("Element")!==-1;
    return html&&element;
}

0

Tengo una forma especial de hacer esto que aún no se ha mencionado en las respuestas.

Mi solución se basa en cuatro pruebas. Si el objeto pasa los cuatro, entonces es un elemento:

  1. El objeto no es nulo.

  2. El objeto tiene un método llamado "appendChild".

  3. El método "appendChild" fue heredado de la clase Node , y no es solo un método impostor (una propiedad creada por el usuario con un nombre idéntico).

  4. El objeto es de Nodo Tipo 1 (Elemento). Los objetos que heredan métodos de la clase Node son siempre nodos, pero no necesariamente elementos.

P: ¿Cómo verifico si una propiedad determinada se hereda y no es solo un impostor?

R: Una prueba simple para ver si un método fue realmente heredado de Node es verificar primero que la propiedad tenga un tipo de "objeto" o "función". Luego, convierta la propiedad en una cadena y verifique si el resultado contiene el texto "[Código nativo]". Si el resultado se parece a esto:

function appendChild(){
[Native Code]
}

Entonces el método ha sido heredado del objeto Node. Ver https://davidwalsh.name/detect-native-function

Y finalmente, uniendo todas las pruebas, la solución es:

function ObjectIsElement(obj) {
    var IsElem = true;
    if (obj == null) {
        IsElem = false;
    } else if (typeof(obj.appendChild) != "object" && typeof(obj.appendChild) != "function") {
        //IE8 and below returns "object" when getting the type of a function, IE9+ returns "function"
        IsElem = false;
    } else if ((obj.appendChild + '').replace(/[\r\n\t\b\f\v\xC2\xA0\x00-\x1F\x7F-\x9F ]/ig, '').search(/\{\[NativeCode]}$/i) == -1) {
        IsElem = false;
    } else if (obj.nodeType != 1) {
        IsElem = false;
    }
    return IsElem;
}

0
(element instanceof $ && element.get(0) instanceof Element) || element instanceof Element

Esto verificará incluso si es un elemento DOM de jQuery o JavaScript


0

La única forma de garantizar que está comprobando un elemento HTMLE real, y no solo un objeto con las mismas propiedades que un elemento HTML, es determinar si hereda del nodo, ya que es imposible crear un nuevo nodo () en JavaScript. (a menos que se sobrescriba la función Node nativa, pero no tendrá suerte). Entonces:

function isHTML(obj) {
    return obj instanceof Node;
}

console.log(
  isHTML(test),
  isHTML(ok),
  isHTML(p),
  isHTML(o),
  isHTML({
    constructor: {
      name: "HTML"
    }
  }),
  isHTML({
    __proto__: {
      __proto__: {
        __proto__: {
          __proto__: {
            constructor: {
              constructor: { 
                name: "Function"
                
              },
              name: "Node"
            }
          }
        }
      }
    }
  }),
)
<div id=test></div>
<blockquote id="ok"></blockquote>
<p id=p></p>
<br id=o>
<!--think of anything else you want--!>

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.