Jak sprawdzić, czy obiekt JavaScript jest obiektem DOM?


247

Próbuję uzyskać:

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

W moich własnych skryptach po prostu używałem tego, ponieważ nigdy nie potrzebowałem tagNamejako właściwości:

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

W przypadku drugiego obiektu opracowałem następujące rozwiązanie jako szybkie rozwiązanie - które w większości działa. ;)

Problem polega na tym, że zależy to od przeglądarki wymuszającej właściwości tylko do odczytu, co nie wszystkie.

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

Czy istnieje dobry zamiennik?


3
Czy zastanawiam się, czy „obiekt DOM” nie powinien obejmować nie tylko elementów, ale także wszystkich węzłów (węzłów tekstowych, atrybutów itp.)? Wszystkie odpowiedzi i sposób, w jaki postawiłeś pytanie, sugerują, że pytanie dotyczy konkretnie elementów ...
Mike Rodent

Odpowiedzi:


300

Może to być interesujące:

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

Jest częścią DOM, Level2 .

Aktualizacja 2 : tak zaimplementowałem go we własnej bibliotece: (poprzedni kod nie działał w Chrome, ponieważ Node i HTMLElement są funkcjami zamiast oczekiwanego obiektu. Ten kod jest testowany w FF3, IE7, Chrome 1 i 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
Warto zauważyć, że nie zadziała to na elementach należących do innych okien / ram. Zalecane jest pisanie kaczką
Andy E

2
Możesz oszukać go:function Fake() {}; Fake.prototype=document.createElement("div"); alert(new Fake() instanceof HTMLElement);
Kernel James

11
Fakt WTF: Firefox 5 i wcześniejsze wersje wracają truedo [] instanceof HTMLElement.
Rob W

6
Btw, HTMLElementzawsze jest function, więc typeofzrzuci cię z toru i wykona drugą część instrukcji. Możesz spróbować, jeśli chcesz instanceof Object, ponieważ funkcja będzie instancją Objectlub po prostu jawnie sprawdzi typeof === "function", Nodeczy i HTMLElementoba są rodzimymi funkcjami obiektowymi.
Roland

2
Kiedy dzwonisz isElement(0), zwraca 0, a nie fałsz ... Dlaczego tak jest i jak mogę temu zapobiec?
Jessica,

68

Poniższy super-prosty kod kompatybilny z IE8 działa idealnie.

Odpowiedź Zaakceptowany nie wykrywa wszystkie typy elementów HTML. Na przykład elementy SVG nie są obsługiwane. Natomiast ta odpowiedź działa dobrze w przypadku HTML i SVG.

Zobacz to w akcji tutaj: https://jsfiddle.net/eLuhbu6r/

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

3
„Element” jest niezdefiniowany w IE7
Dan

49
Uważam, że każdy, kto nadal korzysta z IE7, powinien poświęcić pięć sekund na pobranie lepszej przeglądarki, zamiast narzucać nam inwestowanie dni lub tygodni, próbując obejść się z odmową dotrzymania czasu.
mopsyd

1
Zgadzam się z @mopsyd, ale autor odpowiedzi stwierdza, że ​​działa w IE7, co może wymagać aktualizacji ze względu na poprawność.
Lajos Meszaros

1
Zaktualizowano, by powiedzieć IE9. Nie jestem pewien, czy IE8 obsługuje to.
Monarcha Wadia

1
@MonarchWadia tak, jest obsługiwany w IE8. Należy jednak pamiętać, że nie zwraca to wartości true dla documentelementu (we wszystkich przeglądarkach). jeśli jej potrzebujesz, powinieneś spróbować:x instanceof Element || x instanceof HTMLDocument
S.Serpooshan

11

Wszystkie rozwiązania powyżej i poniżej (w tym moje rozwiązanie) mogą być niepoprawne, szczególnie w IE - całkiem możliwe jest (ponowne) zdefiniowanie niektórych obiektów / metod / właściwości w celu naśladowania węzła DOM powodującego niepoprawność testu.

Dlatego zwykle używam testów typu kaczego: testuję specjalnie pod kątem rzeczy, których używam. Na przykład, jeśli chcę sklonować węzeł, testuję go w następujący sposób:

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

Zasadniczo jest to mały test poczytalności + bezpośredni test metody (lub właściwości), której zamierzam użyć.

Nawiasem mówiąc, powyższy test jest dobrym testem dla węzłów DOM we wszystkich przeglądarkach. Ale jeśli chcesz być bezpieczny, zawsze sprawdzaj obecność metod i właściwości oraz weryfikuj ich typy.

EDYCJA: IE używa obiektów ActiveX do reprezentowania węzłów, więc ich właściwości nie zachowują się jak prawdziwy obiekt JavaScript, na przykład:

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

podczas gdy powinien zwracać odpowiednio „funkcję” i true. Jedynym sposobem na przetestowanie metod jest sprawdzenie, czy są one zdefiniowane.


„typeof document.body.cloneNode” zwraca „obiekt” w moim IE
Dennis C

To wygląda na przyzwoitą odpowiedź. Zobacz jednak moją odpowiedź poniżej, stackoverflow.com/a/36894871/1204556
Monarch Wadia

8

Możesz spróbować dołączyć go do prawdziwego węzła DOM ...

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

    return true;
}

11
czy to działa? To wciąż rozwiązanie. W tym kreatywny.
Justin Meyer,

3
+1 za kreatywność i pewność, jakie to oferuje. Jeśli jednak węzeł jest już częścią DOM, właśnie go usunąłeś! Więc ... ta odpowiedź jest niekompletna bez wykonania pracy, aby w razie potrzeby ponownie dodać element do DOM.
svidgen

4
Czytam to po prawie 5 latach i myślę, że jest to jedna z najfajniejszych. Po prostu trzeba to ulepszyć. Możesz na przykład spróbować dołączyć klon węzła do odłączonego elementu. Jeśli to nie jest obiekt DOM. coś na pewno pójdzie nie tak. Jednak wciąż dość drogie rozwiązanie.
MaxArt

Albo zamiast próbować dołączyć klon elementu, po prostu staramy się sklonować to powinno wystarczyć: obj.cloneNode(false). I nie ma skutków ubocznych.
mauroc8

1
To jest naprawdę drogie i niepotrzebnie skomplikowane. Zobacz moją odpowiedź poniżej, stackoverflow.com/a/36894871/1204556
Monarch Wadia


6

Co powiesz na Lo-Dash_.isElement ?

$ npm install lodash.iselement

I w kodzie:

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

1
Podoba mi się to rozwiązanie. Jest prosty i działa w Edge i IE, nawet dla elementów w oddzielnych ramkach iframe, w przeciwieństwie do większości najwyżej ocenianych rozwiązań tutaj.
Elias Zamaria,

Ta odpowiedź jest pomocna, choć do uruchomienia modułów NPM w przeglądarce potrzebny byłby Webpack.
Edwin Pratt

5

To jest z uroczej biblioteki JavaScript MooTools :

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

12
Ten kod nie potwierdza, że ​​obiekt jest elementem DOM; tylko, że wygląda trochę jak jeden. Dowolny obiekt może otrzymać właściwość nodeName i nodeType i spełniać ten kod.
thomasrutter 10.10.11

Ta odpowiedź nie wykrywa wszystkich typów elementów HTML. Na przykład elementy SVG nie są obsługiwane. Zobacz moją odpowiedź poniżej.
Monarcha Wadia,

Naprawdę nie działa na wszystkie elementy, na przykład SVG. Zobacz moją odpowiedź poniżej, stackoverflow.com/a/36894871/1204556
Monarch Wadia

4

Za pomocą wykrytego tutaj rootowania możemy ustalić, czy np. Alert jest elementem root obiektu, który może wtedy być oknem:

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

Ustalenie, czy obiekt jest bieżącym oknem, jest jeszcze prostsze:

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

To wydaje się być tańsze niż rozwiązanie try / catch w wątku otwierającym.

Don P.


Przetestowałem to w najnowszych przeglądarkach Chrome i FF, a także w IE11, i działa wszędzie, również dla węzłów tekstowych i obiektów utworzonych za pośrednictwem, document.createElement()ale nie wstawionych również w DOM. Niesamowite (: Dziękuję
Geradlus_RU,

To wygląda na przyzwoitą odpowiedź, chociaż moja robi wiele takich samych rzeczy i jest mniej skomplikowana. stackoverflow.com/a/36894871/1204556
Monarch Wadia

4

stary wątek, ale oto zaktualizowana możliwość dla użytkowników ie8 i ff3.5 :

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

4

Sugeruję prosty sposób sprawdzenia, czy zmienna jest elementem DOM

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

lub zgodnie z sugestią HTMLGuy :

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

1
O wiele za dużo. Porównanie zwróci już wartość logiczną:return typeof entity === 'object' && typeof entity.nodeType !== undefined;
HTMLGuy

1
Bardzo interesujące! Czasami, w zależności od typów posiadanych przez ciebie objecti / lub właściwości, może to być bardzo przydatne! 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; },

// W rzeczywistości bardziej prawdopodobne jest, że użyję tych wbudowanych, ale czasami dobrze jest mieć te skróty do kodu instalacyjnego


obj.constructor.name nie działa w IE, ponieważ w IE funkcje nie mają właściwości name. Zastąp przez obj.constructor! = Obiekt.
mathheadinclouds

3

Może to być pomocne: 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);
}

W powyższym kodzie używamy operatora podwójnej negacji , aby uzyskać wartość logiczną obiektu przekazaną jako argument, w ten sposób upewniamy się, że każde wyrażenie ocenione w instrukcji warunkowej ma wartość logiczną, korzystając z oceny zwarcia , a zatem funkcji zwraca truelubfalse


Wszelkie fałszowanie powinno spowodować zwarcie twojego boolean. undefined && window.spam("should bork")na przykład nigdy nie ocenia fałszywej spamfunkcji. Więc nie !!potrzebuję, nie wierzę. Czy możesz podać [nieakademicki] przypadek, w którym jego zastosowanie ma znaczenie?
ruffin

Dziękuję za twoją deklarację. Użyłem * !! * podwójnej negacji, aby przekonwertować wszystkie wyrażenia na wartość logiczną, a nie na prawdę lub fałsz.
jherax,

Tak, ale nie ma praktycznego powodu, aby to zrobić, nie sądzę - patrz tutaj . I z pewnością nie jest konieczne skorzystanie z eval Short-Cut tutaj. Nawet jeśli nie kupiłeś !!argumentu „nigdy nie jest potrzebny” ( a jeśli nie, to jestem ciekawy, dlaczego nie ), możesz edytować ten wiersz return !!(obj && typeof obj === "object" && obj.nodeType === 1 && obj.nodeName);i sprawić, by działał tak samo.
ruffin

Tak właśnie zrobiłem;) bardziej czysty i taki sam efekt. Dziękuję Ci.
jherax,

2

Możesz sprawdzić, czy dany obiekt lub węzeł zwraca typ ciągu.

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,

GORĄCO! Ta odpowiedź powinna być zwycięzcą gry. if (typeof obj.innerHTML! == 'string') // nie jest elementem dom.
user3751385,

1
Początkowo zareagowałem na krytykę @Qtax i thomasruttera na wcześniejszą odpowiedź , ale zaczynam ją kupować. Chociaż wcześniej nie spotkałem psów kwakających jak kaczki dokładnie w ten sposób, widzę, że ktoś nie sprawdza, czy coś jest uruchomionym węzłem notANode.innerHTML = "<b>Whoops</b>";, a potem kazał temu kodowi przekazać swój zanieczyszczony obiekt do tego kodu. Kod defensywny === lepszy kod, wszystkie inne rzeczy są równe, a to ostatecznie nie jest defensywne.
ruffin


2

Myślę, że prototypowanie nie jest zbyt dobrym rozwiązaniem, ale być może jest to najszybsze: Zdefiniuj ten blok kodu;

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

niż sprawdź, czy twoja właściwość isDomElement:

if(a.isDomElement){}

Mam nadzieję, że to pomoże.


1
1) zmiana przedmiotów, których nie posiadasz, nie jest wskazana. 2) nie wykrywa to elementów, które nie są częścią tego samego dokumentu.
fregante

2

Według MDN

Elementjest najbardziej ogólną klasą podstawową, z której Documentdziedziczą wszystkie obiekty . Ma tylko metody i właściwości wspólne dla wszystkich rodzajów elementów.

Możemy wdrożyć isElementprzez prototyp. Oto moja rada:

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

Myślę, że musisz dokładnie sprawdzić niektóre właściwości, które zawsze będą w elemencie dom, ale ich kombinacja najprawdopodobniej nie będzie w innym obiekcie, na przykład:

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

1

W przeglądarce Firefox możesz użyć instanceof Node. To Nodejest zdefiniowane w DOM1 .

Ale to nie jest takie proste w IE.

  1. „instanceof ActiveXObject” może jedynie stwierdzić, że jest to obiekt rodzimy.
  2. „typeof document.body.appendChild == 'object'” informują, że może to być obiekt DOM, ale może też być czymś innym, pełniącym tę samą funkcję.

Możesz tylko upewnić się, że jest to element DOM, używając funkcji DOM i wychwytywać ewentualny wyjątek. Może jednak mieć efekt uboczny (np. Zmienić stan wewnętrzny obiektu / wydajność / wyciek pamięci)


1

Być może jest to alternatywa? Testowane w Opera 11, FireFox 6, Internet Explorer 8, Safari 5 i 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;
}

Funkcja nie da się oszukać np. Przez to

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

2
Dobra próba, ale obsługa wyjątków jest zbyt kosztowna, jeśli można jej uniknąć. Ponadto ES5 pozwala zdefiniować właściwości tylko do odczytu dla obiektów.
Andy E

1

Oto co wymyśliłem:

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

Aby poprawić wydajność, stworzyłem funkcję samo-wywołującą, która testuje możliwości przeglądarki tylko raz i odpowiednio przypisuje odpowiednią funkcję.

Pierwszy test powinien działać w większości nowoczesnych przeglądarek i został już tutaj omówiony. Po prostu sprawdza, czy element jest instancjąHTMLElement . Bardzo proste.

Drugi jest najciekawszy. Oto jego podstawowa funkcjonalność:

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

Sprawdza, czy el jest instancją konstruktora, którym udaje. Aby to zrobić, potrzebujemy dostępu do konstruktora elementu. Dlatego testujemy to w instrukcji if. Na przykład IE7 nie działa, ponieważ (document.createElement("a")).constructorjestundefined w IE7.

Problem z tym podejściem polega na tym, że document.createElementtak naprawdę nie jest to najszybsza funkcja i może łatwo spowolnić twoją aplikację, jeśli testujesz z nią wiele elementów. Aby rozwiązać ten problem, postanowiłem buforować konstruktory. ObiektElementConstructors ma nodeNames jako klucze, a odpowiadające im konstruktory jako wartości. Jeśli konstruktor jest już buforowany, używa go z pamięci podręcznej, w przeciwnym razie tworzy element, buforuje swojego konstruktora do przyszłego dostępu, a następnie testuje na nim.

Trzeci test to nieprzyjemna awaria. Sprawdza, czy el jest an object, ma nodeTypeustawioną właściwość na 1oraz string asnodeName . Oczywiście nie jest to zbyt wiarygodne, ale zdecydowana większość użytkowników nie powinna nawet cofnąć się do tej pory.

Jest to najbardziej niezawodne podejście, jakie wymyśliłem, przy jednoczesnym utrzymaniu jak najwyższej wydajności.


1

Sprawdź, czy objdziedziczy po Węzle .

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

Węzeł to podstawowy interfejs, z którego dziedziczą HTMLElement i tekst.


1

odróżnić surowy obiekt js od HTMLElement

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

posługiwać się:

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

// LUB

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

posługiwać się:

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


0

oto sztuczka przy użyciu jQuery

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

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

więc umieszczenie go w funkcji:

function isElement(obj){

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

}

2
jQuery robi to wewnętrznie, elem.nodeType === 1więc dlaczego nie zaoszczędzić na wywołaniu i zależności jQuery i czy funkcja isElement zrobi to sama?
Joseph Lennox

Jest 2016, po prostu powiedz „nie”.
Thomas McCabe,

0

Nie wbijaj się w to ani nic innego, tylko w przeglądarki zgodne z ES5, dlaczego nie tylko:

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

Nie będzie działać na TextNodes i nie jestem pewien co do Shadow DOM lub DocumentFragments itp., Ale będzie działać na prawie wszystkich elementach tagów HTML.


0

Będzie to działać w prawie każdej przeglądarce. (Tutaj nie ma rozróżnienia między elementami i węzłami)

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

po pierwsze, nie trzeba zwracać wartości true ani false, wystarczy zwrócić instrukcję if. Po drugie, zwróci wartość true dla {nodeType: 1}
bluejayke

0

Absolutnie poprawna metoda, sprawdź cel to prawdziwy kod podstawowy elementu HTML:

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

Testuj w IE 5


0

Każdy DOMElement.constructor zwraca funkcję HTML ... Element () lub [Object HTML ... Element], więc ...

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

Mam specjalny sposób, aby to zrobić, o czym jeszcze nie wspomniano w odpowiedziach.

Moje rozwiązanie opiera się na czterech testach. Jeśli obiekt przechodzi wszystkie cztery, jest to element:

  1. Obiekt nie ma wartości null.

  2. Obiekt ma metodę o nazwie „appendChild”.

  3. Metoda „appendChild” została odziedziczona z klasy Node i nie jest tylko metodą oszustwa (właściwość stworzona przez użytkownika o identycznej nazwie).

  4. Obiekt jest typu węzła 1 (element). Obiekty dziedziczące metody z klasy Node są zawsze Węzłami, ale niekoniecznie elementami.

P: Jak sprawdzić, czy dana właściwość jest dziedziczona i nie jest tylko oszustem?

Odp .: Prostym testem sprawdzającym, czy metoda została naprawdę odziedziczona z Węzła, jest sprawdzenie, czy właściwość ma typ „obiekt” lub „funkcja”. Następnie przekonwertuj właściwość na ciąg znaków i sprawdź, czy wynik zawiera tekst „[Kod macierzysty]”. Jeśli wynik wygląda mniej więcej tak:

function appendChild(){
[Native Code]
}

Następnie metoda została odziedziczona z obiektu Node. Zobacz https://davidwalsh.name/detect-native-function

I na koniec, łącząc wszystkie testy, rozwiązaniem jest:

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

Spowoduje to sprawdzenie, nawet jeśli jest to element DOM jQuery lub JavaScript


0

Jedynym sposobem na zagwarantowanie, że sprawdzasz rzeczywisty element HTMLEement, a nie tylko obiekt o takich samych właściwościach jak element HTML, jest ustalenie, czy dziedziczy on po węźle, ponieważ niemożliwe jest utworzenie nowego węzła () w JavaScript. (chyba że natywna funkcja Węzła jest nadpisana, ale nie masz szczęścia). Więc:

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.