こんにちは!Webコーダー・プログラマーの貝原(@touhicomu)です。
JavaScriptのコードを書く際に、変数の型を知りたいときってよくありますよね。
また、どのクラスのインスタンスなのかを知りたい場合も多いです。
今回はそんな時に使える、JavaScriptのtypeofについて解説したいと思います。
この記事は下記の流れで解説していきます。
【基礎】そもそも型とは?
【基礎】typeofの基本的な型判定方法
【発展】typeofで配列やラッパークラスを判定する方法
【発展】typeofとinstanceofの違い
typeofの使い方をマスターし、正しい場面で使いこなせるよう、しっかり学習を進めていきましょう。
そもそも型とは?
JavaScriptの型判定について解説する前に、そもそも型(かた)とはどんなものなのか、きちんと理解するところから始めましょう。
プログラミングの世界に限らず日常の世界でも”文字”という言葉は色々なものを指しますよね。
日本語のひらがなや英語、それに数字など様々な種類に分類されます。
プログラミングの世界でもコンピュータが扱う”データ”という言葉が指すものとして、いくつかの種類が存在しています。
その種類のことを一般的に”型”と呼んでいます。
例えば、日本語の”おはよう”という文字のデータは文字列型(もしくはString型)と呼ばれ、数字の1や100などは数値型と呼ばれています。
さらにその中で、JavaScriptの基本的な型のことを組み込み型(もしくはプリミティブ型)と呼んでいます。
今回やるような判定の際は、下記のような型がよく使われています。
まだこれでも一部ですが、ひとまずこれだけ押さえておけばOKです。
型名 | 値の例 | 判定で表示される値 | 備考 |
---|---|---|---|
数値型 | 1,2,3など | number | |
文字列型 | おはよう、abcなど | string | String型とも呼ばれる |
真偽値型 | True / False | boolean | |
Null型 | null | object | |
Undefined型 | undefined | undefined | 何も代入されていない変数に設定されている値 |
関数 | function() {} | function | |
他のオブジェクト | {a: 1} | object |
型には本当に色々な種類があります。
一気に覚えるのは大変だと思うので、必要な時に確認してみるといいですね。
型を判定するtypeofの使い方
型の種類についてバッチリ理解できたところで、型の判定方法について確認していきましょう。
型の判定には、typeofという演算子を使います。
基本的な書き方は下記のように、typeofの後ろに型を判定したい値を記述するだけです。
typeof 判定したい値
では、これを使って様々な型を判定して、より理解を深めていきましょう。
組み込み型(プリミティブ型)の場合
typeof演算子で判定するものとして、まずは、文字列や数値型などの組み込み型(プリミティブ型)のtypeofの判定結果を見ていきましょう。
window.onload = function () { // typeofの使用例 // Number console.log( 'typeof 1 = ' + (typeof 1) ); console.log( 'typeof 1.41 = ' + (typeof 1.41) ); console.log( 'typeof Math.PI = ' + (typeof Math.PI) ); console.log( 'typeof Infitity = ' + (typeof Infinity) ); // String console.log( 'typeof "" = ' + (typeof "") ); console.log( 'typeof "abc" = ' + (typeof "abc") ); console.log( 'typeof "123" = ' + (typeof "123") ); console.log( 'typeof (typeof 0) = ' + (typeof (typeof 0)) ); // Boolean console.log( 'typeof true = ' + (typeof true) ); console.log( 'typeof false = ' + (typeof false) ); // Undefined console.log( 'typeof undefined = ' + (typeof undefined) ); }
実行結果:
// Number typeof 1 = number typeof 1.41 = number typeof Math.PI = number typeof Infitity = number // String typeof "" = string typeof "abc" = string typeof "123" = string typeof (typeof 0) = string // Boolean typeof true = boolean typeof false = boolean // Undefined typeof undefined = undefined
以上のように、組み込み型に対して、typeofは正しく動作しているようですね。
また、「typeof (typeof 0) = string」となっているように、typeofの返り値はstring型であることがわかります。
関数やオブジェクト型の場合
次は、関数やオブジェクトに対するtypeofの結果を見ていきましょう。
window.onload = function () { // Function console.log( 'typeof function () { } = ' + (typeof function () { }) ); console.log( 'typeof class abc { } = ' + (typeof class abc { }) ); console.log( 'typeof Math.abs = ' + (typeof Math.abs) ); // Object console.log( 'typeof { prop: 1 } =' + (typeof { prop: 1 }) ); // nullはObject型です。 console.log( 'typeof null = ' + (typeof null) ); // Date()やString()のラッパーオブジェクトはObjectと判定されます。 console.log( 'typeof new String("abc") = ' + (typeof new String("abc")) ); // Array は Objectと判定されます。 console.log( 'typeof [1, 2, 3] = ' + (typeof [1, 2, 3]) ); // Array.isArray や Object.prototype.toString.call などで // 普通のオブジェクトと配列を区別できます。 console.log( 'Array.isArray({ prop: 1 }) = ' + (Array.isArray({ prop: 1 })) ); console.log( 'Array.isArray([1, 2, 3]) = ' + Array.isArray([1, 2, 3]) ); }
実行結果:
// Function typeof function () { } = function typeof class abc { } = function typeof Math.abs = function // Object typeof { prop: 1 } =object // nullはObject型です。 typeof null = object // Date()やString()のラッパーオブジェクトはObjectと判定されます。 typeof new String("abc") = object // Array は Objectと判定されます。 typeof [1, 2, 3] = object // Array.isArray や Object.prototype.toString.call などで // 普通のオブジェクトと配列を区別できます。 Array.isArray({ prop: 1 }) = false Array.isArray([1, 2, 3]) = true
関数やクラス、Mathの組み込み関数などは、"function"と判定されていますね。
また、オブジェクトは"object"と正しく判定されていますが、配列やラッパークラスも”object”と判定されています。
ラッパーオブジェクトは、組み込み型をオブジェクト化したものですので、"object"と判定されてしまうのです。
これでは厳密な判定とは言えませんね。
そんな時、はArray.isArray()メソッドを使えば、配列の場合はtrue、配列以外の場合はfalseを返してくれます。
配列やラッパークラスを判定する
typeofでは、ラッパーオブジェクトがObjectと判定され、ArrayもObjectと判定されていました。
もっと細かく判定ができるよう、これらを改善する関数を作ってみましょう。
下記のgetClassName()という関数を作成してみました。
window.onload = function () { //typeofの関数化の例 function getClassName(obj) { if (typeof obj === "undefined") { // objがundefined return "undefined"; } else if (obj === null) { // objがnull return "null"; } else { // objが有効 // prototype名取得 var className = Object.prototype.toString.call(obj); // "object"以降のクラス名を取得 var matches = className.match(/^[objects(.*)]$/); if (matches.length > 0) { // クラス名が存在 return matches[1]; } else { return className; } } } }
引数がundefinedかnullの場合は、いずれもオブジェクトではないのでそのまま返り値にしています。
この判断にtypeofを使用しています。
nullかどうかは、オブジェクトに===演算子を使って直接nullかを判断するようにしました。
それ以外の場合はprototype名を取得し、その中から正規表現にてクラス名を抜き出しています。
これは、typeofの機能ではありません。
では、作成した関数を以下のコードで判定してみましょう。
window.onload = function () { console.log( 'getClassName("") = ' + getClassName("") ); console.log( 'getClassName(true) = ' + getClassName(true) ); console.log( 'getClassName(0) = ' + getClassName(0) ); // ArrayもArrayと判定できる。 console.log( 'getClassName([1,2,3]) = ' + getClassName([1,2,3]) ); console.log( 'getClassName({a: 1}) = ' + getClassName({a: 1}) ); console.log( 'getClassName(null) = ' + getClassName(null) ); var FuncA = function (a) { return a; }; console.log( 'getClassName(FuncA) = ' + getClassName(FuncA) ); }
実行結果:
getClassName("") = String getClassName(true) = Boolean getClassName(0) = Number // ArrayもArrayと判定できる。 getClassName([1,2,3]) = Array getClassName({a: 1}) = Object getClassName(null) = null getClassName(FuncA) = Function
以上のように、組み込み型およびArrayについてもそのクラス名を取得できています。
また、関数のクラス名も取得できていますね。
類似メソッドinstanceofとの違い
typeof演算子と似たような判定処理を行う演算子にinstanceof演算子があります。
instanceof演算子はオブジェクトがどのクラスのインスタンスかを判定する際に使用します。
使い方は簡単、instanceofに続けて調べたいオブジェクトを指定するだけです。
window.onload = function () { // instanceofの使用例 var arrayData = [1, 2, 3, 4, 5]; console.log( 'arrayData instanceof Array =' + (arrayData instanceof Array) ); console.log( 'arrayData instanceof Object = ' + (arrayData instanceof Object) ); // 組み込み型(プリミティブ型)にはinstanceofは効かない。 console.log( '1 instanceof Number = ' + (1 instanceof Number) ); console.log( '"abc" instanceof String = ' + ("abc" instanceof String) ); console.log( 'true instanceof Boolean = ' + (true instanceof Boolean) ); }
実行結果:
arrayData instanceof Array =true arrayData instanceof Object = true // 組み込み型(プリミティブ型)にはinstanceofは効かない。 1 instanceof Number = false "abc" instanceof String = false true instanceof Boolean = false
以上のように、配列は、ArrayとObjectのインスタンスでした。
これはArrayがObjectを継承したオブジェクトだからですね。
また、組み込み型には、instanceofは使用できませんでした。
これは、組み込み型はオブジェクトを継承した"もの(オブジェクト)"ではなく、単なる"値"なので、組み込み型がなんらかのオブジェクトのインスタンスになることはないからです。
まとめ
いかがでしたか?
typeof演算子は、変数の型を取得するのに便利ですね。
最後に、ポイントをおさらいしておきましょう。
・組み込み型のラッパークラスに対してはうまく動作しない
・instanceof演算子は、オブジェクトがどのインスタンスなのかの判定ができる
・組み込み型のラッパークラスも正しく判定できている
・typeof演算子をうまく関数化すれば便利なコードができる
皆さんもぜひ、ご自分で関数化してみてください。
使い方を忘れてしまったら、是非この記事を思い出してくださいね。