胖蔡叨叨叨
你听我说

js的数据类型之Symbol

一、出现原因

ES5 的对象属性名都是字符串,这容易造成属性名的冲突。为了解决这一问题,在ES6中便新增了一种新的原始数据类型Symbol,它表示独一无二的值。前面我们说过JavaScript的六种数据类型分别是:

undefined, null, Boolean, String, Number, Object

加上现在说的Symbol,现在有七种了。Symbol实际上是一种唯一的标识符,可以作为对象的唯一属性名,这样就不会被覆盖了。

Symbol 值通过Symbol函数生成,于是对象的属性名便有两种类型,一种是原来的字符串,另外就是现在说的Symbol类型。

let a = Symbol()typeof a // symbolconsole.log(a) // Symbol()let b = Symbol('b')typeof b // "symbol"console.log(b) // Symbol(b)

注意:Symbol函数前不能使用new命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。也就是说,由于 Symbol 值不是对象,所以不能添加属性。实际上它是一种类似于字符串的数据类型。

二、特性

1、相同参数的Symbol函数返回的值是不相同的

let a1 = Symbol('a')let a2 = Symbol('a')console.log(a1 == a2,a1,a2) // false Symbol(a) Symbol(a)

这是因为Symbol函数的参数只是对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的。

2、Symbol值不能与其他类型的数据进行运算,但是Symbol值可以显式转为字符串,Symbol值也可以转为布尔值

Symbol() + 1 // Uncaught TypeError: Cannot convert a Symbol value to a number'this is ' + Symbol('a') // Uncaught TypeError: Cannot convert a Symbol value to a string
let str = Symbol('str')console.log(String(str)) // "Symbol(str)"Boolean(str) // true

3、Symbol的值作为对象的属性名,由于Symbol值的唯一性,因此不会覆盖属性名

let attr = Symbol()// 第一种写法let obj = {}obj[attr] = 'Hello!'console.log(obj,obj[attr]) // {Symbol(): "Hello!"}// 第二种写法let obj = { [attr] : 'hello!' }console.log(obj,obj[attr]) // {Symbol(): "Hello!"}// 第三种写法let obj = {}Object.defineProperty(obj, attr, {value: 'hello!'})console.log(obj,obj[attr]) // {Symbol(): "Hello!"}

4、Symbol值作为对象属性名时,不能用点运算符

let attr = Symbol()const obj = {}obj.attr = 'hello!'console.log(obj[attr], obj['attr']) // undefined "hello!"

因为点运算符后面总是字符串,所以不会读取attr作为标识名所指代的那个值,导致obj 的属性名实际上是一个字符串,而不是一个 Symbol 值。所以在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中。

let attr = Symbol()let obj = {  [attr]: function(param){    console.log(param)  }}obj[attr](1234)

5、Symbol类型还可以用于定义一组常量,保证这组常量的值都是不相等的

let greet = {}greet.levels = {  DEBUG: Symbol('debug'),  INFO: Symbol('info'),  WARN: Symbol('warn')  }console.log(greet.levels.DEBUG, 'debug message'); // Symbol(debug) "debug message"console.log(greet.levels.INFO, 'info message'); // Symbol(info) "info message"

注意Symbol 值作为属性名时,该属性还是公开属性,不是私有属性。

三、Symbol 作为属性名的遍历

1、Object.getOwnPropertySymbols() 遍历属性名

当symbol作为属性名时,遍历属性名时,不能从for...infor...of循环中取出,也不会被Object.keys()Object.getOwnPropertyNames()JSON.stringify()返回。

此时需要用Object.getOwnPropertySymbols()方法获取指定对象的所有 Symbol 属性名,该方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。

const attr1 = Symbol('attr1')const attr2 = Symbol('attr2')let obj = {  [attr1]:'hello1',  [attr2]:'hello2',}const res = Object.getOwnPropertySymbols(obj)console.log(res) // [Symbol(attr1), Symbol(attr2)]

2、Reflect.ownKeys() 返回属性名 

Reflect.ownKeys()方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。

let obj = {  a:1,  b:[1,2],  [Symbol('c')]:'str'}Reflect.ownKeys(obj) // ["a", "b", Symbol(c)]

四、Symbol 相关函数使用

1、Symbol.for(),Sysmbol.keyFor()

当我们需要使用相同的Sysmbol值时,Symbol.for()就可以生成相同的值。它需要传一个字符串参数,然后他会先搜索是否存在以该参数作为名称的Symbol的值,如果有则返回这个Symbol的值,否则创建该字符串为名称的Symbol值并将其注册到全局。

let obj1 = Symbol.for('a')let obj2 = Symbol.for('a')console.log(obj1 === obj2) // true

Symbol.for()Symbol()

它们都会生成新的Symbol值,区别是Symbol.for()被登记在全局环境中供搜索而Symbol()则不会。

console.log(Symbol.for('a') === Symbol.for('a')) // trueconsole.log(Symbol('a') == Symbol('a')) // false

Symbol.keyFor()方法返回一个已登记的 Symbol 类型值的key

let obj1 = Symbol.for('a')console.log(Symbol.keyFor(obj1)) // alet obj2 = Symbol('a')console.log(Symbol.keyFor(obj2)) // undefined

Symbol.for()为Symbol值登记的名字,是全局环境的,不管有没有在全局环境运行。

赞(0) 打赏
转载请附上原文出处链接:胖蔡叨叨叨 » js的数据类型之Symbol
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

'); })();