Como você verifica se um objeto JavaScript é um objeto DOM?

247

Estou tentando obter:

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

Nos meus próprios scripts, eu costumava usar isso, pois nunca precisava tagNamecomo uma propriedade:

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

Portanto, para o segundo objeto, criei o seguinte como uma solução rápida - que geralmente funciona. ;)

O problema é que depende dos navegadores que aplicam as propriedades somente leitura, o que nem todos fazem.

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 um bom substituto?

Jonathan Lonowski
fonte
3
Estou sendo indeciso em saber se um "Objeto DOM" não deve abranger não apenas elementos, mas também todos os nós (nós de texto, atributos, etc.)? Todas as respostas e da maneira que você colocou a questão tendem a sugerir esta questão é especificamente sobre Elements ...
mike roedor

Respostas:

300

Isso pode ser do seu interesse:

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

Faz parte do DOM, Nível2 .

Atualização 2 : Foi assim que eu o implementei na minha própria biblioteca: (o código anterior não funcionou no Chrome, porque Node e HTMLElement são funções em vez do objeto esperado. Este código é testado no FF3, IE7, Chrome 1 e 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"
);
}
alguns
fonte
11
Vale a pena notar que isso não funcionará em elementos que pertencem a outras janelas / quadros. Tipagem pato é a abordagem recomendada
Andy E
2
Você pode enganá-lo com:function Fake() {}; Fake.prototype=document.createElement("div"); alert(new Fake() instanceof HTMLElement);
Kernel James
11
Fato da WTF: Firefox 5 e versões anteriores retornam truepara [] instanceof HTMLElement.
Rob W
6
Btw, HTMLElementé sempre um function, por isso typeofo expulsará da pista e executará a segunda parte da declaração. Você pode tentar, se desejar instanceof Object, porque a função será uma instância de Object, ou apenas verificar explicitamente typeof === "function", porque Nodee HTMLElementsão ambas funções de objeto nativas.
Roland
2
Quando você liga isElement(0), retorna 0, não falso ... Por que isso e como posso impedir isso?
Jessica
68

O código super-simples compatível com o IE8 a seguir funciona perfeitamente.

A resposta aceita não detecta todos os tipos de elementos HTML. Por exemplo, elementos SVG não são suportados. Por outro lado, esta resposta funciona tanto para HTML quanto para SVG.

Veja em ação aqui: https://jsfiddle.net/eLuhbu6r/

function isElement(element) {
    return element instanceof Element || element instanceof HTMLDocument;  
}
Monarch Wadia
fonte
3
'Element' é indefinido no IE7
Dan
49
Sou da opinião de que quem ainda usa o IE7 deve gastar cinco segundos para fazer o download de um navegador melhor, em vez de investir em dias ou semanas contornando sua recusa em acompanhar os tempos.
Mopsyd
1
Concordo com o @mopsyd, mas o autor da resposta declara que ele funciona no IE7, que pode precisar ser atualizado por uma questão de correção.
Lajos Meszaros
1
Atualizado para dizer IE9. Não tenho certeza se o IE8 suporta isso.
Monarch Wadia
1
@ MonarchWadia sim, é suportado no IE8. Mas observe que isso não retorna true para o documentelemento (em todos os navegadores). se você precisar, você deve tentar:x instanceof Element || x instanceof HTMLDocument
S.Serpooshan
11

Todas as soluções acima e abaixo (incluindo minha solução) sofrem da possibilidade de estar incorretas, especialmente no IE - é bem possível (re) definir alguns objetos / métodos / propriedades para imitar um nó DOM, tornando o teste inválido.

Geralmente, eu uso o teste de digitação no estilo pato: teste especificamente para as coisas que uso. Por exemplo, se eu quiser clonar um nó, testo-o assim:

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

Basicamente, é uma pequena verificação de sanidade + o teste direto de um método (ou propriedade) que estou planejando usar.

Aliás, o teste acima é um bom teste para nós DOM em todos os navegadores. Mas se você quer estar do lado seguro, verifique sempre a presença de métodos e propriedades e verifique seus tipos.

EDIT: O IE usa objetos ActiveX para representar nós, portanto, suas propriedades não se comportam como objetos JavaScript verdadeiros, por exemplo:

console.log(typeof node.cloneNode);              // object
console.log(node.cloneNode instanceof Function); // false

enquanto deve retornar "function" e truerespectivamente. A única maneira de testar métodos é ver se eles estão definidos.

Eugene Lazutkin
fonte
"typeof document.body.cloneNode" retorna "objeto" no meu IE #
Dennis C
Parece uma resposta decente. Veja minha resposta abaixo, porém, stackoverflow.com/a/36894871/1204556
Monarch Wadia
8

Você pode tentar anexá-lo a um nó DOM real ...

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

    return true;
}
Greg
fonte
11
Isto funciona? Ainda é uma solução. Um criativo nisso.
11557 Justin Meyer
3
+1 pela criatividade e certeza que isso oferece. No entanto, se o nó já faz parte do DOM, você acabou de removê-lo! Então ... essa resposta está incompleta sem fazer o trabalho de adicionar novamente o elemento ao DOM, se necessário.
svidgen
4
Estou lendo isso depois de quase 5 anos e acho que é um dos mais legais. Ele só precisa ser refinado. Você pode tentar anexar um clone do nó a um elemento desanexado, por exemplo. Se esse não é um objeto DOM. algo certamente vai dar errado. Ainda é uma solução bastante cara, no entanto.
MaxArt
Ou em vez de tentar anexar o clone do elemento, apenas tentando clonar ele deve ser suficiente: obj.cloneNode(false). E não tem efeitos colaterais.
mauroc8
1
Isso é realmente caro e desnecessariamente complicado. Veja minha resposta abaixo, stackoverflow.com/a/36894871/1204556
Monarch Wadia
7

Não há necessidade de hacks, basta perguntar se um elemento é uma instância do elemento DOM :

const isDOM = el => el instanceof Element
Damjan Pavlica
fonte
1
Brilhante! Trabalho!
Pedro Ferreira
6

E os Lo-Dash's_.isElement ?

$ npm install lodash.iselement

E no código:

var isElement = require("lodash.iselement");
isElement(document.body);
mightyiam
fonte
1
Eu gosto desta solução. É simples e funciona no Edge e no IE, mesmo para elementos em iframes separados, ao contrário da maioria das soluções mais votadas aqui.
Elias Zamaria
Esta resposta é útil, embora seja necessário o Webpack para executar os módulos NPM no navegador.
Edwin Pratt
5

Isso é da adorável biblioteca JavaScript MooTools :

if (obj.nodeName){
    switch (obj.nodeType){
    case 1: return 'element';
    case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
    }
}
finpingvin
fonte
12
Este código não afirma que o objeto é um elemento DOM; só que parece um pouco com um. Qualquer objeto pode receber uma propriedade nodeName e nodeType e satisfazer esse código.
thomasrutter
Esta resposta não detecta todos os tipos de elementos HTML. Por exemplo, elementos SVG não são suportados. Veja minha resposta abaixo.
Monarch Wadia
Realmente não funciona em todos os elementos, por exemplo, SVG. Veja minha resposta abaixo, stackoverflow.com/a/36894871/1204556
Monarch Wadia
4

Usando a detecção de raiz encontrada aqui , podemos determinar se, por exemplo, o alerta é um membro da raiz do objeto, que provavelmente será uma janela:

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

Para determinar se o objeto é a janela atual é ainda mais simples:

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

Isso parece ser mais barato que a solução try / catch no thread de abertura.

Don P

Don P
fonte
Eu testei isso no Chrome e no FF mais recentes, e também no IE11, e funciona em qualquer lugar, também para nós de texto e objetos criados via document.createElement()mas também não inseridos no DOM. Incrível (: Obrigado
Geradlus_RU 7/16/16
Parece uma resposta decente, embora o meu faça muitas coisas iguais e seja menos complicado. stackoverflow.com/a/36894871/1204556
Monarch Wadia
4

thread antigo, mas aqui está uma possibilidade atualizada para os usuários ie8 e ff3.5 :

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

Sugiro uma maneira simples de testar se uma variável é um elemento DOM

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

ou como HTMLGuy sugeriu:

const isDomEntity = entity => {
  return typeof entity   === 'object' && entity.nodeType !== undefined
}
romano
fonte
1
Muito detalhado. A comparação já retornará um valor booleano:return typeof entity === 'object' && typeof entity.nodeType !== undefined;
HTMLGuy
1
Muito interessante! Às vezes, dependendo dos tipos que você possui em suas propriedades objecte / ou propriedades, isso pode ser muito ú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; },

// Na verdade, é mais provável que eu use esses inline, mas às vezes é bom ter esses atalhos para o código de instalação

Erich Horn
fonte
obj.constructor.name não funciona no IE, porque no IE, as funções não têm a propriedade name. Substitua por obj.constructor! = Object.
mathheadinclouds
3

Isso pode 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);
}

No código acima, usamos o operador de negação dupla para obter o valor booleano do objeto passado como argumento, dessa forma garantimos que cada expressão avaliada na instrução condicional seja booleana, aproveitando a Avaliação de Curto-Circuito , portanto a função retornos trueoufalse

jherax
fonte
Qualquer coisa falsa deve causar um curto-circuito no seu booleano. undefined && window.spam("should bork")nunca avalia a spamfunção falsa , por exemplo. Então não é !!necessário, eu não acredito. Você pode fornecer um caso de borda [não acadêmico] em que seu uso é importante?
Ruffin
Obrigado pela sua declaração. Eu usei * !! * dupla negação para converter toda expressão em valor booleano, não verdadeiro ou falso.
jherax
Certo, mas não há razão prática para fazê-lo, eu acho - veja aqui . E certamente não é necessário tirar proveito da avaliação de atalho aqui. Mesmo se você não comprou o !!argumento "nunca é necessário" ( e, se não compra , estou curioso por que não ), você pode editar essa linha return !!(obj && typeof obj === "object" && obj.nodeType === 1 && obj.nodeName);e fazê-la funcionar da mesma maneira.
Ruffin
Foi o que eu fiz;) mais limpo e com o mesmo efeito. obrigado.
jherax
2

Você pode ver se o objeto ou nó em questão retorna um tipo de sequência.

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
timewaster51
fonte
3
typeof ({innerHTML: ""}).innerHTML === "string"
Qtax
QUENTE! Esta resposta deve ser o vencedor do jogo. if (typeof obj.innerHTML! == 'string') // não é um elemento dom.
user3751385
1
Inicialmente, reagi contra a crítica de @Qtax e thomasrutter em uma resposta anterior , mas estou começando a comprá-la. Embora eu nunca tenha encontrado cachorros grasnando como patos exatamente assim antes, posso ver alguém não verificando se algo está com um nó em execução e notANode.innerHTML = "<b>Whoops</b>";, mais tarde, fazendo com que esse código passe seu objeto contaminado para esse código. Código defensivo === melhor código, todas as outras coisas iguais, e isso não é defensivo.
Ruffin
2

Acho que a prototipagem não é uma solução muito boa, mas talvez seja a mais rápida: defina esse bloco de código;

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

do que verificar sua propriedade isDomElement dos objetos:

if(a.isDomElement){}

Eu espero que isso ajude.

Doğuş Atasoy
fonte
1
1) mudar objetos que você não possui não é aconselhável. 2) isso não detecta elementos que não fazem parte do mesmo documento.
Fregante 30/10
2

De acordo com mdn

Elementé a classe base mais geral da qual todos os objetos em uma Documentherança. Ele possui apenas métodos e propriedades comuns a todos os tipos de elementos.

Nós podemos implementar isElementpor protótipo. Aqui está o meu conselho:

/**
 * @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

xianshenglu
fonte
1

Eu acho que o que você tem a fazer é fazer uma verificação completa de algumas propriedades que estarão sempre em um elemento DOM, mas sua combinação não irá provavelmente estar em outro objeto, assim:

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

No Firefox, você pode usar o instanceof Node. Isso Nodeé definido no DOM1 .

Mas isso não é tão fácil no IE.

  1. "instanceof ActiveXObject" apenas pode dizer que é um objeto nativo.
  2. "typeof document.body.appendChild == 'object'" "diz que pode ser um objeto DOM, mas também pode ser algo que tenha a mesma função.

Você só pode garantir que seja o elemento DOM usando a função DOM e capturar se houver alguma exceção. No entanto, pode ter efeito colateral (por exemplo, alterar estado interno do objeto / desempenho / vazamento de memória)

Dennis C
fonte
1

Talvez isso seja uma alternativa? Testado no Opera 11, FireFox 6, Internet Explorer 8, Safari 5 e 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;
}

A função não será enganada, por exemplo, por

isDOMNode( {'nodeName':'fake'} ); // returns false
Snoozer Man
fonte
2
Boa tentativa, mas o tratamento de exceções é um custo muito caro, se puder ser evitado. Além disso, o ES5 permite definir propriedades somente leitura para objetos.
Andy E
1

Isto é o que eu descobri:

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 melhorar o desempenho, criei uma função auto-invocadora que testa os recursos do navegador apenas uma vez e atribui a função apropriada de acordo.

O primeiro teste deve funcionar nos navegadores mais modernos e já foi discutido aqui. Apenas testa se o elemento é uma instância de HTMLElement. Muito simples.

O segundo é o mais interessante. Esta é sua principal funcionalidade:

return el instanceof (document.createElement(el.nodeName)).constructor

Ele testa se el é uma instância do construtor que finge ser. Para fazer isso, precisamos acessar o contratador de um elemento. É por isso que estamos testando isso na instrução if. O IE7, por exemplo, falha com isso, porque (document.createElement("a")).constructorestá undefinedno IE7.

O problema com essa abordagem é que ela document.createElementrealmente não é a função mais rápida e pode desacelerar facilmente seu aplicativo se você estiver testando vários elementos com ele. Para resolver isso, decidi armazenar em cache os construtores. O objeto ElementConstructorspossui nodeNames como chaves e seus construtores correspondentes como valores. Se um construtor já estiver armazenado em cache, ele o usará do cache; caso contrário, ele criará o Elemento, armazenará em cache seu construtor para acesso futuro e, em seguida, testará contra ele.

O terceiro teste é o fallback desagradável. Ele testa se el é um object, tem uma nodeTypepropriedade definida como 1e uma sequência como nodeName. Isso não é muito confiável, é claro, mas a grande maioria dos usuários nem deveria voltar tão longe.

Essa é a abordagem mais confiável que eu criei, mantendo o desempenho o mais alto possível.

Oliver Sartun
fonte
1

Teste se objherda do .

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

O nó é uma interface básica da qual HTMLElement e Text herdam.

soslan
fonte
1

diferenciar um objeto js bruto de um HTMLElement

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

usar:

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

// OR

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

usar:

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

Bortunac
fonte
0

aqui está um truque usando jQuery

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

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

colocando-o em uma função:

function isElement(obj){

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

}
Matus
fonte
2
O jQuery está fazendo elem.nodeType === 1isso internamente, por que não salvar a sobrecarga de chamada e a dependência do jQuery e sua função isElement faz isso sozinha?
Joseph Lennox
É 2016, basta dizer "não".
Thomas McCabe
0

Para não se preocupar com isso ou qualquer outra coisa, mas para navegadores compatíveis com ES5, por que não apenas:

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

Não funcionará em TextNodes e não tem certeza sobre Sombra DOM ou DocumentFragments etc. mas irá funcionar em quase todos os elementos de tag HTML.

Travis Kaufman
fonte
0

Isso funcionará para quase qualquer navegador. (Nenhuma distinção entre elementos e nós aqui)

function dom_element_check(element){
    if (typeof element.nodeType !== 'undefined'){
        return true;
    }
    return false;
}
Zv_oDD
fonte
Em primeiro lugar, você não precisa retornar verdadeiro ou falso, basta retornar a instrução if. Segundo, isso retornará verdadeiro para {nodeType: 1}
bluejayke
0

Um método absolutamente certo, o destino da verificação é um código primário do 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);

Teste no IE 5

dexiang
fonte
0

Cada DOMElement.constructor retorna a função HTML ... Element () ou [Object HTML ... Element] então ...

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;
}
Paweł
fonte
0

Eu tenho uma maneira especial de fazer isso que ainda não foi mencionada nas respostas.

Minha solução é baseada em quatro testes. Se o objeto passar pelos quatro, será um elemento:

  1. O objeto não é nulo.

  2. O objeto possui um método chamado "appendChild".

  3. O método "appendChild" foi herdado da classe Node e não é apenas um método impostor (uma propriedade criada pelo usuário com um nome idêntico).

  4. O objeto é do Nó Tipo 1 (Elemento). Os objetos que herdam métodos da classe Node são sempre nós, mas não necessariamente elementos.

P: Como verifico se uma determinada propriedade é herdada e não é apenas um impostor?

R: Um teste simples para verificar se um método foi realmente herdado do Node é primeiro verificar se a propriedade possui um tipo de "objeto" ou "função". Em seguida, converta a propriedade em uma sequência e verifique se o resultado contém o texto "[Código Nativo]". Se o resultado for algo parecido com isto:

function appendChild(){
[Native Code]
}

Em seguida, o método foi herdado do objeto Node. Consulte https://davidwalsh.name/detect-native-function

E, finalmente, reunindo todos os testes, a solução é:

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;
}
user3163495
fonte
0
(element instanceof $ && element.get(0) instanceof Element) || element instanceof Element

Isso verificará se é um elemento DOM jQuery ou JavaScript

Arjun Kakkar
fonte
0

A única maneira de garantir que você está verificando um HTMLEement real, e não apenas um objeto com as mesmas propriedades que um Elemento HTML, é determinar se ele é herdado do Node, pois é impossível criar um novo Node () no JavaScript. (a menos que a função Nó nativa seja substituída, mas você não terá sorte). Assim:

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--!>

bluejayke
fonte