编程崽

登录

一叶在编程苦海沉沦的扁舟之上,我是那只激情自射的崽

js 的新数据类型 Symbol

js 的新数据类型 Symbol

以往,js 的数据类型有 Number、String、Boolean、Object、null 和 undefined。

ES6 则引入了一种新的原始数据类型:Symbol,表示独一无二的值。

Symbol 函数栈不能用 new 命令,因为 Symbol 是原始数据类型,不是对象。可以接受一个字符串作为参数,为新创建的 Symbol 提供描述,用来显示在控制台或者作为字符串的时候使用,便于区分。

基本用法演示

js 复制代码
// 使用同一参数创建的 Symbol,生成的值也是不同的
let sym_1 = Symbol('sym')
let sym_2 = Symbol('sym')
console.log(sym_1 === sym_2) // false
console.log(sym_1 === sym_1) // true
console.log(sym_1) // Symbol(sym)
console.log(typeof(sym_1)) // symbol

用作对象的唯一属性名

Symbol 最大的用途是用作对象的唯一属性值,且这个属性是无法遍历的。

js 复制代码
// 使用同一字符串创建的三个 Symbol,可以用作对象的三个key
let key_1 = Symbol('key')
let key_2 = Symbol('key')
let key_3 = Symbol('key')

let obj = {
  a: 1,
  b: 2,
  [key_1]: 10,
  [key_2]: undefined,
}

// 修改已有的值
obj[key_2] = 200

// 在对象外部赋值
obj[key_3] = 300

// 拥有 key 的前提下,不影响使用
console.log(obj[key_1]) // 10
console.log(obj[key_2]) // 200
console.log(obj[key_3]) // 300

// 无法遍历,无法用其他方式获取 key
console.log(JSON.stringify(obj)) // {"a":1,"b":2}
console.log(Object.keys(obj)) // ["a", "b"]

打印对象obj,查看如下: Snipaste_2021-01-04_18-38-34.png

单单查看,无法分清三个 key,如果要读取到一个对象的 Symbol 属性,需要用以下两个方法:

js 复制代码
console.log(Reflect.ownKeys(obj)) // ["a", "b", Symbol(key), Symbol(key), Symbol(key)]
console.log(Object.getOwnPropertySymbols(obj)) // [Symbol(key), Symbol(key), Symbol(key)]
console.log(Object.getOwnPropertySymbols(obj)[0] === key_1) // trye

类似单例模式的记录和追踪

  • Symbol.for(str):类似单例模式,首先会在全局搜索,是否有基于字符串 str 为创建的 Symbol,如果有即返回该 Symbol,若没有则新建该 Symbol 并返回,同时登记在全局环境中,以供之后的搜索。

  • Symbol.keyFor(Symbol):传入一个 Symbol,再全局搜索该 Symbol 是否已登记,已登记的话就返回创建它所基于的那个字符串,否则返回 undefined。

js 复制代码
let sym_not_1 = Symbol('key') // 普通声明
let sym_1 = Symbol.for('key') // 使用 Symbol.for 登记
let sym_2 = Symbol.for('key') // 再次使用 Symbol.for

console.log(Symbol.keyFor(sym_not_1)) // undefined - 因为此 Symbol 没有登记
console.log(Symbol.keyFor(sym_1)) // key - 获取到此 Symbol 的字符串
console.log(sym_1 === sym_2) // true - 类似单例模式,所以两个是相等的
console.log(sym_1 === sym_not_1) // false - 两个毫不相关