Join MDN and developers like you at Mozilla's View Source conference, 12-14 September in Berlin, Germany. Learn more at https://viewsourceconf.org

あらゆるプログラミング言語は、それぞれ異なったデータ構造を持っています。この記事では、JavaScript で使用可能な組み込みデータ構造の一覧と、他のデータ構造の構築にも使えるように、それらがどのような性質を持ち合わせているかについて述べることにします。また可能である場合は、他のプログラミング言語におけるデータ構造との対比も行います。

動的型付け

JavaScript は弱い型付けあるいは動的型付けの言語です。これは、あらかじめ変数の型を宣言する必要がないということです。型はプログラムを処理している間に、自動的に決められます。また、異なる型で同じ変数を持つことができるということでもあります:

var foo = 42;    // この foo は Number
var foo = "bar"; // この foo は String
var foo = true;  // この foo は Boolean

データ型

最新の ECMAScript 標準仕様では 7 つのデータ型が定義されています。

プリミティブ値

object 型をのぞく全ての型は不変 (immutable) な値 (変更することができない値) として定義されています。特筆すべき点としては、 string 型が(Cなどとは違って)不変な値である点です。これらの型の値を、プリミティブ値 (primitive value) と呼びます。詳細は Strings の節で触れることとします。

Boolean 型

Boolean は論理的な実体であり、truefalse の 2 つの値があります。

Null 型

Null 型は値が null の 1 種類しかありません。詳しくは null および Null をご覧ください。

Undefined 型

値を代入していない変数の値は、undefined になります。詳しくは undefined および Undefined をご覧ください。

Number 型

ECMAScript 標準仕様によると、この型は「"倍精度 64 ビット形式による IEEE 754 値"」 (-(253 -1) から 253 -1 の間の数値) となります。特筆すべきは整数であるとは定義されていないという点です。さらに言うならば、この型は浮動小数点数値にもなりますし、+Infinity-InfinityNaN (not-a-number) といった記号的な値も持ち合わせています。

+/-Infinity より大きいまたは小さい値を調べるために、定数 Number.MAX_VALUE および Number.MIN_VALUE を使用できます。また ECMAScript 6 より、Number.isSafeInteger()Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER を使用して数値が倍精度浮動小数点数値の範囲内にあるかを調べることもできます。この範囲を超えた数値は、JavaScript では信頼できません。

Number 型には、2 種類の表現を持つ数値がひとつだけあります。それは 0 であり、-0 および +0 で表します ("0" は +0 の別名です)。実用上、影響はほとんどありません。例えば、+0 === -0true です。ただし、ゼロ除算を行った場合は違いに気づくでしょう:

> 42 / +0
Infinity
> 42 / -0
-Infinity

数値はたいてい数値としてのみ表されるものの、JavaScript はいくつかのバイナリ演算を提供しています。そのため、ビットマスクを用いて、一つの数値で複数の真偽値を表現することも可能です。しかしながら、JavaScript が (真偽値の配列や真偽値のプロパティを複数持つオブジェクトのような) 真偽値の集合を表現する手段を提供していることや、ビットマスクはコードの可読性、わかりやすさ、保守性を大きく損なってしまうことから、この機能はたいてい、バッドプラクティスとして考えられています。ローカルストレージの容量的制約への対処や、ビット単位での転送量を考える必要のある極限状態など、非常に特殊なケースにおいてはこうしたテクニックが必要となるでしょう。このテクニックは、あくまでも最適化が必要な場合の最終手段としてのみ考慮すべきです。

String 型

JavaScript の String 型は、テキストデータを表すために使用します。これは、16 ビット符号なし整数値の "要素" の集合体です。文字列内の各要素は、文字列内の位置を占めます。最初の要素はインデックス 0、次の要素がインデックス 1 となっていきます。また文字列の長さは、内部にある要素の数です。

C のような言語とは異なり、 JavaScript の文字列は 不変 (immutable) です。これは一度生成した文字列は変更が不可能であるということを意味しています。しかしながら、オリジナルの文字列を操作することで別の文字列を生成することは可能となっています。例えば:

  • 個別に文字を抜き出す、または String.substr() を用いて、オリジナルの部分文字列を切り出す
  • 連結演算子 (+) または String.concat() を用いて、2 つの文字列を連結する

「文字列より」のコードに注意!

文字列を用いて複雑なデータ構造を表現したいと思うこともあるでしょう。文字列は以下のような使い勝手の良さを備えています。

  • 文字列連結によって複雑な文字列の構築が簡単である
  • 文字列はデバッグが簡単である(出力される情報は常に文字列の一種である)
  • 文字列は(インプットフィールドローカルストレージの値、 XMLHttpRequestresponseText など)数多くの API において基準として扱われており、全てを文字列で処理したいと思わせる

理屈の上では、文字列を用いることで、あらゆるデータ型の表現が可能ではあります。ですが、あまり良い考えとはいえません。例として、セパレータ文字を使用することでリストの模倣が可能です(役割としては JavaScript の配列の方がよっぽど適していますが)が、残念なことにセパレータ文字が「リスト」の 要素となってしまった場合、そのリストは破綻します。エスケープした文字を使用することでこの問題に対処することは可能ですが、そのルールをすべてに用意する必要がある上、用途に応じて適切な道具を用いなかったことによるメンテナンスコストの増大を招きます。

文字列型の使用はテキストデータや記号データを表すのには向いていますが、別のデータ構造を表す為に文字列のパースや正しい抽象化を用いる必要がある場合には向いていないと言えるでしょう。

Symbol 型

Symbols は、ECMAScript Edition 6 における JavaScript の新機能です。Symbol はユニークかつ不変なプリミティブ値で、オブジェクトのプロパティ識別子として使用します (後述)。Symbol のことを atom と呼ぶプログラミング言語があります。Symbol は、C の名前付き列挙型 (enum) と対比することもできます。詳しくは Symbol および JavaScript における Symbol オブジェクトラッパーをご覧ください。

Object

コンピュータ科学において、オブジェクトは識別子によって参照可能なメモリ内の値とみなせます。

プロパティ

JavaScript において、オブジェクトはプロパティのバッグとみなせます。オブジェクトリテラル構文では、限定されたプロパティセットを初期化します。プロパティは追加および削除が可能です。プロパティの値は、他のオブジェクトを含むあらゆる型の値が設定可能であり、これにより複雑なデータ構造の構築が可能となっています。プロパティは、キー値を使用して識別します。キー値は String 値または Symbol 値です。

オブジェクトには、特定の属性を持つ 2 種類のプロパティがあります。それは、データプロパティとアクセサプロパティです。

データプロパティ

キーと値を関連づけており、以下の属性を持ちます:

データプロパティの属性
属性 説明 既定値
[[Value]] JavaScript の任意の型 プロパティにアクセスすると取り出される値です。 undefined
[[Writable]] Boolean false であれば、プロパティの [[Value]] は変更できません。 false
[[Enumerable]] Boolean true であれば、プロパティは for...in ループで列挙されます。Enumerability and ownership of properties もご覧ください。 false
[[Configurable]] Boolean false であれば、プロパティは削除できません。また、[[Value]] および [[Writable]] 以外の属性を変更できません。 false
廃止された属性 (ECMAScript 3 の属性であり、ECMAScript 5 で改名された)
属性 説明
Read-only Boolean ES5 の [[Writable]] 属性の状態を反転したもの。
DontEnum Boolean ES5 の [[Enumerable]] 属性の状態を反転したもの。
DontDelete Boolean ES5 の [[Configurable]] 属性の状態を反転したもの。

アクセサプロパティ

値を取り出しまたは保存するための 1 つまたは 2 つのアクセサ関数 (get および set) とキーを関連づけており、以下の属性を持ちます:

アクセサプロパティの属性
属性 説明 既定値
[[Get]] Function オブジェクトまたは undefined 値に対して get アクセスが実行されると、関数が引数なしで呼び出されてプロパティの値を取り出します。get もご覧ください。 undefined
[[Set]] Function オブジェクトまたは undefined 指定したプロパティを変更しようとしたときに、代入する値を引数に含めて関数が呼び出されます。set もご覧ください。 undefined
[[Enumerable]] Boolean true であれば、プロパティは for...in ループで列挙されます。 false
[[Configurable]] Boolean false であれば、プロパティの削除やデータプロパティの変更はできません。 false

注記: 属性は通常 JavaScript エンジンが使用しますので、それらに直接アクセスすることはできません (詳しくは Object.defineProperty() をご覧ください。)。これが、属性に角括弧が 2 つついている理由です。

「通常の」オブジェクトおよび関数

JavaScript オブジェクトはキーと値を所持しています。キーは文字列 (または Symbol) ですが、値はなんでもかまいません。これにより、オブジェクトはハッシュマップの様相を呈します。

関数は呼び出し可能という付加機能を持つ、通常のオブジェクトです。

Date

日時についての表現を考慮するとき、組み込みの Date オブジェクトのユーティリティメンバを用いるのが最も妥当でしょう。

インデックス付きコレクション: Array (配列) および Typed Array (型付き配列)

Array は整数値をキーにするプロパティと length プロパティの間に特殊な関係の存在する、標準オブジェクトです。加えて述べるなら、配列は、配列を操作するのに便利ないくつかのメソッドを提供する Array.prototype を継承しています。例えば indexOf (配列中の値の探索) や push (配列への要素の追加) などです。これにより配列はリストまたはセットとして表現するために必要な機能を備えることとなります。

Typed Arrays は ECMAScript Edition 6 における JavaScript の新機能であり、バイナリデータバッファについて配列状のビューを提供します。以下の表で、同等の C データ型を見つけるのに役立つでしょう:

TypedArray オブジェクト

サイズ (バイト数) 説明 Web IDL 型 同等の C 型
Int8Array 1 8 ビット長、2 の補数方式の符号付き整数値 byte int8_t
Uint8Array 1 8 ビット長、符号なし整数値 octet uint8_t
Uint8ClampedArray 1 8 ビット長、符号なし整数値 (切り詰め) octet uint8_t
Int16Array 2 16 ビット長、2 の補数方式の符号付き整数値 short int16_t
Uint16Array 2 16 ビット長、符号なし整数値 unsigned short uint16_t
Int32Array 4 32 ビット長、2 の補数方式の符号付き整数値 long int32_t
Uint32Array 4 32 ビット長、符号なし整数値 unsigned long uint32_t
Float32Array 4 32 ビット長、IEEE 方式 浮動小数点数 unrestricted float float
Float64Array 8 64 ビット長、IEEE 方式 浮動小数点数 unrestricted double double

キー付きコレクション: Map, Set, WeakMap, WeakSet

これらのデータ構造は、キーとしてオブジェクトへの参照を持ち、ECMAScript Edition 6 で導入されました。WeakMap および Map がオブジェクトと値を関連づける一方で、Set および WeakSet はオブジェクトのセットを表します。Map と WeakMap の相違点としては、前者がキーであるオブジェクトの列挙が可能であるのに対し、後者がガベージコレクションに最適化されている点です。

Map と Set は純粋に ECMAScript 5 での実装も可能ではありますが、("完全" な意味での) オブジェクトの比較は不可能であり、キーとしたオブジェクトの線形探索が必要なことによるパフォーマンス上の問題があります。(WeakMap を含む) Map と Set のネイティブな実装では対数を用いることにより概して定数時間でのキーおよび関連する値の探索が可能となっています。

従来ならば、DOM ノードにデータを結び付ける場合は、オブジェクトに直接プロパティを設定するか、data-* 属性を用いるのが普通でした。これらの手法は同じコンテクストで実行されるあらゆるスクリプトからデータの利用が可能であるため、不都合な面を持ち合わせていました。Map および WeakMap を使用することにより、オブジェクトへのプライベートなデータの結びつけを簡単に行うことができます。

構造化データ: JSON

JSON (JavaScript Object Notation) は軽量なデータ交換形式であり、JavaScript 由来ですが多くのプログラミング言語で使用されています。JSON は万能なデータ構造を構築します。詳しくは JSON および JSON をご覧ください。

標準ライブラリに含まれる他のオブジェクト

JavaScript には、組み込みオブジェクトの標準ライブラリがあります。それらのオブジェクトについては、リファレンスをご覧ください。

typeof 演算子を使用して型を検出する

typeof 演算子は、変数の型を知るのに役立ちます。詳細および使用例については、リファレンスページをご覧ください。

仕様

仕様書 策定状況 コメント
ECMAScript 1st Edition (ECMA-262) 標準 最初期の定義
ECMAScript 5.1 (ECMA-262)
Types の定義
標準  
ECMAScript 2015 (6th Edition, ECMA-262)
ECMAScript Data Types and Values の定義
標準  
ECMAScript 2017 Draft (ECMA-262)
ECMAScript Data Types and Values の定義
ドラフト  

関連情報

ドキュメントのタグと貢献者

 このページの貢献者: akiroom, yyss, teoli, adakoda, ethertank, dextra, saneyuki_s
 最終更新者: akiroom,