Set、Map是ES6中新增的两种集合类型,用于在不同的场景中发挥作用
1.Set
Set本身是个构造函数,用来生成Set数据结构,它类似于数组,但是没有随机访问的能力,最重要的是,Set
中的元素具有唯一性,不允许存储相同的元素!Set 内部判断两个值是否不同,使用的算法类似于精确相等运算符(===),可用于数组去重操作。
1.1 创建set集合
//创建一个没有任何内容的set集合
new Set() //Set(0) {size: 0}
//创建一个具有初试内容的set集合,内容来自于可迭代对象每一次迭代的结果
new Set([1,3,2,3])//结果直接去重:Set(3) {1, 3, 2}
//由元素唯一性这个特点,可以利用在数组去重上
//方法一:Array.from()方法就是将一个类数组对象或者可遍历对象转换成一个真正的数组
Array.from(new Set([1,3,2,3])) //[1, 3, 2]
//方法二:拓展运算符
[...new Set(arr)] [1, 3, 2]
1.2 Set 的属性和实例方法
(1) size属性
const s = new Set();
console.log(s.size);//0,返回Set结构的成员总数
(2)操作方法
- add(value):添加某个值,返回Set结构本身
注意:向 Set 加入值的时候,不会发生类型转换,所以1和"1"是两个不同的值 - delete(value):删除某个值,返回一个布尔值,表示删除是否成功
- has(value):返回一个布尔值,表示该值是否为
Set
的成员
clear():清除所有成员,没有返回值
const s= new Set(); //初始化: Set(0) {size: 0}
s.add(0).add("1").add('a').add([1,2]); //添加成员: Set(4) {0, '1', 'a', Array(2)}
s.delete(3) //false, 成员中无 3, 删除失败: Set(4) {0, '1', 'a', Array(3)}
s.has(0) //true, 成员中有 0,返回true
s.clear()//清除所有成员,没有返回值: Set(0) {size: 0}
(3)遍历方法
Set的遍历顺序就是插入顺序
。这个特性有时非常有用,比如使用 Set 保存一个回调函数列表,调用时就能保证按照添加顺序调用。
Set.prototype.keys()
:返回键名的遍历器Set.prototype.values()
:返回键值的遍历器Set.prototype.entries()
:返回键值对的遍历器Set.prototype.forEach()
:使用回调函数遍历每个成员
keys方法、values方法、entries方法返回的都是遍历器对象。由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。此外,Set 结构的实例默认可遍历,它的默认遍历器生成函数就是它的values
方法,可以省略values方法,直接用for...of
循环遍历 Set。。
let set = new Set([1, 2, 3]);
for (let i of set.keys()) {
console.log(i);
}
// 1 2 3
for (let i of set.values()) {
console.log(i);
}
// 1 2 3
for (let i of set) {
console.log(i)
}
//1 2 3
for (let i of set.entries()) {
console.log(i);
}
// [1, 1] [2, 2] [3, 3]
set.forEach(i => {
console.log(i)
})
// 1 2 3
2.Map
Map 是 ES6 中新增的数据结构,Map 类似于对象,Object 结构提供了“字符串—值”的对应,但普通对象的 key 必须是字符串或是数字,而Map 结构提供了“值—值”的对应,而Map 的 key 可以是任何数据类型,是一种更完善的 Hash 结构实现。Map 的用法和普通对象基本一致,如果你需要“键值对”的数据结构,Map 比 Object 更合适。
2.1 创建Map实例
const m = new Map(); //创建一个空映射:Map(0) {size: 0}
//接受可迭代对象作为参数用来初始化,需要包含键/值对数组。可迭代对象中的每个键/值对都会按照迭代顺序插入到新映射实例中(类似于二维数组)
const m = new Map([
[1, 'a'],
[2, 'b'],
[3, 'c']
]); //Map(3) Map(3) {1 => 'a', 2 => 'b', 3 => 'c'}
Array.from(m); // [[1, 'a],[2, 'b],[3, 'c]]
2.2 Map实例的属性和操作方法
(1) size属性
const m = new Map([
[1, 'a'],
[2, 'b'],
[3, 'c']
]);
map.size // 返回 Map 结构的成员总数: 3
(2)操作方法
- Map.prototype.set(key, value):Map设置某个值,返回当前的Map对象,因此可以采用链式写法。
- Map.prototype.get(key):读取key对应的键值,如果找不到key,返回undefined
- Map.prototype.has(key):返回一个布尔值,表示某个键是否在当前 Map 对象之中。
- Map.prototype.delete(key):删除某个键,返回true。如果删除失败,返回false
- Map.prototype.clear():清除所有成员,没有返回值
const m = new Map();
m.set('a', 1) // 键是字符串
m.set(2, 'b') // 键是数值
m.set(undefined, 'c') // 键是 undefined
m.set({p: 'Hello World'}, 'content') // 键是 object
// Map(4) {'a' => 1, 2 => 'b', undefined => 'c', {…} => 'content'}
m.get('a') // 1
m.get(1) // 无键为1的成员对象,返回 undefined
m.has('a') // true, 'a' 在Map对象中
m.has(1) // false, 1不在Map对象中
m.delete(2) //true,删除2成功: Map(3) {'a' => 1, undefined => 'c', {…} => 'content'}
m.delete(1) // false,Map对象中无键1,删除1不成功
m.clear() //清除所有成员,没有返回值: Map(0) {size: 0}
(3)遍历方法
Map 结构原生提供三个遍历器生成函数和一个遍历方法,Map 的遍历顺序就是插入顺序。
- Map.prototype.keys():返回键名的遍历器。
- Map.prototype.values():返回键值的遍历器。
- Map.prototype.entries():返回所有成员的遍历器,Map 结构的默认遍历器接口。
- Map.prototype.forEach():遍历 Map 的所有成员,与数组的forEach方法类似。
const m = new Map([
[1, 'a'],
[2, 'b'],
]);
for (let key of m.keys()) {
console.log(key);
}
// 1 2
for (let value of m.values()) {
console.log(value);
}
// 'a' 'b'
for (let item of m.entries()) {
console.log(item[0], item[1]);
}
// 1 'a' 2 'b'
// 或者
for (let [key, value] of m.entries()) {
console.log(key, value);
}
// 1 'a' 2 'b'
// 等同于使用m.entries()
for (let [key, value] of m) {
console.log(key, value);
}
// 1 'a' 2 'b'
m.forEach((value, key, m) => {
console.log("Key: %s, Value: %s", key, value);
});
//Key: 1, Value: a Key: 2, Value: b
m.forEach(item => {
console.log(item)
})
// 'a' 'b'
2.3 Map与其他数据结构的互相转换
(1)Map 转为数组
const m = new Map()
.set(1, 'a')
.set(2, 'b');
//方法一:Array.from()方法就是将一个类数组对象或者可遍历对象转换成一个真正的数组
Array.from(m) // [[1,'a'], [2, 'b']]
//方法二:拓展运算符
[...m] // [[1,'a'], [2, 'b']]
(2)数组 转为 Map
//将数组传入 Map 构造函数,就可以转为 Map。
new Map([
[1,'a'],
[2, 'b']
])
// Map {1 => 'a', 2 => 'b'}
(3)Map 转为对象
如果所有 Map 的键都是字符串或者数字,它可以无损地转为对象,如果有非字符串的键名,那么这个键名会被转成字符串,再作为对象的键名
。
function strMapToObj(map) {
let obj = Object.create(null); //相当于let obj={}
for (let [k,v] of strMap) {
obj[k] = v;
}
return obj;
}
const m = new Map()
.set('a', 1)
.set(2, 'b')
.set([1,2], 'c');
const obj = strMapToObj(m)
console.log(obj)// { 'a': 1, 2: 'b', '1,2': 'c' }
(4)对象转为 Map
对象转为 Map 可以通过Object.entries()
(ES6新增方法)。
let obj = {1:'a', 2:'b'};
let map = new Map(Object.entries(obj));
//此外,也可以自己实现一个转换函数。
function objToStrMap(obj) {
let strMap = new Map();
for (let k of Object.keys(obj)) {
strMap.set(k, obj[k]);
}
return strMap;
}
objToStrMap({1:'a', 2:'b'})
// Map(2) {'1' => 'a', '2' => 'b'}
(5)Map 转为 JSON
function strMapToJson(map) {
return JSON.stringify(strMapToObj(map));
}//Map 的键名都是字符串
function mapToArrayJson(map) {
return JSON.stringify([...map]);
}//Map 的键名有非字符串
let m = new Map().set(1, 'a').set(2, 'b');
strMapToJson(m)
// '{"1":"a","2":"b"}'
(6)JSON 转为 Map
function jsonToStrMap(jsonStr) {
return objToStrMap(JSON.parse(jsonStr));
} //所有键名都是字符串
jsonToStrMap('{"1": 'a', '2': 'b'}')
// Map {1 => 'a', 2 => 'b'}
function jsonToMap(jsonStr) {
return new Map(JSON.parse(jsonStr));
} //整个 JSON 就是一个数组,且每个数组成员本身,又是一个有两个成员的数组
let jsonStr1='[[1, 'a'],[2,'b']]';
jsonToMap(jsonStr1)
// Map {1 => 'a', 2 => 'b'}
3.Set 和 Map 的区别
不同点:
- 定义不同:Set类似于数组,但是成员的值都是唯一的,没有重复的值;
Map
类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。 - 操作方法不同:Set:add, has, delete, clear;
Map: set, get, has, delete, clear。 - 遍历方法不同: Set 结构的实例有四个遍历方法keys(), values(), entries(),forEach(),可以用于遍历成员,它的默认遍历器生成函数就是它的
values
方法;
Map 结构原生提供三个遍历器生成函数keys(), values(), entries()和一个遍历方法forEach(),Map 结构的默认遍历器接口是entries
方法。
相同点:size属性相同