基本定义
数据类型Symbol
表示独一无二的值,是JavaScript中第七种数据类型。
JavaScript基本数据类型
undefined
null
- 布尔值(Boolean)
- 字符串(String)
- 数值(Number)
- 对象(Object)
生成Symbol值
Symbol值是通过Symbol
函数生成
const s = Symbol();
console.log(typeof s); // 'symbol'
console.log(s); // 'Symbol()'
注意:由于Symbol值不是对象,所以不能使用
new
命令,否则会报错。
函数Symbol
可以接受一个字符串作为参数,这个参数表示对Symbol实例的描述,可以用于在控制台显示或者在转成字符串时比较容易区别。
const s1 = Symbol('foo');
console.log(s1); // Symbol('foo')
console.log(s1.toString()); // 'Symbol('foo')'
当Symbol 的参数是一个对象,就会自动调用这个对象的toString()
方法,将其转为字符串,然后生成一个Symbol值。
const obj = {
toString() {
return 'abc';
}
}
const sym = Symbol(obj);
console.log(sym); // Symbol(abc)
注意:
Symbol
函数的参数指示表示当前Symbol值的描述。两个参数相同的Symbol函数返回值是不相等的
let s1 = Symbol();
let s2 = Symbol();
console.log(s1 === s2); // false
let s3 = Symbol();
let s4 = Symbol();
console.log(s3 === s4); // false
Symbol 值不能与其他类型的值进行运算,会报错
let sym = Symbol('abc');
console.log('this symbol is ' + sym); // 报错 TypeError: can't convert symbol to string
Symbol值可以显示转换成字符串
let sym = Symbol('abc');
console.log(String(sym)); // 'Symbol(abc)';
console.log(sym.toString()); // 'Symbol(abc)';
Symbol值可以显示转换成布尔值,但不能转成数值
let sym = Symbol();
console.log(Boolean(sym)); // true
console.log(!sym); // false
Symbol.prototype.description
创建Symbol的时候,可以通过参数添加 Symbol 的描述
const sym = Symbol('abc');
上面sym
的描述就是foo
- 在***ES2019***之前只能通过转换成字符串来读取这个描述信息
const sym = Symbol('abc');
console.log(String(sym)); // 'Symbol(abc)'
console.log(sym.toString()); // 'Symbol(abc)'
- 在***ES2019***中提供了一个实例的属性
description
,直接返回Symbol的描述
const sym = Symbol('abc');
console.log(sym.description); // 'abc'
作为属性名的Symbol
由于每一个Symbol 值都不相等,所以 Symbol 值可以作为标识符,用于对象的属性名,就可以保证不会出现同名的属性。
const sym = Symbol();
// 第一种写法
const a = {};
a[sym] = 'abc';
// 第二种写法
const a ={
[sym]: 'abc';
}
// 第三种写法
const a = {};
Object.defineProperty(a, sym, { value: 'abc'});
console.log(a[sym]); // 'abc'
需要注意
- Symbol 值作为对象属性名时不能用点运算符
const sym = Symbol();
const a = {};
a.sym = 'abc';
console.log(a[sym]); // undefined
console.log(a['sym']); // 'abc'
上面的代码中,因为点运算符后面总是字符串,所以不会使用sym
作为标识符,从而导致这里的属性名为一个字符串,而不是Symbol值。
- 在对象内部,使用Symbol值定义属性时,Symbol 值必须放在方括号之中
const sym = Symbol();
let obj = {
[sym]: function(arg){
...
}
}
当这里的sym
不在方括号中,这个属性的键名就是字符串s
,而不是s
变量所代表的Symbol值。
采用增强的对象写法,上面的obj
也可以写的简洁一点
let obj = {
[sym](arg){
...
}
}
属性名的遍历
Symbol作为属性名时,使用for...in
、for...of
、Object.keys()
、Object.getOwnPropertyNames()
、JSON.stringify()
都找不到Symbol的属性。
但是 Symbol作为属性名 也不是私有属性。
通过方法Object.getOwnPropertySymbols()
来获取指定对象的所欲Symbol属性名,Object.getOwnPropertySymbols()
会返回一个元素时当前对象的所有用作属性名的Symbol值的数组。
const obj = {};
const a = Symbol('a');
const b = Symbol('b');
obj[a] = 'abc';
obj[b] = 'def';
const objectSymbols = Object.getOwnPropertySymbols(obj);
console.log(objectSymbols); // [Symbol(a), Symbol(b)]
通过方法Reflect.ownKeys()
也可以获得所有类型的键名,包括常规键名和Symbol键名。
const obj = {
[Symbol('a')]: 1,
enum: 2,
};
console.log(obj); ['enum',Symbol('a')]
由于以Symbol 值作为键名,不会被常规方法遍历到,所以可以利用这个特性为对象定义一些非私有,但又只用于内部的方法
Symbol.for() & Symbol.keyFor()
Symbol.for()
方法 Symbol.for()
接受一个字符串作为参数,然后搜索有没有以这个参数作为名称的Symbol值。如果有,就返回这个Symbol值,如果没有就新建一个以这个参数为名称的Symbol值,并将其注册到全局。
const s1 = Symbol.for('abc');
const s2 = Symbol.for('abc');
console.log(s1); // Symbol(abc)
console.log(s1 === s2); // true;
Symbol.for()
与Symbol()
的区别
方法Symbol.for()
与 Symbol()
都会生成新的Symbol,Symbol.for()
会先在全局环境中搜索,Symbol()
不会,并且Symbol.for()
不会每次调用就会返回一个新的Symbol类型的值,而是去检查指定的key是否存在,在指定的key不存在的情况下才会创建一个新的。Symbol.for()
会将创建的Symbol类型的值记录到全局环境,Symbol()
不会记录到全局环境。
Symbol.keyFor()
方法Symbol.keyFor()
方法返回一个已经登记在全局的Symbol类型值的key
.
备注:本文是自己学习阮一峰老师的《ECMAScript 6 入门》所做的笔记,大部分例子来源于此书。