Mach3.laBlog

“isXxx” – Alphabetical Advent Calendar 2013

この記事は賞味期限切れです。(更新から1年が経過しています)

“I” は is の “I”

I

isXxx

値の型を取得する為の isString() や isArray() 等のメソッド群の話です。 もともと実装されているものも多少はありますが、フレームワークやライブラリのメソッドを利用するケースがほとんどでしょう。

typeof が期待できない

そもそも JavaScript には typeof 演算子があるのですが、この子があまり頼りにならず、期待している値を返してくれないケースが多いです。 例えば、文字列かどうかを判別する為に typeof を使用したとします。

typeof "foo"; // "string"
typeof new String("foo"); // "object"

両方とも “string” を返して欲しいところなのですが、 new を使って String のインスタンスを生成した場合は、typeof で “object” が返されてしまいます。

また、null を typeof で調べても “object” が返ってきてしまう現象も知られています。 ここは “null” を期待したいところです。(これは将来的に “null” を返すように改善される予定だそうです)

typeof null; // "object"

厳密に対応したい場合は、また違った工夫が必要の様です。

自作関数で判別してみる

広く使われているのが Object.prototype.toString を借用してみるタイプです。

var isString = function(str){
    return typeof str === "string" 
    || Object.prototype.toString.call(str) === "[object Strng]";
};

isString("foo"); // true
isString(new String("foo")); // true

toString さんをお借りして文字列化してみると、大抵 “object Xxx” という形で返してくれるので、 この “Xxx” の部分をチェックする事でどんなオブジェクトなのかを知る事ができます。 あるいは instanceof String なども使えますが、文字列で判別できた方が関数を共通化しやすいですね。

試しに共通化してみましょう。

var isType = function(value, type){
    return Object.prototype.toString.call(value).toLowerCase() 
        === ("[object " + type + "]").toLowerCase();
};

isType(new String("foobar"), "string"); // true
isType(new Array(), "array"); // true
isType(null, "null"); // true

こんな感じに、色々なライブラリに実装されています。 (勿論、もっとしっかり作られています)

jQueryの場合

jQuery でのタイプの判別は、主として type() で行われています。 「きちんと想定した物を返してくれる typeof」といったような感じで利用できます。 type の中では Object.prototype.toString で返される文字列を元にして判別し、 boolean, number, string, function, array, date, regexp, object, error のいずれかを返してくれます。

$.type(new String("foo")); // "string"
$.type(new Array(100)); // "array"
$.type(true); // "boolean"

その他良く使用されそうな物や、より細かく判別したい物は、 isArrayisFunction といった形で定義されています。

$.isArray([]); // true
$.isFunction(function(){}); // true
$.isPlainObject({}); // true
$.isEmptyObject({}); // true

underscore.js の場合

underscore.js にも多くの isXxx メソッドが実装されています。

arguments, function, string, number, date, regexp の6つについてはjQuery同様に Object.prototype.toString をコールしてその文字列から判別しています。 toString は Object.prototype.toString を参照しています。

each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
    _['is' + name] = function(obj) {
        return toString.call(obj) == '[object ' + name + ']';
    };
});

isArray はネイティブで実装されている Array.isArray があれば それを使用するようになっています。

_.isArray = nativeIsArray || function(obj) {
    return toString.call(obj) == '[object Array]';
};

こちらは undefined を判別する関数ですね。 undefined は代入されてしまう可能性があるので、かならず undefined を返す void を使用しています。

_.isUndefined = function(obj) {
    return obj === void 0;
};

その他、なるほどと思わせるような方法で書かれている物もあるので、 暇があれば underscore.js のコードを一通り目を通してみても、何か新しい発見があるかもしれませんね。

参考資料

追記

2013/01/22
誤植修正(Playing => Plain)

コメント

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*