概要

ES6 では、新しいプリミティブデータ型 Symbol が導入されました。これは唯一無二の値を表し、最も大きな用途はオブジェクトのユニークなプロパティ名を定義することです。

ES6 のデータ型には、Number、String、Boolean、Object、null、undefined に加えて、Symbol が新しく追加されました。


基本的な使い方

Symbol 関数は new コマンドを使用できません。Symbol はプリミティブデータ型であり、オブジェクトではないからです。引数として文字列を受け取ることができ、新しく作成された Symbol に説明を提供し、コンソールでの表示や文字列として使用する際に区別しやすくします。

let sy = Symbol("KK"); console.log(sy); // Symbol(KK) typeof(sy); // "symbol" //同じ引数の Symbol() が返す値は等しくありません let sy1 = Symbol("kk"); sy === sy1; // false

使用シーン

プロパティ名として

使い方

各 Symbol の値は互いに等しくないため、Symbol をオブジェクトのプロパティ名とすることで、プロパティ名の重複を防ぐことができます。

let sy = Symbol("key1"); //書き方1 let syObject = {}; syObject[sy] = "kk"; console.log(syObject); // {Symbol(key1): "kk"} //書き方2 let syObject = { [sy]: "kk" }; console.log(syObject); // {Symbol(key1): "kk"} //書き方3 let syObject = {}; Object.defineProperty(syObject, sy, {value: "kk"}); console.log(syObject); // {Symbol(key1): "kk"}

Symbol をオブジェクトのプロパティ名として使う場合、. 演算子は使えず、角括弧を使う必要があります。. 演算子の後ろは文字列として扱われるため、取得されるのは文字列 sy のプロパティであり、Symbol 値 sy のプロパティではありません。

let syObject = {}; syObject[sy] = "kk"; syObject[sy]; // "kk" syObject.sy; // undefined

注意点

Symbol 値をプロパティ名として使う場合、そのプロパティはプライベートではなくパブリックなプロパティであり、クラスの外部からアクセスできます。ただし、for...in や for...of のループには現れず、Object.keys() や Object.getOwnPropertyNames() によって返されることもありません。オブジェクトの Symbol プロパティを読み取る必要がある場合は、Object.getOwnPropertySymbols() と Reflect.ownKeys() で取得できます。

let syObject = {}; syObject[sy] = "kk"; console.log(syObject); for (let i in syObject) { console.log(i); } //出力なし Object.keys(syObject); // [] Object.getOwnPropertySymbols(syObject); // [Symbol(key1)] Reflect.ownKeys(syObject); // [Symbol(key1)]

定数の定義

ES5 では文字列を使用して定数を表していました。例:

const COLOR_RED = "red";
const COLOR_YELLOW = "yellow";
const COLOR_BLUE = "blue";

しかし、文字列では定数が一意であることを保証できないため、次のような問題が発生する可能性があります:

const COLOR_RED = "red"; const COLOR_YELLOW = "yellow"; const COLOR_BLUE = "blue"; const MY_BLUE = "blue"; function ColorException(message) { this.message = message; this.name = "ColorException"; } function getConstantName(color) { switch (color) { case COLOR_RED : return "COLOR_RED"; case COLOR_YELLOW : return "COLOR_YELLOW "; case COLOR_BLUE: return "COLOR_BLUE"; case MY_BLUE: return "MY_BLUE"; default: throw new ColorException("Can't find this color"); } } try { var color = "green"; //green が例外を発生させる var colorName = getConstantName(color); } catch (e) { var colorName = "unknown"; console.log(e.message, e.name); //例外オブジェクトをエラーハンドラに渡す }

しかし、Symbol を使用して定数を定義すれば、この一連の定数の値がすべて異なることを保証できます。Symbol を使用して上記の例を修正してみましょう。

const COLOR_RED = Symbol("red"); const COLOR_YELLOW = Symbol("yellow"); const COLOR_BLUE = Symbol("blue"); function ColorException(message) { this.message = message; this.name = "ColorException"; } function getConstantName(color) { switch (color) { case COLOR_RED : return "COLOR_RED"; case COLOR_YELLOW : return "COLOR_YELLOW "; case COLOR_BLUE: return "COLOR_BLUE"; default: throw new ColorException("Can't find this color"); } } try { var color = "green"; //green が例外を発生させる var colorName = getConstantName(color); } catch (e) { var colorName = "unknown"; console.log(e.message, e.name); //例外オブジェクトをエラーハンドラに渡す }

Symbol の値は一意であるため、同じ値の定数は発生せず、switch がコードの想定どおりに実行されることを保証できます。

Symbol.for()

Symbol.for() はシングルトンパターンに似ており、まずグローバルで登録された Symbol の中に、その文字列パラメータを名前とする Symbol 値があるかどうかを検索します。あればその Symbol 値を返し、なければその文字列パラメータを名前とする新しい Symbol 値を作成して返し、グローバル環境に登録して検索できるようにします。

let yellow = Symbol("Yellow"); let yellow1 = Symbol.for("Yellow"); yellow === yellow1; // false let yellow2 = Symbol.for("Yellow"); yellow1 === yellow2; // true

Symbol.keyFor()

Symbol.keyFor() は、登録済みの Symbol 型の値のキーを返します。これを使用して、その文字列パラメータを名前とする Symbol 値が登録済みかどうかを確認できます。

let yellow1 = Symbol.for("Yellow"); Symbol.keyFor(yellow1); // "Yellow"