这是我想出的:
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作为键,其对应的构造函数作为值。如果已经缓存了构造函数,则从缓存中使用它,否则它将创建Element,缓存其构造函数以供将来访问,然后对其进行测试。
第三个测试是令人不愉快的后备。它测试el是否为object
,nodeType
属性设置为1
,字符串为nodeName
。这当然不是很可靠,但是到目前为止,绝大多数用户都不应退缩。
这是我想出的最可靠的方法,同时仍保持尽可能高的性能。