WIZ-CODE.blog

JavaScriptやAjaxをテーマとしたブログです。

*

JavaScriptのデータ型判定方法

      2010/05/25

JavaScriptライブラリにはたいてい、データの種類を検出するメソッドが用意されています。たとえば、Prototype.jsにはObject.isArray()Object.isUndefined()などがあり、jQueryにもjQuery.isArray()などがありますね。今回はJavaScriptで一般的に用いられているデータ型やオブジェクトのタイプ判別法を見ていきたいと思います。 typeof演算子を用いる方法 instanceof演算子を用いる方法(ただし、JavaScriptのバージョン1.4以上でないとできない) Object.toString()を用いる方法 typeof演算子を使う場合、それぞれ次のような結果が返ってきます。 文字列 ⇒ ”string” 数値 ⇒ ”number” 未定義値 ⇒ ”undefined” ヌル ⇒ ”object” 関数 ⇒ ”function” 配列 ⇒ ”object” オブジェクト ⇒ ”object” 文字列オブジェクト(new String()) ⇒ ”object” 数値オブジェクト(new Number()) ⇒ ”object” ここで注目されるのは配列やヌル(null)がなぜか生のオブジェクト(Objectオブジェクト: new Object()で作るやつ)と同じ”object”として判定されることです。また、文字列や数値でもnew演算子でオブジェクトに変換してしまうと”object”扱いになります。一方、関数は”function() {}”のリテラル表記でも、コンストラクタ経由(new Function())でも”function”の結果が返ります。そのため、データが配列やオブジェクトであるかを判定するのにtypeof演算子だけでは不向きな一方、関数の判定には有効となります。また文字列/数値/bool値などに関してはデータが仮にオブジェクト化したものである場合、期待通りの判定にならないため注意を要します。ただ、undefinedに関してはPrototype.jsObject.isUndefined()メソッドがそうであるように単純にtypeof演算子を用いた検出が有効です。 次にinstanceof演算子を見てみると、この演算子はそのオブジェクトが何のインスタンスであるかを調べるものであるため、配列や関数などオブジェクト型のデータであればtypeof演算子のときと違って、種類を正確に判定できます。しかし、バージョンによって使用できないという問題のほか、Objectオブジェクトがすべてのタイプのオブジェクトのひな型であることから、Objectオブジェクト自体を検出するのが困難という点が挙げられます。
var string = new String('文字列'); //文字列のオブジェクト
var object = new Object(); //Objectオブジェクト
alert( string instanceof String ); //true これは期待通りの結果
alert( object instanceof Object ); //true これも期待通りの結果
alert( string instanceof Object ); //true どんなオブジェクトでもObjectオブジェクトのインスタンス扱いになってしまう
instanceof演算子の使用は自作のコンストラクタ(オブジェクト)の判定程度にとどめるのが無難でしょうか。 そして、最後のObject.toString()ですが、これはオブジェクトの判定に限れば一番有望な方法に見えます。下の例ではすべてのタイプのオブジェクトにメソッドを適用するためapply()メソッドを使っています。
var object = {}; //new Object()と同じ意味
var array = {}; //new Array()と同じ意味
var string = '文字列';
var stringObj = new String('文字列');

Object.prototype.toString.apply(object); //"[object Object]"
Object.prototype.toString.apply(array); //"[object Array]"
Object.prototype.toString.apply(string); //"[object String]"
Object.prototype.toString.apply(stringObj); //"[object String]"
この方法だと、生のオブジェクトの判定も可能で、さらに文字列/数値などもオブジェクト/非オブジェクトに関係なくデータ型を返すようになります。それでは、データ型別に有効な判定方法をまとめてみます(検証ブラウザFirefox3.5)。 undefined ⇒ typeof演算子 ヌル(null) ⇒ if ( aaa === null ) { …… } 配列 ⇒ instanceof演算子か、Object.toString() 関数 ⇒ typeof演算子かinstanceof演算子か、Object.toString() 正規表現 ⇒ instanceof演算子か、Object.toString() 自作クラス(コンストラクタ) ⇒ instanceof演算子 文字列/数値/bool値 ⇒ Object.toString() ただ、jQuery(v1.4.1)の「Objectオブジェクト」判定メソッドであるjQuery.isPlainObject()は少し違う方法をとっているようです。
........
........
	isPlainObject: function( obj ) {
		// Must be an Object.
		// Because of IE, we also have to check the presence of the constructor property.
		// Make sure that DOM nodes and window objects don't pass through, as well
		if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) {
			return false;
		}
		
		// Not own constructor property must be Object
		if ( obj.constructor
			&& !hasOwnProperty.call(obj, "constructor")
			&& !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) {
			return false;
		}
		
		// Own properties are enumerated firstly, so to speed up,
		// if last one is own, then all properties are own.
	
		var key;
		for ( key in obj ) {}
		
		return key === undefined || hasOwnProperty.call( obj, key );
	},
........
........
jQuery.isPlainObject()を使って次の四つのObjectオブジェクト(obj1, obj2, pro, ins)を試してみました。
var obj1 = {}, //new Object()して作成したオブジェクト
	obj2 = { hoge: 'HOGE' }, //プロパティを追加したオブジェクト
	Con = function() { this.fuga = 'FUGA' },
	pro = Con.prototype, //プロトタイプ(コンストラクタ評価時に自動的に作成されるオブジェクト)
	ins = new Con(); //コンストラクタから作成された新規インスタンス
	
	jQuery.isPlainObject(obj1) //true
	jQuery.isPlainObject(obj2) //true
	jQuery.isPlainObject(pro) //true
	jQuery.isPlainObject(ins) //false
	
普通に作成されたObjectオブジェクトは当然のことながらtrueですが、インスタンス・オブジェクトがはじかれる一方、prototypeプロパティの場合trueを渡すようです。

 - JavaScript/Ajax , ,