概要
ES6 では、新しいプリミティブデータ型 Symbol が導入されました。これは唯一無二の値を表し、最も大きな用途はオブジェクトのユニークなプロパティ名を定義することです。
ES6 のデータ型には、Number、String、Boolean、Object、null、undefined に加えて、Symbol が新しく追加されました。
基本的な使い方
Symbol 関数は new コマンドを使用できません。Symbol はプリミティブデータ型であり、オブジェクトではないからです。引数として文字列を受け取ることができ、新しく作成された Symbol に説明を提供し、コンソールでの表示や文字列として使用する際に区別しやすくします。
let sy = Symbol("KK");
console.log(sy);
typeof(sy);
let sy1 = Symbol("kk");
sy === sy1;
使用シーン
プロパティ名として
使い方
各 Symbol の値は互いに等しくないため、Symbol をオブジェクトのプロパティ名とすることで、プロパティ名の重複を防ぐことができます。
let sy = Symbol("key1");
let syObject = {};
syObject[sy] = "kk";
console.log(syObject);
let syObject = {
[sy]: "kk"
};
console.log(syObject);
let syObject = {};
Object.defineProperty(syObject, sy, {value: "kk"});
console.log(syObject);
Symbol をオブジェクトのプロパティ名として使う場合、. 演算子は使えず、角括弧を使う必要があります。. 演算子の後ろは文字列として扱われるため、取得されるのは文字列 sy のプロパティであり、Symbol 値 sy のプロパティではありません。
let syObject = {};
syObject[sy] = "kk";
syObject[sy];
syObject.sy;
注意点
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);
Reflect.ownKeys(syObject);
定数の定義
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";
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";
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;
let yellow2 = Symbol.for("Yellow");
yellow1 === yellow2;
Symbol.keyFor()
Symbol.keyFor() は、登録済みの Symbol 型の値のキーを返します。これを使用して、その文字列パラメータを名前とする Symbol 値が登録済みかどうかを確認できます。
let yellow1 = Symbol.for("Yellow");
Symbol.keyFor(yellow1);