Я пытаюсь получить:
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;
}
}
Есть хороший заменитель?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Это из прекрасной библиотеки JavaScript MooTools:
if (obj.nodeName){
switch (obj.nodeType){
case 1: return 'element';
case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
}
}
Этот код не утверждает, что объект является элементом DOM; только то, что он немного похож на один. Любому объекту можно присвоить свойство nodeName и nodeType и удовлетворить этот код.
Этот ответ не определяет все типы элементов HTML. Например, элементы SVG не поддерживаются. Смотрите мой ответ ниже.
На самом деле не работает со всеми элементами, например SVG. См. Мой ответ ниже, stackoverflow.com/a/36894871/1204556
Я думаю, что вам нужно сделать тщательную проверку некоторых свойств, которые всегда будут в элементе 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;
}
Это работает? Это все еще решение. Причем творческий.
+1 за креативность и уверенность, которые это предлагает. Однако, если узел уже является частью DOM, вы только что удалили его! Итак ... этот ответ будет неполным без выполнения работы по повторному добавлению элемента в DOM, если это необходимо.
Я читаю это спустя почти 5 лет, и я думаю, что это один из самых крутых. Его просто нужно доработать. Например, вы можете попытаться добавить клон узла к отдельному элементу. Если это не объект DOM. что-то обязательно пойдет не так. Впрочем, это все еще довольно дорогое решение.
Или вместо попытки добавить клон элемента должно быть достаточно просто пытаюсь клонировать это: obj.cloneNode(false). А ТАКЖЕ не имеет побочных эффектов.
Это действительно дорого и излишне сложно. См. Мой ответ ниже, stackoverflow.com/a/36894871/1204556
Это креативно и было бы хорошо, за исключением того, что у него есть ужасный побочный эффект, заключающийся в изменении объекта, который вы тестируете! Т.е. он потенциально удаляет действительный элемент DOM из его текущего родителя! @Greg должен изменить ответ, указав это явно, так как использовать как есть опасно.
Это может быть интересно:
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"); работать во всех браузерах.
Стоит отметить, что это не будет работать с элементами, принадлежащими другим окнам / фреймам. Утиная печать - рекомендуемый подход
Вы можете обмануть это с помощью: function Fake() {}; Fake.prototype=document.createElement("div"); alert(new Fake() instanceof HTMLElement);
WTF факт: Firefox 5 и более ранние версии возвращают true для [] instanceof HTMLElement.
Кстати, HTMLElement всегда является function, поэтому typeof сбивает вас со следа и выполнит вторую часть оператора. Вы можете попробовать, если хотите, instanceof Object, потому что функция будет экземпляром Object, или просто явно проверить наличие typeof === "function", потому что Node и HTMLElement являются собственными объектными функциями.
Например, typeof HTMLElement === "object" в IE10 и typeof HTMLElement === "function" в Chrome. Таким образом, перед использованием typeof HTMLElement следует протестировать o instanceof HTMLElement на предмет "объекта" или "функции".
@some ваша функция isElement возвращает undefined, когда o - это undefined. Вы должны добавить !! после return и перед открывающей скобкой.
Этот ответ не работает для элементов SVG. Кроме того, мало кто больше заботится о поддержке DOM2; См. Мой ответ (поддерживается в IE7) ниже, если вам важны элементы SVG, но не DOM2.
Когда вы вызываете isElement(0), он возвращает 0, а не false ... Почему это так и как это предотвратить?
@Jessica Используйте !! o для предотвращения && короткого замыкания. Что также устраняет необходимость проверки o! == null.
Я не понимаю сложности ... но должен признать, что я не тестировал этот кросс-браузер ... но в любом случае вот мой вариант, основанный на предположении, что 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' ;
Rly, когда это узел, мы сломаем его в чистом методе добавления js?
В Firefox вы можете использовать instanceof Node. Этот Node определен в ДОМ1.
Но в IE это не так просто.
Вы можете только убедиться, что это элемент 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
Это похоже на достойный ответ. См. Мой ответ ниже, stackoverflow.com/a/36894871/1204556
старый поток, но вот обновленная возможность для пользователей 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 позволяет определять свойства объектов только для чтения.
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, если это не элемент.
Вам действительно следует писать код, чтобы его можно было читать. Объявление переменных перед использованием и оставление их с неописательными односимвольными именами для меня является серьезным предупреждением и заставляет меня не утруждать себя чтением вашего кода. Он не более "оптимизирован" для того, чтобы делать это таким образом.
Вы можете увидеть, возвращает ли рассматриваемый объект или узел строковый тип.
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"ГОРЯЧИЙ! Этот ответ должен быть победителем игры. if (typeof obj.innerHTML! == 'string') // не элемент dom.
Сначала я отреагировал на @Qtax и критика Томасруттера на более ранний ответ, но я начинаю покупать его. Хотя я раньше не сталкивался с собаками, которые крякают, как утки, точно так же, как это, я вижу, как кто-то не проверяет, является ли что-то узлом, работает notANode.innerHTML = "<b>Whoops</b>";, а затем этот код передает свой зараженный объект obj в код это. Защитный код === лучший код при прочих равных, и это в конечном итоге не является защитным.
Вот что я понял:
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, скорее всего, произойдет сбой.
вот трюк с использованием 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 сделает это сама?
Это 2016 год, просто скажи «нет».
Используя обнаруженное корневое обнаружение здесь, мы можем определить, например, тревога является членом корня объекта, который, скорее всего, будет окном:
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. Удивительно (: Спасибо
Это похоже на достойный ответ, хотя мой делает то же самое и менее сложный. stackoverflow.com/a/36894871/1204556
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.
Не вдаваться в это или что-то еще, но для браузеров, совместимых с 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. Так что не думаю, что !! нужен. Итак, можете ли вы предоставить [неакадемический] крайний случай, когда его использование имеет значение?
Спасибо за одобрение. Я использовал * !! * двойное отрицание для преобразования всех выражений в логическое значение, а не в правдивость или ложь.
Верно, но для этого нет практических причин, я не думаю - см. здесь. И, конечно, не обязательно использовать здесь Short-Cut eval. Даже если вы не купили аргумент «!! никогда не нужен» (а если нет, мне любопытно, почему бы и нет), вы можете отредактировать эту строку на return !!(obj && typeof obj === "object" && obj.nodeType === 1 && obj.nodeName); и заставить ее работать так же.
Так я и сделал;) более чистый и такой же эффект. Спасибо.
Как насчет _.isElement Ло-Даша?
$ npm install lodash.iselement
И в коде:
var isElement = require("lodash.iselement");
isElement(document.body);
Мне нравится это решение. Это просто и работает в Edge и IE, даже для элементов в отдельных фреймах, в отличие от большинства решений, получивших наибольшее количество голосов.
Этот ответ полезен, хотя для запуска модулей NPM в браузере потребуется Webpack.
Для тех, кто использует 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)."
Это будет работать практически для любого браузера. (Здесь нет различия между элементами и узлами)
function dom_element_check(element){
if (typeof element.nodeType !== 'undefined'){
return true;
}
return false;
}
Во-первых, вам не нужно возвращать true или false, просто верните оператор if. Во-вторых, это вернет истину для {nodeType: 1}
Я обычно использую излишне подробный код (на этом сайте), чтобы прояснить смысл кода;)
Я думаю, что прототипирование - не очень хорошее решение, но, может быть, это самое быстрое: Определите этот блок кода;
Element.prototype.isDomElement = true;
HTMLElement.prototype.isDomElement = true;
чем проверить свойство isDomElement ваших объектов:
if (a.isDomElement){}
Надеюсь, это поможет.
1) менять чужие предметы не рекомендуется. 2) это не обнаруживает элементы, которые не являются частью того же документа.
это все равно не будет обнаружено js var fake = Object.create(Element.prototype)
отличать необработанный объект 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
Интересное решение. Было бы полезно подробнее узнать, почему и как это работает. Что в итоге сравнивает метод?
js все воспринимает как объект, ojects расширяется прототипом, все стандартные элементы dom используют метод toString, который возвращает 4ex "HTMLDivElement"
Спасибо за подробности. Я только что проверил это сам и увидел, что document.body.toString() возвращает строку "[object HTMLBodyElement]". Если я правильно понимаю, другим способом написать isDOM может быть return -1 !== x.toString().indexOf("[object HTML").
Следующий суперпростой код, совместимый с IE8, работает отлично.
принятый ответ не обнаруживает все типы элементов HTML. Например, элементы SVG не поддерживаются. Напротив, этот ответ работает как для HTML, так и для SVG.
Посмотрите это в действии здесь: https://jsfiddle.net/eLuhbu6r/
function isElement(element) {
return element instanceof Element || element instanceof HTMLDocument;
}
'Элемент' не определен в IE7
Я считаю, что любой, кто все еще использует IE7, должен потратить пять секунд на загрузку лучшего браузера вместо того, чтобы заставлять нас тратить дни или недели на работу над своим отказом идти в ногу со временем.
Я согласен с @mopsyd, но автор ответа заявляет, что он работает в IE7, который, возможно, потребуется обновить для правильности.
Обновлено, чтобы сказать IE9. Я не уверен, поддерживает ли это IE8.
@MonarchWadia да, он поддерживается в IE8. Но обратите внимание, что это не возвращает true для элемента document (во всех браузерах). если нужно, попробуйте: x instanceof Element || x instanceof HTMLDocument
изменено в соответствии с вашими комментариями
Я считаю, что не стоит выполнять рендеринг для тех, кто использует браузеры старше, чем говорят, примерно на пять лет от текущего стандарта. Если ваш клиент - старый браузер, вы, вероятно, используете старый компьютер или мобильное устройство, что означает, что у вас меньше шансов потратить. В конце концов, рендеринг в основном касается платящих клиентов.
Обратите внимание, что это не работает в нескольких окнах. Т.е. window.open().document.body instanceof Element возвращает false.
@ nik10110 Вы проверяете, является ли экземпляр body нового окна экземпляром Element старого окна. Это работает, если вы измените свой код, как показано ниже :-) win = window.open(); win.document.body instanceof win.Element; // true
@mopsyd: I.T. отделы и клиенты иногда имеют ограничения на использование браузера (ов).
Я понимаю, что в определенном смысле есть ограничения. Однако суть таких ограничений заключается в ограничении гарантийных обязательств. На этом этапе ограничение IE7 ради безопасности похоже на попытку установить замок с засовом на дверь, которая является тентом.
Абсолютно правильный метод, цель проверки - 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);
В большинстве ответов используется какая-то утиная печать, например, проверка того, что объект имеет свойство 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 Можете ли вы привести пример, который ломает isElement? А насчет щелчка я подумал, что это не так уж и вредно. HTMLElement.prototype не содержит многих методов, но, конечно, использование средства получения свойств (как показано в скрытом фрагменте) было бы более безопасным, но менее понятным.
У меня есть особый способ сделать это, о котором еще не упоминалось в ответах.
Мое решение основано на четырех тестах. Если объект проходит все четыре, то это элемент:
Объект не нулевой.
У объекта есть метод appendChild.
Метод appendChild был унаследован от класса Узел и не является просто методом самозванца (созданное пользователем свойство с таким же именем).
Объект относится к типу узла 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
Блестяще! Работает!
Имеет почти полную совместимость (caniuse.com/mdn-javascript_operators_instanceof), это должен быть принятый ответ
(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;
Очень интересно! Иногда, в зависимости от типов, которые у вас есть на ваших object и / или папках, это может быть очень удобно! Tx, @Roman
Согласно mdn
Elementis the most general base class from which all objects in aDocumentinherit. 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
Я туплю, задаваясь вопросом, не должен ли «объект DOM» охватывать не только элементы, но и все узлы (текстовые узлы, атрибуты и т. д.)? Все ответы и то, как вы задали вопрос, наводят на мысль, что этот вопрос касается именно Элементов ...