我想要:
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;
}
}
有好的替代品吗?
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; },
//事实上我更倾向于内联使用这些快捷方式,但有时为设置代码提供这些快捷方式是很好的
你可能会感兴趣:
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"
);
}
区分一个原始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;
}
});
use:
o = {};o.is("HTML") // false
o = document.body;o.is("HTML") // true
上面和下面的所有解决方案(包括我的解决方案)都有可能是不正确的,特别是在IE上——(重新)定义一些对象/方法/属性来模拟DOM节点,使测试无效是很可能的。
所以我通常使用duck-typing风格的测试:我专门测试我使用的东西。例如,如果我想克隆一个节点,我这样测试它:
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.log(typeof node.cloneNode); // object
console.log(node.cloneNode instanceof Function); // false
而它应该分别返回“function”和true。测试方法的唯一方法是查看是否定义了方法。