关于javascript:ECMAScript 6中的Symbol.for(字符串)

Symbol.for(string) in ECMAScript 6

我花了一段时间,但我终于明白了EcmaScript 6中符号的用途:在将属性附加到共享对象时避免名称冲突-HTML元素,例如(如果您遇到同样的问题,我推荐这篇文章)。

但后来我偶然发现了symbol.for()。显然,ECMAScript 6将维护一个全局符号注册表,您可以通过提供符号描述来使用此函数进行查询。再来一次?如果我使用符号来避免名称冲突,为什么我希望自己的代码以外的代码使用它们?(*)如何避免全局注册表中的名称冲突?共享符号似乎完全颠覆了这个概念,全球注册中心也因此受到了双重破坏。

(*)是的,我知道符号不是真正的私密的,但这也不重要。


如果您不想在GlobalSymbolRegistry中使用您的符号,请不要使用Symbol.for

仅当您希望允许其他代码使用您的符号时才使用它。

在下面的示例中,我创建了一个符号来将数据存储在DOM元素中。我可能希望其他所有代码(例如内部原始未编译处理程序)读取该数据。因此,我使符号全局可用。

1
2
var sym = Symbol.for('storeDataInDOM');
document.querySelector('button')[sym] = 'Hello, world!';
1
<button onclick="alert(this[Symbol.for('storeDataInDOM')])">Click me</button>

这就像创建全局变量:一般来说应该避免,但有它的优点。但是用符号而不是字符串。


If I use symbols to avoid name collisions, why would I want code other than my own to use them?

这并不是符号唯一的用法。另外两个最重要的是:

  • 它们不会与字符串键控属性冲突
  • 通常的机械师不计算这些参数。

Sharing of symbols seems to completely subvert the concept and a global registry doubly so.

不一定。就在你读到的那篇文章中,"当多个网页或同一网页中的多个模块需要共享一个符号时,注册表是有用的。"最好的例子是内在符号——它们保证了跨领域的互操作性,这就是为什么全局符号注册表比全局范围更全局的原因。

例如,您可能拥有一个加载在网页、iframe和Web工作者中的库。如果在这些环境(领域)之间共享数据,库的三个实例都将使用相同的符号。

不同的库之间也有一个真正的互操作性需求,这甚至可能不了解彼此。很好的例子是传感器、代数结构或承诺。如果ES6已经在使用,那么所有这些都将在全局符号注册表中商定通用名称,而不是依赖于这样的字符串或then方法。

另一个很好的例子是由您的引擎定义的自定义钩子,例如,一个Symbol.inspect = Symbol.for("inspect"),您可以使用它来定义console.log要使用的自定义字符串化行为。诚然,该符号不一定需要通过全局符号注册表提供,它也可以放在特定的库对象上(如console.inspect = Symbole("console.inspect"))。

And how would I avoid name collisions in that global registry?

正如您以前对属性或全局模块对象所做的那样:通过使用非常长、非常描述性的名称-或者出于诚意。还有一些命名约定。


我发明了Symbol.for()调用最有用的特性。如果代码中有时使用符号,则在调试时很难使用条件断点。例如,如果变量等于符号类型的值,并且该值绑定在不同的模块中,则需要捕获。第一种困难的方法是将该值用作常量,然后从该模块导出该值。在这种情况下,断点的条件如下:

1
catchedVariable === exportedSymbolConst

但最简单的方法是临时更改模块中添加.forSymbol的代码。然后你可以写下条件:

1
catchedVariable === Symbol.for('string_key')

在成功调试之后,您将更改代码,只需删除.for部分。