概述
ES5的对象名都是字符串,这很容易造成命名冲突。
ES6引入了一种原始的数据类型Symbol,表示独一无二的值。它是JavaScript语言的第7中数据类型。
Symbol值通过Symbol函数生成。也就是说属性名可以有两种类型:一种是原有的字符串,另一种就是新增的Symbol类型。
let s = Symbol();
typeof s //”symbol”
注:Symbol函数前不能使用new命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不是对象。
Symbol函数可以接受一个字符串作为参数,表示对Symbol实例的描述。
var s1 = Symbol(‘foo’);
var s2 = Symbol(‘bar’);
s1 // Symbol(foo)
S2 // Symbol(bar)
s1.toString() //”Symbol(foo)”
s2.toString() //”Symbol(bar)”
注:Symbol函数的参数只表示对当前Symbol值的描述,因此相同参数的Symbol函数的返回值是不相等的。
var s1 = Symbol();
var s2 = Symbol();
s1 === s2 //false
var s1 = Symbol(‘foo’);
var s2 = Symbol(‘foo’);
s1 === s2 //false
Symbol还具有以下几点特性:
Symbol值不能与其他类型的值进行运算,否则会报错。
Symbol值可以显示转化为字符串。
Symbol值也可以转为布尔值,但是不能转为数值。
作为属性名的Symbol
由于每一个Symbol值都不相等,这意味着Symbol值可以作为标识符用于对象的属性名,保证不会出现同名的属性。
var mysymbol = Symbol();
//第一种写法
var a = {};
a[mysymbol ] = ‘hello’;
//第二种写法
var a = {
[mysymbol ] = ‘hello’;
};
//第三种写法
var a = {};
Object.defineProperty(a, mysymbol , { value: ‘hello’});
注:Symbol值作为对象名时不能使用点运算符。
Symbol类型还可以用于一组常量,保证这组常量的值都不相等。
log.levels = {
DEBUG:Symbol(‘debug’),
INFO:Symbol(‘info’)
}
常量使用Symbol值的最大好处就是,其他任何值都不可能有相同的值。
注:Symbol值作为属性名时,该属性还是公开属性,不是私有属性。
属性名的遍历
Symbol作为属性名,该属性不会出现在for ... in、for ... of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()返回。但是它也不是一个私有属性,有一个Object.getOwnPropertySymbols方法可以获取指定对象的所有Symbol属性名。
Object.getOwnPropertySymbols方法返回一个数组,成员是该对象的所有用作属性名的Symbol值。
var obj = {
‘c’ : ‘c’
};
var a = Symbol(‘a’);
var b = Symbol(‘b’);
obj[a] = ‘hello’;
obj[b] = ‘word;
Object.getOwnPropertySymbols(obj); // [Symbol(a), Symbol(b)]
另外一个新的API--Reflect.ownKeys方法也可以返回所有的类型的键名,包括常规的键名和Symbol键名。
Reflect.ownKeys(obj); // [ ‘c’ , Symbol(a), Symbol(b)]
Symbol.for()、Symbol.keyFor()
有时我们希望重新使用同一个Symbol值,Symbol.for可以做到这一点。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的Symbol值。如果有,就返回这个Symbol值,否则就新建并返回一个以该字符串为名称的Symbol值。
var s1 = Symbol.for(‘foo’);
var s2 = Symbol.for(‘foo’);
s1 === s2 //true
Symbol,for()与Symbol()这两种方法都会生成新的Symbol。他们的区别是,前者会被登记在全局环境中搜索,后者不会。
Symbol.for()不会再每次调用时都返回一个新的Symbol类型的值,而是会先检查给定的key是否已经存在,如果不存在才会新建一个值。
Symbol.for(“bar”) === Symbol.for(“bar”) //true
Symbol(“bar”) === Symbol(“bar”) //false
注:Symbol.for为Symbol值登记的名字是全局环境的,可以在不同的iframe或service worker中取到同一值。
内置的Symbol值
除了定义自己使用的Symbol值,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法。
在这里我把他们都罗列出来,就不一一的具体详细解释说明了,有兴趣的朋友可以去查阅一下详细使用说明。
Symbol.hasInstanse
指向一个内部方法,对象使用instanceof运算符时会调用这个方法,判断该对象是否为某个构造函数的实例。
Symbol.isConcatSpreadable
等于一个布尔值,表示该对象使用Array.prototype.concat()时是否可以展开。
Symbol.species
指向当前对象的构造函数。
Symbol.match
指向一个函数,当执行str.match(myObject)时,如果该属性存在,会调用它返回该方法的返回值。
Symbol.replace
指向一个方法,当对象被String.prototype.replace方法调用时会返回该方法的返回值。
Symbol.search
指向一个方法,当对象被String.prototype.search方法调用时会返回该方法的返回值。
Symbol.split
指向一个方法,当对象被String.prototype.split方法调用时会返回该方法的返回值。
Symbol.iterator
指向该对象的默认遍历器方法。
Symbol.toPrimitive
指向一个方法,对象被转为原始类型的值时会调用这个方法,返回该对象对应的原始类型值。
Symbol.toStringTag
指向一个方法,在对象上调用Object.prototype.toString方法时,如果这个属性存在,其返回值会出现在toString方法返回的字符串中,表示对象的类型。
Symbol.unscopables
指向一个对象,指定了使用with关键字时哪些属性会被with环境排除。