关于JavaScript Symbol类型
最近一段时间,在看《JavaScript 权威指南》的时候,发现有一种全新的数据类型Symbol
(符号), 如果利用typeof
去测试它的类型,会返回``Symbol。
const symbol = Symbol()
typeof symbol // -> 'symbol'
我在写这行测试代码的时候就犯了个错误,
Symbol
不是一个构造器,不能够使用new关键字,如果使用会报错。类似于其他的包装类同样有这样的问题const symbol = new Symbol() // -> Uncaught TypeError: Symbol is not a constructor
这应该是一个新的类型,我想借助着书中3.6节的内容、BV1dE411v7mx视频中所看到的,做下笔记。
1. Symbol的声明方式
-
直接声明
let symbol = Symbol()
-
Symbol
也可以指定一个key值,这样子可以很好地去区分几个不同的Symbol对象。Symbol([description])
const symbolWithKey = Symbol('带有key') // -> Symbol(带有key)
-
利用
Symbol.for
方法,此方法类似于一个单例模式。const symbolFor = Symbol.for('for')
2. Symbol的比较
-
对于直接声明的
Symbol
,利用===
比较会返回false
。const symbol = Symbol() const symbol1 = Symbol() symbol === symbol1 // false symbol == symbol1 // false
-
对于带有同一个
key
值比较的Symbol
对象,利用===
比较会返回false
。const symbol = Symbol('a') const symbol1 = Symbol('a') symbol === symbol1 // false symbol == symbol1 // false
-
对于使用
Symbol.for
方法创建的Symbol
对象,使用同一个key
值,利用===
比较会返回true
const key = 'key' const symbol = Symbol.for(key) const symbol1 = Symbol.for(key) symbol === symbol1 // true symbol == symbol1 // true
3. 对象带有Symbol属性遍历需要注意的问题
对于JavaScript现有的对于对象属性遍历的方法一共有四种:for in
, for of
, Object.keys
, Object.getOwnPropertyNames
, Reflect.ownKeys
。而针对 Symbol
,还有专门的Object.getOwnPropertySymbols
方法。
现有一个对象:
const symbol = Symbol()
const person = {
name: '张三',
[symbol]: 'www.baidu.com'
}
首先,对象并非可枚举的,无法利用for of遍历,如果使用将会报错:person is not iterable
。
如果利用如下for...in
,Object.keys
,Object.getOwnPropertyNames
代码遍历对象的话,只能够打印出name
,无法遍历其他属性。
for (const key in person) {
console.log(key)
} // name
console.log(Object.keys(person)) // ['name']
console.log(Object.getOwnPropertyNames(person)) // ['name']
如果需要访问其中的Symbol属性,可以使用Object.getOwnPropertySymbols
,如果访问所有属性包括Symbol属性,可以使用Reflect.ownKeys
。
console.log(Reflect.ownKeys(person)) // ['name', Symbol()]
console.log(Object.getOwnPropertySymbols(person)) // [Symbol()]
4. Symbol在实际开发中的作用
看视频中的例子感觉都有点牵强,在强行用,感觉这个Cache稍微靠谱点,我给摘过来。
现有一个Cache
类,在其中有一个成员变量,利用get
和set
方法进行访问和赋值。
class Cache {
static data = {}
/**
* @description 根据 name 和 Value 设置 Cache 中的值
* @date 2021-11-07
* @param {String} name 属性名
* @param {String} value 属性值
* @returns {any}
*/
static set (name, value) {
return this.data[name] = value
}
/**
* @description 根据 name 返回 data 中属性的值
* @date 2021-11-07
* @param {String} name 属性名
* @returns {any} 属性对应的 Value 值
*/
static get (name) {
return this.data[name]
}
}
假设有一种电商购物网站的场景,可能会有几种对象:
console.log(Cache.get('hdcms'))
let user = {
name: 'apple',
desc: '购物车',
key: Symbol('购物车数据')
}
let car = {
name: 'apple',
desc: '会员资料',
key: Symbol('用户数据')
}
如果需要向Cache
中添加数据,可以使用key
值设置主键以避免重复。
// 添加
Cache.set(user.key, user)
Cache.set(car.key, car)
但是我觉得这个样子有些牵强。首先如果你是接收后端传过来的数据的话,这个key
肯定是指定好的,不需要哦前端怎么操心。如果是使用nodejs作为服务端的话,nodejs也可以连接数据库,并不需要这个来做key
,好像找不到这个东西有什么用武的地方啊,有哪位好汉看到这篇文章,知道有什么好的解决方法,还希望踢我下,谢谢茄子。
Ref:
对于一些Symbol的api可以查看这里