Вот что я понял:
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
. Конечно, это не очень надежно, но подавляющему большинству пользователей пока не стоит отступать.
Это самый надежный подход, который я придумал, сохраняя при этом максимально возможную производительность.