1、Symbol概述
ES6 引入的一种新的原始数据类型Symbol,表示独一无二的值。
它属于JavaScript语言的原生数据类型之一,其他数据类型是:undefined、null、Boolean、String、Number、Bigint、Object。
使用场景:
ES5 的对象属性名都是字符串,这容易造成属性名的冲突。
比如,你使用了一个他人提供的对象,你想为这个对象添加新的方法(mixin模式),这个时候新方法的名字就有可能和现有的方法重名,这个时候就可以使用Symbol,来防止你新追加的方法重名。
2、Symbol的特性
let s = Symbol();
console.log(typeof s); // symbol
上述代码,s就是一个独一无二的值。
注意:Symbol()函数之前不能使用new命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,而不是对象。另外,由于Symbol值不是对象,所以也不能添加属性。基本上它就是一种类似字符串的数据类型。
let s1 = Symbol('s1');
let s2 = Symbol('s2');
console.log(s1, s2); // Symbol(s1) Symbol(s2)
console.log(s1.toString(), s2.toString()); // "Symbol(s1)" "Symbol(s2)"
Symbol()函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述。
这主要是为了在控制台显示,或者转为字符串的时候,比较容易区分。
注意:Symbol()函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的。
let obj = {
toString: function() {
return 'abc';
}
}
console.log(Symbol(obj)); // abc
let s = Symbol('mySymbol');
// console.log(s + '123'); // Uncaught TypeError: Cannot convert a Symbol value to a string
console.log(String(s), s.toString()); // 'Symbol(mySymbol)' 'Symbol(mySymbol)'
console.log(Boolean(s)); // true
console.log(Number(s)); // Uncaught TypeError: Cannot convert a Symbol value to a number
当Symbol函数的参数是一个对象时,会自动调用对象中的toString方法,转成字符串之后,再把这个字符串作为参数去执行。
Symbol可以转成字符串、布尔值,不能转成数字,也不能和其他类型的值进行运算。
3、Symbol.prototype.description
ES2019提供了一个Symbol值的实例属性description,可以直接返回Symbol值的描述。
let s = Symbol('my symbol')
console.log(s.description); // my symbol
4、Symbol作为对象属性名
由于每一个 Symbol 值都是不相等的,这意味着只要 Symbol 值作为标识符,用于对象的属性名,就能保证不会出现同名的属性。
let mySymbol = Symbol('mySymbol');
// 第一种写法
let a = {};
a[mySymbol] = 'hello Symbol';
// 第二种写法
let b = {
[mySymbol]: 'hello Symbol'
}
// 第三种写法
let c = {};
Object.defineProperty(c, mySymbol, { value: 'hello Symbol' });
console.log(a, b, c);
注意:Symbol 值作为对象属性名时,不能用点运算符。
因为点运算符后面总是字符串,所以不会读取mySymbol作为标识名所指代的那个值。
还有一点需要注意,Symbol 值作为属性名时,该属性还是公开属性,不是私有属性。
5、Symbol作为常量
Symbol 类型还可以用于定义一组常量,保证这组常量的值都是不相等的。
const log = {};
log.levels = {
DEBUG: Symbol('debug'),
INFO: Symbol('info'),
WARN: Symbol('warn')
};
console.log(log.levels.DEBUG, 'debug message');
console.log(log.levels.INFO, 'info message');
6、消除魔术字符串
魔术字符串指的是,在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。风格良好的代码,应该尽量消除魔术字符串,改由含义清晰的变量代替。
function getArea(shape, options) {
let area = 0;
switch (shape) {
case 'Triangle': // 魔术字符串
area = .5 * options.width * options.height;
break;
/* ... more code ... */
}
return area;
}
getArea('Triangle', { width: 100, height: 100 }); // 魔术字符串
例如上述代码,Triangle就是一个魔术字符串,它会多次出现在more code部分,与代码形成强耦合。
常用的消除魔术字符串的方法,就是把它写成一个变量。
const shapeType = {
triangle: 'Triangle'
};
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 });
如果仔细分析,可以发现shapeType.triangle等于哪个值并不重要,只要确保不会跟其他shapeType属性的值冲突即可。因此,这里就很适合改用 Symbol 值。
const shapeType = {
triangle: Symbol()
};
7、Symbol常用方法
Symbol.for(key)
- 作用:使用给定的key搜索现有的symbol【key表示symbol中的description】
- 返回值:如果找到,返回该symbol;否则将创建一个新的symbol,key作为description,添加到注册表中并返回。
- 简述:用description找Symbol,找到就返回,找不到就创建一个新的Symbol。
Symbol.keyFor(symbol)
- 作用:从symbol注册表中,返回指定symbol的description,没有则返回undefined。
- 返回值:如果有description,返回;否则返回undefined。
注意:
- 如果使用Symbol()定义的symbol,则不会添加到注册表中;使用Symbol.for()定义的symbol则会添加到注册表中。
- Symbol.for(key)和Symbol.keyFor(sym)都是在Symbol注册表中进行查找。不会找到Symbol()定义的symbol
8、遍历对象中的Symbol
let symbol = Symbol("sym");
let obj = {
name: "symbol_name",
[symbol]: "唯一性"
};
// 访问对象的基本属性
for (const key in obj) {
console.log(key); // name
}
for (const key of Object.keys(obj)) {
console.log(key); // name
}
// 访问对象中的私有属性
for (const key of Object.getOwnPropertySymbols(obj)) {
console.log(key); // Symbol(sym)
}
for (const key of Reflect.ownKeys(obj)) {
// 访问对象的所有属性
console.log(key); // name 、Symbol(sym)
}
注意:
- 对象的属性要使用变量值,必须使用[变量名]
- Symbol类型作为对象的私有属性,通过for/in、for/of无法遍历,必须使用Object.getOwnPropertySymbols(对象)或Reflect.ownKeys(对象)进行遍历
学习参考:
标签:console,log,symbol,数据类型,JS,let,key,Symbol From: https://www.cnblogs.com/luckest/p/16721576.html