Symbol 数据类型
let s = Symbol(); typeof s; // "symbol"
是 ES6 继 Number,String,Boolean,Undefined,Null 之后引入的新数据类型
对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。
Symbol
函数的参数只是表示对当前 Symbol 值的描述
let s1 = Symbol('foo');
let s2 = Symbol('bar'); s1 // Symbol(foo)
s2 // Symbol(bar) s1.toString(); // "Symbol(foo)"
s2.toString(); // "Symbol(bar)"
凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
背景:
ES5 的对象属性名都是字符串,这容易造成属性名的冲突
如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。
- 原始数据类型
Symbol
表示独一无二的值。
它是 JavaScript 语言的第七种数据类型
Symbol 值可以显式转为字符串
Symbol 值可以显式转为布尔值
- Symbol 值不能与其他类型的值进行运算,会报错
-
即使 Symbol
函数参数相同,但是它们是不相等的。 - Symbol 值 作为对象的属性时,只能用 [ ] 访问进行读写
在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中
let s = Symbol();
let obj = {
[s]: function (arg) { ... }
}; obj[s]();- 常量使用 Symbol 值最大的好处,就是其他任何值都不可能有相同的值了,因此可以保证上面的
switch
语句会按设计的方式工作 const COLOR_RED = Symbol();
const COLOR_GREEN = Symbol(); function getComplement(color) {
switch (color) {
case COLOR_RED:
return COLOR_N:
return COLOR_GREEN;
case COLOR_GREERED;
default:
throw new Error('Undefined color');
};
};- 消除魔术字符串的方法,就是把它写成一个变量
const shapeType = {
triangle: Symbol(),
}; function getArea(shape, options) {
let area = 0;
switch (shape) {
case shapeType.triangle:
area = .5 * options.width * options.height;
break;
};
return area;
}; getArea(shapeType.triangle, { width: 100, height: 100 });- Symbol 作为属性时,非私有属性,遍历法
- Symbol 作为属性名,该属性不会出现在
for...in
、for...of
循环中,也不会被Object.keys()
、Object.getOwnPropertyNames()
、JSON.stringify()
返回 - 但是,它也不是私有属性,有一个
Object.getOwnPropertySymbols()
获取指定对象的所有 Symbol 属性名。 - 重新使用同一个 Symbol 值,Symbol.for('aName')
接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。
- 如果有,就返回这个 Symbol 值
- 否则就新建并返回一个以该字符串为名称的 Symbol 值
let s1 = Symbol.for('foo'); // 登记在全局环境*搜索
let s2 = Symbol.for('foo'); // 登记在全局环境*搜索 s1 === s2 // true
Symbol.for()
与Symbol()
这两种写法,都会生成新的 Symbol。
它们的区别是:
前者会被登记在全局环境*搜索,后者不会。
Symbol.for()
不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key
是否已经存在,如果不存在才会新建一个值。
比如,如果你调用Symbol.for("cat")
30 次,每次都会返回同一个 Symbol 值,
但是调用Symbol("cat")
30 次,会返回 30 个不同的 Symbol 值
-
Symbol.keyFor
() 返回一个已登记的 Symbol 类型值的key,即 Symbol.for() 生成的 Symbol 值
注意: 为 Symbol 值登记的名字,是全局环境的,可以在不同的 iframe 或 service worker 中取到同一个值
let obj = {
[Symbol('my_key')]: 1,
enum: 2,
nonEnum: 3
}; Reflect.ownKeys(obj); // ["enum", "nonEnum", Symbol(my_key)]