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式都是布尔值,从而利用短路评估的优势,返回true
或false
您可以看到所讨论的对象或节点是否返回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
在Firefox中,您可以使用instanceof Node
。 该Node
在DOM1中定义。
但在IE中这并不容易。
- “instanceof ActiveXObject”只能说明它是一个本地对象。
- “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是否是一个object
, nodeType
属性设置为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);
每个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。 如果对象通过所有四个,那么它是一个元素:
-
该对象不是null。
-
该对象有一个名为“appendChild”的方法。
-
方法“appendChild”是从Node类inheritance而来的,不仅仅是一个冒名顶替的方法(一个用户创build的名字相同的属性)。
-
该对象是节点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。