概要
オブジェクトにプロパティを追加するとき、次のようなリスクが生まれる:
- 既存プロパティとの 名前の衝突
- 意図しない 上書きや破壊的変更
- フレームワークやライブラリ内部との コンフリクト
これらを完全に回避するために設計されたのが、Symbol型である。
Symbolは、「一意の識別子」であり、「他からアクセスされにくいキー」であり、“設計者の意図を隠す”ための構文的手段でもある。
対象環境
ES6以降(Node.js / モダンブラウザ)
Symbolとは何か?
const key = Symbol('uniqueKey');
const obj = {
[key]: 'hiddenValue'
};
console.log(obj[key]); // 'hiddenValue'
console.log(obj.uniqueKey); // undefined
✅ 特徴:
- 生成される値は常に一意
-
Symbol()
で生成、同じ文字列でも別物 - オブジェクトのプロパティキーとして使える
-
for...in
やObject.keys()
などでは列挙されない
一意性の例
const sym1 = Symbol('id');
const sym2 = Symbol('id');
console.log(sym1 === sym2); // false
→ 同じ説明ラベルでも別の値
非列挙性の例(「隠しプロパティ」)
const id = Symbol('id');
const user = {
name: 'toto',
[id]: 1234
};
console.log(Object.keys(user)); // ['name']
console.log(user[id]); // 1234
→ ✅ システム的な情報や一時的なフラグなどを外部に“見せずに”保持できる
ユースケース①:プロパティ名の衝突回避
function attachMeta(target) {
const _meta = Symbol('meta');
target[_meta] = { created: Date.now() };
}
→ 外部からアクセスされにくく、他と衝突しない安全なプロパティ空間が作れる
ユースケース②:ライブラリ内部での安全設計
const IS_INTERNAL = Symbol('internal');
class Component {
constructor() {
this[IS_INTERNAL] = true;
}
}
→ 外部ユーザーに obj.IS_INTERNAL
でアクセスされない構造を作れる
ユースケース③:enum風の安全な識別子
const STATUS = {
READY: Symbol('READY'),
RUNNING: Symbol('RUNNING'),
DONE: Symbol('DONE')
};
let state = STATUS.READY;
if (state === STATUS.RUNNING) {
// 実行中処理
}
→ ===
判定でも確実にユニーク性が保証されるため、状態識別に使える
Symbolの列挙と取り出し
const symbols = Object.getOwnPropertySymbols(obj);
console.log(symbols); // [Symbol(id)]
→ 列挙可能だが、意図的にアクセスしない限り見えない
グローバルSymbol(Symbol.for
)
const shared = Symbol.for('sharedKey');
const again = Symbol.for('sharedKey');
console.log(shared === again); // ✅ true
→ グローバルレジストリに登録 → 再利用される
→ ✅ モジュールをまたいだ共通キーに使える
使うべき場面 vs 避けるべき場面
状況 | Symbolを使うべきか? | 理由 |
---|---|---|
内部プロパティを隠したい | ✅ Yes | 他者のアクセスを防げる |
プロパティ名の衝突を防ぎたい | ✅ Yes | 外部と安全に共存できる |
状態識別のenumを安全に管理したい | ✅ Yes | === 比較でも安心設計 |
JSONとしてシリアライズしたい | ❌ No | SymbolはJSON.stringifyに含まれない |
UIでキー一覧を表示したい | ❌ No | 非列挙で見えない設計が裏目に出る |
よくある落とし穴
❌ Symbolはシリアライズできない
const obj = { [Symbol('id')]: 123 };
JSON.stringify(obj); // {}
→ ✅ Symbolを含むオブジェクトは、送受信に不向き
→ ✅ APIレスポンスやDB保存には適さない
❌ プロパティアクセスに気づかれない
→ チーム開発では、何か隠してるという事実自体をドキュメント化すべき
結語
Symbolは“高度なJavaScript構文”ではない。
それは「設計を静かに守る仕組み」であり、
「プロパティ空間を安全に分離する記号」である。
- 誰にも触らせたくない内部情報を守るために
- 設計者の意図を暗黙的に反映するために
- 他人のコードと衝突せず、安全に拡張するために
Symbolは“見えない設計力”をコードに宿す道具である。