Voici ce que j'ai compris:
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";
}
}
})();
Pour améliorer les performances, j'ai créé une fonction auto-invoquante qui teste les capacités du navigateur une seule fois et attribue la fonction appropriée en conséquence.
Le premier test devrait fonctionner dans la plupart des navigateurs modernes et a déjà été discuté ici. Il teste simplement si l'élément est une instance de HTMLElement
. Très simple.
Le second est le plus intéressant. Voici sa fonctionnalité principale:
return el instanceof (document.createElement(el.nodeName)).constructor
Il teste si el est une instance du constructeur qu'il prétend être. Pour ce faire, nous devons avoir accès au constructeur d'un élément. C'est pourquoi nous testons cela dans la déclaration if. IE7 par exemple échoue, car (document.createElement("a")).constructor
est undefined
dans IE7.
Le problème avec cette approche est que ce document.createElement
n'est vraiment pas la fonction la plus rapide et pourrait facilement ralentir votre application si vous testez beaucoup d'éléments avec elle. Pour résoudre ce problème, j'ai décidé de mettre en cache les constructeurs. L'objet ElementConstructors
a nodeNames comme clés avec ses constructeurs correspondants comme valeurs. Si un constructeur est déjà mis en cache, il l'utilise à partir du cache, sinon il crée l'élément, met en cache son constructeur pour un accès futur, puis le teste.
Le troisième test est le repli désagréable. Il teste si el est an object
, a une nodeType
propriété définie sur 1
et une chaîne as nodeName
. Bien sûr, ce n'est pas très fiable, mais la grande majorité des utilisateurs ne devraient même pas se replier jusqu'à présent.
C'est l'approche la plus fiable que j'ai trouvée tout en maintenant des performances aussi élevées que possible.