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.
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.
Check it with typeof:
typeof x === 'symbol'
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!
Object.prototype.toString.call(x)
will return '[object Object]'
–
Nucleotide 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.
In that case using instanceof
might be your best bet:
Object(value) instanceof Symbol;// works in most cases
The above is faster than the last method below because of the extra overhead required for a try/catch. However instanceof
fails in some cases such as on objects created in a different window or frame and therefore a different global environment.
Here is a method that solves all of the above problems. It works with symbol primitives, symbols cast as objects regardless global environment, as well as polyfilled Symbol
designed to work in pre-ES6 JavaScript. The reason it works is because Symbol.prototype.toString()
will throw if passed a value that is neither a symbol nor symbol object.
// Annoyingly complex, yet guaranteed to work
function isSymbol(value) {
var isSymbol, type = typeof value;
if (type=="object") 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
}
The most efficient way is to test the constructor of a value:
const result = (value && value.constructor === Symbol);
typeof
does this check under the hood along with 1 or 2 other checks? –
Kosse typeof
returns a string, which forces a string comparison between the value returned and the value you're testing upon (typeof x === 'symbol'
will compare two strings), which is presumably slower than value.constructor === Symbol
(i'd suggest that the latter compares two internal ids, probably numerical). –
Tyrontyrone typeof
is heavily optimised while your solution is slowed by the need to check for truthiness and then access an object property. Ever-so-slightly faster when run ten million times (as I just did), but I'd argue that readability trumps that sort of tiny performance gain, and the average developer is more familiar with typeof
than the constructor
property. –
Roentgenograph typeof x === "knownTypeString"
. Another interesting discovery was that !value
performs as fast as value !== null && value !== void 0 && value === value
(the required minimum to access value's constructor
property). I'd expect the type coercion to slow things down, but it seems to be well-optimized as well. Thanks for pointing this out! –
Tyrontyrone typeof
is an operator that takes anything and returns a string, rather than coerce it into one. Because it's a native operator, it doesn't need type coercion or any other language feature that we as JS devs have access to. The implementation details can be much closer to the metal than anything you or I could write in our JIT-compiled scripting language. V8, for instance, is written in C++. –
Roentgenograph !value
expression. –
Tyrontyrone © 2022 - 2024 — McMap. All rights reserved.
typeof x === 'symbol'
works – Fieldsx instanceof Symbol
doesn't work because x is a primitive. If you cast x to an object that will work ieObject(x) instanceof Symbol//true
However the accepted answer is still the best approach as long as you don't need pre-ES6 support. – Nucleotide