instanceof 演算子でオブジェクトが特定のクラスに属しているのかを確認することができます。また、継承も考慮されます。
このようなチェックが必要なケースは多々あるかもしれません。ここでは、その型に応じて引数を別々に扱う 多形(ポリモーフィック) 関数を構築するために使用します。
instanceof 演算子
構文は次の通りです:
obj instanceof Class
それは obj が Class (または、それを継承しているクラス)に属している場合に true を返します。
例:
コンストラクタ関数でも動作します。:
…また Array のような組み込みクラスでも動作します。:
arr は Object クラスにも属していることに留意してください。Array はプロトタイプ的に Object を継承しているためです。
通常、instanceof 演算子はチェックのためにプロトタイプチェーンを検査します。この動きに対して、静的メソッド Symbol.hasInstance でカスタムロジックが設定できます。
obj instanceof Class のアルゴリズムはおおまかに次のように動作します。:
-
もし静的メソッド
Symbol.hasInstanceがあれば、それ(Class[Symbol.hasInstance](obj))を使います。これはtrueまたはfalseを返す必要があり、これでinstanceofの振る舞いがカスタマイズできます。:例:
-
ほとんどのクラスは
Symbol.hasInstanceを持っていません。このケースでは、通常のロジックが使用されます:obj instanceOf ClassはClass.prototypeがobjのプロトタイプチェーンうちの1つと等しいかをチェックします。言い換えると、以下のような比較を行います:
obj.__proto__ == Class.prototype obj.__proto__.__proto__ == Class.prototype obj.__proto__.__proto__.__proto__ == Class.prototype ... // いずれかが true の場合、 true が返却されます // そうでない場合、チェーンの末尾に到達すると false を返します上の例では、``rabbit.proto === Rabbit.prototype` なので、すぐに回答が得られます。
継承のケースでは、2つめのステップでマッチします:
これは、rabbit instanceof Animal と Animal.prototype を比較したものです。:
ところで、objA.isPrototypeOf(objB) というメソッドもあります。これは objA が objB のプロトタイプチェーンのどこかにあれば true を返します。なので、obj instanceof Class のテストは Class.prototype.isPrototypeOf(obj) と言い換えることができます。
面白いことに、Class コンストラクタ自身はチェックには参加しません! プロトタイプと Class.prototypeのチェーンだけです。
これは prototype が変更されたときに興味深い結果につながります。
このように:
おまけ: 型のための Object toString
私たちは通常の文字列は [object Object] という文字列に変換されることをすでに知っています。:
これが toString の実装です。しかし、実際にはそれよりもはるかに強力な toString を作る隠れた機能があります。それを拡張させて typeof または instanceof の代替として利用することができます。
奇妙に聞こえますか?たしかに。分かりやすく説明しましょう。
スペック(specification)によって、組み込みの toString はオブジェクトから抽出し、任意の値のコンテキストで実行することができます。そして、その結果はその値に依存します。
- 数値の場合、それは
[object Number]になります。 - 真偽値の場合、
[object Boolean]になります。 nullの場合:[object Null]undefinedの場合:[object Undefined]- 配列の場合:
[object Array] - …など (カスタマイズ可能).
デモを見てみましょう:
ここでは、コンテキスト this=arr で関数 objectToString を実行するため、デコレータと転送, call/apply の章で説明した call を使いました。
内部的には、toString アルゴリズムは this を検査し、対応する結果を返します。ほかの例です。:
Symbol.toStringTag
Object toString の振る舞いは特別なオブジェクトプロパティ Symbol.toStringTag を使用してカスタマイズできます。
例:
ほとんどの環境固有のオブジェクトには、このようなプロパティがあります。これはいくつかのブラウザ固有の例です。:
ご覧の通り、結果は正確に Symbol.toStringTag (存在する場合)で、[object ...] の中にラップされています。
最終的には、プリミティブなデータ型だけでなく、組み込みオブジェクトのためにも機能し、カスタマイズすることもできる “強化された typeof” があります。
これは、型を文字列として取得するだけでなく、チェックするために、組み込みオブジェクトに対して instanceof の代わりに使用できます。
サマリ
私たちが知っている型チェックメソッドについて再確認しましょう:
| 対象 | 戻り値 | |
|---|---|---|
typeof |
プリミティブ | 文字列 |
{}.toString |
プリミティブ, 組み込みオブジェクト, Symbol.toStringTag をもつオブジェクト |
文字列 |
instanceof |
オブジェクト | true/false |
ご覧のように、{}.toString は技術的には “より高度な” typeof です。
そして、instanceof 演算子は、クラス階層を扱っていて継承を考慮したクラスのチェックをしたい場合に本当に輝きます。