目录

🔂 JavaScript 映射与集合

# 映射 Map

Map 是一个 带键的数据项 的集合,就像一个 对象 Object 一样。 但是它们 最大的差别Map 允许任何类型的键(key)。

🍎 包含以下方法和属性

  • new Map()创建 一个 map
  • map.set(key, value) :根据 键值 存储值。
  • map.get(key) :根据键 返回 值。如果 map 不存在对应的 key ,则返回 undefined
  • map.has(key) :根据键 查找 值。如果 key 存在则返回 true ,否则返回 false
  • map.delete(key) :根据键 删除 值。
  • map.clear()清空 集合。
  • map.size返回当前元素个数

key 与对象不同,不会被转换成字符串,键可以是 任何类型

注意在集合不建议使用方括号取值,这样会将 map 视为 JavaScript 的 plain object,因此它暗含了所有相应的限制(仅支持 string/symbol 键等)。

🌰 例子 / Map 可以使用 对象 作为键:

let john = {name: 'John'}
let visitsCountMap = new Map()
visitsCountMap.set(john, 'johnValue')
console.log(visitsCountMap.get(john)) // 'johnValue'
1
2
3
4

在对象中不能使用 对象 作为键。因为对象会先讲键转换为字符串,转换为字符串后,内容为 [object Object]

提示

Map比较键Map 使用 SameValueZero 算法比较键值是否相等。它和严格等于 === 差不多,但区别是 NaN 被看成是等于 NaN 。所以 NaN 也可以被 用作键。这个算法不能被改变或者自定义。

提示

Map 的链式调用:每一次 map.set 调用都会返回 map 本身,所以可以进行链式调用:

map.set('1', 'str1')
  .set(1, 'num1')
  .set(true, 'bool1');
1
2
3

# Map 迭代

map 里使用 循环,可以使用以下三个方法:

  • map.keys() :遍历并返回所有的
  • map.values() :遍历并返回所有的
  • 🍎 map.entries() :遍历并返回 所有的实体 [key, value]for..of 在默认情况下使用的就是这个。。

除此之外, Map 有内建的 forEach 方法,与 Array 类似。

🌰 例子 / Map 的三个遍历方法:

let recipeMap = new Map([
  ['cucumber', 500],
  ['tomatoes', 350],
  ['onion',    50]
])

for (let vegetable of recipeMap.keys()) {
  console.log(vegetable)
}

for (let price of recipeMap.values()) {
  console.log(price)
}

for (let entry of recipeMap.entries()) {
  console.log(entry)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

:::

迭代的顺序与插入值的顺序相同。与普通的对象不同, Map 会保留插入值的顺序。

:::

🌰 例子 / 集合中的 forEach 方法:

recipeMap.forEach((value, key, map) => {
  console.log(`${key}: ${value}`)
})
1
2
3

# 从对象中创建 Map Object.entries

当创建一个 Map 后,可以传入一个 带有键值对的数组(或 其它可迭代对象)来进行 初始化

🌰 例子:

// 带有键值对 [key, value] 的数组
let map = new Map([
  ['1',  'str1'],
  [1,    'num1'],
  [true, 'bool1']
]);
1
2
3
4
5
6

如果想从一个已有的普通对象来创建一个 Map ,那么可以使用内建方法 Object.entries(obj) (opens new window),该方法返回 对象的键 / 值对数组,该数组格式完全按照 Map 所需的格式。

🌰 例子:

let obj = {
  name: 'Simon',
  age: 3
}

let map = new Map(Object.entries(obj))
for(let item of map.entries()){
	console.log(item)
} 
1
2
3
4
5
6
7
8
9

Object.entries 返回键 / 值对数组: [ ["name","John"], ["age", 30] ]

🌰 例子 / 从 Map 中转换值为对象

let map = new Map();
map.set('banana', 1);
map.set('orange', 2);
map.set('meat', 4);

let obj = Object.fromEntries(map.entries())
console.log(obj)
1
2
3
4
5
6
7

Object.fromEntries 创建一个普通对象。调用 map.entries() 将返回一个可迭代的键 / 值对,这刚好是 Object.fromEntries 所需要的格式。

可以简化为:

let obj = Object.fromEntries(map)
1

因为 Object.fromEntries 期望得到一个可迭代对象作为参数,而不一定是数组。并且 map 的标准迭代会返回跟 map.entries() 一样的键 / 值对。

因此,可以获得一个普通对象(plain object),其键 / 值对与 map 相同。

# 集合 set

Set 是一个特殊的类型集合「值的集合」(没有键),它的每一个值只能出现一次

🍎 包含以下的方法

  • new Set(iterable) : 创建一个 set ,如果提供了一个可迭代对象(通常是数组),将会从该对象里面 复制 值到 set 中。
  • set.add(value) :添加 value 到集合,返回集合本身
  • set.delete(value) :删除 value 。如果 value 在这个方法调用的时候 存在则返回 true否则返回 false
  • set.has(value) :查找 value 。存在返回 true ,否则返回 false
  • set.clear() :清空 set
  • set.size :返回元素个数。

Set 的主要特点:重复使用同一个值调用 set.add(value) 并不会发生什么改变。这就是 Set 里面的 每一个值只出现一次 的原因。

🌰 例子 / 记录到访的客人,不重复记录已经来访的客人:

let set = new Set()

let john = { name: "John" };
let pete = { name: "Pete" };
let mary = { name: "Mary" };

set.add(john);
set.add(pete);
set.add(mary);
set.add(john);
set.add(mary);

console.log(set.size) // 3
for(let user of set){
  console.log(user.name) // 3个
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

仅用数组实现在插入元素时查重时会带来遍历的时间开销。 Set 内部对唯一性检查进行了更好的优化。

# Set 迭代

可以使用 for..offorEach 来遍历 Set:

🌰 例子 :

let set = new Set(["oranges", "apples", "bananas"]);

for (let item of set) {
  console.log(item)
}

set.forEach((value, valueAgain, set)=>{
  console.log(value)
})
1
2
3
4
5
6
7
8
9

forEach 的回调函数有三个参数:一个 value ,然后是 同一个值 valueAgain ,最后是目标对象。

这三个参数是为了与 Map 兼容。对在特定情况下轻松地用 Set 代替 Map 很有帮助,反之亦然。

Map 中用于迭代的方法在 Set 中也同样支持:

  • set.keys() :遍历并返回所有的值,
  • set.values() : 与 set.keys() 作用相同,这是为了兼容 Map
  • set.entries() :遍历并返回所有的实体, [value, value] ,它的存在也是为了兼容 Map

# 总结

  • Map 是一个带键的数据项的集合。
    • 与普通对象 Object 的不同点:
      • 任何键、对象都可以作为键。
      • 有其他的便捷方法,如 size 属性。
  • Set 是一组唯一值的集合。
  • MapSet 中迭代总是按照值 插入的顺序 进行的,所以我们说这些集合是无序的,但是不能对元素进行重新排序,也不能直接按其编号来获取元素。
📢 上次更新: 2022/09/02, 10:18:16