Greg Gum
Greg Gum

Reputation: 37905

Comparing Javascript Symbols not working

I am learning the Symbol feature of ES6.

So in node, I write the following (in Typescript actually). It compiles fine, but the console logs "Not found" What am I doing wrong? It seems to me that it ought to work.

This example comes from this article

"use strict"

var levels = {
    DEBUG: Symbol('debug'),
    INFO: Symbol('info'),
    WARN: Symbol('warn'),
};
function log(level: Symbol, message)
{
    switch(level)
    {
        case Symbol.for('debug'):
            console.log(`Debug Message: ${message}`);
            break;

        case Symbol.for('info'):
            console.log(`Info Message: ${message}`);
            break;

        case Symbol.for('warn'):
            console.log(`Warn Message: ${message}`);
            break;

        default:
            console.log("Not found");
    }
}


log(levels.DEBUG, 'debug message');
log(levels.INFO, 'info message');

Update

As pointed out in the accepted answer, this will work:

var levels = {
    DEBUG: Symbol.for('debug'),
    INFO: Symbol.for('info'),
    WARN: Symbol.for('warn')
};
function log(level: Symbol, message)
{
    switch(level)
    {
        case Symbol.for('debug'):
            console.log(`Debug Message: ${message}`);
            break;

        case Symbol.for('info'):
            console.log(`Info Message: ${message}`);
            break;

        case Symbol.for('warn'):
            console.log(`Warn Message: ${message}`);
            break;

        default:
            console.log("Not found");
    }
}


log(levels.DEBUG, 'debug message');
log(levels.INFO, 'info message');

Second Update

Also, as pointed out by @Felix Kling, this is even better:

var levels = {
    DEBUG: Symbol('debug'),
    INFO: Symbol('info'),
    WARN: Symbol('warn')
};
function log(level: Symbol, message)
{
    switch(level)
    {
        case levels.DEBUG:
            console.log(`Debug Message: ${message}`);
            break;

        case levels.INFO:
            console.log(`Info Message: ${message}`);
            break;

        case levels.WARN:
            console.log(`Warn Message: ${message}`);
            break;

        default:
            console.log("Not found");
    }
}

Upvotes: 1

Views: 64

Answers (3)

Tom Dezentje
Tom Dezentje

Reputation: 631

Every call to Symbol creates a new instance of a Symbol.

So Symbol('foo') === Symbol('foo') is false.

The Symbol.for method searches for a given key. If the key is not found it will be created. Otherwise it returns the already defined value.

"use strict"

var levels = {
    DEBUG: Symbol.for('debug'),
    INFO: Symbol.for('info'),
    WARN: Symbol.for('warn'),
};
function log(level, message)
{
    switch(level)
    {
        case Symbol.for('debug'):
            console.log(`Debug Message: ${message}`);
            break;

        case Symbol.for('info'):
            console.log(`Info Message: ${message}`);
            break;

        case Symbol.for('warn'):
            console.log(`Warn Message: ${message}`);
            break;

        default:
            console.log("Not found");
    }
}


log(levels.DEBUG, 'debug message');
log(levels.INFO, 'info message');

Upvotes: 3

t.niese
t.niese

Reputation: 40842

The reason is because Symbol('debug') !== Symbol.for('debug').

You need to write:

var levels = {
  DEBUG: Symbol.for('debug'),
  INFO: Symbol.for('info'),
  WARN: Symbol.for('warn'),
};

MDN: Symbol:

The above syntax using the Symbol() function will not create a global symbol that is available in your whole codebase. To create symbols available across files and even across realms (each of which has its own global scope), use the methods Symbol.for() and Symbol.keyFor() to set and retrieve symbols from the global symbol registry.

Upvotes: 3

Justin Niessner
Justin Niessner

Reputation: 245419

Symbol('somestring');

Doesn't create a global Symbol.

Symbol.for('somestring');

Either gets a previously defined global symbol or creates a new global symbol.

Therefore, the first time you check your case statements, you're creating new symbols rather than checking against your previously defined symbols.

If you use Symbol.for('somestring') when defining the symbols in the first place, they'll be found when you check them later.

Upvotes: 4

Related Questions