ES6数据类型Symbol
概述
在ES5 中,对象的属性名都是字符串,这就可能导致属性名的冲突。为了保证每个属性名字都是独一无二的,在ES6中引入了Symbol,它表示独一无二的值。
Symbol 值通过Symbol函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
注意:Symbol函数前不能使用new命令,否则会报错。因为生成的Symbol是一个原始类型的值,并不是对象。Symbol函数可以接受一个字符串作为参数,表示对Symbol实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。如果 Symbol 的参数是一个对象,就会调用该对象的toString
方法,将其转为字符串,然后才生成一个 Symbol 值。
注意:Symbol
函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol
函数的返回值是不相等的。
const obj = {
toString() {
return 'abc';
}
};
const sym = Symbol(obj);
sym // Symbol(abc)
// 没有参数的情况
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 // false
// 有参数的情况
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false
Symbol值不能与其他类型的值进行运算,会报错!Symbol值可以显式转换为字符转,利用toString()可以显式转换为字符串,也可以转为布尔值,但是不能转为数值。
Symbol.prototype.description
在创建Symbol的时候,可以添加一个描述,但是读取描述时,需要先将Symbol显式地转换为字符串,非常不方便。在ES9中,提供了一个实例属性description,能够直接返回Symbol的描述。
const sym = Symbol(‘foo’);
sym.description // "foo"
作为属性名的Symbol
因为每一个Symbol值都是不相等的,则Symbol值可以作为标识符,用于对象的属性名。但是注意,Symbol值作为对象属性名时,不能用点运算符。因为点运算符后面总是字符串,所以不会读取所指代的Symbol值。所以,定义和使用时,都要用在方括号之内,且该属性依然是公开属性。
定义时:
let mySymbol = Symbol();
// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';
// 第二种写法
let a = {
[mySymbol]: 'Hello!'
};
// 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });
// 以上写法都得到同样结果
a[mySymbol] // "Hello!"
所以我们可以用Symbol类型来定义常量,就能保证常量的值互不相等。
属性名的遍历
Symbol 作为属性名,该属性不会出现在for...in
、for...of
循环中,也不会被Object.keys()
、Object.getOwnPropertyNames()
、JSON.stringify()
返回。
但是,它也不是私有属性,有一个Object.getOwnPropertySymbols
方法,可以获取指定对象的所有 Symbol 属性名。 Object.getOwnPropertySymbols
方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。
**Reflect.ownKeys
方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。**
let obj = {
[Symbol('my_key')]: 1,
enum: 2,
nonEnum: 3
};
Reflect.ownKeys(obj)
// ["enum", "nonEnum", Symbol(my_key)]
由于以 Symbol 值作为名称的属性,不会被常规方法遍历得到。我们可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法。
Symbol.for(), Symbol.keyFor()
Symbol.for
接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建并返回一个以该字符串为名称的 Symbol 值。
Symbol.for()
与Symbol()
这两种写法,都会生成新的 Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。Symbol.for()
不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key
是否已经存在,如果不存在才会新建一个值。比如,如果你调用Symbol.for("cat")
30 次,每次都会返回同一个 Symbol 值,但是调用Symbol("cat")
30 次,会返回 30 个不同的 Symbol 值。
Symbol.keyFor
方法返回一个已登记的 Symbol 类型值的key
。需要注意的是,Symbol.for
为 Symbol 值登记的名字,是全局环境的,可以在不同的 iframe 或 service worker 中取到同一个值。
内置的Symbol值
ES6提供了11个内置的Symbol值,指向语言内部的使用方法。具体信息请参考官方文档
本文只做个人学习总结,如有错误,欢迎指出。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。