データ型とリテラル

データ型

JavaScriptは動的型付け言語に分類される言語であるため、 静的型付け言語のような変数の型はありません。

しかし、文字列、数値、真偽値といった値の型は存在します。 これらの値の型のことをデータ型とよびます。

データ型を大きく分けると、プリミティブ型オブジェクトの2つに分類されます。

プリミティブ型(基本型)は名前のとおり、文字列や数値などの基本的な値の型のことです。 プリミティブ型の値は、一度作成したらその値自体を変更することはできないというイミュータブル(immutable)の特性を持ちます。

一方、プリミティブ型ではないものをオブジェクト(複合型)とよび、 オブジェクトは複数のプリミティブ型の値またはオブジェクトからなる集合です。 オブジェクトは、一度作成した後もその値自体を変更できるためミュータブル(mutable)の特性を持ちます。 また、オブジェクトは値そのものではなく、値への参照を使い操作されるため参照型のデータともいえます。

データ型を細かく見ていくと、6つのプリミティブ型とオブジェクトからなります。

  • プリミティブ型(基本型)
    • 真偽値(Boolean): trueまたはfalseのデータ型
    • 数値(Number): 423.14159 などの数値のデータ型
    • 文字列(String): "JavaScript" などの文字列のデータ型
    • undefined: 値が未定義であることを意味するデータ型
    • null: 値が存在しないnull値を意味するデータ型
    • シンボル(Symbol): ES2015から追加された一意で不変な値のデータ型
  • オブジェクト(複合型)
    • プリミティブ型以外のデータ
    • オブジェクト、配列、関数、正規表現、Dateなど

プリミティブ型でないものは、オブジェクトであるということを覚えていれば問題ありません。

typeof演算子を使うことで、次のようにデータ型を調べることができます。

typeof true;// => "boolean"
typeof 42; // => "number"
typeof "JavaScript"; // => "string"
typeof Symbol("シンボル");// => "symbol"
typeof undefined; // => "undefined"
typeof null; // => "object"
typeof ["配列"]; // => "object"
typeof { "key": "value" }; // => "object"
typeof function() {}; // => "function"

残念ながらtypeof null; // => "object"となるのは歴史的経緯のある仕様バグ1です。 他のプリミティブ型の値については、typeof演算子でそれぞれのデータ型を調べることができます。

オブジェクトと一言にいってもJavaScriptではすべてがオブジェクトであると言われるほど、多くの種類が存在します。 typeof演算子ではすべてのオブジェクの種類を判定することはできません。

つまり、typeof演算子は、プリミティブ型またはオブジェクトかを判別するもので、 オブジェクトの詳細なデータ型については別の方法を判定するようになっています。

詳しい判定方法については各オブジェクトの章を参照してください。

リテラル

プリミティブ型の値やオブジェクトはリテラルを使うことでプログラムに表現できます。

TODO: リテラルとはプログラム上で数値や文字列など、直接記述した内容がそのデータ型の値を書ける記法を定義したものです。 たとえば、""で囲んだ文字列と扱えるため、繰り返し扱うデータ型は簡単に書けるようになっています。 リテラル表現がない場合は、その値を作る関数に引数を渡して作成する形になります。 そのような冗長な表現を避ける方法として主要な値にはリテラルが用意されています。

次の3つのプリミティブ型にはそれぞれリテラル表現を持っています。

  • 真偽値
  • 数値
  • 文字列

真偽値(Boolean)

真偽値はtruefalseのリテラルがあります。 それぞれはtruefalseの値を返すリテラルとなります。

true; // => true
false; // => false

数値(Number)

数値は大きく分けて42のような整数リテラルと3.14159のような浮動小数点リテラルがあります。

整数リテラル

整数リテラルは次の4種類があります。

  • 10進数: 先頭が0ではない数値 - 10
  • 2進数: 0b または 0B - 0b1
    • 0b の後ろには0または1 の数値
  • 8進数: 0o または 0O - 0o7 2
    • 0o の後ろには 0から7 までの数値
  • 16進数: 0x または 0X - 0x15
    • 0x の後ろには 0から15までの数値

JavaScriptでは、0から9の数字のみで書かれた数値は10進数として扱われます。

0bから始まる2進数リテラルは、ビットを表現するのによく利用されています。

0b1111; // => 15

0oから始まる8進数リテラルは、ファイルのパーミッションを表現するのによく利用されています。

0o777; // => 511

0xから始まる16進数リテラルは、文字のコードポイントやRGB値の表現などに利用されています。

0xFF; // => 255

TODO: もっと具体的なイメージの話をしたい。

表記例 用途
10進数 42 数値
2進数 0b0001 ビット演算など
8進数 0o777 ファイルのパーミッションなど
16進数 0xEEFF 文字コード、RGB値など

浮動小数点数リテラル

JavaScriptの浮動小数点数はIEEE 754を採用しています。 浮動小数点数をリテラルと書く場合には次の2種類の表記が利用できます。

  • 3.14159 のような .(ドット)を含んだ数値
  • 2e8 のような e または E を含んだ数値

0から始まる浮動小数点数は、0を省略して書くことができます。

.123; // => 0.123

しかし、JavaScriptでは.をオブジェクトにおいて利用する機会が多いため、 0から始まる場合でも省略せずに書いたほうが意図しない挙動を減らせるでしょう。

Note 変数名が数字から始めることができないのは、数値リテラルと衝突してしまうことが理由としてあげられます。

文字列(String)

文字列リテラル共通のルールとして、同じ記号で囲んだ範囲を文字列として扱います。 文字列リテラルとして次の3種類のリテラルがありますが、すべて評価した結果は同じ"文字列"です。

"文字列";
'文字列';
`文字列`;

ダブルクオートとシングルクオート

"(ダブルクオート)と'(シングルクオート)は全く同じ意味となります。 PHPやRubyなどとは違い、どちらのリテラルでも評価結果は同じとなります。

文字列リテラルは同じ記号で囲む必要があるため、次のように文字列の中に同じ記号が出現した場合は、 \'という形で\を使いエスケープしなければなりません。

'8 o\'clock'; // => "8 o'clock"

そのため、文字列内部に出現しないリテラル記号を使うことで、エスケープをせずに書くことができます。

"8 o'clock"; // => "8 o'clock"

ダブルクオートとシングルクオートどちらも改行をそのまま入力することはできません。 次のように改行を含んだ文字列を定義使用すると Syntax Error となります。

"複数行の
文字列を
入れたい"; // Syntax Error

改行の代わりに改行記号のエスケープシーケンス(\n)を使うことで複数行の文字列を書くことができます。

"複数行の\n文字列を\n入れたい";

複数行の文字列は次のテンプレートリテラルを使うことでもっと直感的に書くことができます。

[ES2015] テンプレートリテラル

テンプレートリテラルは ` (バッククオート)で囲んだ範囲を文字列とするリテラルです。 テンプレートリテラルでは、複数行の文字列を改行記号なしに書くことができます。

複数行の文字列も```で囲めば、そのまま書くことができます。

`複数行の
文字列を
入れたい`; // => "複数行の\n文字列を\n入れたい"

また、名前のとおりテンプレートのような機能を持っています。 テンプレートリテラル内で${変数名}と書いた場合に、その変数の値を埋め込むことができます。

const string = "文字列";
console.log(`これは${string}です`); // => "これは文字列です"

テンプレートリテラルも他の文字列リテラルと同様に同じリテラル記号を内包したい場合は、\を使いエスケープする必要があります。

`This is \`code\``;// => "This is `code`"

nullリテラル

nullリテラルはnull値を返すリテラルです。 nullは「値がない」ということを表現する値です。

次のように、未定義の変数を参照した場合は、 参照できないためReferenceErrorの例外が投げられます。

foo;// "ReferenceError: foo is not defined"

fooは値がないということを表現したい場合は、 null値を代入することで、null値をもつfooという変数を定義できます。 これにより、fooを値がない変数として定義し、参照できるようになります。

const foo = null;
console.log(foo); // => null

オブジェクトリテラル

JavaScriptにおいてあらゆるものの基礎となるのがオブジェクトです。 そのオブジェクトを作成する方法のひとつとしてオブジェクトリテラルがあります。 オブジェクトリテラルは{}(中括弧)を書くことで、新しいオブジェクトを作成できます。

const object = {}; // 中身が空のオブジェクトを作成

オブジェクトリテラルはオブジェクトの作成と同時に中身を定義できます。 オブジェクトのキーと値を:で区切ったものを {} の中に書くことで作成と初期化が同時に行えます。

次のコードで作成したオブジェクトは key というキー名と value という値をもつオブジェクトを作成しています。 キー名には、文字列またはSymbolを指定し、値にはプリミティブ型の値からオブジェクトまで何でも入れることができます。

const object = {
    key: "value"
};

このとき、オブジェクトがもつキーのことをプロパティ名と呼びます。 この場合、 objectkey というプロパティを持っていると言います。

objectkeyを参照するには、.(ドット)で繋ぎ参照する方法と、 [](ブラケット)で参照する方法があります。

const object = {
    "key": "value"
};
// ドット記法
console.log(object.key); // => "value"
// ブラケット記法
console.log(object["key"]); // => "value"

ドット記法では、プロパティ名が変数名と同じく識別子である必要があります。 そのため、次のように識別子として利用できないプロパティ名はドット記法として書くことができません。

// プロパティ名は文字列の"123"
var object = {
    "123": "value"
};
// NG: ドット記法では、数値から始まる識別子は利用できない
obj.123
// OK: ブラケット記法では、文字列として書くことができる
console.log(object["123"]); // => "value"

オブジェクトは多くの機能や仕組みを持っていますが、詳細については第n章で紹介します。 そのため、オブジェクトリテラルが出てきたら新しいオブジェクトを作成しているんだなと見てください。

  • [ ] TODO: 第n章を埋める

配列リテラル

最後にもうひとつ重要なリテラルとして配列リテラルがあります。 配列リテラルは[]で値をカンマ区切りで囲み、Arrayオブジェクトを作成します。

const emptyArray = []; // 空の配列を作成
const array = [1, 2, 3]; // 値をもった配列を作成

作成した配列の要素を取得するには、配列に対してarray[index]でアクセスできます。 JavaScriptの配列のインデックスは0から開始する数値となっています。

const array = ["index:0", "index:1", "index:2"];
console.log(array[0]); // => "index:0"
console.log(array[array.length - 1]); // => "index:2"

配列もオブジェクトの一種ですが、アプリケーションを書くこと場合に多く使われます。 配列についての詳細は第n章で紹介します。

  • [ ] TODO: 第n章を埋める

正規表現リテラル

最後にJavaScriptは正規表現をリテラルで書くことができます。 正規表現リテラルは//で正規表現のパターン文字列囲みます。 正規表現のパターン内では、+\(バックスラッシュ)から始まる特殊文字が特別な意味を持ちます。

次のコードでは、数字にマッチする特殊文字である\dを使い、1文字以上の数字にマッチする正規表現をリテラルで表現しています。

const numberRegExp = /\d+/; // 1文字以上の数字にマッチする正規表現
// 123が正規表現にマッチするかをテストする
console.log(numberRegExp.test(123)); // => true

RegExpコンストラクタを使うことで文字列から正規表現オブジェクトを作成することもできますが、 特殊文字の二重エスケープが必要になり直感的に書くことが難しくなります。

正規表現オブジェクトについて詳しくは、文字列の章で紹介します。

まとめ

この章では、データ型とリテラルについて学びました。

  • 6つのプリミティブ型とオブジェクトがある
  • 真偽値、数値、文字列についてリテラル表現がある
  • オブジェクトではオブジェクトと配列リテラルがある

[コラム] undefinedはリテラルではない

プリミティブ型として紹介したundefinedはリテラルではありません。 undefinedはただのグローバル変数で、undefinedという値を持っているだけです。

これを証明するために、varを使ってundefinedという名前のローカル変数を宣言してみます。 次のようにstrict modeではない環境においては、undefinedというローカル変数をvarで定義できます。 もちろんletconstでは、同名の変数は再定義できないためundefinedの再定義はできません。

// strict modeではない実行環境
var undefined = "独自の未定義値"; // undefinedというローカル変数を定義できる
console.log(undefined); // => "独自の未定義値"

これに対してnullは変数ではなくリテラルであるため、varを使っても再定義できません。 リテラルは変数名として利用できない予約語であるため、このような違いが生じています。

var null; // => SyntaxError

このコラムでは、説明のためにundefinedというローカル変数を宣言しましたが、現実ではこのような使い方は非推奨です。 無用な混乱を生むだけなので避けるべきです。またstrict modeの場合や、constletを利用した場合はそもそも定義できません。

参考

1. JavaScriptが最初にNetscapeで実装された際にtypeof null === "object"となるバグがありました。このバグを修正するとすでにこの挙動に依存しているコードは壊れるため、修正が見送られ現在の挙動が仕様となりました。 http://2ality.com/2013/10/typeof-null.htmlを参照
2. 0o は数字のゼロと小文字アルファベットのo

results matching ""

    No results matching ""