• 数据类型 Map and Set(映射和集合)


    数据类型 Map and Set(映射和集合)

    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。
    map.size —— 返回当前元素个数。
    举个例子:

    let map = new Map();

    map.set('1', 'str1'); // 字符串键
    map.set(1, 'num1'); // 数字键
    map.set(true, 'bool1'); // 布尔值键

    // 还记得普通的 Object 吗? 它会将键转化为字符串
    // Map 则会保留键的类型,所以下面这两个结果不同:
    alert( map.get(1) ); // 'num1'
    alert( map.get('1') ); // 'str1'

    alert( map.size ); // 3
    如我们所见,与对象不同,键不会被转换成字符串。键可以是任何类型。

    Map 还可以使用对象作为键

    例如:

    let john = { name: "John" };

    // 存储每个用户的来访次数
    let visitsCountMap = new Map();

    // john 是 Map 中的键
    visitsCountMap.set(john, 123);

    alert( visitsCountMap.get(john) ); // 123
    使用对象作为键是 Map 最值得注意和重要的功能之一。对于字符串键,Object(普通对象)也能正常使用,但对于对象键则不行。

    我们来尝试一下:

    let john = { name: "John" };

    let visitsCountObj = {}; // 尝试使用对象

    visitsCountObj[john] = 123; // 尝试将 john 对象作为键

    // 是写成了这样!
    alert( visitsCountObj["[object Object]"] ); // 123
    因为 visitsCountObj 是一个对象,它会将所有的键如 john 转换为字符串,所以我们得到字符串键 "[object Object]"。这显然不是我们想要的结果。

    Map 是怎么比较键的?
    Map 使用 SameValueZero 算法来比较键是否相等。它和严格等于 === 差不多,但区别是 NaN 被看成是等于 NaN。所以 NaN 也可以被用作键。

    这个算法不能被改变或者自定义。

    链式调用
    每一次 map.set 调用都会返回 map 本身,所以我们可以进行“链式”调用

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


    Map 迭代
    如果要在 map 里使用循环,可以使用以下三个方法:

    map.keys() —— 遍历并返回所有的键(returns an iterable for keys),
    map.values() —— 遍历并返回所有的值(returns an iterable for values),
    map.entries() —— 遍历并返回所有的实体(returns an iterable for entries)[key, value],for..of 在默认情况下使用的就是这个。
    例如:

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

    // 遍历所有的键(vegetables)
    for (let vegetable of recipeMap.keys()) {
    alert(vegetable); // cucumber, tomatoes, onion
    }

    // 遍历所有的值(amounts)
    for (let amount of recipeMap.values()) {
    alert(amount); // 500, 350, 50
    }

    // 遍历所有的实体 [key, value]
    for (let entry of recipeMap) { // 与 recipeMap.entries() 相同
    alert(entry); // cucumber,500 (and so on)
    }
    使用插入顺序
    迭代的顺序与插入值的顺序相同。与普通的 Object 不同,Map 保留了此顺序。

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

    // 对每个键值对 (key, value) 运行 forEach 函数
    recipeMap.forEach( (value, key, map) => {
    alert(`${key}: ${value}`); // cucumber: 500 etc
    });


    Object.entries:从对象创建 Map
    当创建一个 Map 后,我们可以传入一个带有键值对的数组(或其它可迭代对象)来进行初始化,如下所示:

    // 键值对 [key, value] 数组
    let map = new Map([
    ['1', 'str1'],
    [1, 'num1'],
    [true, 'bool1']
    ]);

    alert( map.get('1') ); // str1


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

    所以可以像下面这样从一个对象创建一个 Map:

    let obj = {
    name: "John",
    age: 30
    };

    let map = new Map(Object.entries(obj));

    alert( map.get('name') ); // John
    这里,Object.entries 返回键/值对数组:[ ["name","John"], ["age", 30] ]。这就是 Map 所需要的格式。

    Object.fromEntries:从 Map 创建对象
    我们刚刚已经学习了如何使用 Object.entries(obj) 从普通对象(plain object)创建 Map。

    Object.fromEntries 方法的作用是相反的:给定一个具有 [key, value] 键值对的数组,它会根据给定数组创建一个对象:

    let prices = Object.fromEntries([
    ['banana', 1],
    ['orange', 2],
    ['meat', 4]
    ]);

    // 现在 prices = { banana: 1, orange: 2, meat: 4 }

    alert(prices.orange); // 2
    我们可以使用 Object.fromEntries 从 Map 得到一个普通对象(plain object)。

    例如,我们在 Map 中存储了一些数据,但是我们需要把这些数据传给需要普通对象(plain object)的第三方代码。

    我们来开始:

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

    let obj = Object.fromEntries(map.entries()); // 创建一个普通对象(plain object)(*)

    // 完成了!
    // obj = { banana: 1, orange: 2, meat: 4 }

    alert(obj.orange); // 2
    调用 map.entries() 将返回一个可迭代的键/值对这刚好是 Object.fromEntries 所需要的格式

    我们可以把带 (*) 这一行写得更短:

    let obj = Object.fromEntries(map); // 省掉 .entries()
    上面的代码作用也是一样的,因为 Object.fromEntries 期望得到一个可迭代对象作为参数,而不一定是数组。并且 map 的标准迭代会返回跟 map.entries() 一样的键/值对。因此,我们可以获得一个普通对象(plain object),其键/值对与 map 相同。


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

    它的主要方法如下:

    new Set(iterable) —— 创建一个 set,如果提供了一个 iterable 对象(通常是数组),将会从数组里面复制值到 set 中。
    set.add(value) —— 添加一个值,返回 set 本身
    set.delete(value) —— 删除值,如果 value 在这个方法调用的时候存在则返回 true ,否则返回 false。
    set.has(value) —— 如果 value 在 set 中,返回 true,否则返回 false。
    set.clear() —— 清空 set。
    set.size —— 返回元素个数。
    它的主要特点是,重复使用同一个值调用 set.add(value) 并不会发生什么改变。这就是 Set 里面的每一个值只出现一次的原因。

    例如,我们有客人来访,我们想记住他们每一个人。但是已经来访过的客人再次来访,不应造成重复记录。每个访客必须只被“计数”一次。

    Set 可以帮助我们解决这个问题:

    let set = new Set();

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

    // visits,一些访客来访好几次
    set.add(john);
    set.add(pete);
    set.add(mary);
    set.add(john);
    set.add(mary);

    // set 只保留不重复的值
    alert( set.size ); // 3

    for (let user of set) {
    alert(user.name); // John(然后 Pete 和 Mary)
    }
    Set 的替代方法可以是一个用户数组,用 arr.find 在每次插入值时检查是否重复。但是这样性能会很差,因为这个方法会遍历整个数组来检查每个元素。Set 内部对唯一性检查进行了更好的优化。

    Set 迭代(iteration)
    我们可以使用 for..of 或 forEach 来遍历 Set:

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

    for (let value of set) alert(value);

    // 与 forEach 相同:
    set.forEach((value, valueAgain, set) => {
    alert(value);
    });
    注意一件有趣的事儿。forEach 的回调函数有三个参数:一个 value,然后是 同一个值 valueAgain,最后是目标对象。没错,同一个值在参数里出现了两次。

    forEach 的回调函数有三个参数,是为了与 Map 兼容。当然,这看起来确实有些奇怪。但是这对在特定情况下轻松地用 Set 代替 Map 很有帮助,反之亦然。

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

    set.keys() —— 遍历并返回所有的值(returns an iterable object for values),
    set.values() —— 与 set.keys() 作用相同,这是为了兼容 Map,
    set.entries() —— 遍历并返回所有的实体(returns an iterable object for entries)[value, value],它的存在也是为了兼容 Map。
    总结
    Map —— 是一个带键的数据项的集合。

    方法和属性如下:

    new Map([iterable]) —— 创建 map,可选择带有 [key,value] 对的 iterable(例如数组)来进行初始化。
    map.set(key, value) —— 根据键存储值。
    map.get(key) —— 根据键来返回值,如果 map 中不存在对应的 key,则返回 undefined。
    map.has(key) —— 如果 key 存在则返回 true,否则返回 false。
    map.delete(key) —— 删除指定键的值。
    map.clear() —— 清空 map 。
    map.size —— 返回当前元素个数。
    与普通对象 Object 的不同点:

    任何键、对象都可以作为键。
    有其他的便捷方法,如 size 属性。
    Set —— 是一组唯一值的集合。

    方法和属性:

    new Set([iterable]) —— 创建 set,可选择带有 iterable(例如数组)来进行初始化。
    set.add(value) —— 添加一个值(如果 value 存在则不做任何修改),返回 set 本身。
    set.delete(value) —— 删除值,如果 value 在这个方法调用的时候存在则返回 true ,否则返回 false。
    set.has(value) —— 如果 value 在 set 中,返回 true,否则返回 false。
    set.clear() —— 清空 set。
    set.size —— 元素的个数。
    在 Map 和 Set 中迭代总是按照值插入的顺序进行的,所以我们不能说这些集合是无序的,但是我们不能对元素进行重新排序,也不能直接按其编号来获取元素。

  • 相关阅读:
    asp.net源码坊2015-3月第二周TOP10下载排行
    Asp.Net编程需要学习什么
    面试的同学看过来
    Asp.Net模板生成HTML页面
    毕业设计之房产中介系统源码
    HTML常用状态代码
    Asp.Net毕业设计论文
    网页常用Javascript
    intellij idea使用笔记
    bootstrap-table使用笔记
  • 原文地址:https://www.cnblogs.com/perfectdata/p/15503440.html
Copyright © 2020-2023  润新知