ES6 Symbol

Symbol是ES6新添加的第六种原始类型,可以生成独一无二的值,可以被用于创建私有变量,避免变量名称冲突,消除魔法字符。

使用

通过调用Symbol函数创建,不可以使用new操作

const symbol = Symbol('desc')
const symbol2 = new Symbol('desc') // error 

每个通过Symbol函数创建的Symbol变量都不相等,即使他的描述参数相同

const a1 = Symbol('a')
const a2 = Symbol('a')
a1 === a2 // false 

Symbol不可以和其他变量进行运算

Symbol('1') + 1 // error
Symbol('1') + '1' // error
Symbol('1') / 2 // error 

但可以调用String和toString方法转换为字符串

String(Symbol('hello')) // Symbol(hello)
Symbol('hello').toString() // Symbol(hello) 

也可以通过Boolean函数转换为布尔值

Boolean(Symbol()) // true 

但是不能通过Number转换为数字

几个简单用途举例

创建私有变量

var moduleA = (function () {
   const _private = Symbol('private')
   class A {
       constructor () {
           this[_private] = 'private value'
       }
   }
   return {
       'default': A
   }
})()

const A = moduleA.default
const a = new A()
// 我们用字符串访问a属性的方法是获取不到,这样在一定程度上构建了私有变量
// 但也只是一定程度上,我们通过Object.getOwnPropertySymbols()方法还是可以获得Symbol属性名
const props = Object.getOwnPropoertySymbols(a)
a[props[0]] // 'private value' 

消除魔法字符串

// 摘自我的开源项目
// https://github.com/jeffwcx/ohu-share/blob/master/src/constants.js
const SUPPORT = {
 LEVEL1: 0,
 LEVEL2: 1,
 LEVEL3: 2,
 LEVEL4: 3,
 LEVEL5: 4,
 LEVEL6: 5,
 LEVEL7: 6
} 

这里常量LEVEL1 ~ 7只是想定义7个支持定义,其值(0 ~ 6)并没有什么实际意思,只是想区分对待而已。这里我们可以使用Symbol()来生成独一无二的值

const SUPPORT = {
 LEVEL1: Symbol('level1'),
 LEVEL2: Symbol('level2'),
 LEVEL3: Symbol('level3'),
 LEVEL4: Symbol('level4'),
 LEVEL5: Symbol('level5'),
 LEVEL6: Symbol('level6'),
 LEVEL7: Symbol('level7')
} 

这样我们在代码中就不可能出现0 ~ 6来代指支持等级的情况

switch (support) {
   case 0: 
       doLevel(0);
       break;
   case 1:
       doLevel(1);
       break;
   ...
} 

可以换成

switch (support) {
   case SUPPORT.LEVEL1,
       doLevel(SUPPORT.LEVEL1)
       break;
   case SUPPORT.LEVEL2,
       doLevel(SUPPORT.LEVEL2)
       break;
   ...
} 

共享Symbol

我们可以通过Symbol.for('uid')创建一个全局Symbol,这样我们可以跨文件访问该Symbol

let uid = Symbol.for('uid')
console.log(Symbol.keyFor(uid)) // uid

let uid2 = Symbol.for('uid')

uid === uid2 // true 

Symbol暴露出来的语言内部逻辑

Symbol.hasInstance

可自定义instanceof 操作

Symbol.isConcatSpreadable

将任意对象定义为可进行concat操作的对象,类比数组

Symbol.match, Symbol.replace, Symbol.search, Symbol.split

可以将任意对象定义为字符串可以进行matchsplit, search, split的对象,类比RegExp

Symbol.toPrimitive

自定义 类型转换为原始值时的操作

Symbol.toStringTag

自定义Object.prototype.toString方法

Symbol.unscopables

自定义with语句中不能被引用的值

Symbol.species

自定义子类操作(map, filter等)的返回类型

Symbol.iterator

自定义的对象默认遍历器