これは私が理解したものです:
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";
}
}
})();
パフォーマンスを改善するために、ブラウザーの機能を 1 回だけテストし、それに応じて適切な関数を割り当てる自己呼び出し関数を作成しました。
最初のテストは、最新のブラウザーのほとんどで動作するはずであり、既にここで説明されています。要素が のインスタンスであるかどうかをテストするだけですHTMLElement
。非常に簡単です。
2 つ目は、最も興味深いものです。これはそのコア機能です:
return el instanceof (document.createElement(el.nodeName)).constructor
el がコンストラクターのインスタンスであるかどうかをテストします。そのためには、要素のコンストラクターにアクセスする必要があります。そのため、if ステートメントでこれをテストしています。たとえばIE7はIE7にあるため、これに失敗し(document.createElement("a")).constructor
ますundefined
。
このアプローチの問題は、document.createElement
実際には最速の関数ではなく、多くの要素をテストしている場合、アプリケーションの速度が簡単に低下する可能性があることです。これを解決するために、コンストラクターをキャッシュすることにしました。オブジェクトElementConstructors
には、対応するコンストラクターを値として持つキーとして nodeNames があります。コンストラクターが既にキャッシュされている場合は、キャッシュからそれを使用します。それ以外の場合は、要素を作成し、将来のアクセスのためにコンストラクターをキャッシュしてから、それに対してテストします。
3 番目のテストは、不愉快なフォールバックです。el が であるかどうかobject
、nodeType
プロパティが に設定され1
、文字列が であるかどうかをテストしますnodeName
。もちろん、これはあまり信頼できるものではありませんが、大多数のユーザーはこれまでのところフォールバックすることさえすべきではありません.
これは、可能な限り高いパフォーマンスを維持しながら、私が思いついた最も信頼性の高いアプローチです。