JavaScript isDOM – 你如何检查一个JavaScript对象是否是一个DOM对象?

我试图得到:

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

在我自己的脚本中,我以前只是使用这个,因为我从来不需要tagName作为属性:

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

所以对于第二个对象,我提出了以下作为一个快速解决scheme – 主要工作。 ;)

问题是,这取决于浏览器执行只读属性,这不是所有的。

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

有没有好的替代品?

这可能是有趣的:

 function isElement(obj) { try { //Using W3 DOM2 (works for FF, Opera and Chrom) 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"); } } 

它是DOM的一部分,Level2

更新2 :这是我在自己的库中实现它的原因(以前的代码在Chrome中不起作用,因为Node和HTMLElement是函数而不是预期的对象,代码在FF3,IE7,Chrome 1和Opera 9中testing)

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

上面和下面的所有解决scheme(包括我的解决scheme)都有可能是不正确的,尤其是在IE上 – 很有可能(重新)定义一些对象/方法/属性来模仿DOM节点使testing失效。

所以通常我会使用鸭子式的testing:我专门testing我使用的东西。 例如,如果我想克隆节点,我testing它是这样的:

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

基本上,这是一个有点理智的检查+我打算使用的方法(或财产)的直接testing。

顺便说一下,上面的testing对所有浏览器上的DOM节点都是一个很好的testing。 但是,如果你想要安全的一面总是检查方法和属性的存在,并validation它们的types。

编辑: IE使用ActiveX对象来表示节点,所以他们的属性不像真正的JavaScript对象,例如:

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

而应分别返回“function”和“ true ”。 testing方法的唯一方法是看看是否定义。

以下超级简单代码对于HTML和SVG都非常适用:

 function isElement(element) { // works on major browsers back to IE7 return element instanceof Element; } 

接受的答案不检测所有types的HTML元素。 例如,不支持SVG元素。

在这里看到它的行动: https : //jsfiddle.net/eLuhbu6r/

你可以试着把它附加到一个真正的DOM节点上

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

_.isElement_.isElement怎么_.isElement

 $ npm install lodash.iselement 

在代码中:

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

这是来自可爱的JavaScript库MooTools :

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

使用这里find的根检测,我们可以确定alert是否是对象根的成员,这可能是一个窗口:

 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解决scheme更便宜。

唐P

旧的线程,但这里是ie8和ff3.5用户更新的可能性:

 function isHTMLElement(o) { return (o.constructor.toString().search(/\object HTML.+Element/) > -1); } 
 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; }, 

//事实上,我更喜欢使用这些内联,但是有时这些快捷方式对于设置代码是很好的

这可能会有所帮助: 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); } 

在上面的代码中,我们使用双重否定运算符来获取作为parameter passing的对象的布尔值,这样我们可以确保在条件语句中评估的每个expression式都是布尔值,从而利用短路评估的优势,返回truefalse

您可以看到所讨论的对象或节点是否返回stringtypes。

 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 

对于使用Angular的人来说:

 angular.isElement 

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

在Firefox中,您可以使用instanceof Node 。 该Node在DOM1中定义。

但在IE中这并不容易。

  1. “instanceof ActiveXObject”只能说明它是一个本地对象。
  2. “typeof document.body.appendChild =='object'”告诉它可能是DOM对象,也可能是别的东西有相同的function。

您只能通过使用DOM函数确保它是DOM元素,并捕获是否有exception。 但是,它可能有副作用(例如,改变对象的内部状态/性能/内存泄漏)

也许这是一个select? 经过Opera 11,FireFox 6,Internet Explorer 8,Safari 5和Google Chrome 16的testing。

 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 

这是我想出的:

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

为了提高性能,我创build了一个自我调用函数,它只testing一次浏览器的能力,并相应地分配相应的函数。

第一个testing应该在大多数现代浏览器中工作,并已经在这里讨论。 它只是testing元素是否是HTMLElement一个实例。 非常简单。

第二个是最有趣的一个。 这是它的核心function:

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

它testingel是否是它假装的构造的一个实例。 为此,我们需要访问元素的构造器。 这就是为什么我们要在if语句中testing这个。 IE7举例失败,因为(document.createElement("a")).constructor在IE7中是undefined的。

这种方法的问题是, document.createElement实际上不是最快的function,如果你正在testing大量的元素,可能会很容易地减慢你的应用程序的速度。 为了解决这个问题,我决定caching构造函数。 ElementConstructors对象具有nodeNames作为键以及其对应的构造函数作为值。 如果一个构造函数已经被caching了,它就使用caching中的构造函数,否则它会创buildElement,caching它的构造函数以供将来访问,然后对它进行testing。

第三个testing是令人不快的倒退。 它testingel是否是一个objectnodeType属性设置为1 ,string为nodeName 。 这当然不是很可靠,但绝大多数用户不应该退缩到目前为止。

这是我提出的最可靠的方法,同时仍然保持尽可能高的性能。

testingobj是否从Nodeinheritance。

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

Node是HTMLElement和Textinheritance的基本接口 。

我认为原型是不是一个很好的解决scheme,但也许这是最快的:定义这个代码块;

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

比检查你的对象isDomElement属性:

 if(a.isDomElement){} 

我希望这有帮助。

区分一个原始的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

我认为你所要做的就是彻底检查一些总是处于dom元素中的属性,但是它们的组合不可能存在于另一个对象中,例如:

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

这里有一个使用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)); } 

不要殴打这个或任何东西,但符合ES5标准的浏览器,为什么不只是:

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

不能在TextNodes上工作,不能确定Shadow DOM或DocumentFragments等,但几乎可以处理所有的HTML标签元素。

这几乎适用于任何浏览器。 (这里没有元素和节点的区别)

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

一个绝对正确的方法,检查目标是一个真正的 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); 

测试在IE 5中

每个DOMElement.constructor返回函数HTML … Element()[Object HTML … Element]

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

我有一个特殊的方法来做到这一点,在答案中还没有提到。

我的解决scheme是基于四个testing。 如果对象通过所有四个,那么它是一个元素:

  1. 该对象不是null。

  2. 该对象有一个名为“appendChild”的方法。

  3. 方法“appendChild”是从Node类inheritance而来的,不仅仅是一个冒名顶替的方法(一个用户创build的名字相同的属性)。

  4. 该对象是节点types1(元素)。 从Node类inheritance方法的对象始终是节点,但不一定是元素。

问:如何检查一个给定的财产是否被inheritance,而不仅仅是冒名顶替者?

答:一个简单的testing,看看一个方法是否真正从Nodeinheritance,首先要validation该属性是否有一个“对象”或“函数”types。 接下来,将该属性转换为string,并检查结果是否包含文本“[Native Code]”。 如果结果看起来像这样:

 function appendChild(){ [Native Code] } 

然后该方法已经从Node对象inheritance。 请参阅https://davidwalsh.name/detect-native-function

最后,将所有testing结合在一起,解决scheme是:

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

不需要黑客,你可以问一个元素是否是元素的一个实例:

 const isElement = element => { element instanceof Element; }; 
 (element instanceof $ && element.get(0) instanceof Element) || element instanceof Element 

这将检查,即使它是一个jQuery或JavaScript的DOM元素

我build议一个简单的方法来testing一个variables是否是一个DOM元素

  function isDomEntity(entity) { if( typeof entity === 'object' && entity.nodeType != undefined){ return true; } else{ return false; } } 
 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上testing了这个。 我找不到一个方法来破解它。
理论上,它通过在它之前插入脚本标签来testing提出的元素的每个祖先以及元素本身。
如果它的第一个祖先追溯到一个已知的元素,比如<html><head>或者<body> ,并且它一直没有抛出错误,我们有一个元素。
如果第一个祖先没有附加到文档中,我们创build一个元素并尝试将提出的元素放置在其中(然后将其从新元素中移除)。
所以它可以追溯到已知的元素,成功地附着到已知的元素或失败。
它返回元素,如果不是元素,则返回null。

检测元素是否属于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. 

testingIE6,IE7,IE8,IE9,IE10,FF,Chrome,Safari,Opera。