C/C++ プログラマのための JavaScript 入門: データ型

no extension

さて, そろそろ中身に入っていきましょう。 まずは JavaScript のデータ型について整理していきたいと思います。 ここからは「プロローグ」で挙げた文献を頻繁に参照しています。 これらの文献を参照しながらご覧になることをお薦めします。

JavaScript がサポートするデータ型は以下の6つです。

  • 数値
  • 文字列
  • 論理値
  • 関数
  • オブジェクト
  • 配列

数値の取り扱いは注意が必要です。 リテラルの表現としては整数(123, 012, 0xabc など)もありますが, 内部的には8バイトIEEE浮動小数点形式(いわゆる double 型)で保持されます。 従って桁数の大きい値では精度が落ちます。

C/C++ プログラマにとって JavaScript の関数表現は少し変わって見えると思います。 通常の関数定義は以下のような形式になります。

function square(x) {
  return x*x;
}

JavaScript ではこれ以外にリテラル表現で関数を定義することが可能です。

var square = function(x) {
  return x*x;
}

この例では無名の関数を定義し変数 square に格納しています。 リテラル表現を使ったこのような関数を「ラムダ関数」と呼ぶことがあります。

余談ですが, JavaScript では1行内にひとつの命令しかない場合はセミコロンを省略できますが, これが思わぬ副作用をもたらし場合があります。 例えば

function square(x) {
  return x*x
}

は正しく動作しますが,

function square(x) {
  return
    x*x;
}

では返り値に何もセットされません。 しかもエラーにもなりません。 C/C++ では読みやすさの都合で文を改行で分割することはよくありますが, JavaScript では副作用を伴うことがあるので要注意です。

さて本題に戻りまして, オブジェクトの実体は名前つき値(プロパティ)の集合です。 以下のように表現できます。

var point = { x:1 , y:2 }; //オブジェクトのリテラル表現
WScript.Echo("point.x = " + point.x);
WScript.Echo("point.y = " + point.y);
WScript.Echo("point[\"x\"] = " + point["x"]);
WScript.Echo("point[\"y\"] = " + point["y"]);

例の後半は連想配列の表現をとっています。 オブジェクトは連想配列として扱うことができます。 各プロパティの値には任意のデータ型が使えます(つまりオブジェクトを入れ子にできます)。 プロパティは後から設定することもできます。

var point = new Object(); //空のオブジェクトを生成
point.x = 10;
point.y = 20;
WScript.Echo("point.x = " + point.x);
WScript.Echo("point.y = " + point.y);

Object() はコンストラクタ関数です(コンストラクタ関数についてはいずれ。 C++ のコンストラクタとは少し違います)。 オブジェクトは JavaScript の肝となる部分ですので, 改めて書いてみたいと思います。

配列はオブジェクトと同じく値の集合ですが, 値には名前ではなくインデックス番号がつくところが違います。 C/C++ と違い JavaScript の配列の値では異なるデータ型が混在していても構いません。

var a = [1.2, "JavaScript", true, { x:1 , y:2 } ]; //配列のリテラル表現
WScript.Echo("a[0] = " + a[0]);
WScript.Echo("a[1] = " + a[1]);

配列もオブジェクトと同じく後から値を設定することができます。

var a = new Array(); //コンストラクタ関数で空の配列を生成
a[0] = 1.2;
a[2] = "JavaScript";
WScript.Echo("a[0] = " + a[0]);
WScript.Echo("a[1] = " + a[1]); // undefined になる
WScript.Echo("a[2] = " + a[2]);

この例では a[1] の出力は undefined になります。 undefined は未定義状態を表す特別な値です。 他にも値がない状態(Null)を表す null もあります。

さてプロパティ等に値を格納する際の振る舞いを考えたとき, JavaScript のデータ型は基本型と参照型の2つに分けることができます。 参照型は C++ のリファレンスと似たようなふるまいをします。 以下に例を示します。

var a = [ 1, 2, 3 ];
var b = a;
a[0] = 99;
WScript.Echo("a = " + a);
WScript.Echo("b = " + b); // 配列 a と同じ値になる

他のデータ型についても各操作での振る舞いを以下に挙げておきます。

データ型 コピー 引数渡し 比較
数値 by value by value by value
文字列 immutable immutable by value
論理値 by value by value by value
関数 by reference by reference by reference
オブジェクト by reference by reference by reference
配列 by reference by reference by reference

このなかで文字列は振る舞いが特殊です。 これは JavaScript の仕様では文字列は不変(immutable)の値として扱われるためです。

C++ などと違い JavaScript では基本型か参照型かを見た目で区別できません。 ただし JavaScript ではデータ型を調べるための typeof 演算子が用意されています。

var a = [ 1, 2, 3 ];
var b = 123;
WScript.Echo("type of a = " + (typeof a)); //object
WScript.Echo("type of b = " + (typeof b)); //number

typeof 演算子ではデータ型によって以下の文字列を返します。

数値 "number"
文字列 "string"
論理値 "boolean"
関数 "function"
オブジェクト・配列・null "object"
undefined "undefined"

つまり "number", "boolean" が基本型で, "function", "object" が参照型というわけです。