JavaScript有了第七种数据类型:Symbol,创建一个独一无二的值;它用于对象的属性,设计初衷是为了避免对象属性冲突的问题。要获取对象symbol类型的属性,要用Object.getOwnPropertySymbols( );还提供了Symbol.for( )和Symbol.keyFor( )方法用于搜索对应的symbol值
- 在介绍Symbol之前,我们简单介绍一下JavaScript的数据类型:
- JavaScript有6中数据类型,分别是:
1
2
3
4
5
6String 字符串类型
Number 数字类型
Object 对象类型
Boolean 布尔值类型
Null 空值
Undefined 未定义而ES6给我们带来一种全新的数据类型:Symbol。
Symbol的初衷:解决对象的属性名冲突
- 为了根本上解决命名问题,我们需要给属性或者方法起一个独一无二的名称,这样,才能从根本上防止属性名冲突的问题
1 | //定义一个symbol类型的变量 |
- 从上面代码案例看到,我们用一个Symbol( )函数来创建一个symbol类型的变量,我们打印了一下变量sm,得到的结果是控制台输出:Symbol( ),它代表着一个独一无二的值,虽然我们看不到它长什么样子,但基本上,它有点类似字符串
- 接着,我们用typeof来检测一下变量sm的类型,得到的结果是:symbol。
怎样判断symbol它是独一无二的值呢?
1
2
3
4
5
6
7let sm1 = Symbol();
let sm2 = Symbol();
console.log(sm1 === sm2) //结果:false
console.log(sm1);//结果:Symbol()
console.log(sm2);//结果:Symbol() - 我们定义两个symbol类型的变量sm1,sm2,然后用全等符号 === 进行比较,得到的是false。也就是他们都是独一无二的值,并不相等。
- 接着,我们分别打印两个变量,控制台输出的都是Symbol( ),看起来长得一模一样,实际是不相等的
两个不一样的值,控制台输出的一样,这样无疑给我们开发调试带来一定的不便,有没有办法让他们看起来不一样呢?
Symbo( )函数接受参数,用于对实例值的描述 区分 Symbol
1 | let sm1 = Symbol('sm1'); |
- 用字符串sm1和sm2作为参数,结果打印出来的变量sm1和sm2就是Symbol(sm1)和Symbol(sm2),等于加上了描述,很容易区分出来
- 需要注意的是,即使参数一样,描述一样,得到的两个值也是不相等的,不信我们来看看:
1
2
3let sm1 = Symbol('sm');
let sm2 = Symbol('sm');
sm1 === sm2 //结果:false - 即使两个变量的描述都是“sm”,但是终究对应的值还是不一样的,symbol永远都是独一无二的值
那在实际使用中我们怎么取到Symbol这个值呢 比如恢复和还原 Symbol.for()
Symbol.for()
- 首先在全局中搜索有没有以该参数作为名称的Symbol值,如果有,就返回这个Symbol值,否则就新建并返回一个以该字符串为名称的Symbol值。和直接的Symbol就点不同了。
1
2
3
4var s1 = Symbol.for('foo');
var s2 = Symbol.for('foo');
s1 === s2 // true使用场景
1
2
3
4
5
6
7
8
9
10let a1 = Symbol('abc')
let obj = {
[a1]:'123',
'abc':'345',
'c':'456'
}
console.log('obj',obj )
//abc: "345"
// c: "456"
// Symbol(abc): "123"属性名的遍历
当symbol类型的值作为属性名的时候,该属性是不会出现在for…in和for…of中的,也不会被Object.keys( )获取到。我们来看案例:
1
2
3
4
5
6
7
8
9
10
11
12
13let a1 = Symbol('abc')
let obj = {
[a1]:'123',
'abc':'345',
'c':'456'
}
// 跟遍历相关联的三个元素 entries 、keys 、values
for(let [key,value] of Object.entries(obj)){
console.log(key,value)
}
// abc 345
// c 456
// 并没有打印出Symbol('abc') - 并没有打印出Symbol(‘abc’)
getOwnPropertySymbols( )函数
- 如果我们硬是想要获取symbol类型的属性怎么办?我们可以用一个方法:Object.getOwnPropertySymbols( ),它会找到symbol类型的属性并且返回一个数组,数组的成员就是symbol类型的属性值
1
2
3
4
5
6
7
8
9
10//定义两个symbol类型的变量name,age
let name = Symbol("name");
let age = Symbol("age");
let person = {
[name]:"张三", //symbol类型
[age]:12 //symbol类型
};
console.log( Object.getOwnPropertySymbols(person)) ;
//结果:[Symbol(name), Symbol(age)] - forEach循环取出symbol类型属性的数据
1
2
3
4
5Object.getOwnPropertySymbols(person).forEach(function(item){
console.log('person[item]',person[item])
})
// 张三
// 12getOwnPropertySymbols()只拿到了Symbol的属性,而let in,let of 拿到了非Symbol的属性,这样的话,获取字符串类型的属性和获取symbol类型的属性要分开两种不同的方式来获取,难免有有时候会很不方便有木有什么办法让我们一次性获取所有类型的属性,不管它是字符串类型还是symbol类型呢?
Reflect.ownKeys( )函数
1
2
3
4
5
6
7
8//定义一个对象,含有两种类型的属性
let person = {
[Symbol('name')]:"张三",
"age": 21
};
console.log(Reflect.ownKeys(person))
//结果:["age",Symbol(name)] - 因为拿到的是数组 所以要想拿到数据需要forEach循环
1
2
3
4
5
6
7
8let person = {
[Symbol('name')]:"张三",
"age": 21
};
Reflect.ownKeys(person).forEach(function(item){
console.log(person[item])
})Symbol( )创建symbol值不会被登记在全局环境中供Symbol.for( )和Symbol.keyFor( )搜索;