一文明白ES6新数据类型 Map

小知识,大挑战!本文正在参与“ 程序员必备小知识 ”创作活动。

今天我们来学习ES6中的另一个新数据类型 Map ,和 Set 数据结构不同, Map 主要来存储key-value结构数据,让我们来看看它和JS中的对象有何不同。

Map 简介

在没有ES6之前,我们要用到key-value数据结构时,经常会使用对象,因为对象可以将key对应的值设置成任何数据类型。

然而使用对象也有一些问题:

  • JS中的对象都有prototype属性
  • 对象的key必须是字符串或者symbol,不能使用对象作为key
  • 对象没有表示对象长度的属性,像size或者length
  • ES6提供了新的数据类型 Map 解决了这些问题。

    Map 对象也是一种key-value的数据结构,任何类型的值都可以作为key或者value,另外 Map 对象还会记住key的原始插入顺序,这点和 Set 一样。

    创建一个 Map 对象

    let map = new Map([iterable]);
    

    Map()可传入一个可迭代对象,其元素为key-value结构

    一些常用 Map() 方法

  • clear() – 清空Map中全部key-value
  • delete(key) – 删除Map中的指定key,如果key存在,返回该元素,如不存在返回false。
  • entries() – 返回一个可迭代对象,结构为数组 [key, value],按照其插入顺序。
  • forEach(callback[, thisArg]) – 循环Map中每个元素,按照插入顺序,可选thisArg设置回调函数中的this值。
  • get(key) – 返回和key关联的值,如不存在返回undefined。
  • has(key) – 如果key存在返回true,否则返回false。
  • keys() – 返回可迭代对象,其值为插入顺序时的key。
  • set(key, value) – 向Map中添加key-value数据,返回本身Map对象,可使用链式调用。
  • values() 返回可迭代对象,其值为插入顺序时的value。
  • Map 使用示例

    创建Map对象

    假如我们有下面的一些汽车数据

    let bmw = {brand: 'bmw'},
        byd = {brand: 'byd'},
        ford = {brand: 'ford'};
    

    我们假设要把这些汽车和对应的国家做映射

    let carsCountry = new Map();
    

    carsCountry为我们创建的Map实例,它是object类型

    console.log(typeof(carsCountry));
    // 输出:object
    console.log(carsCountry instanceof Map);
    // 输出:true
    

    添加数据到Map

    使用set()方法向Map中添加数据

    carsCountry.set(bmw, 'Germany');
    

    使用set()方法将bmw对象映射到Germany,set方法会返回Map本身对象,所以也可以使用链式调用

    carsCountry.set(byd, 'China')
      .set(ford, 'America');
    

    带有初始数据

    我们可以在创建Map对象时,将初始数据传入Map构造函数中,数据格式为一个二维的数组

    let carsCountry = new Map([
      [bmw, 'Germany'],
      [byd, 'China'],
      [ford, 'America']
    

    Map中获取数据

    从Map中获取数据也很简单,使用get()方法

    carsCountry.get(bmw); 
    // 输出:Germany
    

    如果数据不存在,会返回undefined

    let foo = {name: 'Foo'};
    carsCountry.get(foo); 
    // 输出:undefined
    

    判断一个key是否存在

    使用has方法判断key是否存在于Map对象中

    carsCountry.has(foo); 
    // 输出:false
    carsCountry.has(bmw); 
    // 输出:true
    

    获取Map中元素数量

    使用size属性得到Map中的元素数量

    console.log(carsCountry.size);
    // 输出:3
    

    迭代Map中的key

    使用keys()方法来获取Map中的所有key,keys()方法返回一个可迭代对象。

    for (let car of carsCountry.keys()) {
      console.log(car.brand);
    // bmw
    // byd
    // ford
    

    迭代Map中的value

    同样,使用values()方法可以获取Map中的所有值,同样返回一个可迭代对象。

    for (let country of carsCountry.values()) {
      console.log(country);
    // Germany
    // China
    // America
    

    迭代Map元素

    同样,使用 entries() 方法也会返回可迭代对象,每个元素为一个数据结构包含key-value,像这样[key,value]。

    for (let elem of carsCountry.entries()) {
      console.log(`${elem[0].brand}: ${elem[1]}`);
    // bmw: Germany
    // byd: China
    // ford: America
    

    为了使代码更加清晰明了,我们可以使用ES6的解构方法

    for (let [car, country] of carsCountry.entries()) {
      console.log(`${car.brand}: ${country}`);
    

    除了使用for/of循环,Map对象同样提供了forEach方法

    carsCountry.forEach((country, car) =>
      console.log(`${car.brand}: ${country}`)
    

    Map中的key转换数组

    有时我们可能需要使用数组,而不是可迭代对象,这时我们可以使用ES6的展开运算符

    var keys = [...carsCountry.keys()];
    console.log(keys);
    
    [{brand: 'bmw'},
     {brand: 'byd'}, 
     {brand: 'ford'}]
    

    同样,也可以把value转换为数组

    var countrys = [...carsCountry.values()];
    console.log(countrys);
    
    ['Germany', 'China', 'America']
    

    删除Map中元素

    使用delete()方法删除Map中的元素,传入对应的key,删除成功后会返回true

    carsCountry.delete(bmw);
    // true
    

    清空Map中全部元素

    清空Map对象使用clear()方法

    carsCountry.clear();
    

    接着查看Map的长度,变为0

    console.log(carsCountry.size); 
    

    WeakMap

    WeakMap 类似于MapWeakMap 的key必须是对象,如果对象被GC垃圾回收,对应的值也会从内存中释放。

    WeakMap 只有 Map 的几个子集方法:

  • get(key)
  • set(key, value)
  • has(key)
  • delete(key)
  • 下面是MapWeekMap`的主要区别:

  • WeakMap 不能被迭代
  • WeakMap 不能被clear一次性清空掉
  • WeakMap 不能使用size查看长度
  • 今天我们主要学习了Map的使用,和一些简单的示例,以及和WeakMap的主要区别。