Symbol
概念
ES5的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是ES6引入Symbol的原因。
1 | eg:var a = { name: 'lucy'}; |
Undefined、Null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。
Symbol值通过Symbol函数生成,不能用new命令,基本上,它是一种类似于字符串的数据类型。
1 | let s = Symbol(); |
Symbol可以接收字符串 为参数 Symbol值可以显示转为字符串 下面提到
1 | var s1 = Symbol('foo'); |
Symbol 接收参数是一个对象的话 就会调用该对象的toString方法,将其转为字符串,然后才生成一个 Symbol 值。
1 | const obj = { |
Symbol函数是为了独一无二,相同参数的Symbol函数的返回值是不相等的
1 | // 没有参数的情况 |
++++++s1和s2是两个Symbol值。如果不加参数,它们在控制台的输出都是Symbol(),不利于区分。有了参数以后,就等于为它们加上了描述,输出的时候就能够分清,到底是哪一个值。
Symbol值不能与其他类型的值进行运算,会报错。
1 | var sym = Symbol('My Symbol'); |
Symbol值可以显式转为字符串,也可以转为布尔值
1 | var sym = Symbol('My Symbol'); |
作为属性名的Symbol
由于每一个Symbol值都是不相等的,这意味着Symbol值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。
下面代码通过方括号结构和Object.defineProperty,将对象的属性名指定为一个Symbol值。
mySymbol
1 |
|
还有一种是点运算符 赋值 先看下
1 | var mySymbol = Symbol(); |
1 | var mySymbol = Symbol(); |
因为点运算符后面总是字符串,所以不会读取mySymbol作为标识名所指代的那个值,导致a的属性名实际上是一个字符串,而不是一个Symbol值。
*****在对象的内部,使用Symbol值定义属性时,Symbol值必须放在方括号之中。 [Symbol(‘你想要的’)]:‘你想要的’ 取值一直没找到问题所在
1 | let s = Symbol(); |
属性名的遍历
Symbol 作为属性名,该属性不会出现在for…in、for…of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。但是,它也不是私有属性,有一个Object.getOwnPropertySymbols方法,可以获取指定对象的所有 Symbol 属性名。
Object.getOwnPropertySymbols方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。
1 | var obj = {}; |
另一个例子,Object.getOwnPropertySymbols方法与for…in循环、Object.getOwnPropertyNames方法进行对比的例子。
1 | var obj = {}; |
使用Object.getOwnPropertyNames方法得不到Symbol属性名,需要使用Object.getOwnPropertySymbols方法。另一个新的API,Reflect.ownKeys方法可以返回所有类型的键名,包括常规键名和 Symbol 键名
1 | let obj = { |
Symbol.for(),Symbol.keyFor()
Symbol.for() 首先在全局中搜索有没有以该参数作为名称的Symbol值,如果有,就返回这个Symbol值,否则就新建并返回一个以该字符串为名称的Symbol值。和直接的Symbol就点不同了。
Symbol.for()与Symbol()这两种写法,都会生成新的Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。Symbol.for()不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key是否已经存在,如果不存在才会新建一个值。比如,如果你调用Symbol.for(“cat”)30次,每次都会返回同一个 Symbol 值,但是调用Symbol(“cat”)30次,会返回30个不同的Symbol值。
1 | var s1 = Symbol.for('foo'); |
Symbol.keyFor方法返回一个已登记的Symbol类型值的key。实质就是检测该Symbol是否已创建
1 | var s1 = Symbol.for("foo"); |
内置Symbol
除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法
1、Symbol.haslnstance
一个在执行instanceof时调用的内部方法,用于检测对象的继承信息
2、Symbol.isConcatSpreadable
一个布尔值,用于表示当传递一个集合作为Array.prototype.concat()方法的参数时,是否应该将集合内的元素规整到同一层级
3、Symbol.iterator
一个返回迭代器的方法
4、Symbol.match
一个在调用String.prototype.match()方法时调用的方法,用于比较字符串
5、Symbol.replace
一个在调用String.prototype.replace()方法时调用的方法,用于替换字符串的子串
6、Symbol.search
一个在调用String.prototype.search()方法时调用的方法,用于在字符串中定位子串
7、Symbol.species
用于创建派生类的构造函数
8、Symbol.split
一个在调用String.prototype.split()方法时调用的方法,用于分割字符串
9、Symbol.toprimitive
一个返回对象原始值的方法
10、Symbol.ToStringTag
一个在调用Object.prototype.toString()方法时使用的字符串,用于创建对象描述
11、Symbol.unscopables
一个定义了一些不可被with语句引用的对象属性名称的对象集合