1. Symbol的简介
在es6之前,对象属性在命名时很容易造成命名冲突,为了保证每个属性的名字都是独一无二的,这就从根本上防止了属性名的冲突,这就是引入Symbol的原因。
Symbol是一种新的原始数据类型,表示独一无二的值。
至此,JavaScript语言总共有7中数据类型:undefined,null,Boolean,String,Number,Object,Symbol
2. Symbol的生成及使用规则
Symbol值通过Symbol函数生成。现在对象的属性名可有两种类型,一种是原来的字符串,另一种就是新增的Symbol类型。1
2let symbol = Symbol();
typeof symbol; // "symbol"
Symbol函数前面不能使用new命令,否则会报错,这是因为生成的Symbol是一种原始数据类型,不是对象。也就是说,由于Symbol的值不是对象,所以不能添加属性。
Symbol是一种类似于字符串的数据类型。
Symbol函数可以接受一个字符串作为参数,表示对symbol实例的描述:1
2
3
4
5let s1 = Symbol('foo');
let s2 = Symbol('bar');
s1 // Symbol('foo')
s1.toString(); // 'Symbol(foo)'
如果Symbol的参数是一个对象,就会调用该对象的toString方法,将其转为字符串,然后生成一个Symbol值1
2
3
4
5
6
7const obj = {
toString(){
return 'abc';
}
}
const sym = Symbol(obj);
sym; // Symbol(abc)
Symbol函数的参数只是对当前Symbol值的描述,因此相同参数的Symbol函数的返回值不相等:1
2
3
4
5
6
7
8//无参数
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 // false
//有参数
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false
Symbol值不能与其他类型的值进行运算,否则报错;1
2let s1 = Symbol('foo');
"symbol is "+ s1; // TypeError: can't convert symbol to string
Symbol值可以显示转为字符串:
1 | let s1 = Symbol('foo'); |
Symbol 值可以转为布尔值,但是不能转为数值:
1 | let s1 = Symbol('foo'); |
3. Symbol作为属性名
由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15let s1 = Symbol();
//first:
let a = {};
a[s1] = 'hello';
//second:
let a = {
[s1]: 'hello'
}
//third:
let a = {};
Object.defineProperty(a,s1,{value:'hello'});
a[s1]; // "hello"
Symbol 值作为对象属性名时,不能用点运算符;
在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中;
Symbol 类型还可以用于定义一组常量,保证这组常量的值都是不相等的;
Symbol 值作为属性名时,该属性还是公开属性,不是私有属性。
4. 属性名的遍历
Symbol 作为属性名,该属性不会出现在for…in、for…of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。
1)Object.getOwnPropertySymbols
Object.getOwnPropertySymbols方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。1
2
3
4
5
6
7
8
9
10const obj = {};
let a = Symbol('a');
let b = Symbol('b');
obj[a] = 'Hello';
obj[b] = 'World';
const objectSymbols = Object.getOwnPropertySymbols(obj);
objectSymbols
// [Symbol(a), Symbol(b)]
2)Reflect.ownKeys
Reflect.ownKeys方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。1
2
3
4
5
6
7
8let obj = {
[Symbol('a')]: 1,
aaa: 2,
bbb: 3
};
Reflect.ownKeys(obj)
// ["aaa", "bbb", Symbol(a)]
5. Symbol.for() 和 Symbol.keyFor()
1)Symbol.for()
Symbol.for()接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建并返回一个以该字符串为名称的 Symbol 值。
Symbol.for()与Symbol()这两种写法,都会生成新的 Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。1
2
3
4
5Symbol.for("bar") === Symbol.for("bar")
// true
Symbol("bar") === Symbol("bar")
// false
2)Symbol.keyFor()
Symbol.keyFor方法返回一个已登记的 Symbol 类型值的key。1
2
3
4
5let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined