JavaScript isDOM - Как проверить, является ли объект JavaScript объектом DOM? - PullRequest
213 голосов
/ 21 декабря 2008

Я пытаюсь получить:

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

В своих собственных сценариях я использовал это, поскольку мне никогда не требовалось tagName в качестве свойства:

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

Итак, для второго объекта я придумал следующее как быстрое решение - которое в основном работает. ;)

Проблема в том, что браузеры используют свойства только для чтения, что не все делают.

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

Есть хороший заменитель?

Ответы [ 32 ]

0 голосов
/ 10 февраля 2017
(element instanceof $ && element.get(0) instanceof Element) || element instanceof Element

Будет проверяться, даже если это DOM-элемент jQuery или JavaScript

0 голосов
/ 29 марта 2012
var isElement = function(e){
    try{
        // if e is an element attached to the DOM, we trace its lineage and use native functions to confirm its pedigree
        var a = [e], t, s, l = 0, h = document.getElementsByTagName('HEAD')[0], ht = document.getElementsByTagName('HTML')[0];
        while(l!=document.body&&l!=h&&l.parentNode) l = a[a.push(l.parentNode)-1];
        t = a[a.length-1];
        s = document.createElement('SCRIPT');   // safe to place anywhere and it won't show up
        while(a.length>1){  // assume the top node is an element for now...
            var p = a.pop(),n = a[a.length-1];
            p.insertBefore(s,n);
        }
        if(s.parentNode)s.parentNode.removeChild(s);
        if(t!=document.body&&t!=h&&t!=ht)
            // the top node is not attached to the document, so we don't have to worry about it resetting any dynamic media
            // test the top node
            document.createElement('DIV').appendChild(t).parentNode.removeChild(t);
        return e;
    }
    catch(e){}
    return null;
}

Я проверял это на Firefox, Safari, Chrome, Opera и IE9. Я не мог найти способ взломать его.
Теоретически, он проверяет каждого предка предложенного элемента, а также сам элемент, вставляя тег script перед ним.
Если его первый предок восходит к известному элементу, такому как <html>, <head> или <body>, и по пути он не выдал ошибку, у нас есть элемент.
Если первый предок не прикреплен к документу, мы создаем элемент и пытаемся поместить предложенный элемент внутри него (а затем удаляем его из нового элемента).
Таким образом, он либо отслеживает известный элемент, либо успешно подключается к известному элементу, либо завершается ошибкой.
Возвращает элемент или ноль, если это не элемент.

0 голосов
/ 18 октября 2016

Каждый DOMElement.constructor возвращает функцию HTML ... Элемент () или [Объект HTML ... Элемент] 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;
}
0 голосов
/ 15 октября 2016

У меня есть особый способ сделать это, который еще не был упомянут в ответах.

Мое решение основано на четырех тестах. Если объект проходит все четыре, то это элемент:

  1. Объект не нулевой.

  2. У объекта есть метод с именем "appendChild".

  3. Метод "appendChild" был унаследован от класса Node и является не просто методом-самозванцем (пользовательское свойство с идентичным именем).

  4. Объект имеет тип узла 1 (элемент). Объекты, которые наследуют методы от класса Node , всегда являются узлами, но не обязательно элементами.

В: Как я могу проверить, является ли данное свойство наследуемым и не просто самозванцем?

A: Простой тест, чтобы увидеть, действительно ли метод унаследован от Узла , заключается в том, чтобы сначала убедиться, что свойство имеет тип «объект» или «функция». Затем преобразуйте свойство в строку и проверьте, содержит ли результат текст «[Native Code]». Если результат выглядит примерно так:

function appendChild(){
[Native Code]
}

Тогда метод был унаследован от объекта Node. См https://davidwalsh.name/detect-native-function

И, наконец, объединяя все тесты, решение:

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 голосов
/ 29 августа 2016

В большинстве ответов используется какая-то утка, например, проверяется, есть ли у объекта свойство nodeType. Но этого недостаточно, поскольку неузлы также могут иметь свойства, подобные узлам.

Другим распространенным подходом является instanceof, который может давать ложные срабатывания, например, с Object.create(Node), который не является узлом, несмотря на наследование свойств узла.

Кроме того, оба вышеупомянутых подхода вызывают внутренние существенные методы, которые могут быть проблематичными, например, если проверенное значение является прокси.

Вместо этого я рекомендую заимствовать метод узла и вызывать его для нашего объекта. Браузер проверит, что значение является узлом, вероятно, посмотрев внутренние слоты, не настраиваемые в прокси, поэтому даже они не смогут помешать нашей проверке.

function isNode(value) {
  try {
    Node.prototype.cloneNode.call(value, false);
    return true;
  } catch(err) {
    return false;
  }
}

Вы также можете использовать свойства getter, если хотите.

function isNode(value) {
  try {
    Object.getOwnPropertyDescriptor(Node.prototype,'nodeType').get.call(value);
    return true;
  } catch(err) {
    return false;
  }
}

Аналогично, если вы хотите проверить, является ли значение элементом, вы можете использовать

function isElement(value) {
  try {
    Element.prototype.getAttribute.call(value, '');
    return true;
  } catch(err) {
    return false;
  }
}
function isHTMLElement(value) {
  try {
    HTMLElement.prototype.click.call(value);
    return true;
  } catch(err) {
    return false;
  }
}
0 голосов
/ 06 мая 2016

Абсолютно правильный метод, цель проверки - элемент real 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);

Test In IE 5

0 голосов
/ 15 августа 2013

Самый простой и кроссбраузерный способ определить, является ли элемент частью HTML DOM, выглядит следующим образом:

function inHTMLDom(myelement){
    if(myelement.ownerDocument.documentElement.tagName.toLowerCase()=="html"){
        return true;
    }else{
        return false;
    }
}

inHTMLDom(<your element>); // <your element>:element you are interested in checking.

протестировано в IE6, IE7, IE8, IE9, IE10, FF, Chrome, Safari, Opera.

0 голосов
/ 30 мая 2015

Это будет работать практически для любого браузера. (Здесь нет различия между элементами и узлами)

function dom_element_check(element){
    if (typeof element.nodeType !== 'undefined'){
        return true;
    }
    return false;
}
0 голосов
/ 09 ноября 2013

вот трюк с использованием jQuery

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

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

так что поместив его в функцию:

function isElement(obj){

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

}
0 голосов
/ 21 декабря 2008

Я думаю, что вам нужно сделать тщательную проверку некоторых свойств, которые всегда будут в элементе dom, но их комбинация не будет , скорее всего , в другом объекте, например так:

var isDom = function (inp) {
    return inp && inp.tagName && inp.nodeName && inp.ownerDocument && inp.removeAttribute;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...