Вот что я понял:
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-Statement. IE7, например , не может это, потому что (document.createElement("a")).constructorэто undefinedв IE7.
Проблема этого подхода заключается в том, что document.createElementна самом деле это не самая быстрая функция, и она может легко замедлить работу вашего приложения, если вы тестируете с его помощью множество элементов. Чтобы решить эту проблему, я решил кешировать конструкторы. Объект ElementConstructorsимеет nodeNames в качестве ключей и соответствующие конструкторы в качестве значений. Если конструктор уже кэширован, он использует его из кэша, в противном случае он создает элемент, кэширует его конструктор для будущего доступа, а затем проверяет его.
Третий тест - неприятный запасной вариант. Он проверяет, есть ли el object, имеет ли nodeTypeсвойство свойство 1и строку как nodeName. Конечно, это не очень надежно, но подавляющее большинство пользователей не должно даже отступать.
Это самый надежный подход, который я предложил, при этом сохраняя максимально высокую производительность.