WeakMap better than Private Symbols? (was: direct_proxies "problem")

Domenic Denicola domenic at domenicdenicola.com
Thu Jan 10 08:48:53 PST 2013

It's funny: I've been considering a similar thread, but the opposite. I.e. "private symbols better than weak maps?"

In particular, given the freezing clarification, the use cases for weak maps instead of private symbols seem to reduce to adding *new* symbols to extension-prevented objects.

Is that the only case, or am I missing something obvious?

From: es-discuss-bounces at mozilla.org [es-discuss-bounces at mozilla.org] on behalf of Nathan Wall [nathan.wall at live.com]
Sent: Thursday, January 10, 2013 11:22
To: es-discuss at mozilla.org
Subject: WeakMap better than Private Symbols? (was: direct_proxies "problem")

> Choosing symbols or a weakmap would make a huge difference in how proxy
> replacement would react to DOM algorithms.
> If the DOM in terms of accessing private properties, then proxies can
> replace DOM objects transparently. Their "unknownPrivateSymbol" trap
> will be called [2] and if they don't throw, the access to the private
> property will be transparently forwarded to the target without the
> private symbol ever leaking (it actually wouldn't need to exist in
> implementations).

Private Symbols are great for their syntactic advantages, but they're also more observable than WeakMaps, and can't be used as a replacement to closures for representing internal state. As a library author, I find this unhelpful. Consider the following SimpleDate implementations:

    // ES5
    function SimpleDate(timestamp) {

        timestamp = +timestamp;

        this.setTime = function setTime(time) {
            timestamp = +time;

        this.getTime = function getTime() {
            return timestamp;


Trying to rewrite it in ES6 produces these possibilities:

    // ES6 Symbols

    // Forgive me for not knowing what the current
    // correct syntax is for creating a symbol:
    let timestamp = new Symbol();

    class SimpleDate {

        construct(time) {

        setTime(time) {
            this[timestamp] = +time;

        getTime() {
            return this[timestamp];


    // ES6 WeakMap

    let timeMap = new WeakMap(),
        // Store WeakMap methods to maintain integrity of the internal state.
        WeakMapGet = Function.prototype.call.bind(WeakMap.prototype.get),
        WeakMapSet = Function.prototype.call.bind(WeakMap.prototype.set);

    class SimpleDate {

        construct(time) {

        setTime(time) {
            WeakMapSet(timeMap, this, +time);

        getTime() {
            return WeakMapGet(timeMap, this);


AFAIK the two ES6 implementations above should function the same, except when (1) a Proxy uses a SimpleDate as the target and (2) a SimpleDate is frozen.

In the case of (1), the implementation using a private symbol will have internal accesses to the `timestamp` symbol exposed through the unknownPrivateSymbol trap.

In the case of (2), the implementation using a private symbol will fail on a call to `setTime` when the object is frozen (I think).

It sounds to me like if I am writing defensive library code, I will always want to use a WeakMap instead of a Symbol. In both (1) and (2), I would want my object to behave the way the WeakMap implementation behaves, not the Symbol way. Note that, though there are other deviations the ES5 implementation makes, in both (1) and (2) the ES5 one behaves the same as the WeakMap one -- the closure hides the internal state from the unknownPrivateSymbol trap and protects it against freezing.

Initially, one of the things I loved about Symbols was that it allowed internal state to be specified without using closures, so that prototypal inheritance can be more fully relied upon.  However, due to these considerations, I'm not sure Symbols have much use to me anymore.

es-discuss mailing list
es-discuss at mozilla.org

More information about the es-discuss mailing list