J'essaie d'obtenir:
document.createElement('div') //=> true
{tagName: 'foobar something'} //=> false
Dans mes propres scripts, je l'utilisais simplement car je n'avais jamais besoin de tagName
comme propriété:
if (!object.tagName) throw ...;
Donc, pour le deuxième objet, j'ai proposé ce qui suit comme solution rapide - ce qui fonctionne généralement. ;)
Le problème est que cela dépend des navigateurs qui appliquent des propriétés en lecture seule, ce que tous ne font pas.
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;
}
}
Y a-t-il un bon substitut?
Cela pourrait être intéressant:
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");
}
}
Cela fait partie du DOM, Level2 .
Update 2: Voici comment je l'ai implémenté dans ma propre bibliothèque: (Le code précédent ne fonctionnait pas dans Chrome, car Node et HTMLElement sont des fonctions et non l'objet attendu. Ce code est testé dans FF3. , IE7, Chrome 1 et 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"
);
}
Le code suivant, super simple, compatible IE8, fonctionne parfaitement.
Le réponse acceptée ne détecte pas tous les types d'éléments HTML. Par exemple, les éléments SVG ne sont pas supportés. En revanche, cette réponse fonctionne bien pour HTML comme SVG.
Voir en action ici: https://jsfiddle.net/eLuhbu6r/
function isElement(element) {
return element instanceof Element || element instanceof HTMLDocument;
}
Toutes les solutions ci-dessus et ci-dessous (ma solution y compris) risquent d'être incorrectes, en particulier sur IE - il est tout à fait possible de (re) définir certains objets/méthodes/propriétés pour imiter un nœud DOM rendant le test invalide.
Donc, d'habitude, j'utilise le test de style de frappe de canard: je teste spécifiquement les éléments que j'utilise. Par exemple, si je veux cloner un nœud, je le teste comme suit:
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);
}
Fondamentalement, il s’agit d’un petit test de contrôle et du test direct d’une méthode (ou d’une propriété) que je prévois d’utiliser.
Incidemment, le test ci-dessus est un bon test pour les nœuds DOM sur tous les navigateurs. Mais si vous voulez être du bon côté, vérifiez toujours la présence de méthodes et de propriétés, ainsi que leurs types.
EDIT: IE utilise des objets ActiveX pour représenter les nœuds. Par conséquent, leurs propriétés ne se comportent pas comme de vrais objets JavaScript, par exemple:
console.log(typeof node.cloneNode); // object
console.log(node.cloneNode instanceof Function); // false
alors qu'il devrait renvoyer "fonction" et true
respectivement. La seule façon de tester les méthodes est de voir si elles sont définies.
Vous pouvez essayer de l'ajouter à un véritable nœud DOM ...
function isDom(obj)
{
var Elm = document.createElement('div');
try
{
Elm.appendChild(obj);
}
catch (e)
{
return false;
}
return true;
}
Que diriez-vous de Le _.isElement
de Lo-Dash?
$ npm install lodash.iselement
Et dans le code:
var isElement = require("lodash.iselement");
isElement(document.body);
Ceci est extrait de la jolie bibliothèque JavaScript MooTools :
if (obj.nodeName){
switch (obj.nodeType){
case 1: return 'element';
case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
}
}
ancien fil, mais voici une possibilité mise à jour pour ie8 et ff3.5 users:
function isHTMLElement(o) {
return (o.constructor.toString().search(/\object HTML.+Element/) > -1);
}
En utilisant la détection de racine trouvée ici , nous pouvons déterminer si par ex. alert est un membre de la racine de l'objet, qui sera alors probablement une fenêtre:
function isInAnyDOM(o) {
return (o !== null) && !!(o.ownerDocument && (o.ownerDocument.defaultView || o.ownerDocument.parentWindow).alert); // true|false
}
Pour déterminer si l'objet est la fenêtre en cours, c'est encore plus simple:
function isInCurrentDOM(o) {
return (o !== null) && !!o.ownerDocument && (window === (o.ownerDocument.defaultView || o.ownerDocument.parentWindow)); // true|false
}
Cela semble être moins coûteux que la solution try/catch dans le thread d'ouverture.
Don P
Cela pourrait être utile: 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);
}
Dans le code ci-dessus, nous utilisons l'opérateur double negation pour obtenir la valeur booléenne de l'objet passé en argument. Ainsi, nous nous assurons que chaque expression évaluée dans l'instruction conditionnelle soit booléenne, en tirant parti du . Évaluation de court-circuit, ainsi la fonction retourne true
ou false
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; },
// En fait, je suis plus susceptible de les utiliser en ligne, mais il est parfois utile d'avoir ces raccourcis pour le code d'installation
Je suggère un moyen simple de tester si une variable est un élément DOM
function isDomEntity(entity) {
if( typeof entity === 'object' && entity.nodeType != undefined){
return true;
}
else{
return false;
}
}
Pas besoin de hacks, vous pouvez simplement demander si un élément est une instance de Element :
const isElement = el => el instanceof Element
Pour ceux qui utilisent Angular:
angular.isElement
https://docs.angularjs.org/api/ng/function/angular.isElement
Vous pouvez voir si l'objet ou le noeud en question renvoie un type de chaîne.
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
différencier un objet js brut d'un HTMLElement
function isDOM (x){
return /HTML/.test( {}.toString.call(x) );
}
utilisation:
isDOM( {a:1} ) // false
isDOM( document.body ) // true
// OU
Object.defineProperty(Object.prototype, "is",
{
value: function (x) {
return {}.toString.call(this).indexOf(x) >= 0;
}
});
utilisation:
o={}; o.is("HTML") // false
o=document.body; o.is("HTML") // true
Dans Firefox, vous pouvez utiliser le instanceof Node
. Cette Node
est définie dans DOM1 .
Mais ce n'est pas si facile dans IE.
Vous pouvez uniquement vous assurer qu'il s'agit d'un élément DOM en utilisant la fonction DOM et en captant une exception éventuelle. Cependant, cela peut avoir un effet secondaire (par exemple, changer l’état/la performance/la fuite de mémoire interne de l’objet).
C'est ce que j'ai compris:
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";
}
}
})();
Pour améliorer les performances, j'ai créé une fonction d'invocation automatique qui teste les fonctionnalités du navigateur une seule fois et attribue la fonction appropriée en conséquence.
Le premier test devrait fonctionner dans la plupart des navigateurs modernes et a déjà été discuté ici. Il vérifie simplement si l'élément est une instance de HTMLElement
. Très simple.
Le second est le plus intéressant. Voici sa fonctionnalité principale:
return el instanceof (document.createElement(el.nodeName)).constructor
Il teste si el est une instance du constructeur qu'il prétend être. Pour ce faire, nous devons avoir accès au constructeur de l'élément. C'est pourquoi nous testons cela dans la déclaration if. IE7, par exemple, échoue, car (document.createElement("a")).constructor
est undefined
dans IE7.
Le problème avec cette approche est que document.createElement
n’est vraiment pas la fonction la plus rapide et peut facilement ralentir votre application si vous testez beaucoup d’éléments avec. Pour résoudre ce problème, j'ai décidé de mettre en cache les constructeurs. L'objet ElementConstructors
a nodeNames en tant que clés avec les constructeurs correspondants en tant que valeurs. Si un constructeur est déjà mis en cache, il l'utilise à partir du cache. Dans le cas contraire, il crée l'élément, met en cache son constructeur pour un accès ultérieur, puis le teste.
Le troisième test est le repli désagréable. Il teste si el est un object
, a une propriété nodeType
définie sur 1
et une chaîne en tant que nodeName
. Bien sûr, ce n’est pas très fiable, mais la grande majorité des utilisateurs ne devrait même pas reculer jusqu’à présent.
C’est l’approche la plus fiable que j’ai proposée tout en maintenant des performances aussi élevées que possible.
C'est peut-être une alternative? Testé sous Opera 11, FireFox 6, Internet Explorer 8, Safari 5 et 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 fonction ne sera pas dupe par exemple ce
isDOMNode( {'nodeName':'fake'} ); // returns false
Je pense que le prototypage n’est pas une très bonne solution mais c’est peut-être la plus rapide: Définissez ce bloc de code;
Element.prototype.isDomElement = true;
HTMLElement.prototype.isDomElement = true;
vérifiez que la propriété isDomElement de vos objets:
if(a.isDomElement){}
J'espère que ça aide.
Cela fonctionnera pour presque tous les navigateurs. (Pas de distinction entre les éléments et les nœuds ici)
function dom_element_check(element){
if (typeof element.nodeType !== 'undefined'){
return true;
}
return false;
}
Je pense que ce que vous devez faire est de vérifier minutieusement certaines propriétés qui seront toujours dans un élément dom, mais leur combinaison ne sera probablement pas dans un autre objet, comme ceci:
var isDom = function (inp) {
return inp && inp.tagName && inp.nodeName && inp.ownerDocument && inp.removeAttribute;
};
Ne pas marteler sur ce sujet ou quoi que ce soit, sauf pour les navigateurs compatibles ES5, pourquoi ne pas simplement:
function isDOM(e) {
return (/HTML(?:.*)Element/).test(Object.prototype.toString.call(e).slice(8, -1));
}
Ne fonctionnera pas sur les TextNodes et ne suis pas sûr du Shadow DOM ou du DocumentFragments, etc., mais will fonctionnera sur presque tous les éléments de balises HTML.
Chaque DOMElement.constructor retourne function HTML ... Element () ou [Objet HTML ... Element] so ...
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;
}
voici une astuce en utilisant jQuery
var obj = {};
var element = document.getElementById('myId'); // or simply $("#myId")
$(obj).html() == undefined // true
$(element).html() == undefined // false
donc le mettre dans une fonction:
function isElement(obj){
return (typeOf obj === 'object' && !($(obj).html() == undefined));
}
J'ai un moyen spécial de faire cela qui n'a pas encore été mentionné dans les réponses.
Ma solution est basée sur quatre tests. Si l'objet passe tous les quatre, alors c'est un élément:
L'objet n'est pas nul.
L'objet a une méthode appelée "appendChild".
La méthode "appendChild" a été héritée de la classe Node et n'est pas simplement une méthode imposter (une propriété créée par l'utilisateur avec un nom identique).
L'objet est de type de nœud 1 (élément). Les objets qui héritent des méthodes de la classe Node sont toujours des nœuds, mais pas nécessairement des éléments.
Q: Comment puis-je vérifier si une propriété donnée est héritée et n'est pas simplement un imposteur?
R: Un simple test pour voir si une méthode a vraiment été héritée de Node consiste d'abord à vérifier que la propriété a le type "objet" ou "fonction". Ensuite, convertissez la propriété en chaîne et vérifiez si le résultat contient le texte "[Code natif]". Si le résultat ressemble à ceci:
function appendChild(){
[Native Code]
}
Ensuite, la méthode a été héritée de l'objet Node. Voir https://davidwalsh.name/detect-native-function
Et finalement, en rassemblant tous les tests, la solution est la suivante:
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;
}
Une méthode tout à fait correcte, check target est un élément html real html Primary code:
(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);
(element instanceof $ && element.get(0) instanceof Element) || element instanceof Element
Ceci vérifiera même s'il s'agit d'un élément jQuery ou JavaScript DOM
Selon mdn
Element
est la classe de base la plus générale à partir de laquelle tous les objets d'uneDocument
héritent. Il n'a que des méthodes et des propriétés communes à toutes sortes d'éléments.
Nous pouvons implémenter isElement
par prototype. Voici mon conseil:
/**
* @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