ES6 Symbol
ES5的语法中,属性名都是以字符串的形式呈现的,对于简单的对象来说,少量的属性并不会造成属性名重复的现象,但是当你想引用别人的模块到自己的项目中并且想对模块中的对象添加新的属性或者方法时,字符串形式的属性名就很容易出现重名或者冲突,在修改起来会变得很麻烦。
ES6语法中引入了一种新的数据类型Symbol,它是一种原始数据类型,且定义的每一个Symbol数据都代表独一无二的值,也是Javascript的第七种数据类型,前六种为 undefined,null,String(字符串),Number(数值),Object(对象),Boolean(布尔值)。
创建一个基本的Symbol类型的值
let sym = Symbol();
typeof sym;
//Symbol
创建Symbol值的时候不能使用new运算符,因为Symbol是原始数据类型而不是对象,所以不能给Symbol添加属性名。同样因为每一个Symbol都代表着独一无二的值且Symbol函数里面的参数仅表示对当前Symbol值的描述,所以当创建两个具有相同值参数的Symbol函数时,尽管参数一样,但是返回值不同
let first = Symbol("a");
let second = Symbol("a");
second === first;
//false;
Symbol值不能与其他的字符串进行运算,Symbol值可以转换为布尔值和字符串,但是不能转换为数值
let sym = Symbol();
console.log("hello"+sym);
//报错:TypeError: Cannot convert a Symbol value to a string
Bollean(sym) //true
!sym //false
Number(sym) //报错: Cannot convert a Symbol value to a number
Symbol当做属性名使用
symbol值也可以当作对象的属性名来使用,因为每一个symbol值都是独一无二的,所以symbol值作为属性名也是独一无二的,避免的因为属性名冲突造成的修改问题
实例
let sym = Symbol();
let a = {};
a[sym] = "hello";
//第一种
a{
[sym]:"hello"
}
//第二种
Object.defineProperty(a,sym,{value:"hello"})
//第三种
console.log(a[sym]);
//hello
在用Symbol值作为属性名的时候,要用方括号括起来,否则就会当作普通的字符串处理,读取该属性名的值的时候,不能使用点运算符,因为点运算符后面跟的为字符串常量,必须要用方括号括起来才能读取到正确的值
Symbole还可以作为常量使用,最大的好处是其他任何的值都不会再有相同的值了,可以保证一些逻辑顺序按照正常执行而不用担心判断中的值出现冲突或者重名而导致错误
const RED = Symbol();
const GREEN = Symbol();
let sym = (color)=>{
switch(color){
case RED:
console.log("red");
break;
case GREEN:
console.log("green");
break;
default:
console.log("NOT FOND");
}
}
sym(RED);
//red
实例:利用Symbol消除魔术字符串
function first(name){
switch(name){
case "小明":
console.log("first");
case "小红":
console.log("second");
case "小张":
console.log("third");
}
}
first("小明");
//first
函数在定义和附加参数的时候,要定义两处变量的值,分别是函数的参数和case后面的判断值,在修改的时候如果参数相对多或者判断内容相对复杂,无疑增加了修改难度。
let name_ = {
xiaoming:Symbol(),
xiaohong:Symbol(),
xiaozhang:Symbol()
}
function first(name){
switch(name){
case name_.xiaoming:
console.log("first");
case name_.xiaohong:
console.log("second");
case name_.xiaozhang:
console.log("third");
}
}
first(name_.xiaoming);
利用Symbol值来优化之前函数中的一些代码耦合,同时Symbol值也可以确定为唯一的值,之后的定义就不用再担心与前面的值相冲突了。
Symbol.for()和Symbol.keyFor()
在使用Symbol的时候,因为Symbol类型的值是独一无二的,所以每次定义的Symbol值都是不同的,那么如果我们在有些操作中需要定义的值想要使用相同的Symbol值该怎么办呢?
Symbol.for()方法可以做到这一点
let s1 = Symbol.for("foo");
let s2 = Symbol.for("foo");
console.log(s1 === s2) //true
实例定义了s1,s2两个Symbol值,如果通过Symbol()函数定义的话,尽管参数相同,但是返回值并不相同,Symbol.for()方法可以解决这个问题,该方法首先会从全局中搜索受否存在带有参数的Symbol值,如果有,则不会创建新的Symbol值,如果没有,则会创建一个带有该参数的Symbol值。
Symbol.keyFor()方法可以返回一个登记过的Symbol类型值的key值
let s1 = Symbol.for("foo");
let s2 = Symbol("foo");
Symbol.keyFor(s1); //foo
Symbol.keyFor(s2); //undefined
因为Symbol()函数不存在登记机制,所以导致每次创建的Symbol值都是不同的,Symbol.for首先会登记在全局变量中进行搜索,同时通过Symbol.for()方法创建的Symbol值也可以在方法或者函数中使用,因为该Symbol()值是登记在全局范围内的。这就导致Symbol.keyFor(s1)返回的是s1的key值,而Symbol.keyFor(s2)返回的是undefined