KDE BLOG

Webデザインやコーディングについて書いています

【JavaScript基礎】typeof演算子、constructorプロパティ、instanceof演算子を使ってデータ型、コンストラクタ関数を特定する

<目次>

データ型の特定

「この変数にはどんなデータ型の値が入っているのか知りたい」、「この関数の引数に指定した型以外の値が設定されたらエラーを吐きたい」といった、データ型を調べたい場面は少なくありません。
そんな時は下記のtypeof演算子、あるいはconstructorプロパティを使うことで型を知ることができます。

typeof演算子

調べたい変数や式の前にtypeof演算子を付けることでデータ型を示す文字列を返します。
戻り値の種類についてMDNのサイトを参照頂ければと思いますが、注意点としては下記が挙げられます。

  • nullは"object"を返す。
  • オブジェクトのうち関数は"function"を返す。
  • 配列は"object"を返す。

このような挙動から、世の中にはtypeof演算子を拡張した機能を持たせた関数もあります。

サンプルとして下記をご確認ください。

console.log(
    typeof 'Hello', // 'string'
    typeof 10, // 'number'
    typeof true, // 'boolean'
    typeof {a:1},// 'object'
    typeof [1, 2, 3], // 'object'
    typeof Symbol(), // 'symbol'
    typeof function(){}, // 'function'
    typeof undefined, // 'undefined',
    typeof null, // 'Object' -> nullにはならないので注意!

    typeof Infinity, // 'number'
    typeof NaN, // 'number'

    typeof String("Hello"), //  'string';
    typeof String, //  'function'; -> コンストラクタ関数のため
    typeof new String("Hello") // 'object'; -> new演算子とコンストラクタ関数でオブジェクトが返されるため
); 

使い方としては、最近自分が使ったのは、関数でコールバック関数を定義したときに(初期値はnull)、その値が関数であったら実行するというものでした。 この場合、function以外の引数が指定された場合はコールバック関数には影響を与えません。

function myFunc(callback = null) {
    console.log('hello!');
    if (typeof callback === 'function') {
        callback();
    }
}

myFunc(function() {
    console.log('callback!');
});

constructorプロパティ

typeof演算子はfunction以外のオブジェクトの戻り値はすべて"object"となります。そのためもっと細かく判別したいときは、constructorプロパティを使います。

constructorプロパティは、コンストラクタ関数を使って生成されたオブジェクトのインスタンスに自動的に生成されるプロパティで、そのインスタンスを生成した元のコンストラクタ関数を示します。
言葉でいうとややこしいですが、要はその値のコンストラクタ関数を示します。

※オブジェクトのインスタンスに自動的に生成されるプロパティと言いましたが、プリミティブ値であっても、それらがnew演算子とコンストラクタ関数を使ってオブジェクトとして扱われた場合はconstructorプロパティにアクセスができます。
下記の例のように、new演算子を使わずに直接プリミティブ値にconstructorプロパティにアクセスしても、裏側ではラッパーオブジェクトが生成されコンストラクタが呼ばれるためアクセスが可能です。しかし値自体はあくまでプリミティブ型なのは変わりません。

// すべてtrue
console.log(
    'a'.constructor === String,
    (123).constructor === Number,
    true.constructor === Boolean,
    {}.constructor === Object,
    [].constructor === Array,
    new Date().constructor === Date,
    new Error().constructor === Error,
    /./.constructor === RegExp,
    String.constructor === Function,
    new String().constructor === String
);

オブジェクトのClassを用いた判定

途中で気づいたのですが、下記記事を発見した中でお勧めされていたのはオブジェクトのClassを用いた判定でした。
詳しくは下記記事をご覧ください。

コンストラクタ関数の特定

次に、オブジェクトに対してコンストラクタ関数を特定する場合について考えてみます。
これには、先ほどのconstructorプロパティがそのまま目的に合致するので使えます。
またもうひとつ、instanceof演算子を使うことで特定できます。

instanceof演算子

instaceof演算子は、あるオブジェクトが特定のコンストラクタ関数のインスタンスであるか真偽値を返します。

// コンストラクタ関数定義
const MyConstructor = function() {
    this.name = '山田'
}
// インスタンス化
const instanceMyConstructor = new MyConstructor();

console.log(instanceMyConstructor instanceof MyConstructor);

console.log(
    {a: 1} instanceof Object, // 'true' ① 
    [1, 2, 3] instanceof Array, // 'false'
    'aaa' instanceof String, // 'false' ②
    new String('aaa') instanceof String, // 'true' ③
    String instanceof Function // 'false'
);

すべてのオブジェクトはObject()を継承しているので、あるオブジェクトがObjectのインスタンスであるかを調べたとき、常にtrueとなりますので要注意です。(上記①のケースです)

また、②のようにプリミティブ値を対象に使用すると、ラッパーオブジェクトが生成されるのですが、その場合instanceof演算子は常にfalseを返します。new演算子を使ってオブジェクトとして生成されている場合は③のようにtrueとなります。
instanceof演算子はオブジェクトにのみ使用できます。

参考

開眼!  JavaScript ―言語仕様から学ぶJavaScriptの本質

開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質