关于JavaScript Symbol类型

关于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的声明方式

  1. 直接声明

    let symbol = Symbol()
    
  2. Symbol也可以指定一个key值,这样子可以很好地去区分几个不同的Symbol对象。Symbol([description])

    const symbolWithKey = Symbol('带有key') // -> Symbol(带有key)
    
  3. 利用Symbol.for 方法,此方法类似于一个单例模式。

    const symbolFor = Symbol.for('for')
    

2. Symbol的比较

  1. 对于直接声明的Symbol,利用===比较会返回false

    const symbol = Symbol()
    const symbol1 = Symbol()
    symbol === symbol1 // false
    symbol == symbol1 // false
    
  2. 对于带有同一个key值比较的Symbol对象,利用===比较会返回false

    const symbol = Symbol('a')
    const symbol1 = Symbol('a')
    symbol === symbol1 // false
    symbol == symbol1 // false
    
  3. 对于使用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...inObject.keysObject.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类,在其中有一个成员变量,利用getset方法进行访问和赋值。

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:

ECMAScript 6 入门

好用的 JavaScript Symbol 类型

对于一些Symbol的api可以查看这里

上一篇:前端面试 【JavaScript】— 对象转原始类型是根据什么流程运行的?


下一篇:HighCharts之2D数值带有百分数的面积图