ECMAScript 6 中的 Symbol.for(string)

Posted

技术标签:

【中文标题】ECMAScript 6 中的 Symbol.for(string)【英文标题】:Symbol.for(string) in ECMAScript 6 【发布时间】:2015-09-08 04:39:44 【问题描述】:

我花了一段时间,但我终于弄清楚了 ECMAScript 6 中符号的用途是:在将属性附加到共享对象时避免名称冲突 - html 元素,例如(如果你遇到同样的问题,我推荐this article。)

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

(*) 是的,我知道符号不是真正私有的,但这不是重点。

【问题讨论】:

由于您的问题不清楚,因此 Symbol('some description'); 不会在全局注册表中注册内容。仅当您通过 Symbol.for 明确要求全局注册符号时。 是的,感谢您的澄清! 这里作者回答了你的问题:hacks.mozilla.org/2015/06/es6-in-depth-symbols/comment-page-1/… 虽然这不是一个例子。简单地说明代码可能需要访问跨库和/或 iframe 的属性并不能说明为什么符号注册表是答案。 【参考方案1】:

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

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

在以下示例中,我创建了一个符号来将数据存储在 DOM 元素中。而且我可能希望所有其他代码(例如internal raw uncompiled handlers)读取该数据。所以我让符号全局可用。

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

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

【讨论】:

问题是:我为什么要分享我的符号? @PeterCoester 我添加了一个示例。但问题是:为什么不呢? ES6 提供了这样做的方法,如果你感兴趣就使用它,否则忽略它。 但是符号的共享不会产生与创建符号来解决的问题完全相同的问题吗?您的示例并未完全显示共享符号的用例。 @PeterCoester 是的,存在碰撞风险。但是全局变量也有同样的问题,人们无论如何都会使用它们。在我的示例中:您将如何访问内部原始未编译处理程序中的符号?引入 GlobalSymbolRegistry 允许这样做而不会污染全局对象。 嗯。是的,我想我现在可以看到一堆用例......符号可以像 jQuery 中的 .data() 函数一样使用,您可以通过这种方式附加和操作 UI 控件,例如谢谢!这有帮助。我赞成你的回答。【参考方案2】:

如果我使用符号来避免名称冲突,我为什么要我自己的代码以外的代码使用它们?

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

它们不会与字符串键属性冲突 通常的机制没有列举它们

符号共享似乎完全颠覆了这个概念,而全球注册表则加倍如此。

不一定。就在that article 你读到:“当多个网页或同一网页中的多个模块需要共享一个符号时,注册表很有用。” 最好的例子是内在符号- 它们保证跨领域的互操作性,这就是为什么global symbol registry 比您的全球范围更全球化。

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

不同的库之间也确实需要互操作性,它们甚至可能不知道彼此。很好的例子是transducers、algebraic structures 或promises。如果 ES6 已经在使用,所有这些都将在全局符号注册表中就通用名称达成一致,而不是依赖于像 these 或 then 方法这样的字符串。

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

我将如何避免该全局注册表中的名称冲突?

就像您之前对属性或全局模块对象所做的那样:使用非常长、非常具有描述性的名称 - 或者出于善意。还有some naming conventions。

【讨论】:

【参考方案3】:

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

catchedVariable === exportedSymbolConst

但最简单的方法是临时更改模块内的代码,将.for 添加到Symbol。然后就可以写条件了:

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

调试成功后,您将把代码改回来,只删除.for 部分。

【讨论】:

以上是关于ECMAScript 6 中的 Symbol.for(string)的主要内容,如果未能解决你的问题,请参考以下文章

理解Ecmascript 6中的类和继承

dW 编辑推荐:ECMAScript 6 中的函数增强

ECMAScript 6 中的快捷语法汇总及代码示例

理解ECMAScript 6中的for...of循环

数组是 JavaScript ECMAScript 中的左值吗?

ECMAScript 6 笔记