Alexander Mills
Alexander Mills

Reputation: 100000

Check if value is a Symbol in JavaScript

How can I check if a value is Symbol in JS?

I do not see a Symbol.isSymbol(x) method. My test of (x instanceof Symbol) does not seem to work either.

Upvotes: 25

Views: 17527

Answers (4)

PHP Guru
PHP Guru

Reputation: 1558

The most simple way of testing for a symbol is indeed:

typeof value=="symbol"

But you may not want to rely on typeof because it will return "object" for symbols that have been cast to an object. Such symbols still function as symbols in every way and should not be dismissed.

Symbols that have been polyfilled for pre-ES6 browsers also return "object" when using typeof because the return type of "symbol" was not yet available before ES6.

So if you want to include symbol objects and support pre-ES6 polyfills, you can either use instanceof:

Object(value) instanceof Symbol;// works in most cases

or check the constructor:

value && value.constructor === Symbol;

The above solutions won't work across global environments but that's easily solvable by comparing the constructor to the string representation of the Symbol function. So here is your best bet. If the constructor is non-nullish, it is coerced to a string:

value && value.constructor == Symbol.toString();

The above won't work if the constructor property is overwritten which is an edge case you probably never need to worry about. But for completeness here is a solution that guarantees success. It uses try/catch which is slow so you might not want to do it this way.

// Annoyingly complex, yet guaranteed to work

function isSymbol(value) {
    var isSymbol, type = typeof value;
    if (type=="object" && value) try {
        Symbol.prototype.toString.call(value)// Throws if value is not a Symbol primitive or object
        isSymbol = 1;// This is only set if it didn't throw
    }
    catch(e) {
    }
    return type=="symbol" || !!isSymbol;// cast to boolean
}

Upvotes: 1

daemone
daemone

Reputation: 1191

Updated 2022: Go with the accepted answer! If you're working in an environment so outdated that Symbol needs to be polyfilled, then you'll know that already. You'll be excruciatingly aware of it. You'll be haunted by it. Then, sure, use my answer. Otherwise don't bother. typeof x === 'symbol' is almost definitely all you need these days.


In ES 2015 and up, typeof x === 'symbol' is all that's needed. But it won't work if you're transpiling your code to ES 5.1 or earlier, even if you're using a polyfill for the Symbol builtin.

Every polyfill I've seen, including the babel-polyfill, implements Symbol as an object (i.e. typeof x === 'object') using a constructor function called Symbol. So in those cases you can check that Object.prototype.toString.call (x) === '[object Symbol]'*.

Putting it all together, then, we get:

function isSymbol (x) {
    return typeof x === 'symbol'
        || typeof x === 'object' && Object.prototype.toString.call (x) === '[object Symbol]';
}

*Note that I'm not using instanceof in the transpiled scenario. The problem with instanceof is that it only returns true for objects that were created within the same global context as the assertion being made. So if, say, a web worker passes a symbol back to your page, or symbols are passed between iframes, then x instanceof Symbol will return false! This has always been true of all object types, including the builtins. instanceof often works just fine, but if there's any chance of your code being in a "multi-frame" scenario as I've described, use with caution!

Upvotes: 6

Danny Apostolov
Danny Apostolov

Reputation: 497

The most efficient way is to test the constructor of a value:

const result = (value && value.constructor === Symbol);

Upvotes: 0

jordiburgos
jordiburgos

Reputation: 6302

Check it with typeof:

typeof x === 'symbol'

Upvotes: 37

Related Questions