Map

ES6 提供了 Map 数据结构,它类似对象,也是键值对的集合,但是‘键’的范围不限于字符串,各种类型的值(包括对象)都可以当做键。Map 结构是一种更完善的 Hash 结构实现。如果需要‘键值对’的数据结构,Map 比 Object 更合适。

1
2
3
4
let m = new Map()
const o = { p: "hello" }
m.set(o, "content")
m.get(o) //'content'

Map 也可以接受一个数组作为参数,该数组的成员是一个表示键值对的数组:

1
2
3
4
5
6
7
8
const map = new Map([
["name", "张三"],
["title", "test"],
])

map.size //2
map.has("name") //true
map.get("name") //'张三'

Map 构造函数接受数组作为参数,实际上执行的是下面的算法:

1
2
3
4
5
6
const item = [
["name", "张三"],
["title", "test"],
]
const map = new Map()
item.forEach(([key, valule]) => map.set(key, value))

同名问题

Map 的键实际上是和内存地址绑定的,只要内存地址不一样,就视为两个键。如果 Map 的键是一个简单类型的值(数字、字符串、布尔值),则只要两个值严格相等,Map 就视其为一个键,包括-0 和 0。另外,虽然 NaN 不严格等于自身,但 Map 将其视为同一个键。

实例的属性和操作方法

  • size 属性
    size 属性返回 Map 结构的成员总数。
  • set(key, value)
    set 方法设置 key 所对应的键值,返回整个 Map 结构。如果 key 已经有值,则键值更新,否则新生成键值。
  • get(key)
    get 方法读取 key 对应的键值,如果找不到 key,返回 undefined。
  • has(key)
    has 方法返回一个布尔值,表示某个键是否在 Map 数据结构中。
  • delete(key)
    delete 方法删除某个键,返回 true。如果删除失败,返回 false。
  • clear()
    clear 方法清除所有成员,没有返回值。

遍历方法

  • keys():返回键名的遍历器
  • values():返回键值的遍历器
  • entries():返回所有成员的遍历器
  • forEach():遍历 Map 的所有成员

Map 的遍历顺序就是插入顺序

Map 与其他数据结构相互转换

  • Map 转为数组
    1
    2
    const myMap = new Map().set(true, 1).set(false, 2).set({ foo: 1 }, ["abc"])
    ;[...myMap] //[[true, 1], [false, 2], [{foo:1}, ['abc']]]
  • 数组转为 Map
    1
    2
    3
    4
    new Map([
    [true, 1],
    [{ foo: 3 }, ["abc"]],
    ])
  • Map 转为对象
    如果 Map 的所有键都是字符串,则可以转为对象。
    1
    2
    3
    4
    5
    6
    7
    function strMapToObj(strMap) {
    let obj = Object.create(null)
    for (let [k, v] of strMap) {
    obj[k] = v
    }
    return obj
    }
  • 对象转为 Map
    1
    2
    3
    4
    5
    6
    7
    function objToStrMap(obj) {
    let strMap = new Map()
    for (let k of Object.keys(obj)) {
    strMap.set(k.obj[k])
    }
    return strMap
    }
  • Map 转为 JSON
  1. Map 的键名都是字符串:
    1
    2
    3
    function strMapToJson(strMap) {
    return JSON.stringify(strMapToObj(strMap))
    }
  2. 键名有非字符串
    1
    2
    3
    function mapToArrayJson(map) {
    return JSON.stringify([...map])
    }
  • JSON 转为 Map
  1. 正常情况下所有键名都是字符串
    1
    2
    3
    function jsonToStrMap(jsonStr) {
    return objToStrMap(JSON.parse(jsonStr))
    }
  2. JSON 就是一个数组的情况
    1
    2
    3
    function jsonToMap(jsonStr) {
    return new Map(JSON.parse(jsonStr))
    }

WeakMap

  • 只接受对象作为键名(null 除外)
  • WeakMap 中的对象都是弱引用,如果其他对象都不再引用该对象,那么 GC 会自动回收该对象所占的内存,不考虑该对象是否在 WeakMap 中
  • 没有 size 属性,没有 clear 方法

WeakMap 的专用场景就是它的键所对应的对象可能会在将来消失的场景,有助于防止内存泄露