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

4

我正在开发一个使用ES6的应用程序,其中涉及将一些数据发送到网络。其中一部分涉及作为ES6 Symbol实现的标识符。例如:

const FOO = Symbol('foo');

调用 Foo.toString() 会返回 Symbol(foo)。当我将它们通过网络传输时,我想将其作为 foo 传递。然而,据我所知,除了使用正则表达式(具体来说是 /^Symbol\((.*)\)$/)之外,没有其他方法可以从 Symbol(foo) 中提取 foo

我应该依赖于正则表达式始终匹配吗?或者未来 ES6 的更新是否可能会破坏这一点?如果我不能依赖于正则表达式匹配,那么我将只能将其作为 Symbol(foo) 发送到网络上。


你会提出哪个正则表达式? - Sebastian Simon
提议使用正则表达式/^Symbol\((.*)\)$/,然后使用第一个捕获组作为名称。已添加到问题中。 - Ryan Kennedy
1
根据规范,它总是"Symbol(" + description + ")"。你最好使用FOO.toString().slice(7, -1),因为符号描述本身可能包含括号、换行等。例如,.不匹配换行符。 - Sebastian Simon
太棒了,谢谢!这正是我在寻找的答案类型。 - Ryan Kennedy
2个回答

4
根据 规范,它总是"Symbol(" + description + ")"Symbol.prototype.toString 返回一个字符串,从内部方法调用SymbolDescriptiveString(sym)而来:

desc成为sym[[Description]]值。
如果descundefined,让desc成为空字符串。
[...]
返回"Symbol("desc")"的字符串拼接。

现在,在2019年更新这个答案,您有两个选项:
  1. 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"

  2. 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"

由于描述周围的字符串是固定的,使用slice是一个不错的选择,尤其是因为符号描述本身可能包含括号、换行符、字符串"Symbol"等,而正则表达式中的.不会匹配换行符。


3
@Xufox的回答已经非常好了,但是需要补充一点的是,Symbol.prototype.toString可能会被篡改(覆盖),这种情况下它可能会返回其他内容。考虑到这并不是你想要或需要考虑的场景,所以使用.toString().slice(7, -1);应该没问题。
另一个你可能想考虑的解决方案是使用全局symbol。如果你打算在数据之间传递,并且需要防止名称冲突,那么这将是一个合适的用例(假设你不是编写供第三方使用的库)。
你可以使用:
const FOO = Symbol.for("foo");
//                 ^^^

然后,通过这种方式,可以获得符号的名称(也是其描述)

Symbol.keyFor(FOO) // "foo"

这很好,但如果您必须使用其描述设置为“foo”的单独符号,则无法工作,因为由Symbol.for(“foo”)进行的所有分配都将分配相同的符号。 - Redu
@Redu 这就是它们成为全局变量的原因,确实如此。你需要仔细选择 foo - Bergi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接