问题
I'm working on an ES6 app that sends some of its data over the network. Part of this involves identifiers that are implemented as ES6 Symbol
s. For example:
const FOO = Symbol('foo');
Calling Foo.toString()
yields Symbol(foo)
. When I pass these over the network, I'd like to pass it as just foo
. However, to my knowledge, there is no way to extract foo
from Symbol(foo)
other than to pull it out with a regular expression (specifically, /^Symbol\((.*)\)$/
).
Should I rely on the regular expression always matching? Or is it possible that future updates to ES6 will break this? If I can't rely on the regex matching then I'll just send it over the wire as Symbol(foo)
.
回答1:
According to the spec it’s always "Symbol(" + description + ")"
.
Symbol.prototype.toString
returns a string from an internal method call to SymbolDescriptiveString(sym)
:
Let desc be sym’s
[[Description]]
value.
If desc isundefined
, let desc be the empty string.
[…]
Return the string-concatenation of"Symbol("
, desc, and")"
.
Now, updating this answer in 2019, you have two options:
Use (or polyfill) Symbol.prototype.description, which is part of ECMAScript 2019 and is supported by all modern JavaScript engines:
const foo = Symbol("foo"), bar = Symbol.for("bar"), iter = Symbol.iterator; console.log(foo.description); // "foo" console.log(bar.description); // "bar" console.log(Symbol.iterator.description); // "Symbol.iterator"
Or use
Symbol.prototype.toString
like so:const foo = Symbol("foo"), bar = Symbol.for("bar"), iter = Symbol.iterator; console.log(foo.toString().slice(7, -1)); // "foo" console.log(bar.toString().slice(7, -1)); // "bar" console.log(iter.toString().slice(7, -1)); // "Symbol.iterator" // Or without “magic numbers”: console.log(foo.toString().slice("Symbol(".length, -")".length)); // "foo" console.log(bar.toString().slice("Symbol(".length, -")".length)); // "bar" console.log(iter.toString().slice("Symbol(".length, -")".length)); // "Symbol.iterator"
Since the strings surrounding the description are fixed, slice
is a good option to use, especially because a symbol description could itself contain parentheses, line breaks, the string "Symbol"
, etc, and the .
in the regular expression won’t match line breaks for example.
回答2:
The only thing to add to @Xufox' answer is that Symbol.prototype.toString
could be compromised (overwritten), in which case it might return something else. Given that that's hardly a scenario you'll want/need to consider, it should be fine; go for .toString().slice(7, -1);
.
An alternative solution you might want to consider would be to use a global symbol. If you are going to pass your data around, and will require to prevent name collisions anyway, this would be a suitable use case (assuming you're not writing a library that's supposed to be used by third parties).
You'd use
const FOO = Symbol.for("foo");
// ^^^
and could then get the symbol's name (which is also its description) back through
Symbol.keyFor(FOO) // "foo"
来源:https://stackoverflow.com/questions/33595946/can-i-rely-on-the-string-representation-of-an-es6-symbol