更新:最近出现了一个brilliant article from Mozilla。如果你好奇的话就读读吧。
正如你可能知道的,他们计划在ECMAScript 6中包含新的Symbol原语类型(更不用说其他一些疯狂的东西)。我一直认为Ruby中的:symbol
概念是不必要的;我们可以很容易地使用普通字符串,就像我们在JavaScript中所做的那样。现在他们决定用它来复杂化JS中的事情。
我不明白动机。有人能解释一下JavaScript中是否真的需要符号吗?
更新:最近出现了一个brilliant article from Mozilla。如果你好奇的话就读读吧。
正如你可能知道的,他们计划在ECMAScript 6中包含新的Symbol原语类型(更不用说其他一些疯狂的东西)。我一直认为Ruby中的:symbol
概念是不必要的;我们可以很容易地使用普通字符串,就像我们在JavaScript中所做的那样。现在他们决定用它来复杂化JS中的事情。
我不明白动机。有人能解释一下JavaScript中是否真的需要符号吗?
8条答案
按热度按时间zu0ti5jz1#
将符号引入Javascript的最初动机是启用 private 属性。
不幸的是,他们最终被严重降级。它们不再是私有的,因为您可以通过反射找到它们,例如,使用
Object.getOwnPropertySymbols
或代理。它们现在被称为 unique 符号,它们唯一的用途是避免属性之间的名称冲突。例如,ECMAScript本身现在可以通过特定的方法引入扩展钩子,这些方法可以放在对象上(例如:例如,定义它们的迭代协议),而不冒它们与用户名冲突的风险。
这是否足以成为在语言中添加符号的动机是有争议的。
7xllpg7q2#
符号并不能保证真正的隐私,但可以用来区分对象的公共属性和内部属性。让我们举一个例子,我们可以使用
Symbol
来拥有私有属性。让我们举一个例子,其中对象的属性不是私有的。
以上,
Pet
类属性type
不是私有的。为了让它私人化,我们必须创建一个关闭。下面的例子说明了如何使用闭包使type
成为私有的。上述方法的缺点:我们为创建的每个
Pet
示例引入了一个额外的闭包,这可能会损害性能。现在我们介绍
Symbol
。这可以帮助我们使属性私有化,而无需使用额外的不必要的闭包。下面的代码示例:5n0oy7gb3#
这篇文章是关于
Symbol()
的,提供了我可以找到/制作的实际例子和我可以找到的事实和定义。TLDR;
Symbol()
是ECMAScript 6(ES6)发布时引入的数据类型。关于象征有两个奇怪的事实。
Symbol()
定义的变量都得到唯一的内容,但它不是真正的private。如何初始化符号?
1.获取可调试的唯一标识
你可以这样做:
或者这样:
"some text here"
字符串不能从符号中提取,它只是用于调试目的的描述。它不会改变符号的行为。尽管如此,你可以console.log
它(这是公平的,因为这个值是用于调试的,以免把日志与其他日志条目错误地混淆):2.获取某个字符串数据的符号
在这种情况下,* 实际上 * 考虑符号的值,并且这样两个符号可以是非唯一的。
让我们把这些符号称为“第二类”符号。它们不与“第一类型”符号(即,“第二类型”符号)相交。即用
Symbol(data)
定义的那些)。接下来的两段只涉及 * 第一类型 * 符号。
使用Symbol替代旧数据类型有什么好处?
让我们首先考虑一个对象,一个标准数据类型。我们可以在那里定义一些键值对,并通过指定键来访问这些值。
如果我们有两个人都叫彼得呢?
这样做:
也说不通。
所以,这似乎是两个完全不同的人有相同的名字的问题。然后,让我们引用新的
Symbol()
。这就像真实的生活中的一个人--任何人都是独一无二的,但他们的名字可以是平等的。让我们定义两个“人”。现在我们有两个名字相同的人。我们的人真的不同吗?他们是;你可以检查这个:
我们如何从中受益?
我们可以在你的对象中为不同的人做两个条目,他们不会以任何方式被弄错。
注:
不过,值得注意的是,用
JSON.stringify
字符串化对象将丢弃所有用Symbol作为键初始化的对。执行
Object.keys
也不会返回这样的Symbol()->value
对。使用这种初始化,绝对不可能将条目误认为第一和第二人称。为它们调用
console.log
将正确输出它们的第二个名称。在对象中使用时,与定义非枚举属性有何不同?
事实上,已经存在一种方法来定义一个属性,使其对
Object.keys
和枚举隐藏。这就是:Symbol()
有什么区别?不同的是,您仍然可以通过通常的方式获得使用Object.defineProperty
定义的属性:如果使用前一段中的符号定义:
只有在知道它的变量i的情况下,你才有能力接收它的值。e.
此外,在键
"apple"
下定义另一个属性将使对象删除旧的属性(如果硬编码,它可能会抛出错误)。不要再吃苹果了!真遗憾参考上一段,符号是唯一的,将键定义为Symbol()
将使其唯一。类型转换和检查
Symbol()
不可能转换为任何其他数据类型。Symbol(data)
,可以根据原始数据类型“生成”符号。hjqgdpho4#
符号是一种新的、特殊的对象,可用作对象中的唯一属性名称。使用符号而不是字符串允许不同的模块创建彼此不冲突的属性。符号也可以被有效地私有化,这样,任何人都不能直接访问符号。
Symbols是一种新的原语,就像数字、字符串和布尔原语一样。与其他原语不同,符号没有文字语法(例如。例如
string
是如何拥有''
的)-创建它们的唯一方法是使用Symbol
构造函数,方法如下:实际上,符号只是将属性附加到对象的一种稍微不同的方式-您可以轻松地提供众所周知的符号作为标准方法,就像
Object.prototype.hasOwnProperty
一样,它出现在从Object
继承的所有内容中。下面是
Symbol
基元类型的一些好处。符号内置可调试性
可以给符号提供一个描述,这实际上只是用于调试,以便在将它们记录到控制台时更容易一些。
符号可以作为对象键
这就是符号变得非常有趣的地方。它们与物体紧密地交织在一起。可以将符号指定为对象的键,这意味着您可以将无限数量的唯一符号指定给对象,并确保这些符号永远不会与字符串键或其他唯一符号冲突。
符号可以作为唯一值
假设您有一个日志库,它包含多个日志级别,如
logger.levels.DEBUG
、logger.levels.INFO
、logger.levels.WARN
等。在ES 5代码中,你会喜欢使用这些字符串(比如logger.levels.DEBUG === 'debug'
)或数字(logger.levels.DEBUG === 10
)。这两个都不是理想的,因为这些值不是唯一值,但符号是!所以logger.levels
简单地变成:在great article中阅读更多。
n3ipq98p5#
我是这么看的。符号提供了“额外的隐私级别”,通过防止对象的密钥/属性通过一些流行的方法(如Object)暴露。keys()和JSON。stringify()。
虽然给定了对象本身,但这些属性仍然可以通过反射、代理、Object公开。getOwnPropertySymbols()等。,没有自然的方法通过一些直接的方法来访问它们,从OOP的Angular 来看,这些方法有时可能就足够了。
t2a7ltrp6#
JS符号是一种新的原始数据类型。它们是作为唯一ID的令牌。可以使用
Symbol
构造函数创建符号。以MDN的这个片段为例:使用符号作为唯一的对象属性键通常很方便,例如:
iibxawm47#
符号有两个主要用例:
1.“隐藏”对象属性。如果我们想将一个属性添加到一个“属于”另一个脚本或库的对象中,我们可以创建一个符号并将其用作属性键。符号属性不会出现在
for..in
中,因此不会意外地与其他属性一起处理。另外,它不会被直接访问,因为另一个脚本没有我们的符号。因此,该属性将受到保护,以防意外使用或覆盖。因此,我们可以使用符号属性,“秘密地”将我们需要的东西隐藏到对象中,但其他人不应该看到。
Symbol.*
访问。我们可以使用它们来改变一些内置的行为。例如,。.....Symbol.iterator
用于可迭代对象,Symbol.toPrimitive
用于设置对象到原语的转换,等等。来源
cfh9epnr8#
以下是我如何描述符号,从我的Angular 来看,以及为什么***我认为它们是无用的垃圾***:
快速说明:
Symbols是JavaScript中内置的、唯一的、
enum
值的等价物,带有一个“description”字符串,该字符串与Symbol的值和唯一性无关。但行为会发生很大变化,具体取决于您使用的是Symbol()
还是Symbol.for()
!!!正如其他人已经指出的:
另请参阅,关于包含符号的对象的枚举:
问题一。..
现在,所有这些对您来说似乎都很好,并且可行,直到您发现
Symbol.for()
。..:Symbol.for()
静态方法使用给定的键在运行时范围的符号注册表中搜索现有的符号,如果找到就返回它。否则,将在全局符号注册表中使用此键创建一个新符号。因此,虽然
Symbol()
创建了一个具有totally-value-and-unique-inrelevant“description”字符串的Symbol,但Symbol.for()
创建了一个具有 globally-mapped“description”字符串的Symbol。但是,因为Symbol()
的描述字符串是不相关的,Symbol()
和Symbol.for()
在两个完全独立的世界中运行, 同时使用相同的符号类型和类似的术语 。....!超级清晰,感谢JavaScript霸主!
更多问题。..
所以为了澄清,这就是为什么符号是无用的。..:
Symbol
。您必须使用它来确定在运行时使用了哪种符号创建方法:Object.defineProperty()
并将enumerable
设置为false
。Symbols所做的一切都是给语言增加了不必要的复杂性,因为现在你必须使用Reflect.ownKeys()
这样的其他东西来访问对象的所有属性。正如MDN所说..:[
Reflect.ownKeys()
]是在一次调用中获得所有自己的属性-可枚举和不可枚举、字符串和符号的唯一方法,而无需额外的过滤逻辑。例如,Object.getOwnPropertyNames()
获取Reflect.ownKeys()
的返回值,并仅过滤到字符串值,而Object.getOwnPropertySymbols()
仅过滤到符号值。Object.freeze()
实现)。...),但这更多的是一个障碍而不是一个功能。例如,您可能希望执行以下操作:Symbol()
在其构造函数中接受其他类型的描述(或者根本不接受)(它不使用new
)。..),但它stringifies无论你把它,e。例如:太有用了!
总结
所以,我的建议?不要使用符号,如果你能帮助它。使用基本的
{}
对象,class
es,[]
数组,字符串,数字-基本上任何其他-代替。JS没有让枚举变得更容易like they should have,而是添加了这个复杂的、比有用的符号更无用的垃圾。