Symbol
本来有六种(Number、String、Object、Undefined、Null、Boolean)
一种新的原始数据类型(就是有七种了)
Symbol可以通过其英文含义标志、象征来理解,标志、象征是独一无二的。所以Symbol的第一个特征是,两个Symbol对象之间永远是不等的。Symbol可以认为是一种不会相等的字符串
定义Symbol输出
这里要注意,Symbol和Number、String、Object不一样,他是没有包装类型(Boolean,Number,String包装类型的作用就是可以使用方法,所以他的生命周期就是调用方法(比如说类型转换啥的)的那一瞬间。)的,加new是会报错的
let s1 = Symbol()
let s2 = Symbol('a111')
分别会输出Symbol()和Symbol(a111)(字符串注意要加’’)
如果参数是个对象,就会先把对象进行obj.toString()然后再传进去。
Symbol.for()
使用Symbol.for()定义的与之间定义的不同,使用Symbol.for()定义是全局的**(不管当前环境如何)**,如果再定义一个一样的,就会先找之前有没有一样的,如果有就会直接拿过来用。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 结果是true,因为s2就是把s1的那个直接拿来用了。
Symbol.keyFor()
会把全局登记的Symbol(就是用Symbol.for()定义的)括号中的内容输出出来。
下例中的sk的value是aaa。
let s = Symbol.for('aaa');
let sk = Symbol.keyFor(s);
Symbol的使用场景
1.可以当key,比如两个人名字相同,如果用名字当key后面的就会把前面的覆盖掉,这个时候用Symbol(名字)就没事了。
下面只会输出22的Leon
const name1 = 'Leon';
const name2 = 'Leon';
const Table = {
[name1]:{age:18},
[name2]:{age:22}
}
用Symbol两个就都出来了
const name1 = Symbol('Leon');
const name2 = Symbol('Leon');
const Table = {
[name1]:{age:18},
[name2]:{age:22}
}
2.保护属性
这里再例举遍历对象属性的方法for in、for of Object.keys、for of Object.getOwnPropertySymbols()(和Object.getOwnPropertyNames()相反)。前两种只能遍历普通属性,第三种只能遍历Symbol属性。
for of Reflect.ownKeys()两种都可以遍历。
3.可以消除魔术字符串
魔术字符串就是重复出现的字符串。
什么意思呢?
打个比方两个属性,如果我们并不在意里面的内容,我们之间把内容换成Symbol()就行了。
let a = {
qq:'qwertyu',
ww:'asdfghj'
}
改为
let a = {
qq:Symbol(),
ww:Symbol()
}
Set
一种新的数据结构,里面的数值都是唯一的(哈希表?和哈希表又不一样,Set也有key也有value但是key和value一样,像是一种特殊的数组)。
方法:
添加用**add()方法
删除用delete()**方法
括号中的参数都是内容
**clear()**方法清空
**has()**方法判断有没有该元素
s.size(注意用的是size不是length)
数组能用的遍历Set也能用
Set的应用场景
1.去重
获得的会是一个去重之后的结果。
let arr = [1,2,3,3,4,5];
let s = new Set(arr);
可以这么快去重,那么力扣上刷题不是就特别投机了吗?
其实单单这样肯定是过不了的,因为Set毕竟只是个伪数组。
得将其变成一个真正的数组,可以用之前介绍过的Array.from方法,也可以用[…set]。
2.合并去重
let arr1 = [1,2,3,4]
let arr2 = [2,3,4,5,6]
let s = new Set([...arr1,...arr2])
3.求交集
可以通过Set中的has方法来获得交集。
这里需要再次强调的是,只要返回一个true,那么filter就会将该元素放入新的数组中(在之前的数组遍历中提过)
let arr1 = [1,2,3,6,3,4,5,5];
let arr2 = [2,3,4,5];
let s1 = new Set(arr1);
let s2 = new Set(arr2);
let result = new Set(arr1.filter(item => s2.has(item)))
console.log(result);
4.求差集
很简单,在交集的前提上取反就好了,然后将两个结果合并。
WeakSet
特殊的Set内部只能存放对象
因为存放内容是对象,所以就会有一个问题,delete()方法的参数是一个对象,前面提到过对象栈和堆的问题。也就是说如果像下面代码这样,删除是不会成功的。
let ws = new WeakSet();
ws.add({name:a,age:10});
ws.delete({name:a,age:10});
要这样处理才行。
let ws = new WeakSet();
const obj = {name:a,age:10};
ws.add(obj);
ws.delete(obj);
同理,用has()方法也是。
弱引用
还有一点要注意的是WeakSet是不能遍历的。
Map
之前在力扣上刷题,就觉得Map和C#里的Dictionary很像,就是一种哈希表,是一种键值对的形式。
Map添加内容的方法set(),获取用的是get(),删除用的是delete(),也有has()和size属性(对于对象内容的操作,也要注意上文WeakSet所提到的内容)。
map.set(key,value);
初始化时添加内容,要用[]数组形式每个数组会是他的成员。
1.注意外面还要加个[]。
2.内部键值对中,value后的索引再写内容不会被显示。
let newM = new Map([[key,value],['a',111]]);
map.set(key,value)时,如果key已存在,会将原来存在的键值对中的value更改。
map的遍历
有三种可选
let key of map.keys
let value of map.values
let [key,value] of map.entries()
和前面相对应的,也有个WeakMap,定义也很像,WeakMap的key只能是引用类型。其他和WeakSet一样,也不支持遍历,也是弱引用。