我想要:
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;
}
}
有好的替代品吗?
你可能会感兴趣:
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");
}
}
它是DOM的一部分,第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"
);
}
我有一个特殊的方法来做到这一点,在答案中还没有提到。
我的解决方案基于四个测试。如果对象通过了这四个,那么它就是一个元素:
该对象不是空的。
对象有一个叫做“appendChild”的方法。
方法“appendChild”继承自Node类,而不仅仅是一个冒名方法(具有相同名称的用户创建的属性)。
对象类型为Node Type 1 (Element)。从Node类继承方法的对象总是Node,但不一定是element。
问:如何检查给定的属性是否是继承的,而不是冒名顶替的?
答:要判断一个方法是否真正继承自Node,一个简单的测试是首先验证该属性是否具有“对象”或“函数”类型。接下来,将属性转换为字符串,并检查结果是否包含文本“[Native Code]”。如果结果看起来像这样:
function appendChild(){
[Native Code]
}
然后从Node对象继承了该方法。参见https://davidwalsh.name/detect-native-function
最后,把所有的测试放在一起,解决方案是:
function ObjectIsElement(obj) {
var IsElem = true;
if (obj == null) {
IsElem = false;
} else if (typeof(obj.appendChild) != "object" && typeof(obj.appendChild) != "function") {
//IE8 and below returns "object" when getting the type of a function, IE9+ returns "function"
IsElem = false;
} else if ((obj.appendChild + '').replace(/[\r\n\t\b\f\v\xC2\xA0\x00-\x1F\x7F-\x9F ]/ig, '').search(/\{\[NativeCode]}$/i) == -1) {
IsElem = false;
} else if (obj.nodeType != 1) {
IsElem = false;
}
return IsElem;
}
一个绝对正确的方法,检查目标是一个真正的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);