Symbol でプライベートな値を作る

Experimental JavaScript Features の方に Symbol が使えると書かれていたので早速。

Symbol ってのはなんて言うか、固有のプロパティのキーになれるもの?っていう説明で良いのかな。

var s = new Symbol();
var obj = {};
obj[s] = "OK";

obj[s] // "OK";

obj[s]s は文字列化されずに、Symbolそのものとして動く。文字列キーとしては存在しないためs を使わずに得ることは不可能なのだ。

"use strict";
(function(global){
  var className = new Symbol,
      name = new Symbol;

  var BaseProto = {};
  BaseProto[className] = "Base";
  Object.defineProperty(BaseProto, "className", {
    get: function () {
      return this[className];
    },
  });

  function Person (aName) {
    this.name = aName;
  }
  Person.prototype = Object.create(BaseProto);
  Person.prototype[className] = "Person";
  Object.defineProperty(Person.prototype, "name", {
    get: function () {
      return this[name];
    },
    set: function (val) {
      if (!val || typeof val !== "string")
        throw new TypeError("must be non-empty string");
      
      return this[name] = val;
    },
  });

  global.Person = Person;
}(this));


var p = new Person("t");
console.log(p.name); // "t"
p.name = "teramako";
console.log(p.name); // "teramako"
console.log(p.className); // "Person"

こんな感じで、(function(){ ... }())の中でSymbol定義してやれば、他所からアクセスできないプロパティの出来上がりだ。

追記

と思ったけど、

var s = new Symbol;
var o = {};
o[s] = "OK";

Object.keys(o); // => 0;
Object.getOwnPropertyNames(o)[0] === s; // => true

Object.getOwnPropertyNamesからSymbolを取れてしまうことが判明。Object.keysでは取れないのに...。

仕様なのかバグなのか...バグだと思いたいけど、よく分からん...

追記(2013-04-12)

報告し忘れてた

See: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-15.2.3.4
Step 6.c.iv: makes sure key is String.

とバグ報告したものの、Revision: r14056で修正されていることが分かってクローズしてもらった。

ということで上記追記はそのうち修正されてCanaryに落ちてくると思われる。