JavaScript入門:Symbol(ユニークな識別子)とは
Symbolは「絶対に重ならない一意の値」を作るためのデータ型です。オブジェクトの“衝突しないキー”や、内部的な印(タグ)として使われます。文字列や数値のように見えますが、性質がまったく違います。
基本:常にユニークな値を作る
- 同じ説明(ラベル)を付けても、作られる値は毎回別物です。
const s1 = Symbol("id");
const s2 = Symbol("id");
console.log(s1 === s2); // false(説明が同じでも別物)
JavaScript- 型は
symbol。
console.log(typeof s1); // "symbol"
JavaScript- 文字列連結はできません(TypeError)。表示したいときは
String(sym)やsym.descriptionを使います。
const tag = Symbol("tag");
// console.log("Tag: " + tag); // TypeError
console.log("Tag: " + String(tag)); // "Tag: Symbol(tag)"
console.log(tag.description); // "tag"
JavaScript代表的な使いどころ
1. オブジェクトの“衝突しないキー”として使う
- ライブラリ同士や別ファイルでも、同名キーの上書きを避けられます。
const ID = Symbol("id");
const user = { name: "Taro", [ID]: 12345 };
console.log(user[ID]); // 12345
console.log(Object.keys(user)); // ["name"](Symbolキーは列挙に出ない)
JavaScript2. 半プライベートなデータを隠す
Object.keysやfor...inに現れず、JSONにも含まれないため“見えにくい”保存場所になります。
const secret = Symbol("secret");
const obj = { public: 1, [secret]: "hidden" };
console.log(JSON.stringify(obj)); // {"public":1}(Symbolは無視される)
JavaScript- ただし、完全な秘密ではありません。
Object.getOwnPropertySymbols(obj)で取得できます。
3. 既定の動作を拡張する「有名なシンボル」を使う
- 言語に組み込まれた特別なSymbolで、オブジェクトのふるまいを定義できます。
// 反復可能(for...of)にする
const collection = {
items: [1, 2, 3],
[Symbol.iterator]() {
let i = 0;
return {
next: () => ({ value: this.items[i++], done: i > this.items.length })
};
}
};
for (const v of collection) console.log(v); // 1 2 3
// toString時のタグ名を変える
const person = { name: "Taro", [Symbol.toStringTag]: "Person" };
console.log(Object.prototype.toString.call(person)); // "[object Person]"
JavaScriptグローバルレジストリ:Symbol.for と Symbol.keyFor
- 「同じ名前なら同じSymbol」を共有したいときは、レジストリを使います。
const a = Symbol.for("app.config");
const b = Symbol.for("app.config");
console.log(a === b); // true(レジストリ経由は共有される)
console.log(Symbol.keyFor(a)); // "app.config"
JavaScriptSymbol()は毎回ユニーク。Symbol.for()は名前に紐づく“共有Symbol”。
列挙と取得の挙動(知っておくと安心)
Object.keys(obj)・for...in・JSON.stringify(obj)は Symbolキーを無視します。- 取得したい場合は以下を使います。
const syms = Object.getOwnPropertySymbols(obj); // Symbolキー一覧
const all = Reflect.ownKeys(obj); // 文字列+Symbolキーすべて
JavaScriptよくあるつまずきと回避策
- 文字列連結できない →
String(sym)かsym.descriptionを使う。 - 完全な「秘密」ではない →
Object.getOwnPropertySymbolsで見つけられる。 - NumberやStringとは混ぜて比較・連結しない → 振る舞いが違うため、キー用途やメタ情報に限定する。
実用ミニパターン
- 名前衝突を避けたい拡張ポイント
const EXT = Symbol("ext");
const plugin = { [EXT]: () => "plugin-data" };
JavaScript- 「内部状態」を他コードから触られにくくする
const stateSym = Symbol("state");
class Counter {
constructor() { this[stateSym] = 0; }
inc() { this[stateSym]++; }
value() { return this[stateSym]; }
}
const c = new Counter();
c.inc();
console.log(c.value()); // 1
JavaScriptミニ練習
- 問1:同じ説明で作った Symbol が等しいか確認せよ。
const s1 = Symbol("id");
const s2 = Symbol("id");
console.log(s1 === s2); // false
JavaScript- 問2:Symbolキーのプロパティを Object.keys で見えるか確認せよ。
const K = Symbol("k");
const obj = { a: 1, [K]: 2 };
console.log(Object.keys(obj)); // ["a"]
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(k)]
JavaScript- 問3:レジストリを使って同じキーを共有せよ。
const x = Symbol.for("share");
const y = Symbol.for("share");
console.log(x === y); // true
console.log(Symbol.keyFor(x)); // "share"
JavaScriptまとめ
- Symbolは「絶対に被らない一意の値」。オブジェクトキーや内部タグに最適。
Symbol()は毎回ユニーク、Symbol.for()は名前で共有。- 列挙・JSONに出ないため“半プライベート”に使えるが、完全な秘匿ではない。
- 有名シンボル(Symbol.iterator など)でオブジェクトの既定動作を拡張できる。
