es6新增第七种数据类型symbol

224 阅读3分钟

概念

symbol 是一个 ES6 标准种新增的一种基本数据类型,在 JavaScript 中,共有七种基本数据类型:string、number、bigint、boolean、null、undefined、symbol。并且除了 null 和 undefined 之外,每个基本类型都有其包装对象。

symbol 的值是通过 Symbol() 函数生成,每一个 symbol 的值都是唯一的,并且 symbol 类型的值可以作为对象的属性标识符使用,这也是 symbol 类型设计的目的。

所以现在对象属性名可以为两种类型:一种就是原本的字符串类型,一种即为新增的 symbol 类型。凡是使用 symbol 命名的属性都是独一无二的,保证不与其他属性名产生冲突。

JavaScript 中大多数的数值都支持隐式转换为字符串,但 symbol 不会转换:

let s = Symbol("sym");
alert(s); //TypeError:cannot convert a Symbol value to a string

symbol也不能与其他数据类型的值进行计算:

console.log("symbol is"+s);//TypeError:cannot convert a Symbol value to a string

但是如果有必要,可以手动将symbol转换成字符串:

    console.log(s.toString());

或者获得定义symbol时的参数:

console.log(s.description);

用法

创建一个 symbol 的值需要使用 Symbol() 函数,而不能使用 new 命令。

let s = Symbol('sym');

由于生成的 symbol 是一个值而不是对象,所以不能为其添加属性。

Symbol() 函数可以接受一个字符串作为参数,表示对该值的描述,因此即使定义 symbol 使用相同的参数互相之间也不是相同的:

let s1 = Symbol('sym');
let s2 = Symbol('sym');
s1 === s2 ; // false

Symbol.for() 、 Symbol.keyFor()

如果我们要重复使用一个 symbol 时,可以用到 Symbol.for() 方法。Symbol.for() 方法接受一个字符串参数,会在全局中搜索有没有以该参数命名的 symbol 的值,如果查找到就返回这个值。如果没有查到则重新生成一个值,并将该值以参数名称注册到全局。

let s1 = Symbol.for('sym');
let s2 = Symbol.for('sym');
s1 === s2; // true

Symbol.for()Symbol() 方法都会生成新的 symbol 类型的值,不同的是 Symbol.for() 方法会查找命名参数是否在全局中注册过,如果注册过的就不会创建新的值,而是会直接返回,所以我们可以使用到相同的 symbol 值。但使用 Symbol() 方法每次都会创建一个新的值,且不会注册到全局。

Symbol.keyFor() 方法表示获取一个 symbol 的值在全局中注册的命名参数 key,只有使用 Symbol.for() 创建的值才会有注册的命名参数,使用 Symbol() 生成的值则没有:

let s4 = Symbol('sym');
let s5 = Symbol.for('sym');
Symbol.keyFor(s4); // undefined
Symbol.keyFor(s5); // sym

应用场景

1.使用 symbol 作为对象的属性名

由于每一个 symbol 的值都是不相同的,所以使用 symbol 作为属性名可以保证不会出现同名属性。防止某一个属性被改写覆盖:

let s1 = Symbol('sym');
let obj = {  name: 'test obj',  [s1]: 'this is symbol'}
obj[s1]; // this is symbol

注意使用 symbol 作为对象的属性名时,是无法通过 Object.keys()for...in 来遍历对象的属性的:

Object.keys(obj); // ["name"]
for(let name in obj){  
    console.log(name);// name
}

因此,在将对象进行 JSON 转换时: JSON.stringify() ,symbol 的属性也会被排除:

JSON.stringify(obj); // "{"name":"test obj"}"

需要注意的是,使用 symbol 定义的属性,还是公有的属性,不是私有属性。

2. 使用 symbol 定义常量

使用 symbol 定义的常量能保证常量的值都是不相等的。

const COLOR_RED    = Symbol();
const COLOR_GREEN  = Symbol();
function getComplement(color) {  
    switch (color) {    
        case COLOR_RED:      return COLOR_GREEN;    
        case COLOR_GREEN:     return COLOR_RED;    
        default:      
        throw new Error('Undefined color');  
    }
}