JavaScript の Symbol の分類
2022年の sosukesuzuki 1人アドベントカレンダー 17 日目です。
JavaScript には Symbol というプリミティブなデータ型があります。まあまあ便利で色々使ったりすると思います。
さて、Symbol は 3 種類に分類できます。
1 つめは Symbol
コンストラクタ で普通に作ったユニークなシンボルです。
const s = Symbol("foo");
こういうやつですね。よく見る。
2 つめは Symbol.for
で作った、いわゆる Registered Symbol というシンボルです。
Symbol.for
は引数で与えられたキーに対応するシンボルを、ランタイムごとに存在するグローバルシンボルレジストリから探して返します。対応するシンボルが見つからなければ新たに作成してグローバルシンボルレジストリに登録した上で返します。つまり、同じキーで Symbol.for
を複数回呼び出すと、毎回同じシンボルへとアクセスできます。
const s1 = Symbol.for("foo");
const s2 = Symbol.for("foo");
console.log(s1 === s2); // true
逆に Symbol
コンストラクタは毎回異なるシンボルを作成して返します。
const s1 = Symbol("foo");
const s2 = Symbol("foo");
console.log(s1 === s2); // false
3 つめは Well-known Symbols です。Symbol.iterator
のようにあらかじめ設定されているシンボルで、ECMAScript の様々な挙動において特別な扱いを受けます。
console.log(typeof Symbol.iterator); // "symbol"
console.log(typeof Symbol.hasInstance); // "symbol"
表にまとめます。
種類 | 例 |
---|---|
ユニークなシンボル | Symbol("foo") |
Registered symbol | Symbol.for("foo") |
Well-known symbol | Symbol.iterator |
現在 Stage 3 の Symbols as WeakMap keys というプロポーザルがあります。これは名前の通り Symbol を WeakMap のキーとして使えるようにするプロポーザルです。
シンボルは、その種類によって GC で回収されるかどうかにも違いがあるので、その特性によって WeakMap のキーとするべきかどうか、というのも変わってきます。Symbols as WeakMap keys のプロポーザルの仕様として、まだ最終的にどのシンボルを WeakMap のキーとして許容するのか結論は出ていないようです。
が、どちらにしてもシンボルの種類をなんらかの方法で判断できると便利そうです。そこで、新しいプロポーザル Symbol Predicates が誕生しました。Symbol Predicates は次の 2 つの関数を提供します。
Symbol.isRegistered(symbol)
Symbol.isWellKnown(symbol)
名前の通り、それぞれあるシンボルが Registerd symbol であるかどうか、Well-known symbol であるかどうかを判定します。どちらにも当てはまらなければ通常のユニークなシンボルというわけです。
まあ便利そうですね。