Symbol

JavaScript では、 Symbol は プリミティブ値 です。

Symbol データ型を持つ値は「シンボル値」として見ることができます。 JavaScript の実行時環境では、シンボル値は Symbol 関数を呼び出すことで生成され、動的に無名の一意の値を生み出します。シンボルはオブジェクトプロパティとして使用されることがあります。

Symbol は任意で説明を持つことができますが、これはデバッグ目的のみに利用されます。

Symbol 値は固有の識別子を表します。例えば以下のように使用します。

// 二つのシンボルを同じデスクリプションで使用
let Sym1 = Symbol("Sym")
let Sym2 = Symbol("Sym")
  
console.log(Sym1 === Sym2) // "false" を返す
// シンボルは固有であることが保証されます。
// 同じデスクリプションでたくさんのシンボルが生成されても、
// 異なる値を持ちます。

メモ: Ruby (または他の言語) の "symbols" と呼ばれる機能をよくご存知であれば、間違えないでください。 JavaScript のシンボルは異なります。

Symbol 型は ECMAScript 2015 の新機能であり、 ECMAScript 5 にはシンボルに相当するものはありません。

プログラミング言語によっては、シンボルデータ型は「アトム」と呼ばれています。

シンボルは文字列に「自動変換」されない

JavaScript の大部分の値は文字列への暗黙的な返還に対応しています。例えば alert はほぼすべての値で表示することができ、動作します。シンボルは特殊です。自動変換は行われます。

例を示します。

let Sym = Symbol("Sym")
alert(Sym)  // TypeError: Cannot convert a Symbol value to a string

これは混合しないための「言語ガード」で、これは文字列とシンボルが根本的に異なるため、そして他の型に変換するべきものではないためです。

本当にシンボルを表示したいのであれば、 .toString() を呼び出す必要があります。

let Sym = Symbol("Sym")
alert(Sym.toString())  // Symbol(Sym), now it works

または、 symbol.description プロパティを使用して、ディスクリプションを取得することができます。

let _Sym = Symbol("Sym");

alert(_Sym.description); // Sym

Well-known symbol

Symbol クラスには、 well-known symbols と呼ばれる定数があります。これらのシンボルによって、 JavaScript がオブジェクトをどのように扱うかを、プロパティキーとして使用することで構成することができます。

well-known symbol の例としては、配列風オブジェクトのための Symbol.iterator、文字列オブジェクトのための Symbol.search などがあります。

仕様書のWell-known symbol の表に挙げられているものは次の通りです。

  • Symbol.hasInstance
  • Symbol.isConcatSpreadable
  • Symbol.iterator
  • Symbol.toPrimitive
  • …and so on.

グローバルシンボルレジストリ

グローバルシンボルレジストリを扱うメソッドは Symbol.for() and Symbol.keyFor() があります。これらは、グローバルシンボルテーブル(または「レジストリ」)とランタイム環境の間を仲介します。シンボルレジストリは、主に JavaScript コンパイラーインフラストラクチャが構築しており、その中の symbol の内容は、 JavaScript ランタイムインフラストラクチャでは上記のメソッド以外で扱えません。

Symbol.for("tokenString") メソッドはレジストリ内のシンボル値を返し、 Symbol.keyFor(symbolValue) メソッドはレジストリからトークンの文字列を返します。この二つは対照的で、下記の結果は true です。

Symbol.keyFor(Symbol.for("tokenString")) === "tokenString" // true

関連情報

一般知識