ES5的对象属性名都是字符串,这容易造成属性名的冲突。ES6引入一种新的原始数据类型Symbol,表示独一无二的值。它是Javascript的第七种数据类型。其他六种为Undefined、Null、String、Boolean、Number、Object。
对象的属性名现在可以有两种类型:
一是原来就有的字符串类型,二新增的Symbol类型。只要属性名属于Symbol类型,就是独一无二的。
let s=Symbol();
typeof s;//"symbol"
Symbol函数的参数只表示对当前Symbol值的描述,因此相同参数的Symbol函数的返回值是不相等的。
//没有参数的情况
var s1=Symbol();
var s2=Symbol();
s1===s2//false
var s3=Symbol('foo');
var s4=Symbol('foo');
s3===s4//false
//Symbol不能与其他类型的值进行运算,否则会报错。Symbol可以显式转为字符串,也可以转为布尔值,但是不能转为数值
var sym=Symbol('symbol');
sym.toString();//'Symbol('symbol')'
Boolean(sym);//true
Number(sym);//TypeError
由于每一个Symbol值都是不相等的,这就意味着Symbol值可以作为标识符用于对象的属性保证不会出现同名属性。
将对象的属性指定为一个Symbol值
var symbol=Symbol();
//第一种方法
var a={};
a[symbol]='happy';
//第二种方法
var a={
[symbol]:'happy';
}
//第三种方法
var a={};
Object.definedProperty(a,symbol,{value:'happy'});
a[symbol]//'happy'
注意:Symbol值作为对象属性名时不能使用点运算符。
在对象内部,使用Symbol值定义属性时,Symbol值必须放在方括号中。
var s=Symbol();
var obj={
[s]:function(arg){...}
}
obj[s](123);
//也可以简写为
var obj={
[s](arg){...}
}
Symbol类型还可用于定义一组常量,保证这组常量的值都是不相等的
log.levels={
DEBUG:Symbol('debug'),
INFO:Symbol('info'),
WARN:Symbol('warn')
};
log(log.levels.DEBUG,'debug message');
log(log.levels.INFO,'info message');
Object.getOwnPropertySymbols方法可以获取指定对象的所有Symbol属性名。返回一个数组,成员是当前对象的所有用作属性名的Symbol值。
var obj={};
var a=Symbol('a');
var b=Symbol('b');
obj[a]='happy';
obj[b]='day';
var s=Object.getOwnPropertySymbols(obj);
s//[Symbol(a),Symbol(b)]
如果希望使用同一个Symbol值,Symbol.for方法可以做到这一点。它接收一个字符串作为参数,然后搜索有没有以该参数作为名称的Symbol值。如果有,就返回这个Symbol值,否则就新建并返回一个以该字符串为名称的Symbol值。
var s1=Symbol.for('foo');
var s2=Symbol.for('foo');
s1===s2//true
Symbol()写法没有登记机制,所以每次调用都会返回一个不同的值,Symbol.keyFor()方法返回一个已登记的Symbol类型值的key。
var s=Symbol.for("foo");
Symbol.keyFor(s1);//"foo"
var ss=Symbol("foo");
Symbol.keyFor(ss);//undefined
注意
Symbol不能new
Symbol()返回是一个唯一值
Symbol是一个单独数据类型,就叫基本类型
如果Symbol作为key,用for…in循环不出来
内置的Symbol的值
1.Symbol.hasInstance
对象使用instanceof运算符时会调用这个方法,判断对象是否为某个构造函数的实例,比如 foo instanceof Foo,在语言内部实际调用的是FooSymbol.hasInstance
class A{
[Symbol.hasInstance](foo){
return foo instanceof Array;
}
}
[1,2,3] instanceof new A();//true
2.Symbol.isConcatSpreadable
对象的Symbol.isConcatSpreadable属性是一个布尔值,表示该对象使用Array.prototype.concat()时是否可以展开。
var arr1=['b','c'];
['a'].concat(arr1,'d');//['a','b','c','d']
arr1[Symbol.isConcatSpreadable]//undefined
var arr2=['b','c'];
arr1[Symbol.isConcatSpreadable]=false;
['a'].concat(arr2,'d');//['a',['b','c'],'d']
3.Symbol.species
对象的Symbol.species属性指向当前的对象的构造函数。常在实例时默认会调用这个方法,即使用这个属性返回的函数当做构造函数来创造新的实例对象。
class A extends Array{
static get[Symbol.species](){return Array;}
}
var a=new A(1,2,3);
var b=a.map(x=>x*x);
b instanceof A;//false
b instanceof Array;//true
4.Symbol.match
对象的Symbol.match属性指向一个函数,当执行str.match(obj)时,如果该属性存在,会调用它返回该方法的返回值。
class A{
[Symbol.match](String){
return 'happy'.indexOf(string);
}
}
'a'.match(new A());//1
5.Symbol.replace
对象的Symbol.replace属性指向一个方法,当对象被String.prototype.replace方法调用时会返回该方法的返回值。
var obj={};
obj[Symbol.replace]=(...s)=>console.log(s);
'hello'.replace(obj,'world');//['hello','world']
6.Symbol.search
对象的Symbol.search属性指向一个方法,当对象被String.prototype.search方法调用时会返回该方法的返回值。
class A{
constructor(value){
this.value=value;
}
[Symbol.search](string){
return string.indexOf(this.value);
}
}
'happy'.search(new A('ha'));//0
7.Symbol.split
对象的Symbol.split属性指向一个方法,当对象被String.prototype.split方法调用时会返回该方法的返回值。
class A{
constructor(value){
this.value=value;
}
[Symbol.split](string){
var index=string.indexOf(this.value);
if(index===-1){return string;}
return [
string.substr(0,index);
string.substr(index+this.value.length)
];
}
}
'happy'.split(new A('pa'));//['h','py']
8.Symbol.iterator
对象的Symbol.iterator属性指向该对象的默认值遍历器方法。
var obj={};
obj[Symbol.iterator]=function* (){
yield 1;
yield 2;
yield 3;
};
console.log([...obj]);//[1,2,3]
9.Symbol.toPrimitive
对象的Symbol.toPrimitive属性指向一个方法,当对象被转为原始类型的值时会调用这个方法,返回对象对应的原始类型值。
var obj={
[Symbol.toPrimitive](hint){
switch(hint){
case:'number':
return 123;
case:'string':
return 'str';
case:'defalut':
return 'defalut';
default:
throw new Error();
}
}
};
2*obj//234
3+obj//'3+default'
obj==='default'//true
String(obj)//'str'
10.Symbol.toStringTag
对象的Symbol.toStringTag属性指向一个方法,在对象上调用Object.prototype.toString方法时,如果这个属性存在,其返回值出现在toString方法返回的字符串中,表示对象的类型。也就是说,这个属性可用于制定[object Object]或[object Array]中object后面的字符串。
({[Symbol.toStringTag]:'Foo'}.toString())
//[object Foo]
11.Symbol.unscopables
对象的Symbol.unscopables属性指向一个对象,指定了使用with关键字时哪些属性会被with环境排除。
Array.prototype[Symbol.unscopables]
//{
// copyWithin:true,
//entries:true,
//fill:true,
//find:true,
//findindex:true,
//includes:true,
//keys:true
//}
Object.keys(Array.prototype[Symbol.unscopables])
//['copyWithin','entries','fill','find','findIndex','includes','keys']
//没有unscopables时
class A{
foo(){return 1;}
}
var foo=function(){return 2;}
with(A.prototype){
foo();//1
}
//有unscopables时
class A{
foo(){return 1;}
get [Symbol.unscopables](){
return {foo:true};
}
}
var foo=function(){return 2;}
with(A.prototype){
foo();//2
}
注:内容参考ES6标准入门第三版阮一峰著