今天来说说Set和Map那些事,Set和Map都是ES6新引入的数据结构,了解Java的同学对这两个词不会感到陌生,事实上在ES6的概念中这两种数据结构和Java有很多想通之处。
Set是一种新的数据结构,它类似数组,但成员都是**唯一的没有重复的值**
let set = new Set();
/*Set函数可以接受一个数组或类数组作为参数来初始化*/
let s1 = new Set([1,2,3,1]);
console.log([...s1]); // [1,2,3]
/*所以这也是数组去重的一种新方法 [...new Set(Array)] */
/*利用Set和Array.from()数组去重 Array.from(new Set(array))*/
/*Set加入值得时候不会发生类型转换 1 和 '1' 是两个不同的值 最主要的是在Set中NaN等于自身,也就是说Set中不会出现两个NaN*/
let s2 = new Set();
s2.add(1);
s2.add('1');
s2.add(NaN);
s2.add(NaN);
console.log([...s2]); // [1,'1',NaN]
/*另外,两个对象总是不相等的。*/
let s3 = new Set();
s3.add({});
s3.add({});
console.log([...s3]); // [{},{}] 虽然添加的是两个空对象 但是它们是不相等的
/*Set的属性和方法*/
/*属性 : size*/
let s4 = new Set([1,2,3,4]);
console.log(s4.size); //4
/*Set的操作方法*/
// add(value) 添加某个值 返回添加后的Set结构
// delete(value) 删除某个值 返回Boolean 表示删除是否成功
// has(value) 返回Boolean 表示该值是否为Set的成员
// clear() 清楚所有成员 没有返回值
let s5 = new Set();
s5.add(1).add(2).add(3).add(4);
s5.size // 4
s5.has(1) // true
s5.has(5) // false
s5.delete(1);
s5.has(1); // false
console.log(...s5.keys());
s5.clear();
s5.size // 0
/*Set的遍历操作 Set的遍历顺序就是它的插入顺序*/
// keys(); 返回键名
// values() 返回键值
// entries() 返回键值对
// forEach() 遍历成员
/*因为Set只有键值没有键名(或者说键值和键名是同一个值) 所以 keys() 和 values() 的行为一致*/
let s6 = new Set(['red','green','black']);
[...s6.keys()]; // ['red','green','black']
[...s6.values()]; // ['red','green','black']
[...s6.entries()]; // [['red','red'],['green','green'],['black','black']]
s6.forEach((value, key) => console.log(value+'App') ); // redApp greenApp blackApp
/*Map和Object一样也是键值对的集合 不同的是Object的键只能是字符串而Map的键可以是各种数据类型甚至可以是一个对象,Map是一种更完善的Hash结构*/
let m = new Map();
let o = {'name' : 'tom'};
m.set(o,'hello');
m.get(o); // hello
console.log(...m);
/*Map接受一个数组作为参数,该数组的成员是一个个表示键值对的数组*/
let m1 = new Map([['name','tom'],['age',20]]);
m1.size; // 2
console.log([...m1]); // [['name','tom'],['age',20]]
/*只有对同一个对象的引用,Map结构才将其视为同一个键*/
let m2 = new Map();
m2.set(['a'],'hello');
m2.get(['a']); //undefined
// get和set方法中的['a']表面针对同一个键 实际是两个值 因为两者指向不同的内存地址
/*Map的属性和操作方法和Set大致相同*/
let map = new Map();
map.set('foo', true);
map.set('bar', false);
map.size // 2
map.set('hello','world');
map.get('hello'); // world
map.has('hello'); // true
map.delete('hello');
map.has('hello'); //false
//map.clear();
//map.size; // 0
/*遍历方法*/
//keys()
for(let key of map.keys()){
console.log(key);
}
// values()
for(let value of map.values()){
console.log(value);
}
//entries()
for(let item of map.entries()){
console.log(item); //['foo',true] ['bar',false]
}
/*Map ↔ 数组*/
let map2 = new Map([['name','tom'],['age',20]]); // 数组转Map
[...map2] // [['name','tom'],['age',20]] // Map转数组
/*Map转对象*/
function strMapToObj(strMap){
let obj = {};
for(let [key,value] of strMap.entries()){
obj[key]=value;
}
return obj;
}
strMapToObj(map2); // {'name' : 'tom','age' : 20}
/*对象转Map*/
function objToStrMap(obj){
let map = new Map();
for(let key in obj){
map.set(key,obj[key])
}
//console.log(...map);
return map;
}
objToStrMap({'name' : 'tom'});
/*Map转JSON*/
// 1、Map的键都是字符串
function strMapToJson(strMap){
console.log(JSON.stringify(strMapToObj(strMap)));
return JSON.stringify(strMapToObj(strMap));
}
strMapToJson(map2);
/*2、另一种情况是,Map的键名有非字符串,这时可以选择转为数组JSON。*/
function mapToArrayJson(map){
return JSON.stringify([...map])
}
let myMap = new Map().set(true, 7).set({foo: 3}, ['abc']);
mapToArrayJson(myMap);
/*JSON转Map*/
// 1、JSON转为Map,正常情况下,所有键名都是字符串。
function jsonToStrMap(json){
return objToStrMap(JSON.parse(json)); //先转为Object然后再转Map
}
jsonToStrMap('{"name" : "Tom"}');
//2、有一种特殊情况,整个JSON就是一个数组,且每个数组成员本身,又是一个有两个成员的数组
function jsonToMap(jsonStr) {
return new Map(JSON.parse(jsonStr));
}
jsonToMap('[[true,7],[{"foo":3},["abc"]]]');