在ECMAScript 6(简称 ES6)中,引入了一个新的数据类型——Symbol。Symbol 类型是一种原始数据类型,在 JavaScript 中只有它自己和另外五种(undefined、null、boolean、string、number)数据类型一样。Symbol 类型的值是唯一的和不可改变的,可以认为是一种标志。在本文中,我们将详细介绍 Symbol 类型,包括创建 Symbol 类型的几种方式、Symbol 值的作用与用法以及一些实际应用的示例。
创建 Symbol 类型
要创建 Symbol 值,我们可以使用全局函数 Symbol()
:
--- --- - --------- ------------------ ----- -- --------
Symbol()
函数接受一个可选的字符串参数,用于指定 Symbol 的描述,主要用于 Symbol 的调试。例如:
--- ---- - -------------- --- ---- - -------------- ---------------- --- ------ -- ----- ----------------------------- -- -------------
我们可以看到,两个相同描述的 Symbol 值不相等,描述不同的 Symbol 值才相等。
除了 Symbol()
函数,还有几种用于创建 Symbol 的方式,如下:
Symbol.for(key)
:该方法接受一个字符串参数,用于在全局 Symbol 注册表中查找或创建一个 Symbol 值。如果找到则返回该 Symbol 值,否则创建新的 Symbol 值并在全局 Symbol 注册表中注册,然后返回该 Symbol 值。例如:--- ---- - ------------------ --- ---- - ------------------ ---------------- --- ------ -- ---- ----------------------------- -- -------------
在该示例中,我们创建了两个描述相同的 Symbol 值,发现它们是相等的。这是因为我们使用了
Symbol.for()
方法并传入相同的参数。这样创建出来的 Symbol 值会在全局注册表中进行查找,如果找到了就返回已有的,否则创建新的并注册之后返回。Symbol.iterator
:该方法返回对象默认可迭代的迭代器。我们可以用这个方法来自定义对象的迭代器。例如:--- --- - --- --- --- ---- - ----------------------- ------------------------- -- - ------ -- ----- ----- - ------------------------- -- - ------ -- ----- ----- - ------------------------- -- - ------ ---------- ----- ---- -
在该示例中,我们使用
arr[Symbol.iterator]()
方法返回arr
的默认迭代器,然后使用iter.next()
方法来获取迭代器中的每个值。当迭代器遍历完所有值后,done
属性值为true
,value
属性值为undefined
。
Symbol 值的作用与用法
在 ES6 中,Symbol 类型的值主要有三个用途:
对象属性名的唯一性
--- --- - --- --- - --------------- -------- - --------- ---------------------- ----------
在上面的例子中,我们使用了一个 Symbol 值作为
obj
对象属性名。由于 Symbol 的值是唯一的,我们可以确保该属性名不会冲突,即便obj
对象中同时存在相同变量名属性。这也是 Symbol 类型存在的原初意义:解决属性命名冲突问题。私有属性的模拟
--- ------ - ----------- - --- ---- - -------------- ----- ------ - ---------------- - ---------- - ---- - --- ----- - ------ ----------- - --- ---------- - ---------- - ------ - - ------ ------- ----- --- - - --- ----------- ------------------- -- -- ----- - --- ------------------- -- -- --------------------- -- ---------
在上面的代码中,我们模拟了一个私有属性。使用 Symbol 值作为私有属性的名称,避免了被改写的风险,同时保证了私有属性访问的安全和灵活性。在该示例中,通过把
_age
作为 Symbol 值赋予对象来模拟私有属性,get
和set
方法让我们能够像使用普通属性一样来访问和修改私有属性。枚举值遍历
----- --- - -------------- ----- -- - ------------- ----- -- - ------------- --- --- - ----- --- ---- --- ---- --- -- ---- - ----------------- - -- ----------- -- ---------- -- ----------
在该示例中,我们将多个不同的 Symbol 值放到了一个数组中,在遍历时,我们可以使用
for…of
循环进行遍历。因为 Symbol 类型的值是不可被枚举的,所以我们可以在for…of
循环中正确地遍历整个数组。
示例代码
我们再来看两个更具体的示例代码,更展示 Symbol 类型的实际应用。
实现唯一标识符
-------- ------ - --- -- - -- -- ------------- - -------------- - ----------------------------------- ------ ----------- - ---- - --- - ---- - --- - ---- - --- - ---- - --- - ---- - ---- - ------ - --- -- - ------- --------------------------- ------------------------------------------------
在该示例中,我们创建了一个
uuid()
函数,该函数使用 Symbol 值作为返回值,同时 Symbol 值的描述使用了一种随机算法来生成唯一标识符,确保每次调用uuid()
函数都可以获得一个唯一的标识符。该方法类似于通常用于生成 GUID 的方式。该方法生成出来的 Symbol 值既有唯一性,也有较高的随机性。实现对对象成员的封装
----- ----- - --------------- ---- - -------------- ----- ------ - ----------------- ---- - ----------- - ----- ---------- - ---- - --- ---------------------- - ------ --------- - ------- - ---------------- --- -------------- --- --- ------------- ----- ------- - ------ ------------ ---- - ------ --- ------------ ----- - - --- - - ----------------------- ---- ----------------------------------- ---------- ---------- -- ---- --- ------ --- --- -- ----- -----
在该示例中,我们使用了
_name
和_age
的 Symbol 值作为私有属性,以便我们可以封装对象属性。由于 Symbol 类型的全局唯一性,它可以和普通字符串属性名作为相同等价,放到对象内作为属性。get [Symbol.toStringTag]
方法允许我们对对象的字符串表示形式进行自定义。例如,在终端中输出console.log(p)
得到结果为:------ -------------- --------- ------------ ---
这里
Symbol(name)
和Symbol(age)
成功封装了私有属性,不会显式输出。
结论
Symbol 类型是 JavaScript 语言中的一种新的数据类型,其作为一种原始数据类型,具有不可变性和唯一性,可用于处理特定领域的问题——如定义对象的属性名、枚举值遍历、实现松散耦合等。在实际应用中,我们可以采用以上几种方式创建和应用 Symbol 类型,更可发挥出它的功效来。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6735a1b10bc820c5824f94a2