Set与Map都是ES6标准中新增的数据结构.
Set
Set是一种类似数组的数据结构,也是一种数据集合,但并不是数组.区别在于Set的值不能重复,Set本身是一个构造函数,用来生成Set数据结构.使用Set有两种数据传入的方式,一种就是在实例化Set的时候传入一个数组,另外一种是为Set实例使用add方法.
数据传入
Set是一个构造函数,在实例化对象的时候,传入一个数组
let arr = [1,1,2,2,3,3,5,6,3,2,4,5];
let s = new Set(arr);
console.log(s); //Set { 1, 2, 3, 5, 6, 4 }
从示例中可以看出,Set数据结构为我们解决了一个数组的问题,数据去重的问题.这个问题在数组中需要我们做处理,而到了Set中,直接就把重复的数据去除掉了.虽然去重了,但是数据类型变了,变成了Set的类型了,并不是数组了.如果我们的代码中必须要使用数组的话,而我们的去重处理恰恰又是使用的Set,那么我们就需要多做一步了,需要将Set数据结构转换为数组类型.
Set转换为Array
set可以与扩展运算符的结合使用,可以完成数组去重后的浅拷贝
let arr = [1,1,2,2,3,3,5,6,3,2,4,5];
let s = new Set(arr);
let newArr = [...s];
console.log(Array.isArray(newArr)); //true
说明我们已经将Set转换成Array了.
Set实例使用add方法添加项
let arr = [1,1,2,2,3,3,5,6,3,2,4,5];
let s = new Set(arr);
let newArr = [...s];
console.log(Array.isArray(newArr)); //true
s.add(9);
console.log(s);//Set { 1, 2, 3, 5, 6, 4, 9 }
也可以通过Array的from方法将Set转换为Array.
let arr = [1,2];
const s1 = new Set(arr);
console.log(Array.isArray(s1)); //false
let newArr = Array.from(s1);
console.log(Array.isArray(newArr)); //true
然后这里就有一个隐藏的技术点需要来总结下了:Set和Array的相互转换:
Set转换为数组
let arr = [1,2];
const s1 = new Set(arr);
console.log(Array.isArray(s1)); //false
let newArr = Array.from(s1);
let newArr2 = [...s1];
console.log(Array.isArray(newArr)); //true
console.log(Array.isArray(newArr2)); //true
数组转换为Set
let arr = [1,2];
const s1 = new Set(arr);
console.log(s1); //Set { 1, 2 }
Set的长度
前面我们提到Set是一个种类数组的数据结构,数组有一个使用频率非常高的属性,就是length,很多时候我们会根据数组的length属性来做一些操作,那么Set是否和数组一样也有这个属性呢?
Set也有这个属性,但是和数组不同的是,Set的这个length属性是Set这个类的,而不是Set的实例对象的.如:
let arr = [1,1,2,2,3,3,5,6,3,2,4,5];
let s = new Set(arr);
console.log(s); //Set { 1, 2, 3, 5, 6, 4 }
console.log(Set.length); //0,说明Set这个类型的length属性为0,和具体的实例没有关系
console.log(s.length); //undefined,说明了Set的实例对象是没有这个属性的
在Set中,是通过实例对象的size属性来获取实例的项的个数的.
let arr = [1,1,2,2,3,3,5,6,3,2,4,5];
let s = new Set(arr);
console.log(s);
console.log(Set.length); //0
console.log(s.length); //undefined
console.log(s.size);//6
Set常用方法
1.判断set实例中是否有某个值:
has(value):返回值:Boolean,true、false
let arr = [1,1,2,2,3,3,5,6,3,2,4,5];
let s = new Set(arr);
console.log(s.has(12)); //false
console.log(s.has(4)); //true
2.添加元素
add(value):向set末尾添加值为value的项
let arr = [1,1,2,2,3,3,5,6,3,2,4,5];
let s = new Set(arr);
console.log(s); //Set { 1, 2, 3, 5, 6, 4 }
s.add(22);
console.log(s); //Set { 1, 2, 3, 5, 6, 4, 22 }
let arr = [1,2];
const s1 = new Set(arr);
let obj = {a:3,b:4};
s1.add(obj);
console.log(s1); //Set { 1, 2, { a: 3, b: 4 } }
Set可以通过add添加对象元素.
3.清空元素
clear():清空set实例
let arr = [1,1,2,2,3,3,5,6,3,2,4,5];
let s = new Set(arr);
console.log(s); //Set { 1, 2, 3, 5, 6, 4 }
s.clear();
console.log(s); //Set {}
4.移除Set中与这个值相等的元素
delete(value):移除set中值为value的元素
let arr = [1,1,2,2,3,3,5,6,3,2,4,5];
let s = new Set(arr);
console.log(s); //Set { 1, 2, 3, 5, 6, 4 }
s.delete(3);
console.log(s); //Set { 1, 2, 5, 6, 4 }
5.数据遍历
既然Set是类数组的数据结构,那么在使用中肯定就会涉及到对数据的遍历.
forEach(callback,[args]):
callback:每个元素都会执行的函数,有3个参数:
- 元素的值
- 元素的索引
- 将要遍历的集合对象
Set对象是没有索引值的(keys),所以callback的前2个参数都是Set中的元素值(values).
let arr = [1,2];
const s1 = new Set(arr);
s1.add(42);
console.log(s1); //Set { 1, 2, 42 }
s1.forEach((item)=>{
console.log(item); //1、2、42
});
for……of:遍历set,可以直接是一个set实例,可以是一个set实例的values,也可以是set的keys
let arr = [1,2];
const s1 = new Set(arr);
for(let item of s1){
console.log(item); //1、2
}
for(let item of s1.values()){
console.log(item);//1、2
}
for(let item of s1.keys()){
console.log(item);//1、2
}
for(let [key,value] of s1.entries()){
console.log(key); //1、1
console.log(value); //2、2 key和value相等
}
Map
同上面的Set类似,Map是一种类对象的数据结构,只有一点不同的是对象的key只能是String类型的,而Map的key可以是任意类型的.通过Map构造函数实例化Map对象的时候,只能传入数组参数,如果有多个元素,那么每个元素都只能以数组想的形式传入,否则无法识别元素.
let m2 = new Map([["name","stark"],[2,3],[4,6]]);
如实例代码,传入的参数只能是数组格式.实例的Map对象m2的3个元素["name","stark"],[2,3],[4,6],这些元素也只能是数组格式的,只是每个数组里面只有2个数组项,一个为map的key,另一个为map的value.如果不是以数组格式传入的,那么map就不能正确获取到这些元素,在获取这些值的时候就会为undefined.
let m2 = new Map([["name","stark"],{2:3},[4,6]]);
console.log(m2); //Map { 'name' => 'stark', undefined => undefined, 4 => 6 }
Map也可以通过set添加元素
let map = new Map();
let keyObj = {};
let keyFun = function(){};
let keyString = "A String";
map.set(keyString,"和键a string相关的值");
通过get取值
let map = new Map();
let keyFun = function(){};
map.set(keyFun,"和键keyFun相关的值");
console.log(map.get(keyFun)); //和键keyFun相关的值
通过size属性获取map的元素个数
let map = new Map();
let keyFun = function(){};
map.set(keyFun,"和键keyFun相关的值");
console.log(map.get(keyFun)); //和键keyFun相关的值
console.log(map.size); //1
Map的常用方法
1.清空元素
clear()移除map中所有的元素
let map = new Map();
let keyFun = function(){};
map.set(keyFun,"和键keyFun相关的值");
console.log(map.get(keyFun)); //和键keyFun相关的值
console.log(map.size); //1
map.clear();
console.log(map); //Map {}
2.添加元素
上面已经说过
3.获取元素
上面已经说过
4.移除元素
delete(key):如果map中存在该元素,返回true,如果不存在,则返回false
let map = new Map();
let keyFun = function(){};
map.set(keyFun,"和键keyFun相关的值");
console.log(map.delete(keyFun)); //true
5.判断map中是否含有某个key对应的值
has(key):判断map中是否有key对应的值,如果有,返回true,没有返回false
let map = new Map();
let keyFun = function(){};
map.set(keyFun,"和键keyFun相关的值");
console.log(map.has("name")); //false
console.log(map.has(keyFun)); //true
6.map元素遍历
forEach(callback,[,thisArg])
callback:回调函数,包括3个参数:
- value:元素的值value
- key:元素的键key
- map:当前正在被遍历的对象
这个方法会返回一个多余的undefined,现在没有搞清楚原因呢.
let map = new Map();
map.set("name","Nicholas");
console.log(map);
console.log(map.forEach((value,key) => {
console.log(key+ ": " + value); //name: Nicholas,undefined
}));
for …… of:map的这个遍历方法和Set的相同,就不再描述了.