首先,我们先来谈谈,什么是Symbol呢?Symbol是ES6新增的一种数据类型。
那么这种数据类型到底应该怎么用呢,让我们先开看看普通字符串的声明吧。
let name = 'Joker';
let title = 'Joker';
console.log(name === title) //true
当我们拿两个值相同的字符串进行比较的时候,返回的结果为true。
let name = Symbol();
let title = Symbol();
console.log(name === title) //false
但如果我们声明两个Symbol类型的时候,他们是永远不会一样的,所以打印的结果为false。因此我们可以把Symbol理解为一种唯一标识符。简单理解,我们可以把Symbol当成是一个永远不会重复的字符串。
除此之外,我们还能在Symbol里面添加相应的描述(通过描述能清楚区分该symbol的作用是什么)。
let name = Symbol('我的英文名为Joker');
console.log(name) //Symbol(我的英文名为Joker)
此时我们打印这个Symbol的时候就能看到Symbol类型和相应的描述了。
另外系统还给我们提供了一个名为description的属性,我们通过这个属性能获取到symbol的描述信息。
console.log(name.description) //我的英文名为Joker
除了上面这种定义symbol的方式外,我们还能通过Symbol.for的方式定义。
let name = Symbol.for("我的英文名为Joker");
console.log(name.description) //我的英文名为Joker
这两种定义的方式的区别在于:如果我们通过Symbol.for的方式定义的话,系统会帮我们记录有一个Symbol且它的描述为"我的英文名为Joker",在下一次定义symbol的时候,系统就会先查询内存中是否已经声明了一个相同的symbol,如果有就把Symbol拿过来。因此,即使我们用Symbol.for声明一百次一千次,实际上就只有一个Symbol。但通过Symbol()的方式声明则不同,如果我们声明一百次,那么就有一百个Symbol。
let name = Symbol.for("我的英文名为Joker");
let title = Symbol.for("我的英文名为Joker");
console.log(name === title) //true
这里的Symbol虽然看起来是两个,但却指向的是同一个symbol,因此这里的打印结果为true。
除此之外,二者之间还有一个区别:
let name = Symbol.for("我的英文名为Joker");
let title = Symbol("我的英文名为Joker");
console.log(Symbol.keyFor(name)); //我的英文名为Joker
console.log(Symbol.keyFor(title)); //undefined
通过Symbol.for的方式声明的时候,是在全局定义的,因此可以通过Symbol.keyFor()的方式获取到Symobl的描述。
但通过Symbol()的声明方式则不是全局定义的,因此得到的值为undefined。
好了关于Symbol这一个新增的数据类型相信大家已经有了初步的了解,接下来让我们来看看Symbol应该用在什么场景上呢?
假如有一个对象里面存着一次考试的学生成绩,但由于这次测试的学生名字都为“Joker”,但对象的属性名却要唯一,这可怎么办呢?这时候我们就可以使用我们的Symbol()啦。
let student1 = {
name: "Joker",
key: Symbol()
};
let student2 = {
name: "Joker",
key: Symbol()
};
let test = {
[student1.key]: {js: 100, css: 89},
[student2.key]: {js: 55, css: 68}
};
console.log(test)
这时候就能顺利的把两个学生的考试信息都打印出来了。
思路:将Symbol作为我们对象的key值,由于Symbol()是唯一的,因此我们再也不怕对象的属性值重复的问题啦。
不过如果我们把Symbol作为对象的属性名,那么普通的for in和for of是不能遍历出来的,这时候我们就要用特殊的遍历方法。
for (const key of Reflect.ownKeys(test)) {
console.log(key);
}