JavaScriptで値がどのような型を持つかはtypeofを使えば調べられます。
ですが1つ問題点があってそれは必ずしも正確な型情報を返すわけではないということ
そこでここではtypeofの問題点や代わりになるコードについて紹介します。
typeofは必ずしも正確な型を返さない
まず初めにtypeofの何が問題なのかについて説明しましょう。
それは冒頭でも書いたように必ずしも正確な型を返すとは限らない、ということ
「そもそもtypeofって何?」という人もいるかもしれないので説明すると、
値や式に対して typeof 値や式 でそのデータ型を返す構文のことです。
例えば次はtypeofに値や式を渡してコンソールに表示しているコード例
1 2 3 4 5 6 |
console.log( typeof 100 ); /// => number console.log( typeof "hello" ); /// => string console.log( typeof (1 != 0) ) /// => boolean |
コンソールにはコメント文に書いたような number とか string とかの型名が表示されます。
ですが問題となるのは次のように配列とかクラスオブジェクトを渡した場合
1 2 3 4 5 6 |
console.log(typeof [1, 2, 3, 4, 5]); /// => object console.log(typeof new String('Hello')); /// => object console.log(typeof new Number(100)); /// => object |
上のコードだと Array とか String とか Number とかが返ってくると思いがち
ですが残念ながら全部 object で返ってきます。
「クラスはまだしも、なんで配列までobjectになるの?」
と思ってしまいますが、それはtypeofが対応している型を調べれば分かります。
実際MDNのリファレンスを見るとtypeofの返すことができる値の一覧表が載っています。
その一覧表の一部をここにも載せておくと次の通り
型 | 戻り値 |
---|---|
未定義 | "undefined" |
Null | "object" |
真偽値 | "boolean" |
数値 | "number" |
文字列 | "string" |
シンボル | "symbol" |
関数オブジェクト | "function" |
他のオブジェクト | "object" |
一部省略していますが、typeofは基本プリミティブ型を判定するためのものです。
配列にも対応してなく、ましてやStringとかNumberとかのクラス名を返すこともできません。
それらは「他のオブジェクト」に分類されるので全て object という値が返されるわけです。
つまりここまでをまとめると
typeofは基本的な型以外は全てobjectとして返されてしまう
ということ
ではそうすれば具体的な型名を調べられるのか、その方法を次で紹介しましょう。
typeofを使わず具体的な型名を調べる方法
その詳しいコードについては次のStackoverFlowページに載っていました。
一番最初の回答のなかにある次のコードです。
1 2 3 4 5 |
Object.prototype.getName = function() { var funcNameRegex = /function (.{1,})\(/; var results = (funcNameRegex).exec((this).constructor.toString()); return (results && results.length > 1) ? results[1] : ""; }; |
このコードを一番最初に書くことでObjectを継承している全てのクラスでgetName関数が使用できるようになります。
実際にこのコードを使って配列とかクラスの型名を調べることが可能です。
例えば次は先ほどの配列やクラスを getName に置き換えたコード例
1 2 3 4 5 6 |
console.log(new String('Hello').getName()); /// => String console.log(new Number(100).getName()); /// => Number console.log([1, 2, 3, 4, 5].getName()); /// => Array |
コメントを見てもらえば分かるようにちゃんとクラス名が返ってきます。
一応これがどういう原理でクラス名を取得しているか解説すると次の通り
- クラスのコンストラクタ関数にマッチする正規表現を用意
1var funcNameRegex = /function (.{1,})\(/;
- コンストラクタ関数を文字列化してマッチ部分を取得
1var results = (funcNameRegex).exec((this).constructor.toString());
- 正しい結果ならコンストラクタ関数の関数名だけを返す
1return (results && results.length > 1) ? results[1] : "";
大まかな仕組みを説明するとこんな感じですかね。
これで今まで取得できなかったクラス名まで取得できるようになりました。
もちろんプリミティブな型に対してはtypeofを使った方がいいです。
ですがどうしてもクラス名や配列かどうか調べたい場合にはこちらの方法を使うのがベスト
ここまでのまとめ
ということで簡単にここまでのまとめ
- typeofは配列やクラスでは使えない
typeof [1, 2, 3] とか typeof new Number(10) とかしても全て object が返ってきてしまう
- コンストラクタ関数の名前を調べればOK
なので配列やクラスに限っては getName などを自作して調べれば取得可能
typeofでは基本的な型以外は名前を取得できないことに注意です。
なのでクラスや配列に対して型名を調べたいときはStackOverflowのようなコードが役立ちます。
ではでは($・・)/~~~