我可以依赖 ES6 `Symbol` 的字符串表示吗?

Can I rely on the string representation of an ES6 `Symbol`?

我正在开发一个通过网络发送部分数据的 ES6 应用程序。其中一部分涉及作为 ES6 Symbols 实现的标识符。例如:

const FOO = Symbol('foo');

调用 Foo.toString() 产生 Symbol(foo)。当我通过网络传递这些时,我想将其作为 foo 传递。但是,据我所知,除了使用正则表达式(具体来说,/^Symbol\((.*)\)$/)之外,没有办法从 Symbol(foo) 中提取 foo

我应该依靠正则表达式始终匹配吗?或者未来对 ES6 的更新是否有可能打破这个?如果我不能依赖正则表达式匹配,那么我将通过网络将其作为 Symbol(foo).

发送

根据 spec 它总是 "Symbol(" + description + ")"

Symbol.prototype.toString returns 来自内部方法调用的字符串 SymbolDescriptiveString(sym):

Let desc be sym’s [[Description]] value.
If desc is undefined, let desc be the empty string.
[…]
Return the string-concatenation of "Symbol(", desc, and ")".

现在,在 2019 年更新此答案,您有两个选择:

  1. 使用(或 polyfill)Symbol.prototype.description, which is part of ECMAScript 2019 并被所有现代 JavaScript 引擎支持:

    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"
    

  2. 或者像这样使用Symbol.prototype.toString

    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"
    

由于描述周围的字符串是固定的,slice 是一个很好的选择,特别是因为交易品种描述本身可以包含括号、换行符、字符串 "Symbol" 等,并且例如,正则表达式中的 . 不会匹配换行符。

唯一要添加到@Xufox 的答案是 Symbol.prototype.toString 可能会受到损害(覆盖),在这种情况下它可能 return 其他东西。考虑到您 want/need 几乎不会考虑这种情况,应该没问题;争取 .toString().slice(7, -1);.


您可能要考虑的替代解决方案是使用全局符号。如果你要传递你的数据,并且无论如何都需要防止名称冲突,这将是一个合适的用例(假设你没有编写一个应该被第三方使用的库)。

你会用

const FOO = Symbol.for("foo");
//                 ^^^

然后可以通过

取回符号的名称(也是它的描述)
Symbol.keyFor(FOO) // "foo"