概要
JavaScriptの Symbol
は、一意かつ衝突のないプロパティキーを生成するためのプリミティブ型である。
これは以下のような構造的課題を解決するために導入された:
- オブジェクトに“他人に見えないプロパティ”を定義したい
- ライブラリ間の命名衝突を完全に防ぎたい
- 内部的に使うデータを安全に封じたい
- フレームワーク・ランタイムがオーバーライドされない設計を実現したい
この記事では、Symbolの基本構文・設計目的・ユースケース・ビルトインSymbolの正体を網羅的に整理する。
1. Symbolの基本構文と性質
const sym = Symbol('description');
- ✅
Symbol
は 一意性を保証する識別子 - ✅ 同じ説明でも別物
Symbol('x') === Symbol('x'); // false
2. オブジェクトに衝突のないプロパティを定義
const secret = Symbol('secret');
const user = {
name: 'Toto',
[secret]: 'classified'
};
console.log(user[secret]); // classified
console.log(user.secret); // undefined
- ✅ 他コードから偶発的に
secret
にアクセスされることはない - ✅
for...in
,Object.keys
,JSON.stringify
では列挙不可
3. グローバルSymbolレジストリの利用
const a = Symbol.for('shared');
const b = Symbol.for('shared');
console.log(a === b); // true
- ✅
Symbol.for()
を使うとグローバルに共有される - ✅ 同じ文字列で生成されたSymbolは同一と見なされる
Symbol.keyFor(a); // 'shared'
4. 設計ユースケース:衝突回避と設計隔離
✅ ライブラリ間でプロパティ名が重複しても衝突しない
const internal = Symbol('internal');
function enhance(obj) {
obj[internal] = { status: 'hidden' };
}
✅ クラスの内部状態を保護する設計
const _status = Symbol('status');
class Secure {
constructor() {
this[_status] = 'locked';
}
getStatus() {
return this[_status];
}
}
const s = new Secure();
console.log(s._status); // undefined
→ ✅ Symbol
によって“外から見えない状態”を保有できる
5. ビルトインSymbol:言語仕様を拡張・カスタム可能にする
Symbol名 | 用途例 |
---|---|
Symbol.iterator |
for...of 対応 |
Symbol.toPrimitive |
オブジェクトをプリミティブ変換する際の挙動制御 |
Symbol.toStringTag |
Object.prototype.toString.call(obj) の表示名 |
Symbol.hasInstance |
instanceof の振る舞いをカスタマイズ |
Symbol.isConcatSpreadable |
Array.prototype.concat の動作制御 |
例:Symbol.iterator
const iterable = {
*[Symbol.iterator]() {
yield 1;
yield 2;
}
};
for (const val of iterable) {
console.log(val); // 1, 2
}
例:Symbol.toPrimitive
const obj = {
value: 42,
[Symbol.toPrimitive](hint) {
if (hint === 'number') return this.value;
return null;
}
};
console.log(+obj); // 42
設計判断フロー
① 名前衝突を完全に防ぎたい → Symbol
② プロパティを“列挙不可かつ非公開”にしたい → Symbol
③ 複数スクリプトで同一キーを共有したい → Symbol.for()
④ オブジェクトの動作を定義・カスタムしたい → ビルトインSymbol
⑤ オブジェクトを独自のiterableにしたい → Symbol.iterator 実装
よくある誤解
❌ Symbolはセキュリティ機能ではない
→ 隠されているが、Object.getOwnPropertySymbols()
で取得可能
❌ Symbol('x') === Symbol('x') は true?
Symbol('x') === Symbol('x'); // false ❌
Symbol.for('x') === Symbol.for('x'); // true ✅
結語
Symbol
は、単なる“変わったキー”ではない。
それは プロパティ設計における衝突回避と、オブジェクトの意味を拡張する構文的手段である。
- 名前空間ではなく、一意性を持つ構造的記号
- カスタム動作を担う語彙のようなメタプロパティ
- 設計意図をコードに埋め込む「構文的ドメイン言語」
“見えない設計”を実現する。それがSymbolの力である。