Ich versuche zu bekommen:
document.createElement('div') //=> true
{tagName: 'foobar something'} //=> false
In meinen eigenen Skripten benutzte ich das einfach, da ich tagName
nie als Eigenschaft brauchte:
if (!object.tagName) throw ...;
Für das zweite Objekt habe ich mir als schnelle Lösung folgendes ausgedacht - was meistens funktioniert. ;)
Das Problem ist, es hängt davon ab, dass Browser schreibgeschützte Eigenschaften erzwingen, was nicht alle tun.
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;
}
}
Gibt es einen guten Ersatz?
Das könnte von Interesse sein:
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 ist Teil des DOM, Level2 .
Update 2: So habe ich es in meiner eigenen Bibliothek implementiert: (Der vorherige Code funktionierte in Chrome nicht, da Node und HTMLElement Funktionen anstelle des erwarteten Objekts sind. Dieser Code wird in FF3 getestet , IE7, Chrome 1 und 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"
);
}
Der folgende IE8-kompatible, supereinfache Code funktioniert einwandfrei.
Die akzeptierte Antwort erkennt nicht alle Arten von HTML-Elementen. Beispielsweise werden SVG-Elemente nicht unterstützt. Im Gegensatz dazu funktioniert diese Antwort für HTML auch als SVG.
Sehen Sie es in Aktion hier: https://jsfiddle.net/eLuhbu6r/
function isElement(element) {
return element instanceof Element || element instanceof HTMLDocument;
}
Bei allen oben und unten aufgeführten Lösungen (einschließlich meiner Lösung) besteht die Möglichkeit, dass sie falsch sind, insbesondere auf IE. Es ist durchaus möglich, einige Objekte/Methoden/Eigenschaften (neu) zu definieren, um einen DOM-Knoten zu imitieren, der den Test ungültig macht.
Normalerweise verwende ich das Enten-Typing-Testen: Ich teste speziell für Dinge, die ich verwende. Wenn ich zum Beispiel einen Knoten klonen möchte, teste ich ihn folgendermaßen:
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);
}
Im Grunde ist es eine kleine Vernunftsprüfung + der direkte Test für eine Methode (oder eine Eigenschaft), die ich verwenden möchte.
Der obige Test ist übrigens ein guter Test für DOM-Knoten in allen Browsern. Wenn Sie jedoch auf der sicheren Seite sein möchten, überprüfen Sie immer das Vorhandensein von Methoden und Eigenschaften und deren Typ.
EDIT: IE verwendet ActiveX-Objekte zur Darstellung von Knoten, sodass sich ihre Eigenschaften nicht als echtes JavaScript-Objekt verhalten. Beispiel:
console.log(typeof node.cloneNode); // object
console.log(node.cloneNode instanceof Function); // false
während es "function" und true
zurückgeben soll. Die einzige Möglichkeit, Methoden zu testen, ist zu sehen, ob sie definiert sind.
Sie könnten versuchen, es an einen echten DOM-Knoten anzuhängen ...
function isDom(obj)
{
var Elm = document.createElement('div');
try
{
Elm.appendChild(obj);
}
catch (e)
{
return false;
}
return true;
}
Wie wäre es mit Lo-Dash's _.isElement
?
$ npm install lodash.iselement
Und im Code:
var isElement = require("lodash.iselement");
isElement(document.body);
Dies ist aus der schönen JavaScript-Bibliothek MooTools :
if (obj.nodeName){
switch (obj.nodeType){
case 1: return 'element';
case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
}
}
alter Thread, aber hier ist eine aktualisierte Möglichkeit für ie8 und ff3.5 Benutzer:
function isHTMLElement(o) {
return (o.constructor.toString().search(/\object HTML.+Element/) > -1);
}
Durch Verwendung der gefundenen Wurzelerkennung hier können wir feststellen, ob z. alert ist ein Mitglied des Stammverzeichnisses des Objekts, das dann wahrscheinlich ein Fenster ist:
function isInAnyDOM(o) {
return (o !== null) && !!(o.ownerDocument && (o.ownerDocument.defaultView || o.ownerDocument.parentWindow).alert); // true|false
}
Noch einfacher ist es festzustellen, ob das Objekt das aktuelle Fenster ist:
function isInCurrentDOM(o) {
return (o !== null) && !!o.ownerDocument && (window === (o.ownerDocument.defaultView || o.ownerDocument.parentWindow)); // true|false
}
Dies scheint weniger teuer zu sein als die try/catch-Lösung im Eröffnungs-Thread.
Don P
Das könnte hilfreich sein: 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);
}
Im obigen Code verwenden wir den Operator double negation, um den als Argument übergebenen booleschen Wert des Objekts abzurufen. Auf diese Weise stellen wir sicher, dass jeder in der bedingten Anweisung ausgewertete Ausdruck boolean ist, wobei die Kurzschlussauswertung, die Funktion gibt also true
oder false
zurück
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; },
// Ich verwende diese Inline-Programme wahrscheinlich eher, aber manchmal ist es gut, diese Abkürzungen für den Setup-Code zu haben
Ich schlage einen einfachen Weg vor, um zu testen, ob eine Variable ein DOM-Element ist
function isDomEntity(entity) {
if( typeof entity === 'object' && entity.nodeType != undefined){
return true;
}
else{
return false;
}
}
Keine Notwendigkeit für Hacks, Sie können nur fragen, ob ein Element eine Instanz des Elements ist:
const isElement = el => el instanceof Element
Für diejenigen, die Angular verwenden:
angular.isElement
https://docs.angularjs.org/api/ng/function/angular.isElement
Sie können sehen, ob das betreffende Objekt oder der betreffende Knoten einen Zeichenfolgentyp zurückgibt.
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
unterscheiden Sie ein unformatiertes js-Objekt von einem HTMLElement
function isDOM (x){
return /HTML/.test( {}.toString.call(x) );
}
benutzen:
isDOM( {a:1} ) // false
isDOM( document.body ) // true
// ODER
Object.defineProperty(Object.prototype, "is",
{
value: function (x) {
return {}.toString.call(this).indexOf(x) >= 0;
}
});
benutzen:
o={}; o.is("HTML") // false
o=document.body; o.is("HTML") // true
In Firefox können Sie den instanceof Node
verwenden. Diese Node
ist in DOM1 definiert.
Das ist aber im IE nicht so einfach.
Sie können nur sicherstellen, dass es sich um ein DOM-Element handelt, indem Sie die DOM-Funktion verwenden und eine Ausnahme abfangen. Es kann jedoch Nebeneffekte haben (z. B. Ändern des internen Status des Objekts/Leistung/Speicherverlust).
Das habe ich herausgefunden:
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";
}
}
})();
Um die Leistung zu verbessern, habe ich eine selbstaufrufende Funktion erstellt, mit der die Funktionen des Browsers nur einmal getestet und die entsprechende Funktion entsprechend zugewiesen wird.
Der erste Test sollte in den meisten modernen Browsern funktionieren und wurde hier bereits diskutiert. Es wird lediglich geprüft, ob das Element eine Instanz von HTMLElement
ist. Sehr einfach.
Der zweite ist der interessanteste. Dies ist seine Kernfunktionalität:
return el instanceof (document.createElement(el.nodeName)).constructor
Es prüft, ob el eine Instanz des Konstruktors ist, den es vorgibt zu sein. Dazu benötigen wir Zugriff auf den Konstruktor eines Elements. Deshalb testen wir das im if-Statement. IE7 zum Beispiel schlägt dies fehl, weil (document.createElement("a")).constructor
im IE7 undefined
ist.
Das Problem bei diesem Ansatz ist, dass document.createElement
wirklich nicht die schnellste Funktion ist und Ihre Anwendung leicht verlangsamen könnte, wenn Sie viele Elemente damit testen. Um dieses Problem zu lösen, entschied ich mich, die Konstruktoren zwischenzuspeichern. Das Objekt ElementConstructors
hat nodeNames als Schlüssel mit den entsprechenden Konstruktoren als Werte. Wenn ein Konstruktor bereits zwischengespeichert ist, verwendet er ihn aus dem Cache. Andernfalls erstellt er das Element, speichert seinen Konstruktor für den zukünftigen Zugriff und testet es anschließend.
Der dritte Test ist der unangenehme Fallback. Es wird geprüft, ob el eine object
ist, eine nodeType
-Eigenschaft, die auf 1
gesetzt ist, und eine Zeichenfolge als nodeName
. Dies ist natürlich nicht sehr zuverlässig, dennoch sollte die große Mehrheit der Nutzer nicht einmal zurückgreifen.
Dies ist der zuverlässigste Ansatz, den ich mir ausgedacht habe und dabei die Leistung so hoch wie möglich halten.
Vielleicht ist das eine Alternative? Getestet in Opera 11, Firefox 6, Internet Explorer 8, Safari 5 und 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;
}
Die Funktion wird nicht von z. diese
isDOMNode( {'nodeName':'fake'} ); // returns false
Testen Sie, ob obj
von Node erbt.
if (obj instanceof Node){
// obj is a DOM Object
}
Knoten ist eine grundlegende Schnittstelle , von der HTMLElement und Text erben.
Ich denke, dass Prototyping keine sehr gute Lösung ist, aber vielleicht ist dies die schnellste:.
Element.prototype.isDomElement = true;
HTMLElement.prototype.isDomElement = true;
Überprüfen Sie Ihre Objekte isDomElement-Eigenschaft:
if(a.isDomElement){}
Ich hoffe das hilft.
Dies funktioniert für fast jeden Browser. (Keine Unterscheidung zwischen Elementen und Knoten hier)
function dom_element_check(element){
if (typeof element.nodeType !== 'undefined'){
return true;
}
return false;
}
Ich denke, Sie müssen einige Eigenschaften, die sich immer in einem dom-Element befinden, gründlich überprüfen, aber ihre Kombination wird nicht höchstwahrscheinlich in einem anderen Objekt sein, wie zB:
var isDom = function (inp) {
return inp && inp.tagName && inp.nodeName && inp.ownerDocument && inp.removeAttribute;
};
Um nicht auf dieses oder irgendetwas zu hämmern, sondern für ES5-kompatible Browser, warum nicht einfach:
function isDOM(e) {
return (/HTML(?:.*)Element/).test(Object.prototype.toString.call(e).slice(8, -1));
}
Funktioniert nicht mit TextNodes und ist nicht sicher über Shadow DOM oder DocumentFragments usw., aber will funktioniert mit fast allen HTML-Tag-Elementen.
Jedes DOMElement.constructor gibt function HTML ... Element () oder [Object HTML ... Element] so zurück ...
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;
}
hier ist ein Trick mit jQuery
var obj = {};
var element = document.getElementById('myId'); // or simply $("#myId")
$(obj).html() == undefined // true
$(element).html() == undefined // false
so in eine Funktion setzen:
function isElement(obj){
return (typeOf obj === 'object' && !($(obj).html() == undefined));
}
Ich habe einen besonderen Weg, dies zu tun, der in den Antworten noch nicht erwähnt wurde.
Meine Lösung basiert auf vier Tests. Wenn das Objekt alle vier durchläuft, ist es ein Element:
Das Objekt ist nicht null.
Das Objekt hat eine Methode namens "appendChild".
Die Methode "appendChild" wurde von der Klasse Node geerbt und ist nicht nur eine Imposter-Methode (eine vom Benutzer erstellte Eigenschaft mit einem identischen Namen).
Das Objekt hat den Knotentyp 1 (Element). Objekte, die Methoden von der Klasse Node erben, sind immer Knoten, jedoch nicht notwendigerweise Elemente.
F: Wie überprüfe ich, ob eine bestimmte Eigenschaft vererbt wird und nicht nur ein Betrüger ist?
A: Ein einfacher Test, um herauszufinden, ob eine Methode wirklich von Node geerbt wurde, ist zunächst zu überprüfen, ob die Eigenschaft den Typ "Objekt" oder "Funktion" hat. Konvertieren Sie anschließend die Eigenschaft in eine Zeichenfolge und prüfen Sie, ob das Ergebnis den Text "[Native Code]" enthält. Wenn das Ergebnis ungefähr so aussieht:
function appendChild(){
[Native Code]
}
Dann wurde die Methode vom Node-Objekt geerbt. Siehe https://davidwalsh.name/detect-native-function
Und zum Schluss, alle Tests zusammen zu bringen, ist die Lösung:
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;
}
Eine absolut richtige Methode, check target ist ein real html-Element Primärcode:
(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
Dies prüft, ob es sich um ein jQuery- oder JavaScript-DOM-Element handelt
Nach mdn
Element
ist die allgemeinste Basisklasse, von der alle Objekte in einerDocument
erben. Es hat nur Methoden und Eigenschaften, die für alle Arten von Elementen gelten.
Wir können isElement
per Prototyp implementieren. Hier ist mein Rat:
/**
* @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