Symbolを使ったプロパティ定義 | シンボルとユニークプロパティ | JavaScript 超完全入門 基本から発展までのすべて

スポンサーリンク
スポンサーリンク
amazon
スマイルSALE
--:--:--
ad. 価格範囲を指定して商品を探せます

Symbolを使ったプロパティ定義とは?

Symbolは、JavaScriptで一意の値を作成するためのプリミティブ型です。Symbol()を使うと、他のプロパティ名と衝突しにくいユニークなプロパティキーを作成できます。

特に、ライブラリや外部コードと同じオブジェクトを扱う場合に、プロパティ名の衝突を避ける目的で利用されます。

ただし、Symbolは完全なプライベート機能ではありません。取得方法を知っていればアクセスできるため、現在のJavaScriptで本当にプライベートな値を扱いたい場合は、クラスのプライベートフィールド(#name)なども選択肢になります。

Symbolの基本的な使い方

Symbolを作成するには、Symbol()関数を使用します。引数には説明用の文字列を指定できますが、この文字列はあくまでデバッグ用の説明であり、同じ文字列を指定しても同じSymbolになるわけではありません。

Symbolの定義とプロパティの設定


const mySymbol = Symbol("uniqueKey");

const myObject = {
    [mySymbol]: "このプロパティはSymbolキーを持ちます"
};

console.log(myObject[mySymbol]);

この例では、mySymbolをプロパティキーとして使用しています。

Symbolをプロパティキーにする場合は、オブジェクトリテラル内で[mySymbol]のように角括弧を使います。

Symbolのプロパティはユニーク

Symbolは、それぞれが一意の値です。同じ説明文字列を指定しても、作成されるSymbolは別物になります。

Symbolと通常のプロパティの違い


const obj = {
    name: "Alice"
};

const sym1 = Symbol("key");
const sym2 = Symbol("key");

obj[sym1] = "値1";
obj[sym2] = "値2";

console.log(obj.name);
console.log(obj[sym1]);
console.log(obj[sym2]);
console.log(sym1 === sym2);

sym1sym2は、どちらも"key"という説明を持っていますが、別々のSymbolです。

そのため、obj[sym1]obj[sym2]は別のプロパティとして扱われます。

Symbolを使ったプロパティの特徴

Symbolを使ったプロパティには、通常の文字列キーのプロパティとは異なる特徴があります。

特徴 説明
一意性 Symbol()で作成したSymbolは、それぞれ異なる値になります。
名前衝突の回避 他のコードが同じ名前のプロパティを追加しても衝突しにくくなります。
通常の列挙に出ない for...inObject.keys()では取得されません。
完全な非公開ではない Object.getOwnPropertySymbols()を使うと取得できます。
グローバル共有も可能 Symbol.for()を使うと、同じキーでSymbolを共有できます。

Symbolを使用したプロパティの例

Symbolは、外部から簡単には見えない内部用プロパティを定義したい場合に使えます。

内部用プロパティの作成例


const PRIVATE = Symbol("privateProperty");

const myObj = {
    [PRIVATE]: "これは内部用のプロパティです",
    name: "Sample"
};

console.log(myObj[PRIVATE]);

for (const key in myObj) {
    console.log(key);
}

console.log(Object.keys(myObj));

この例では、Symbolを使って内部用のプロパティを作成しています。

for...inObject.keys()ではSymbolプロパティは表示されません。ただし、次のようにすればSymbolプロパティを取得できます。


const symbols = Object.getOwnPropertySymbols(myObj);

console.log(symbols);
console.log(myObj[symbols[0]]);

このように、Symbolプロパティは見つけにくいだけであり、完全に隠されているわけではありません。

グローバルシンボルの使用

Symbol.for()を使用すると、グローバルシンボルレジストリに登録されたSymbolを取得できます。

同じキーを指定すれば、別の場所からでも同じSymbolを取得できます。

Symbol.for()によるグローバルシンボルの共有例


const symbol1 = Symbol.for("sharedSymbol");
const symbol2 = Symbol.for("sharedSymbol");

console.log(symbol1 === symbol2);

const obj1 = {
    [symbol1]: "オブジェクト1の値"
};

const obj2 = {
    [symbol2]: "オブジェクト2の値"
};

console.log(obj1[symbol1]);
console.log(obj2[symbol2]);

この例では、symbol1symbol2は同じSymbolです。

Symbol()は毎回新しいSymbolを作りますが、Symbol.for()は同じキーに対して同じSymbolを返します。

Symbolのユースケース

Symbolは、次のような場面で利用されます。

  • プロパティ名の衝突を避けたい場合。
  • ライブラリ内部で使うプロパティを定義したい場合。
  • 通常の列挙処理に出したくないプロパティを作りたい場合。
  • JavaScriptの組み込み動作をカスタマイズしたい場合。

組み込みSymbolの例

JavaScriptには、特別な意味を持つ組み込みSymbolがあります。代表的なものにSymbol.iteratorがあります。


const numbers = [1, 2, 3];

const iterator = numbers[Symbol.iterator]();

console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

Symbol.iteratorは、オブジェクトを反復可能にする仕組みで使われます。

配列がfor...ofで処理できるのは、この仕組みを持っているためです。

Symbol.toStringTagの例

Symbol.toStringTagを使うと、Object.prototype.toString.call()で表示される名前をカスタマイズできます。


const customObject = {
    [Symbol.toStringTag]: "CustomObject"
};

console.log(Object.prototype.toString.call(customObject));

この例では、オブジェクトの内部的な表示名としてCustomObjectを設定しています。

初心者が覚えておきたいポイント

  • Symbol()は一意の値を作成します。
  • 同じ説明文字列を指定しても、同じSymbolにはなりません。
  • Symbolはオブジェクトのプロパティキーとして利用できます。
  • SymbolプロパティはObject.keys()for...inでは表示されません。
  • Symbolは完全なプライベート機能ではありません。
  • 同じSymbolを共有したい場合はSymbol.for()を使います。

まとめ

  • SymbolはJavaScriptのプリミティブ型の1つで、一意の値を作成できる。
  • Symbolをプロパティキーにすると、名前の衝突を避けやすくなる。
  • Symbol()は呼び出すたびに異なるSymbolを返す。
  • Symbol.for()を使うと、同じキーでSymbolを共有できる。
  • Symbolプロパティは通常の列挙処理には表示されない。
  • Symbolは完全なプライベート機能ではないため、用途を理解して使うことが重要である。