JavaScriptとRubyのSymbolの違い
シンボルとは
Ruby
Rubyの内部実装では、メソッド名や変数名、定数名、クラス名など の`名前'を整数で管理しています。これは名前を直接文字列として処理するよりも 速度面で有利だからです。そしてその整> 数をRubyのコード上で表現したものがシンボルです。
シンボルは、ソース上では文字列のように見え、内部では整数として扱われる、両者を仲立ちするような存在です。
名前を管理するという役割上、シンボルと文字列は一対一に対応します。 また、文字列と違い、immutable (変更不可)であり、同値ならば必ず同一です。
stringとは違い、同じ名前のシンボルであれば、同一のオブジェクトになるわけですね。
サンプルを見てみましょう
まず、stringであれば、別個に定義したstr1
とstr2
はそれぞれオブジェクトが作られるので、
二つは等価にはなりません。
str1 = "foo" str2 = "foo" p str1.equal?(str2) # => false
対してSymbolであれば、バラバラに定義しても同一のオブジェクトになるので、
二つは等価になります。
sym1 = :foo sym2 = :foo p sym1.equal?(sym2) # => true
JavaScript
symbolは、ユニークで不変なデータ型で、オブジェクトのプロパティ識別子として使われたりします。symbolオブジェクトは、Symbolプリミティブデータ型をラップした暗黙的なオブジェクトです。
JavaScriptのシンボルは毎回新しいSymbolオブジェクトを生成します。 そのため、以下はfalseになります。
const sym1 = Symbol("foo"); const sym2 = Symbol("foo"); console.log(sym1 === sym2) // -> false
一方、 文字列比較は単純に同一の値か否かなので以下は 等しくなります。
const str1 = "foo" const str2 = "foo" console.log(str1 === str2) // -> true
つまり、Rubyとは等価性の判定が逆になります。
JavaScriptでRubyのようにSymbolを扱うには
Symbol.for(key)
を使うことでRubyのように同一のオブジェクトを参照できます。
与えられたkeyで存在するシンボルを検索し、見つかればそれを返します。もしくは、グローバルsymbolレジストリにこのkeyで新しいsymboleを生成します。
const sym3 = Symbol.for("foo") const sym4 = Symbol.for("foo") console.log(sym3 === sym4) // -> true
なお、Symbol.for(key)
はSymbol(key)
で作ったオブジェクトとは等価にならないのでご注意を
const sym5 = Symbol("foo") const sym6 = Symbol.for("foo") console.log(sym5 === sym6) // -> false