25 Symbol的理解与使用
诞生原因
之前我们的对象属性的数据类型都是字符串,没有其他的了。所以会导致属性名重复,导致属性值被覆盖的情况。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法,在添加的操作就很容易覆盖了原有的方法。所以需要一个独一无二的数据类型来完成这个使命。所以Symbol出来主持大局了。
一句话:为了避免添加对象属性导致原有的属性被覆盖而设计一个独一无二的数据类型
唯一性
console.log(NaN === NaN) //false
console.log(Symbol() === Symbol()) //false
console.log(Symbol('a') === Symbol('a')) //false 被修饰的字符串变量a都是唯一
与其他数据类型之间的转换
Symbol不能用四则运算进行操作,否则报错。它只能用显示的方式转为字符串和布尔值,即:String(Symbol()) / Boolean(Symbol())
对象属性的遍历(https://segmentfault.com/a/1190000039142445)
以上说了对象属性的创建,但是我们要格外的注意,Symbol作为属性名,该属性不会出现在for…in、for…of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。所以我们可以用Object.getOwnPropertySymbols方法,获取指定对象的所有Symbol 属性名。
看到这是不是感觉用Symbol类型创建的对象属性这么麻烦吗?如果一个对象里面有字符串的属性又有Symbol的属性,难不成要分来获取对象属性吗?答案是不用,那必须使用新的API方法:Reflect.ownKeys(),这个方法就可以返回对象所有的属性,也就是字符串属性和Symbol属性。所以这里要留意了。
//对象的遍历
let person = {
name:'sikara',
[Symbol('age')]:12,
age:123,
}
for (const i in person) {
console.log(i)
}
//person并不具备迭代器的接口 person.iterator
// for (let person1 of person) {
// console.log(person1)
// }
//键值返回的类型都是数组
console.log(Object.keys(person)) // 获取symbol以外的键
console.log(Object.getOwnPropertySymbols(person))//获取symbol键
console.log(Reflect.ownKeys(person))//获取全部键值
console.log(Object.getOwnPropertyNames(person))//同keys
console.log(Object.getOwnPropertyNames([1,2,3]))//数组则不建议用这种 ['0', '1', '2', 'length']
Symbol.for(),Symbol.keyFor()使用
注意,这里的Symbol.for()和Symbol()创建的都是Symbol类型,但是他们的创建机制有所不同,Symbol.for(‘a’)的创建方式会在创建之前在全局中寻找,有没有用Symbol.for()的方式,并且key是’a’的字符串创建了Symbol类型(创建了就会在全局中登记),如果有则不重复创建,直接用已创建的(已登记的)。然而Symbol(‘a’)的创建是不会去检索全局的,是直接创建一个新的Symbol类型。这也是用Symbol('a")创建的两个Symbol类型不相等的根本原因。
Symbol.keyFor()方法返回一个已登记的Symbol类型值的key.
// Symbol.for(),Symbol.keyFor()使用
let s1 = Symbol.for('a')
let s2 = Symbol.for('a')
let s3 = Symbol('a')
console.log(s1 === s2)//true
console.log(s1 === s3)//false
// let test = {
// a:'aaa',
// b:'aaa',
// c:'ccc',
// }
let test = {
a:Symbol('aaa'),//确保 属性值都唯一
b:Symbol('aaa'),
c:Symbol('ccc'),
}
function get(type) {
if (type === test.a){
console.log(111)
}
if (type === test.b){
console.log(222)
}
}
//通过属性名即可判断变量,无需担心属性值重复情况
get('aaa')//空 已经不通过值判断了
get(test.a)//111
get(test.b)//222