概述
symbol是一种新的原始类型,表示独一无二的值。是JavaScript中第七种数据类型。symbol值通过symbol函数生成。
对象的属性名可以有两种类型:
- 字符串
- symbol类型
let s = Symbol();
typeof s // 'symbol'
Symbol函数前不能使用new命令,因为生成的symbol是原始类型的值,不是对象。由于symbol不是对象,所有不能添加属性。基本上他是一种类似于字符串的数据类型。
symbol函数可接受字符串作为参数,表示对symbol参数的描述,主要是为了在控制台显示或者转为字符串时区分。
let s = Symbol('foo');
s // Symbol(foo)
s.toString() // "Symbol(foo)"
如果symbol的参数是一个对象,就会调用toString方法,将其转为字符串,然后才生成一个symbol值。
const obj = {
toString() {
return 'abc'
}
};
const sym = Symbol(obj);
sym // Symbol(abc)
symbol函数的参数只表示对当前symbol值的描述,因此相同参数的symbol函数的返回值是不想等的。
// 没有参数
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 // false
// 有参数
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false
symbol不能与其他类型的值进行运算,否则会报错。
symbol值可显示转换为字符串
let sym = Symbol('My Symbol');
sym.toString() // "Symbol(My Symbol)"
String(sym) // "Symbol(My Symbol)"
symbol值可转化为布尔值
let sym = Symbol();
Boolean(sym) // true
作为属性名的symbol
let mySymbol = Symbol();
// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';
// 第二种写法
let a = {
[mySymbol]: 'Hello!'
};
// 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, {value: 'Hello!'});
a[mySymbol] // "Hello!"
注意symbol值作为对象属性名时不能使用点运算符。
let mySymbol = Symbol();
let a = {};
a.mySymbol = 'hello';
a[mySymbol] // undefined
a.mySymbol // "hello"
a['mySymbol'] // "hello"
点运算符后面是字符串,所以不会读取mySymbol作为标识所指代的值,导致a的属性名实际上是一个字符串,而不是symbol值。
在对象的内部,使用symbol值定义属性时,symbol值必须放在方括号内。
symbol作为属性名时,该属性是公开属性,不是私有属性。
属性名的遍历
symbol作为属性名,不会出现在for...in、for...of循环中,也不会被Object.keys和Object.getOwnPropertyNames返回。但他也不是私有属性,Object.getOwnPropertySymbols方法可以获取指定对象的所有symbol属性。
该方法返回一个数组,成员是当前对象的所有用作属性名的symbol值。
let obj = {};
let a = Symbol(a);
let b = Symbol(b);
obj[a] = 'Hello';
obj[b] = 'World!';
let objectSymbols = Object.getOwnPropertySymbols(obj);
// [Symbol(a), Symbol(b)]
Reflect.ownKeys方法可以返回所有类型的键名,包括常规键名和是symbol键名。
let obj = {
[Symbol('My_kye')]: 1,
enum: 2,
nonEnum: 3
}
Reflect.ownKeys(obj) // ["enum", "nonEnum", Symbol(My_kye)]
Symbol.for方法和Symbol.keyFor方法
Symbol.for方法接受一个字符串作为参数,然后搜索有没有以该参数作为名称的symbol值。如果有,就返回这个symbol值,如果没有就新建并返回一个以该字符串为名称的symbol值。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2
true
Symbol.keyFor方法返回一个已登记的symbol类型值的key。
let s1 = Symbol.for('foo');
Symbol.keyFor(s1) // "foo"
let s2 = Symbol('foo');
Symbol.keyFor(s2) // undefined
内置的Symbol值
除了定义自己使用的Symbol值,ES6 还提供了11个内置的Symbol值,指向语言内部使用的方法。