Symbol的简单理解
Symbol
1.Symbol 的意义
之前我们的对象属性的数据类型都是字符串,没有其他的了。所以会导致属性名重复,导致属性值被覆盖的情况。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法,在添加的操作就很容易覆盖了原有的方法。所以需要一个独一无二的数据类型来完成这个使命。所以Symbol
出来主持大局了。
2.Symbol的介绍
-
唯一性
Symbol
这个英文单词表示“唯一",它是Javascript的第七种数据类型(Number
,String
,Boolean
,null
,undefined
,Object
),表示它是唯一的。
创建一个Symbol
类型不需要用new
操作符,否则会报错,因为生成的Symbol
是一个原始类型的值,不是对象。直接let s = Symbol();
测试s
就是Symbol
类型了。怎么说他是唯一的呢?let s = Symbol(); let ss = Symbol(); console.log(s == ss); //false //或者 let s = Symbol('a'); let ss = Symbol('a'); console.log(s == ss);//结果是false
通过以上的比较,我们对
Symbol
的唯一性,有了一定的了解。也就是说当你创建了一个Symbol
数据后,那么就是独一无二的存在了。 -
数据类型的修饰
有人会好奇Symbol('a')
里面的参数a
又是怎么回事呢?字符串a
表示一种修饰,对你当前创建的Symbol
类型的一种修饰,作为区分使用,否则当你创建多个Symbol
数据时,容易混淆。let s = Symbol('a'); let ss = Symbol('a'); console.log(s == ss);//false
-
与其他数据类型之间的转换
Symbol
不能用四则运算进行操作,否则报错。它只能用显式的方式转为字符串和布尔值,即:String(Symbol()) / Boolean(Symbol())
-
作为对象的属性
- 作为对象的属性时,注意要用以下三种方式来书写:
// 1. 作为对象的属性 let hobby = Symbol("hobby"); let level = Symbol("level"); let sex = Symbol("sex"); let person = { name: "小米", age: 21, [hobby]: "游泳" //1.1 } person[level] = "A" // 1.2 // 1.3 Object.defineProperty(person,sex,{ value: "男" }) console.log(person.level); //undefined console.log(person[hobby]); //游泳
- 对象属性的创建
以上说了对象属性的创建,但是我们要格外的注意,
Symbol
作为属性名,该属性不会出现在for...in
、for...of
循环中,也不会被Object.keys()
、object.getOwnPropertyNames()
、JSON.stringify()
返回。所以我们可以用Object.getOwnPropertySymbols
方法,获取指定对象的所有Symbol
属性名。
看到这是不是感觉用Symbol
类型创建的对象属性这么麻烦吗?如果一个对象里面有字符串的属性又有Symbol
的属性,难不成要分来获取对象属性吗?答案是不用,那必须使用新的API方法:Reflect.ownKeys()
,这个方法就可以返回对象所有的属性,也就是字符串属性和Symbol
属性。所以这里要留意了。// 2.遍历迭代不出 以symbol命名的属性 console.log(Object.keys(person)); //(2) ["name", "age"] console.log(Object.getOwnPropertySymbols(person));//(3) [Symbol(hobby), Symbol(level), Symbol(sex)] console.log(Object.getOwnPropertyNames(person));// ["name", "age"] // 解决: console.log(Reflect.ownKeys(person));// (5) ["name", "age", Symbol(hobby), Symbol(level), Symbol(sex)]
-
Symbol.for()
和Symbol.keyFor()
有时,我们希望重新使用同一个
Symbol
值,以上我们都说了Symbol
数据类型是唯一的,所有只用Symbo()
方法创建的Symbol
类型是无法实现的。所有我们可以用Symbol.for()
这个方法来实现。let s1 = Symbol.for("foo"); let s2 = Symbol.for("foo"); console.log(s1 === s2); //true // 使用Symbol.for会在全局查找有没有和自己一样的存在,如果没有,就创建并在全局登记,如果在全局登记中有,则直接用已经登记创建过的。所以s1 === s2
注意,这里的
Symbol.for()
和Symbol()
创建的都是Symbol
类型,但是他们的创建机制有所不同,Symbol.for(a')
的创建方式会在创建之前在全局中寻找,有没有用Symbol.for()
的方式,并且key
是'a'
的字符串创建了Symbol
类型(创建了就会在全局中登记),如果有则不重复创建,直接用已创建的(已登记的)。然而Symbol("a')
的创建是不会去检索全局的,是直接创建一个新的Symbol
类型。这也是用Symbol(a')
创建的两个Symbol
类型不相等的根本原因。
Symbol.keyFor()
方法返回一个已登记的Symbol
类型值的key
。let s1 = Symbol.for("foo"); let s2 = Symbol.for("foo"); let s3 = Symbol("foo"); console.log(Symbol.keyFor(s1));// foo console.log(Symbol.keyFor(s2));// foo console.log(Symbol.keyFor(s3));// undefined // Symbol.keyFor返回一个已经登记的 Symbol类型的 key