it-swarm.com.de

JavaScript isDOM - Wie prüfen Sie, ob ein JavaScript-Objekt ein DOM-Objekt ist?

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?

201

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

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;  
}
29
Monarch Wadia

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.

11
Eugene Lazutkin

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

Wie wäre es mit Lo-Dash's _.isElement ?

$ npm install lodash.iselement

Und im Code:

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

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';
    }
}
5
finpingvin

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

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

4
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

3
jherax
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

3
Erich Horn

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;
        }
    }
2
Roman

Keine Notwendigkeit für Hacks, Sie können nur fragen, ob ein Element eine Instanz des Elements ist:

const isElement = el => el instanceof Element
2
Damjan Pavlica

Für diejenigen, die Angular verwenden:

angular.isElement

https://docs.angularjs.org/api/ng/function/angular.isElement

2
Alvis

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
2
timewaster51

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

1
bortunac

In Firefox können Sie den instanceof Node verwenden. Diese Node ist in DOM1 definiert.

Das ist aber im IE nicht so einfach.

  1. "instanceof ActiveXObject" kann nur feststellen, dass es sich um ein systemeigenes Objekt handelt.
  2. "typeof document.body.appendChild == 'object'" sagen aus, dass es sich um ein DOM-Objekt handeln kann, aber es kann auch sein, dass etwas anderes dieselbe Funktion hat.

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).

1
Dennis C

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.

1
Oliver Sartun

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
1
Snoozer Man

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.

1
soslan

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.

1
Doğuş Atasoy

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;
}
0
Zv_oDD

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;
};
0
Andreas Grech

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.

0
Travis Kaufman

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

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

}
0
Matus

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:

  1. Das Objekt ist nicht null.

  2. Das Objekt hat eine Methode namens "appendChild".

  3. 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).

  4. 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;
}
0
user3163495

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

 Test In IE 5

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

Dies prüft, ob es sich um ein jQuery- oder JavaScript-DOM-Element handelt 

0
Arjun Kakkar

Nach mdn

Element ist die allgemeinste Basisklasse, von der alle Objekte in einer Document 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

0
xianshenglu