javascript 符号
JavaScript is one of the cores of web development. JavaScript, also known as ECMAScript was standardized in 1997. Since then, the below primitive values were present in the language.
JavaScript是Web开发的核心之一。 JavaScript,也称为ECMAScript,于1997年进行了标准化。此后,该语言中出现了以下原始值。
- Undefined 未定义
- Null空值
- Big Int(newly added in ES2020)Big Int(在ES2020中新增)
- Boolean 布尔型
- Number数
- String串
null
is labeled as one of the primitive values in JavaScript, since its action is apparently primitive. But in some situations, null
is not as “primitive” as it first seems! Every Object is derived from null
value, and therefore typeof
operator returns an object for it.
null
被标记为JavaScript中的原始值之一,因为它的作用显然是原始的。 但是在某些情况下, null
并不像它最初看起来那样“原始”! 每个Object都是从null
值派生的,因此typeof
运算符将为其返回一个对象。
But with the release of ES6 in 2015, a newer primitive type — Symbol, was added. They were quite different from the previous primitives. They were simply values, not strings, nor numbers nor even Objects. They were just Symbols.
但是随着2015年ES6的发布,添加了更新的原始类型— Symbol 。 它们与以前的原始方法有很大的不同。 它们只是值,而不是字符串,数字,甚至对象。 他们只是象征。
这是什么新的原始内容? (What is This New Primitive All About?)
The Symbol primitive is all about uniqueness. Its value is a unique identifier. You can simply call Symbol()
and get a unique identifier. Optionally, you can pass a description as well.
Symbol原语是关于唯一性的。 它的值是一个唯一的标识符。 您可以简单地调用Symbol()
并获得唯一的标识符。 (可选)您也可以传递描述。
One of the key things you should remember is that, Symbols are always unique. Even if you pass the same description to two Symbols, they will still be different.
您应该记住的关键事情之一是,符号始终是唯一的。 即使您将相同的描述传递给两个符号,它们也将有所不同。
A lot of people think of Symbols as a way of receiving a unique value. But only part of this is true. Although Symbols are unique, you will never receive the unique value by console logging it. You can only assign it to a variable and use that variable as a unique identifier.
许多人认为符号是一种获得独特价值的方式。 但是,只有一部分是正确的。 尽管符号是唯一的,但是您将永远不会通过控制台记录它来获得唯一的值。 您只能将其分配给变量,并将该变量用作唯一标识符。
In other words, your Symbol would not give a unique value like an ID which might look like 285af1ae40223348538204f8c3a58f34
. But rather, when you console a Symbol, you will receive Symbol()
or Symbol(description)
. Remember that it would not be a string, rather a plain old Symbol.
换句话说,您的Symbol不会提供像ID那样的唯一值,该ID可能看起来像285af1ae40223348538204f8c3a58f34
。 但是,相反,当您操纵一个Symbol时,您将收到Symbol()
或Symbol(description)
。 请记住,它不是字符串,而是普通的旧Symbol。
typeof Symbol()
"symbol"
You can obtain a string by calling the toString()
method on the Symbol. But that too would only give you a string representation of the previously obtained value.
您可以通过在Symbol上调用toString()
方法来获取字符串。 但这也只会为您提供先前获得的值的字符串表示形式。
Tip: Share your reusable components between projects using Bit (Github). Bit makes it simple to share, document, and organize independent components from any project.
提示:使用Bit ( Github )在项目之间共享可重用组件。 Bit使共享,记录和组织来自任何项目的独立组件变得简单。
Use it to maximize code reuse, collaborate on independent components, and build apps that scale.
使用它可以最大程度地重复使用代码,在独立组件上进行协作以及构建可扩展的应用程序。
Bit supports Node, TypeScript, React, Vue, Angular, and more.
Bit支持Node,TypeScript,React,Vue,Angular等。
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/f49df6953ca17600cdfb21f1cd5ea81e.png)
注意事项(Things to keep in mind)
没有自动转换为字符串(No auto-conversion to string)
The window.alert()
receives a parameter of type string. But even if you do pass a number
or even null
, you will not receive an error. Rather JavaScript implicitly converts the data type into a string and displays it. But with the case of Symbols, JavaScript does not implicitly convert it to a string. It is to keep these two separate as they are fundamentally different and should not accidentally convert one into another.
window.alert()
接收字符串类型的参数。 但是,即使您传递了number
甚至是null
,也不会收到错误。 而是JavaScript隐式地将数据类型转换为字符串并显示它。 但是对于Symbols,JavaScript不会将其隐式转换为字符串。 应当将这两者分开,因为它们在根本上是不同的,不应偶然将它们转换为另一种。
在对象文字中使用符号作为键 (Using Symbols as keys in an Object literal)
Take a look at the below code.
看下面的代码。
let id = Symbol("id");let obj = {
id: 1
};
//This is string "id" as key. Not our Symbol
In the above example, although we have assigned a id
property to our obj
object, it is not the id
variable we had defined the line before. In order to set the id
variable as a key, we should use [ ]
.
在上面的示例中,尽管我们已经为obj
对象分配了id
属性,但这不是我们之前定义的那行的id
变量。 为了将id
变量设置为键,我们应该使用[ ]
。
let id = Symbol("id");let obj = {
[id]: 1
};
Similarly, you can’t access symbol-keyed properties using the dot-syntax. You have to use square brackets like above.
同样,您不能使用点语法访问符号键属性。 您必须使用上面的方括号。
console.log(obj.id);
//undefinedconsole.log(obj[id]);
//1
通用对象检查功能会跳过符号 (Symbols are skipped by common object inspection features)
As Symbols were designed to avoid collisions, Symbolic properties are skipped in JavaScript’s most common object-inspection features such as for-in
loop. Symbols as property keys are also ignored in Object.keys(obj)
and Object.getOwnPropertyNames(obj)
.
由于符号是为避免冲突而设计的,因此在JavaScript最常见的对象检查功能(例如for-in
循环)中会跳过符号属性。 在Object.keys(obj)
和Object.getOwnPropertyNames(obj)
中,也将忽略作为属性键的符号。
Also note that Symbol properties of an object are ignored when you use JSON.stringify()
.
还要注意,当您使用JSON.stringify()
时,将忽略对象的Symbol属性。
全球符号注册 (Global Symbol Registry)
As we have seen above, Symbols are unique, even with the same descriptions we pass as parameters. But there might be instances where you need multiple web pages or multiple modules within the same web page to share a Symbol. At moments like this, you can use the Global Symbol Registry.
正如我们在上面看到的,即使符号具有与参数相同的描述,符号也是唯一的。 但是在某些情况下,您可能需要多个网页或同一网页中的多个模块来共享一个符号。 在这样的时刻,您可以使用全局符号注册表。
Although it sounds like a complicated system, the interface is quite simple to use.
尽管听起来像是一个复杂的系统,但该界面非常易于使用。
Symbol.for(密钥) (Symbol.for(key))
This method searches for existing symbols in the global symbol registry with the provided key and returns it if found. If not found, it would create a Symbol with the key in the global symbol registry and returns it.
此方法使用提供的键在全局符号注册表中搜索现有符号,如果找到,则将其返回。 如果未找到,它将使用全局符号注册表中的键创建一个Symbol并将其返回。
Symbol.keyFor(sym)(Symbol.keyFor(sym))
This method performs the reverse of the Symbol.for()
method. This retrieves a shared symbol key from the global symbol registry for the given symbol.
此方法与Symbol.for()
方法相反。 这将从全局符号注册表中检索给定符号的共享符号键。
用例(Use Cases)
隐藏属性(Hidden properties)
Let’s imagine that you want to develop a library to sort a list of items.
假设您要开发一个库来对项目列表进行排序。
How can you solve this?
您如何解决呢?
You have many ways of solving this. You can ignore whether the list is sorted and re-sort it. Although the end result would be a sorted list, it will be inefficient as the algorithm implements the actual sorting process on an already sorted array.
您有多种解决方法。 您可以忽略列表是否已排序,然后重新排序。 尽管最终结果将是一个排序列表,但是由于该算法对已经排序的数组实施了实际的排序过程,因此效率不高。
Rather than implementing a solution that would be an overkill, we can simply set a flag to denote whether the list has been sorted or not. This would easily allow us to sort our list only when it has not been sorted.
我们可以简单地设置一个标志来表示列表是否已排序,而不是实施一个过大的解决方案。 这将很容易地使我们仅在未排序列表时对其进行排序。
The implementation would look somewhat similar to this.
该实现看起来与此类似。
if (list.isSorted) {
sortAlgorithm(list);
}
list.isSorted = true;
Although the above implementation does its job perfectly, it fails under certain aspects.
尽管以上实现可以很好地完成其工作,但是在某些方面却失败了。
Any other code accessing your list can stumble over your property when using
for-in
orObject.keys()
.使用
for-in
或Object.keys()
时,访问列表的任何其他代码都可能使您的财产绊倒。If you are using a library to implement the sort algorithm, the clever library owner might have set a
isSorted
flag already. You doing the same thing would be an overkill if the context was bigger.如果您使用库来实现排序算法,那么聪明的库所有者可能已经设置了
isSorted
标志。 如果上下文更大,那么您做同样的事情将是过大的。- If you were the owner of the library and a clever developer tries to set the flag themself, it would be similar to the above scenario. 如果您是该库的所有者,而一个聪明的开发人员尝试自己设置该标志,则类似于上述情况。
In a situation like this, Symbols would be perfect as they avoid collisions.
在这种情况下,Symbols会很完美,因为它们可以避免碰撞。
系统符号(System Symbols)
JavaScript uses several internal Symbols to fine tune it’s performance under various aspects. Some of them are,
JavaScript使用多个内部符号来在各个方面调整其性能。 他们之中有一些是,
- Symbol.asyncIterator Symbol.asyncIterator
- Symbol.hasInstance Symbol.hasInstance
- Symbol.isConcatSpreadable Symbol.isConcatSpread
- Symbol.iterator 符号迭代器
You can read more about them over here.
您可以在此处阅读有关它们的更多信息。
Note: Symbols are not 100% totally hidden
注意:符号不是100%完全隐藏
You can still users methods such as Object.getOwnPropertySymbols(obj)
and Reflect.ownKeys(obj)
to receive the Symbols used as Object keys. You might wonder why. I personally feel that Symbols were created to avoid unintentional naming collisions. If someone really wanted to overwrite the Symbolic property key, then I think it would be possible for them to do so.
您仍然可以使用Object.getOwnPropertySymbols(obj)
和Reflect.ownKeys(obj)
来接收用作对象键的符号。 您可能想知道为什么。 我个人认为创建Symbol是为了避免意外的命名冲突。 如果有人真的想覆盖符号属性键,那么我认为他们有可能这样做。
React关于符号的普遍问题 (Popular Issue Raised in React Regarding Symbols)
During the discussion with the editor of Bits and Pieces, I was asked to address an issue raised in React JS involving Symbols. Below is a link to the raised issue.
在与Bits and Pieces编辑器的讨论中,我被要求解决React JS中涉及符号的问题。 以下是所提出问题的链接。
正在请求功能 (Feature being requested)
For those who did not go through the above link or did not understand what was happening, below is a summary for you.
对于那些没有通过上面的链接或不了解正在发生的事情的人,以下是为您提供的摘要。
React developers should be familiar with the concept of keys. Below is an extract from the glossary of React docs.
React开发人员应该熟悉密钥的概念。 以下是React文档词汇表的摘录。
A “key” is a special string attribute you need to include when creating arrays of elements. Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside an array to give the elements a stable identity.
“键”是创建元素数组时需要包括的特殊字符串属性。 按键可帮助React识别哪些项目已更改,添加或删除。 应该为数组内的元素提供键,以赋予元素稳定的身份。
I believe the above passage explains what keys are.
我相信以上文章解释了什么是键。
The fundamental reason for keys is uniqueness. It is needed to be able to identify sibling elements in an array uniquely. This sounds like a great use case for Symbols as they are unique and can be used to identify each sibling element in an array uniquely.
密钥的根本原因是唯一性。 需要能够唯一地识别阵列中的同级元素。 对于符号来说,这听起来像是一个很好的用例,因为它们是唯一的,并且可以用于唯一地标识数组中的每个同级元素。
But when you add a Symbol as a key to an array element, you will receive the following error. You can view the source code for the below example over here.
但是,当您将符号添加为数组元素的键时,您将收到以下错误。 您可以在此处查看以下示例的源代码。
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/f89313c293e89468c028c2202c408ae9.png)
The reason for the above error is that keys are expected to be of type string. If you remember what we had gone through, Symbols are not of string type and they do not implicitly convert themselves unlike other primitive data types.
出现上述错误的原因是,预期键的类型为string 。 如果您还记得我们经历过的事情,则符号不是字符串类型的,它们不会像其他原始数据类型那样隐式地进行自身转换。
The feature being requested is to allow support for Symbols as keys natively because they do not auto convert themselves to strings.
所请求的功能是允许将Symbols作为本机键来支持,因为它们不会自动将其自身转换为字符串。
为什么团队拒绝并解决此问题 (Why the team refused and closed this issue)
Dan Abramov commented and closed down this issue mentioning “I don’t see a practical use case for allowing Symbols, except a misunderstanding”. He also mentions that you can simply use the “customer ID, or username” or something that comes with the data you’re handling.
丹·阿布拉莫夫(Dan Abramov)评论并关闭了此问题,并提到“除误解外,我没有看到允许使用符号的实际用例”。 他还提到,您可以简单地使用“客户ID或用户名”或您要处理的数据随附的内容。
I would like to voice out my opinion from both perspectives.
我想从两个角度表达我的意见。
First of all, there can be instances where you would be handling a list of data without an ID as such. This can happen when the data is collected from the front-end and displayed as a list. Think of the number list example I had used in the demo. What if the numbers were entered by the user? You would have to set a counter to assign a unique key to each entry. Some would take the approach of assigning the array index to each element, but that is known to be a really bad idea. You cannot make the input value as a key because there can be duplicate inputs. As proposed, Symbols would make an easier alternative.
首先,在某些情况下,您可能会在没有ID的情况下处理数据列表。 当从前端收集数据并显示为列表时,可能会发生这种情况。 想想我在演示中使用的号码清单示例。 如果用户输入了数字怎么办? 您将必须设置一个计数器,以便为每个条目分配唯一的键。 有些人会采用为每个元素分配数组索引的方法,但这是一个非常糟糕的主意。 您不能将输入值作为键,因为可能有重复的输入。 按照建议,Symbols将成为更容易的替代方法。
但…。 (But….)
There is something fundamentally wrong in the proposal. Have a look at the below code example.
该提案有根本上的错误。 看下面的代码示例。
As you can see, all 4 keys are unique. When there is a change in an element value, React knows which one has changed, and triggers a rebuild. But when the tree is rebuilt, the key of that specific element would change again as Symbol()
would give a unique value every time it is called as it is being used inline. The key
would be different on every render, which would force React to re-mount the element/component.
如您所见,所有四个键都是唯一的。 当元素值发生变化时,React知道哪一个发生了变化,并触发重建。 但是当重建树时,该特定元素的键将再次更改,因为Symbol()
每次在被内联使用时都会被赋予唯一值。 每个渲染上的key
都不同,这将迫使React重新安装元素/组件。
If you are not clear on how the tree building process and change detection work in the above scenario, please go through this explanation given in the docs.
如果您不清楚在上述情况下树的构建过程和更改检测的工作方式,请仔细阅读docs中给出的说明。
You can avoid this re-render issue by using the global symbol registry — Symbol.for(key)
as every time you call for a Symbol, you would look for the Symbol in the global registry and if found, it will be returned.
通过使用全局符号注册表Symbol.for(key)
,可以避免此重新呈现问题,因为每次调用Symbol时,都会在全局注册表中查找Symbol,如果找到,它将被返回。
但是再一次。 (But again….)
There is something wrong with this approach too. For you to retrieve a Symbol from the global registry, you should provide the key of the Symbol which itself is unique. If you think about it, that key itself is unique to identify each element. Then why do we need to create a Symbol at that instance?
这种方法也有问题。 为了从全局注册表中检索符号,应提供符号的键,该键本身是唯一的。 如果您考虑一下,该键本身就是唯一可识别每个元素的键。 那为什么我们需要在那个实例上创建一个符号呢?
注意 (NOTE)
But there was a solution provided by Eduardo where you initialize the object or array once with the Symbols and then they are never re-initialized. Which means the value will not be re-calculated on each render and therefore the values(Symbols) will always be the same. This approach can work on certain situations only.
但是Eduardo提供了一种解决方案,您可以使用Symbols一次初始化对象或数组,然后再不对其进行初始化。 这意味着该值不会在每次渲染时重新计算,因此值(符号)将始终相同。 此方法只能在某些情况下起作用。
You should note that all of the given solutions would work, but they would trigger unnecessary re-mounts and cause unwanted load on the memory and CPU. The goal is to come up with a solution using Symbols that can be efficient as well.
您应该注意,所有给定的解决方案都可以使用,但是它们会触发不必要的重新安装,并在内存和CPU上造成不必要的负载。 目标是提出一种使用符号的解决方案,该解决方案也应有效。
If you have any comments, please feel free to drop them below.
如果您有任何意见,请随时将其放在下面。
Thank you for reading and happy coding.
感谢您的阅读和愉快的编码。
学到更多 (Learn More)
ResourcesJavaScript InfoMozilla BlogMDN DocsECMA Script SpecsReact Docs
翻译自: https://blog.bitsrc.io/mastering-javascript-es6-symbols-6453da3bd46c
javascript 符号