Как проверить, является ли объект JavaScript объектом DOM?

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

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

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

Я туплю, задаваясь вопросом, не должен ли «объект DOM» охватывать не только элементы, но и все узлы (текстовые узлы, атрибуты и т. д.)? Все ответы и то, как вы задали вопрос, наводят на мысль, что этот вопрос касается именно Элементов ...

mike rodent 03.10.2017 23:21
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
266
1
202 221
34
Перейти к ответу Данный вопрос помечен как решенный

Ответы 34

Это из прекрасной библиотеки JavaScript MooTools:

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

Этот код не утверждает, что объект является элементом DOM; только то, что он немного похож на один. Любому объекту можно присвоить свойство nodeName и nodeType и удовлетворить этот код.

thomasrutter 10.10.2011 11:11

Этот ответ не определяет все типы элементов HTML. Например, элементы SVG не поддерживаются. Смотрите мой ответ ниже.

Monarch Wadia 06.02.2017 19:24

На самом деле не работает со всеми элементами, например SVG. См. Мой ответ ниже, stackoverflow.com/a/36894871/1204556

Monarch Wadia 06.02.2017 19:25

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

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

Вы можете попробовать добавить его к реальному узлу DOM ...

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

    return true;
}

Это работает? Это все еще решение. Причем творческий.

Justin Meyer 10.10.2012 20:28

+1 за креативность и уверенность, которые это предлагает. Однако, если узел уже является частью DOM, вы только что удалили его! Итак ... этот ответ будет неполным без выполнения работы по повторному добавлению элемента в DOM, если это необходимо.

svidgen 22.03.2013 18:54

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

MaxArt 13.09.2013 02:05

Или вместо попытки добавить клон элемента должно быть достаточно просто пытаюсь клонировать это: obj.cloneNode(false). А ТАКЖЕ не имеет побочных эффектов.

mauroc8 14.01.2017 06:55

Это действительно дорого и излишне сложно. См. Мой ответ ниже, stackoverflow.com/a/36894871/1204556

Monarch Wadia 06.02.2017 19:26

Это креативно и было бы хорошо, за исключением того, что у него есть ужасный побочный эффект, заключающийся в изменении объекта, который вы тестируете! Т.е. он потенциально удаляет действительный элемент DOM из его текущего родителя! @Greg должен изменить ответ, указав это явно, так как использовать как есть опасно.

logidelic 09.02.2017 19:00
Ответ принят как подходящий

Это может быть интересно:

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

Это часть ДОМ, Уровень 2.

Обновление 2: Вот как я реализовал это в своей собственной библиотеке: (предыдущий код не работал в Chrome, потому что Node и HTMLElement являются функциями вместо ожидаемого объекта. Этот код протестирован в FF3, IE7, Chrome 1 и 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"
);
}

Не W3 DOM2, вероятно, должен быть return (typeof obj === "object") && (obj.nodeType === 1) && (typeof obj.tagName === "string"); работать во всех браузерах.

some 21.12.2008 19:25

Стоит отметить, что это не будет работать с элементами, принадлежащими другим окнам / фреймам. Утиная печать - рекомендуемый подход

Andy E 10.04.2012 16:47

Вы можете обмануть это с помощью: function Fake() {}; Fake.prototype=document.createElement("div"); alert(new Fake() instanceof HTMLElement);

Kernel James 03.10.2012 10:14

WTF факт: Firefox 5 и более ранние версии возвращают true для [] instanceof HTMLElement.

Rob W 07.01.2013 18:28

Кстати, HTMLElement всегда является function, поэтому typeof сбивает вас со следа и выполнит вторую часть оператора. Вы можете попробовать, если хотите, instanceof Object, потому что функция будет экземпляром Object, или просто явно проверить наличие typeof === "function", потому что Node и HTMLElement являются собственными объектными функциями.

Roland 21.08.2013 17:14

Например, typeof HTMLElement === "object" в IE10 и typeof HTMLElement === "function" в Chrome. Таким образом, перед использованием typeof HTMLElement следует протестировать o instanceof HTMLElement на предмет "объекта" или "функции".

Oleg 05.06.2015 17:30

@some ваша функция isElement возвращает undefined, когда o - это undefined. Вы должны добавить !! после return и перед открывающей скобкой.

Karol 24.12.2015 00:20

Этот ответ не работает для элементов SVG. Кроме того, мало кто больше заботится о поддержке DOM2; См. Мой ответ (поддерживается в IE7) ниже, если вам важны элементы SVG, но не DOM2.

Monarch Wadia 27.04.2016 18:55
Важный: обратите внимание, при проверке этого на iframe он не будет работать в Chrome. Вам явно придется проверять внутри контекста iframe, как описано здесь!
dude 19.08.2016 09:56

Когда вы вызываете isElement(0), он возвращает 0, а не false ... Почему это так и как это предотвратить?

Jessica 07.09.2016 23:31

@Jessica Используйте !! o для предотвращения && короткого замыкания. Что также устраняет необходимость проверки o! == null.

Quentin Engles 19.10.2017 01:21

Я не понимаю сложности ... но должен признать, что я не тестировал этот кросс-браузер ... но в любом случае вот мой вариант, основанный на предположении, что HTMLElement никогда не меняется, поэтому он здесь, когда он здесь, всегда - так что проверьте это один раз ... И что HTMLElement является объектом или функцией, мне все равно ... просто не будь undefined. КОД ---> const isHTMLElement = typeof HTMLElement !== 'undefined' ? obj => obj instanceof HTMLElement : obj => typeof obj === 'object' && obj !== null && obj.nodeType === 1 && typeof obj.nodeName === 'string' ;

Shlomi Assaf 21.10.2018 03:19

Rly, когда это узел, мы сломаем его в чистом методе добавления js?

BOZ 30.03.2019 01:01

В Firefox вы можете использовать instanceof Node. Этот Node определен в ДОМ1.

Но в IE это не так просто.

  1. «instanceof ActiveXObject» может сказать только, что это собственный объект.
  2. "typeof document.body.appendChild == 'object'" сообщает, что это может быть объект DOM, но также может быть что-то еще, имеющее ту же функцию.

Вы можете только убедиться, что это элемент DOM, используя функцию DOM и перехватить исключение. Однако это может иметь побочные эффекты (например, изменение внутреннего состояния объекта / производительности / утечки памяти).

Все решения выше и ниже (включая мое решение) страдают от возможности быть неправильными, особенно в IE - вполне возможно (пере) определить некоторые объекты / методы / свойства, чтобы имитировать узел DOM, делающий тест недействительным.

Поэтому обычно я использую тестирование в стиле «утка»: я тестирую именно то, что использую. Например, если я хочу клонировать узел, я тестирую его следующим образом:

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

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

Между прочим, приведенный выше тест является хорошим тестом для узлов DOM во всех браузерах. Но если вы хотите быть в безопасности, всегда проверяйте наличие методов и свойств и проверяйте их типы.

Обновлено: IE использует объекты ActiveX для представления узлов, поэтому их свойства не ведут себя как истинные объекты JavaScript, например:

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

в то время как он должен вернуть «функцию» и true соответственно. Единственный способ проверить методы - посмотреть, определены ли они.

"typeof document.body.cloneNode" возвращает "объект" в моем IE

Dennis C 23.12.2008 08:07

Это похоже на достойный ответ. См. Мой ответ ниже, stackoverflow.com/a/36894871/1204556

Monarch Wadia 06.02.2017 19:27

старый поток, но вот обновленная возможность для пользователей ie8 и ff3.5:

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

Может, это альтернатива? Протестировано в Opera 11, FireFox 6, Internet Explorer 8, Safari 5 и 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;
}

Функцию не обмануть, например, это

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

Хорошая попытка, но обработка исключений обходится слишком дорого, если ее можно избежать. Кроме того, ES5 позволяет определять свойства объектов только для чтения.

Andy E 10.04.2012 18:01
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. Я не смог найти способ его взломать. Теоретически он проверяет каждого предка предложенного элемента, а также сам элемент, вставляя перед ним тег скрипта. Если его первый предок восходит к известному элементу, например <html>, <head> или <body>, и при этом не выдал ошибку, у нас есть элемент. Если первый предок не прикреплен к документу, мы создаем элемент и пытаемся поместить в него предложенный элемент (а затем удалить его из нового элемента) .
Таким образом, он либо ведет к известному элементу, либо успешно присоединяется к известному элементу, либо терпит неудачу. Он возвращает элемент или null, если это не элемент.

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

Joseph Lennox 27.09.2014 05:27

Вы можете увидеть, возвращает ли рассматриваемый объект или узел строковый тип.

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
typeof ({innerHTML: ""}).innerHTML === "string"
Qtax 10.02.2013 01:18

ГОРЯЧИЙ! Этот ответ должен быть победителем игры. if (typeof obj.innerHTML! == 'string') // не элемент dom.

user3751385 17.11.2014 20:08

Сначала я отреагировал на @Qtax и критика Томасруттера на более ранний ответ, но я начинаю покупать его. Хотя я раньше не сталкивался с собаками, которые крякают, как утки, точно так же, как это, я вижу, как кто-то не проверяет, является ли что-то узлом, работает notANode.innerHTML = "<b>Whoops</b>";, а затем этот код передает свой зараженный объект obj в код это. Защитный код === лучший код при прочих равных, и это в конечном итоге не является защитным.

ruffin 12.11.2015 20:11

Вот что я понял:

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

Для повышения производительности я создал самозапускающуюся функцию, которая проверяет возможности браузера только один раз и соответствующим образом назначает соответствующую функцию.

Первый тест должен работать в большинстве современных браузеров и уже обсуждался здесь. Он просто проверяет, является ли элемент экземпляром HTMLElement. Очень просто.

Второй - самый интересный. Это его основная функциональность:

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

Он проверяет, является ли el экземпляром конструкции, за которую он претендует. Для этого нам нужен доступ к конструктору элемента. Вот почему мы тестируем это в if-выражении. IE7, например, терпит неудачу, потому что (document.createElement("a")).constructor - это undefined в IE7.

Проблема с этим подходом заключается в том, что document.createElement на самом деле не самая быстрая функция и может легко замедлить работу вашего приложения, если вы тестируете с ее помощью множество элементов. Чтобы решить эту проблему, я решил кэшировать конструкторы. Объект ElementConstructors имеет nodeNames в качестве ключей с соответствующими конструкторами в качестве значений. Если конструктор уже кэширован, он использует его из кеша, в противном случае он создает элемент, кэширует свой конструктор для будущего доступа, а затем проверяет его.

Третий тест - неприятный откат. Он проверяет, является ли el object, имеет ли свойство nodeType, установленное на 1, и строку как nodeName. Конечно, это не очень надежно, но подавляющему большинству пользователей пока не стоит даже отступать.

Это самый надежный подход, который я придумал, при этом сохраняя при этом максимальную производительность.

Самый простой и кросс-браузерный способ определить, является ли элемент частью 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.

Если myelement не является объектом DOM, скорее всего, произойдет сбой.

Max Nanasy 21.08.2013 23:43

вот трюк с использованием 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));

}

jQuery внутренне выполняет elem.nodeType === 1, так почему бы не сохранить накладные расходы на вызовы и зависимость jQuery, а ваша функция isElement сделает это сама?

Joseph Lennox 27.09.2014 05:30

Это 2016 год, просто скажи «нет».

theflowersoftime 02.08.2016 01:02

Используя обнаруженное корневое обнаружение здесь, мы можем определить, например, тревога является членом корня объекта, который, скорее всего, будет окном:

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

Определить, является ли объект текущим окном, еще проще:

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

Это кажется менее затратным, чем решение try / catch в открывающем потоке.

Дон П

Я тестировал это в последних версиях Chrome и FF, а также в IE11, и он работает везде, в том числе для текстовых узлов и объектов, созданных с помощью document.createElement(), но также не вставленных в DOM. Удивительно (: Спасибо

Geradlus_RU 07.03.2016 21:26

Это похоже на достойный ответ, хотя мой делает то же самое и менее сложный. stackoverflow.com/a/36894871/1204556

Monarch Wadia 06.02.2017 19:27
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; },

// На самом деле я, скорее всего, не использую эти встроенные, но иногда полезно иметь эти ярлыки для кода настройки

obj.constructor.name не работает в IE, потому что в IE функции не имеют свойства name. Заменить на obj.constructor! = Object.

mathheadinclouds 21.01.2017 01:43

Проверьте, наследуется ли obj от Узел.

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

Узел - это базовый Интерфейс, от которого наследуются HTMLElement и Text.

Не вдаваться в это или что-то еще, но для браузеров, совместимых с ES5, почему бы и не просто:

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

Не будет работать с TextNodes и не уверен в Shadow DOM или DocumentFragments и т. д., Но будут работает почти со всеми элементами тегов HTML.

Это может быть полезно: 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);
}

В приведенном выше коде мы используем оператор двойное отрицание для получения логического значения объекта, переданного в качестве аргумента, таким образом мы гарантируем, что каждое выражение, вычисленное в условном операторе, будет логическим, используя преимущество Оценка короткого замыкания, таким образом, функция возвращает true или false.

Любая ложь должна закоротить ваше логическое значение. Например, undefined && window.spam("should bork") никогда не оценивает фальшивую функцию spam. Так что не думаю, что !! нужен. Итак, можете ли вы предоставить [неакадемический] крайний случай, когда его использование имеет значение?

ruffin 12.11.2015 20:00

Спасибо за одобрение. Я использовал * !! * двойное отрицание для преобразования всех выражений в логическое значение, а не в правдивость или ложь.

jherax 12.11.2015 20:27

Верно, но для этого нет практических причин, я не думаю - см. здесь. И, конечно, не обязательно использовать здесь Short-Cut eval. Даже если вы не купили аргумент «!! никогда не нужен» (а если нет, мне любопытно, почему бы и нет), вы можете отредактировать эту строку на return !!(obj && typeof obj === "object" && obj.nodeType === 1 && obj.nodeName); и заставить ее работать так же.

ruffin 12.11.2015 20:30

Так я и сделал;) более чистый и такой же эффект. Спасибо.

jherax 12.11.2015 20:35

Как насчет _.isElement Ло-Даша?

$ npm install lodash.iselement

И в коде:

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

Мне нравится это решение. Это просто и работает в Edge и IE, даже для элементов в отдельных фреймах, в отличие от большинства решений, получивших наибольшее количество голосов.

Elias Zamaria 03.11.2018 02:23

Этот ответ полезен, хотя для запуска модулей NPM в браузере потребуется Webpack.

Edwin Pratt 24.03.2019 17:59

Для тех, кто использует Angular:

angular.isElement

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

Более полезно включить Код Angular: function isElement(node) { return !!(node && (node.nodeName || (node.prop && node.attr && node.find))); } Немного похоже на @ Finpingvin's. Обратите внимание, что он определяет "если ссылка является элементом DOM (или обернутым элементом jQuery)."

ruffin 12.11.2015 20:20

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

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

Во-первых, вам не нужно возвращать true или false, просто верните оператор if. Во-вторых, это вернет истину для {nodeType: 1}

bluejayke 12.04.2020 15:55

Я обычно использую излишне подробный код (на этом сайте), чтобы прояснить смысл кода;)

Zv_oDD 27.06.2020 02:24

Я думаю, что прототипирование - не очень хорошее решение, но, может быть, это самое быстрое: Определите этот блок кода;

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

чем проверить свойство isDomElement ваших объектов:

if (a.isDomElement){}

Надеюсь, это поможет.

1) менять чужие предметы не рекомендуется. 2) это не обнаруживает элементы, которые не являются частью того же документа.

fregante 30.10.2016 10:46

это все равно не будет обнаружено js var fake = Object.create(Element.prototype)

Meir Blachman 14.03.2021 22:29

отличать необработанный объект js от HTMLElement

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

использовать:

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

// ИЛИ ЖЕ

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

использовать:

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

Интересное решение. Было бы полезно подробнее узнать, почему и как это работает. Что в итоге сравнивает метод?

Philipp 18.07.2020 00:07

js все воспринимает как объект, ojects расширяется прототипом, все стандартные элементы dom используют метод toString, который возвращает 4ex "HTMLDivElement"

bortunac 18.07.2020 12:12

Спасибо за подробности. Я только что проверил это сам и увидел, что document.body.toString() возвращает строку "[object HTMLBodyElement]". Если я правильно понимаю, другим способом написать isDOM может быть return -1 !== x.toString().indexOf("[object HTML").

Philipp 18.07.2020 13:39

Следующий суперпростой код, совместимый с IE8, работает отлично.

принятый ответ не обнаруживает все типы элементов HTML. Например, элементы SVG не поддерживаются. Напротив, этот ответ работает как для HTML, так и для SVG.

Посмотрите это в действии здесь: https://jsfiddle.net/eLuhbu6r/

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

'Элемент' не определен в IE7

Dan 15.12.2017 16:21

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

mopsyd 09.05.2018 07:27

Я согласен с @mopsyd, но автор ответа заявляет, что он работает в IE7, который, возможно, потребуется обновить для правильности.

Lajos Meszaros 26.07.2018 18:36

Обновлено, чтобы сказать IE9. Я не уверен, поддерживает ли это IE8.

Monarch Wadia 27.07.2018 09:16

@MonarchWadia да, он поддерживается в IE8. Но обратите внимание, что это не возвращает true для элемента document (во всех браузерах). если нужно, попробуйте: x instanceof Element || x instanceof HTMLDocument

S.Serpooshan 13.10.2018 09:32

изменено в соответствии с вашими комментариями

Monarch Wadia 15.10.2018 03:10

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

Jules Manson 27.12.2018 07:00

Обратите внимание, что это не работает в нескольких окнах. Т.е. window.open().document.body instanceof Element возвращает false.

nik10110 25.02.2019 22:56

@ nik10110 Вы проверяете, является ли экземпляр body нового окна экземпляром Element старого окна. Это работает, если вы измените свой код, как показано ниже :-) win = window.open(); win.document.body instanceof win.Element; // true

Monarch Wadia 21.04.2019 02:38

@mopsyd: I.T. отделы и клиенты иногда имеют ограничения на использование браузера (ов).

mnemotronic 23.01.2020 17:34

Я понимаю, что в определенном смысле есть ограничения. Однако суть таких ограничений заключается в ограничении гарантийных обязательств. На этом этапе ограничение IE7 ради безопасности похоже на попытку установить замок с засовом на дверь, которая является тентом.

mopsyd 31.01.2020 18:35

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

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

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

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

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

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

Вы также можете использовать средства получения свойств, если хотите.

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

вы isElement можете вернуть true для других объектов со свойством value, ваш isHTMLElement выдает щелчок

kofifus 06.09.2016 04:39

@kofifus Можете ли вы привести пример, который ломает isElement? А насчет щелчка я подумал, что это не так уж и вредно. HTMLElement.prototype не содержит многих методов, но, конечно, использование средства получения свойств (как показано в скрытом фрагменте) было бы более безопасным, но менее понятным.

Oriol 06.09.2016 04:43

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

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

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

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

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

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

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

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

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

Каждый DOMElement.constructor возвращает функция HTML ... Element () или [Объект HTML ... Элемент], так что ...

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

Никаких хаков, вы можете просто спросить, является ли элемент экземпляром DOM Элемент:

const isDOM = el => el instanceof Element

Блестяще! Работает!

Pedro Ferreira 16.05.2020 23:01

Имеет почти полную совместимость (caniuse.com/mdn-javascript_operators_instanceof), это должен быть принятый ответ

Ben Winding 28.03.2021 13:53
(element instanceof $ && element.get(0) instanceof Element) || element instanceof Element

Это будет проверять, даже если это элемент JQuery или JavaScript DOM

Простой способ проверить, является ли переменная элементом DOM (подробный, но более традиционный синтаксис :-)

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

Или, как предложил HTMLGuy (короткий и чистый синтаксис):

const isDomEntity = typeof entity === 'object' && entity.nodeType !== undefined

Слишком многословно. Сравнение уже вернет логическое значение: return typeof entity === 'object' && typeof entity.nodeType !== undefined;

HTMLGuy 12.07.2019 22:10

Очень интересно! Иногда, в зависимости от типов, которые у вас есть на ваших object и / или папках, это может быть очень удобно! Tx, @Roman

Pedro Ferreira 16.05.2020 23:12

Согласно mdn

Element is the most general base class from which all objects in a Document inherit. It only has methods and properties common to all kinds of elements.

Мы можем реализовать isElement по прототипу. Вот мой совет:

/**
 * @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.info(isElement(document)) // true
console.info(isElement(document.documentElement)) // true
console.info(isElement(document.body)) // true
console.info(isElement(document.getElementsByTagName('svg')[0])) // true or false, decided by whether there is svg element
console.info(isElement(document.getElementsByTagName('svg'))) // false
console.info(isElement(document.createDocumentFragment())) // false

Единственный способ гарантировать, что вы проверяете реальный HTMLEement, а не просто объект с теми же свойствами, что и элемент HTML, - это определить, наследуется ли он от Node, поскольку в JavaScript невозможно создать новый Node (). (если только встроенная функция Node не будет перезаписана, но тогда вам не повезло). Так:

function isHTML(obj) {
    return obj instanceof Node;
}

console.info(
  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--!>

если вы используете jQuery, попробуйте это

$('<div>').is('*') // true
$({tagName: 'a'}).is('*') // false
$({}).is('*') // false
$([]).is('*') // false
$(0).is('*') // false
$(NaN).is('*') // false

Другие вопросы по теме