Symbol BigInt
Symbol 和 BigInt 类型都是es6及之后引入的,从现实中来看,相对的使用频率也不算特别高。
Symbol
Symbol 是 ES6 中引入的新数据类型,它表示一个唯一的常量,通过 Symbol 函数来创建对应的数据类型,创建时可以添加变量描述,该变量描述在传入时会被强行转换成字符串进行存储。
var a = Symbol('1')
var b = Symbol(1)
a.description === b.description // true
var c = Symbol({id: 1})
c.description // [object Object]
var _a = Symbol('1')
_a == a // false
有一个全局的symbol注册中心,用Symbol.for()
创建的symbol会添加到这个注册中心,并用它的 description作为索引键。也就是说,如果你用Symbol.for()
创建带有相同 description的两个 symbol,它们就是相等的。
const symbol1 = Symbol.for('test');
const symbol2 = Symbol.for('test');
symbol1 === symbol2; // true
console.log(symbol1); // 'Symbol(test)'
通常来说,除非你有非常好的理由,否则不应该使用全局注册中心,因为这会造成命名冲突。
symbol不会出现在JSON.stringify()
的结果里,确切地说是JSON.stringify()
会忽略symbol属性名和属性值:
const symbol = Symbol('test');
const obj = { [symbol]: 'test', test: symbol };
JSON.stringify(obj); // "{}"
基于上面的特性,Symbol 属性类型比较适合用于两类场景中:常量值和对象属性。
避免常量值重复
假设有个 getValue 函数,根据传入的字符串参数 key 执行对应代码逻辑。代码如下所示:
function getValue(key) {
switch(key){
case 'A':
...
...
case 'B':
...
}
}
getValue('B');
这段代码对调用者而言非常不友好,因为代码中使用了魔术字符串(魔术字符串是指在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值),导致调用 getValue 函数时需要查看函数源码才能找到参数 key 的可选值。所以可以将参数 key 的值以常量的方式声明出来。
const KEY = {
alibaba: 'A',
baidu: 'B',
...
}
function getValue(key) {
switch(key){
case KEY.alibaba:
...
...
case KEY.baidu:
...
}
}
getValue(KEY.baidu);
但这样也并非完美,假设现在我们要在 KEY 常量中加入一个 key,根据对应的规则,很有可能会出现值重复的情况:
const KEY = {
alibaba: 'A',
baidu: 'B',
...
bytedance: 'B'
}
这显然会出现问题:
getValue(KEY.baidu) // 等同于 getValue(KEY.bytedance)
所以在这种场景下更适合使用 Symbol,我们不关心值本身,只关心值的唯一性。
const KEY = {
alibaba: Symbol(),
baidu: Symbol(),
...
bytedance: Symbol()
}
PS:当然,这个其实也是相对的。大部分情况下,直接走字典也是可行的。比如:
const KEYMAP = {
ALIBABA: 'ALIBABA',
BAIDU: 'BAIDU',
...
}
避免对象属性覆盖
假设有这样一个函数 fn,需要对传入的对象参数添加一个临时属性 user,但可能该对象参数中已经有这个user属性了,如果直接赋值就会覆盖之前的值。此时就可以使用 Symbol 来避免这个问题。
创建一个 Symbol 数据类型的变量,然后将该变量作为对象参数的属性进行赋值和读取,这样就能避免覆盖的情况,示例代码如下:
function fn(o) { // {user: {id: xx, name: yy}}
const s = Symbol()
o[s] = 'new user obj'
...
}
获取目标target 的 symbol属性:
Object.getOwnPropertySymbols(target);
Symbol 唯一的用途就是标识对象属性解决属性冲突,表明对象支持的功能。如果不需要那么追求完美,似乎都用不上这个。
BigInt
BigInt 是一种内置对象,它提供了一种方法来表示大于 2^53 - 1
的整数。这原本是 Javascript中可以用 Number 表示的最大数字。BigInt 可以表示任意大的整数。
它在某些方面类似于 Number ,但是也有几个关键的不同点:不能用于 Math 对象中的方法;不能和任何 Number 实例混合运算,两者必须转换成同一种类型。在两种类型来回转换时要小心,因为 BigInt 变量在转换成 Number 变量时可能会丢失精度。
在实际项目中,出于精度考虑也可能会直接使用类似 BigDecimal 这个npm。
更多详情:BigInt