这就是我想出的:
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
。这当然不是很可靠,但绝大多数用户甚至不应该退缩到现在。
这是我想出的最可靠的方法,同时仍然保持尽可能高的性能。