我正在用Javascript重建一个旧的Java项目,并意识到在JS中没有好的方法来做枚举.
我能想到的最好的是:
const Colors = {
RED: Symbol("red"),
BLUE: Symbol("blue"),
GREEN: Symbol("green")
};
Object.freeze(Colors);
Run Code Online (Sandbox Code Playgroud)
的const保持Colors被重新分配,并冷冻它防止突变的键和值.我正在使用符号,这Colors.RED是不等于0,或除了它自己之外的任何其他东西.
这个配方有问题吗?有没有更好的办法?
(我知道这个问题有点重复,但以前的Q/As都很老了,ES6给了我们一些新功能.)
编辑:
另一个解决序列化问题的解决方案,但我认为仍存在领域问题:
const enumValue = (name) => Object.freeze({toString: () => name});
const Colors = Object.freeze({
RED: enumValue("Colors.RED"),
BLUE: enumValue("Colors.BLUE"),
GREEN: enumValue("Colors.GREEN")
});
Run Code Online (Sandbox Code Playgroud)
通过使用对象引用作为值,可以获得与Symbols相同的冲突避免.
var sym = Symbol();
Run Code Online (Sandbox Code Playgroud)
是window['sym']这已经是全球范围.
但是MDN说:
使用该
Symbol()函数的上述语法不会创建整个代码库中可用的全局符号.要创建跨文件和类似全局范围的环境中可用的符号,请使用这些方法Symbol.for()并Symbol.keyFor()从全局符号注册表中设置和检索符号.
sym 已经在浏览器的全局范围内,具有上述声明语法.
什么是全球符号注册表?
每个html文档都与window对象绑定.
那么,在浏览器世界中,跨文件/领域的符号可用性范围与全局范围(对象)有何不同window?
当我使用这样的代码时:
const sym = Symbol('toAvoidInterference');
document.querySelector('#someid')[sym] = 'Hello, world!';
Run Code Online (Sandbox Code Playgroud)
避免干扰其他属性名称是有意义的。但使用有什么区别和好处:
const sym = Symbol.for('attributeName');
document.querySelector('#someid')[sym] = 'Hello, world!';
Run Code Online (Sandbox Code Playgroud)
如果是一样的话我们可以这样写:
document.querySelector('#someid')['attributeName'] = 'Hello, world!';
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,另一个开发人员可能会使用同名的属性,尽管它被包装到or notfor的方法中Symbol,因为我们无法确定该字符串是唯一的。为什么需要使用 Symbol.for() 而不是使用纯字符串?
UPD。我突然发明了call这个最有用的功能Symbol.for()。如果代码中存在使用符号,有时在调试时很难使用条件断点。例如,您需要捕获变量是否等于符号类型的值并且该值绑定在不同的模块中。第一个困难的方法是使用该值作为常量并将其从该模块导出。在这种情况下,断点的条件将如下所示:
catchedVariable === exportedSymbolConst
Run Code Online (Sandbox Code Playgroud)
但最简单的方法是暂时更改模块内的代码添加.for到Symbol. 然后你可以写出条件:
catchedVariable === Symbol.for('string_key')
Run Code Online (Sandbox Code Playgroud)
成功调试后,您将把代码改回只是删除.for部分。
我正在玩ES6,看着符号.与您编写的ruby不同:symbol,ES6符号似乎允许任何"标准"变量名称.说实话,我觉得这很混乱:
var privateProperty = Symbol();
var obj = {};
obj[privateProperty] = 'some value goes here';
Run Code Online (Sandbox Code Playgroud)
因为它往往让我觉得这privateProperty可能是一个像前几年一样简单的字符串.使用:privateProperty无效.
就像$bar用于jQuery对象或bar$RxJS/Bacon流一样,我想知道在ES6中是否已经建立了用于命名符号的约定?
JS ES6 中有注册表符号这样的东西(可在这篇 Mozilla 文章中找到)。
它与Symbol()(有关 Stack Overflow 的相关问题)不同,可以通过Symbol.for(data).
打电话
Symbol.for(string)。这将访问一组称为符号注册表的现有符号。与由 定义的唯一符号不同Symbol(),符号注册表中的符号是共享的。如果你调用Symbol.for("cat")三十次,它每次都会返回相同的符号。当多个网页或同一网页中的多个模块需要共享一个符号时,注册表非常有用。
我一直在搜索关于这个主题的信息,我在 Stack Overflow 上读过类似的问题(有什么是“全局符号注册表”?但它没有涵盖这个问题 - 为什么使用注册表符号而不是字符串)。
尽管我似乎已经获得了(几乎)关于用 定义的唯一符号的所有信息Symbol(),但注册表符号 ( Symbol.for()) 对我来说根本没有多大意义。
我的意思是,看看那里的例子:
Symbol.for('foo'); // create a new global symbol
Symbol.for('foo'); // retrieve the already created symbol
// Same global symbol, but not locally
Symbol.for('bar') === Symbol.for('bar'); // true
//ADDED BY ME
Symbol.for('far') === Symbol.for('bar'); …Run Code Online (Sandbox Code Playgroud) 我尝试用Symbol键创建对象并找到相应的值Symbol.for,但它不起作用:
const sym = Symbol("x");
let obj = {
[sym]: "val"
}
console.log(obj[sym]); // "val"
console.log(obj[Symbol.for("x")]); // undefined, but expected "val"
Run Code Online (Sandbox Code Playgroud)
为什么?