~文法メモ~ シンボル

  • シンボルは「呼び出す度に一意な値」を返す

    この性質は他の言語にはあまり存在しない概念ですから、もう少しよくみてみましょう。

    シンボルとコンストラクタ

    シンボルはSymbolクラスのコンストラクタを呼ぶことで作成されます。
    引数を指定することが出来ます。

    sb1 = Symbol()
    sb2 = Symbol('name')
    

    シンボルはSymbolクラスのコンストラクタを呼ぶ度に新しい値が生成されます。
    よって下記コードのように同じ'name'を引数としたとしても、呼び出す度に違う値が生成されます。

    sb1 = Symbol()
    sb2 = Symbol('name')
    sb3 = Symbol('name')
    
    sb2 === sb3 // false
    Symbol('name') === Symbol('name') // false
    
  • シンボル名で値を共有したい場合は、Symbol.for(...)で作成

    let a = Symbol.for('name'); // 新しくシンボルが作られる
    let b = Symbol.for('name'); // すでに存在すればそのシンボルが返される
    hm.debuginfo(a == b) // true
    
  • Symbol.keyForで、シンボルからシンボル名への逆引きが可能

    let a = Symbol.for('name'); // 新しくシンボルが作られる
    
    hm.debuginfo(Symbol.keyFor(a)) // name
    

    enumの替わりに使う

    const RED    = Symbol();
    const YELLOW = Symbol();
    const BLUE   = Symbol();
    
    // …
    
    let color = RED;
    
    
    if (color == RED) {
       hm.debuginfo("色は赤です");
    }
    

    このようにすることで、「数値など」と比較し手抜きをすることは不可能となり、
    あくまでも RED or YELLOW or BLUE との比較を課すことが出来ます。

    classのメンバ変数をどうしてもprivateにしたい

    classやオブジェクトの特定のプロパティを外部から見えなくするのに使えなくもないですが、
    余計にソースが歪みますので、あまりそのような目的に利用するべきではないでしょう。

    keysなどで取得させたくないメンバに利用する

    private目的というよりも、こちらのkeysでは取得させたくないメンバとして利用する、
    というのは仕掛けとして有りだと思います。

  • Symbolsとfor...inイテレーション

    Symbolはfor...inイテレーションからは見えません。

    var obj = {};
    
    obj[Symbol("a")] = "a";
    obj[Symbol.for("b")] = "b";
    obj["c"] = "c";
    obj.d = "d";
    
    for (var i in obj) {
       hm.debuginfo(i); // 結果 "c" and "d"
    }
    
  • SymbolsとJSON.stringify()

    for...in同様、こちらからもSymbolのプロパティは無視されます。

    JSON.stringify({[Symbol("foo")]: "foo"});
    // '{}'