ES6 - 基础学习(12): Set、WeakSet、Map、WeakMap补充

Set 遍历的应用

  1、由于扩展运算符(...)内部使用了 for...of 循环,因此可以用扩展运算符(...)将 Set数据结构 转换为 数组。

let arrayToSet = new Set(["value1", "value2", "value3"]);
console.log(arrayToSet);                             // Set(3) {"value1", "value2", "value3"}

let setToArray = [...arrayToSet];
console.log(setToArray);                           // ["value1", "value2", "value3"]    Set和Array 数据输出格式都不一样

  2、扩展运算符和 Set 数据结构相结合,可以去除数组内的重复成员。

let tampArray = [1,2,3,3,2,1,4,5];
let setToArray = [...new Set(tampArray)];          // 先将数组 Set格式化,再用扩展运算符转为数组
console.log(setToArray);                            //  [1, 2, 3, 4, 5]

  3、将数组的 map和 filter方法间接用于 Set数据结构,可以获取两个 Set实例的并集(Union)、交集(Intersect) 以及 差集(Difference)。

复制代码
let aSet = new Set([1, 2, 3, 'aSet']);
let bSet = new Set(['bSet', 4, 3, 2]);

// 并集
let union = new Set([...aSet, ...bSet]);                                     // Set(6) {1, 2, 3, "aSet", "bSet", 4}

// 交集
let intersect = new Set([...aSet].filter(item => bSet.has(item)));            // Set(2) {2, 3}

// 差集
let differenceA = new Set([...aSet].filter(item => !bSet.has(item)));         // Set(2) {1, "aSet"}    以 aSet为主体,和 bSet求差集
let differenceB = new Set([...bSet].filter(item => !aSet.has(item)));         // Set(2) {"bSet", 4}    以 bSet为主体,和 aSet求差集

// 跟数组 直接使用filter方法异曲同工
let aArray = [1, 2, 3, 'aSet'];
let bArray = ['bSet', 4, 3, 2];
let differenceA = aArray.filter(item => !bArray.includes(item));             // [1, "aSet"]    以 aArray为主体,和 bArray求差集
let differenceB = bArray.filter(item => !aArray.includes(item));             // ["bSet", 4]    以 bArray为主体,和 aArray求差集

// 如果想在 Set实例的遍历操作中,同步改变原实例内数据,有两种方式:一种是将原 Set实例映射到一个新的数据结构(一般是数组)内,然后操作执行这个新的数据结构,最后再通过 Set构造函数将这个新的数据结构赋值给原来的 Set实例。
// 另一种是Array.from方法。
let tempSet = new Set([1, 2, 3]);
tempSet = new Set([...tempSet].map(item => item * 2));                     // Set(3) {2, 4, 6}    数组的 map方法

tempSet = new Set(Array.from(tempSet, item => item * 2));                  // Set(3) {2, 4, 6}    Array.from方法
复制代码

WeakSet 的应用

由于 WeakSet数据结构成员都是弱引用,随时都可能消失,遍历机制无法保证成员的存在,很可能刚刚遍历结束,成员就取不到了,所以WeakSet不能遍历。因此 WeakSet的一个巧妙用处,是储存 DOM节点,就算 DOM节点从文档被移除后,也不用担心会引发内存泄漏。

 

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

  1、Map结构 转为 数组结构、数组结构 转为 Map结构

    Map数据结构 转为 数组结构,比较快速的方式是:遍历方法 + 扩展运算符(...

复制代码
let testMap = new Map([
    [1, 'aaa'],
    [2, 'bbb'],
    [3, 'ccc'],
]);

// keys数组
let keysList = [...testMap.keys()];                // [1, 2, 3]

// values数组
let valuesList = [...testMap.values()];            // ["aaa", "bbb", "ccc"]

// entries数组
let entriesList = [...testMap.entries()];        // [[1, "aaa"], [2, "bbb"], [3, "ccc"]]

// 直接转为数组
let testMapList = [...testMap];                    // [[1, "aaa"], [2, "bbb"], [3, "ccc"]]

// 结合数组的 map方法、filter方法,可以对 Map实例内的成员进行遍历和过滤操作,执行方式和 Set实例一样(Map和Set一样,本身并没有map和filter方法)。
复制代码

    数组结构转为 Map数据结构,直接将该数组结构作为参数传入 Map构造函数,就可以转换为 Map数据结构

复制代码
let testMap = new Map([
    [1, 'aaa'],
    [2, 'bbb'],
    [3, 'ccc'],
]);
// 或
let tempArray = [
    [1, 'aaa'],
    [2, 'bbb'],
    [3, 'ccc'],
];
let testMap = new Map(tempArray);
复制代码

  2、Map结构 转为 对象结构、对象结构 转为 Map结构

    Map数据结构 转为 对象结构 有两种场景:1、Map实例内 所有成员的键名都是字符串,则可以全部无损地转为对象结构;2、有成员的键名是非字符串,则该键名会先被转成字符串,然后以该字符串 作为该成员在 对象结构内存储的新键名。

复制代码
// 将 Map结构 转为 对象结构
function mapToObj(map) {
    let obj = {};
    for (let [key, value] of map) {
        obj[key] = value;
    }
    return obj;
}

let testMap1 = new Map([
    ['aaa', 1],
    ['bbb', 2],
    ['ccc', 3],
]);
// console.log(testMap1);                // Map(3) {"aaa" => 1, "bbb" => 2, "ccc" => 3}

let testMap2 = new Map([
    [123, 'aaa'],
    [null, 'bbb'],
    [NaN, 'ccc'],
]);
// console.log(testMap2);                // Map(3) {123 => "aaa", null => "bbb", NaN => "ccc"}

let tempObj1 = mapToObj(testMap1);      // {aaa: 1, bbb: 2, ccc: 3}
let tempObj2 = mapToObj(testMap2);        // {123: "aaa", null: "bbb", NaN: "ccc"}
console.log(tempObj2[null]);              // bbb
console.log(tempObj2['null']);            // bbb    证明在进行转换时,是先将 null对象 转成 字符串null,再以'null'作为该成员在 对象结构内存储的新键名
console.log(tempObj2[NaN]);               // ccc
console.log(tempObj2['NaN']);             // ccc
复制代码

    对象结构 转为 Map数据结构:可以通过 Object.entries()方法,也可以自行封装。

复制代码
let tempObj = {"aaa": 1, "bbb": 2};
// Object.entries()
let tempMap = new Map(Object.entries(tempObj));
console.log(tempMap);            // Map(2) {"aaa" => 1, "bbb" => 2}

// 自行封装
function objToMap(obj) {
    let keysList = Object.keys(obj), tempMap = new Map();
    for (let key of keysList) {
        tempMap.set(key, obj[key]);
    }
    return tempMap;
}
let tempMap = objToMap(tempObj);
console.log(tempMap);            // Map(2) {"aaa" => 1, "bbb" => 2}
复制代码

  3、Map结构 转为 JSON数据、JSON数据 转为 Map结构

    Map数据结构 转为 JSON数据 也有两种场景:1、Map实例内 所有成员的键名都是字符串,则可以全部无损转为 JSON对象;2、若有成员的键名是非字符串,则和 Map数据结构 转为 对象结构 第二种场景相同,先转为对象结构,然后再将该 对象实例JSON格式化。

复制代码
// Map实例转为 JSON对象,先将 Map实例转为 对象结构,然后将对象实例 JSON格式化即可
function mapToJson(strMap) {
    let obj = {};
    for (let [key, value] of strMap) {
        obj[key] = value;
    }
    return JSON.stringify(obj);
}

let testMap = new Map([
    ['aaa', 1],
    ['bbb', 2],
    ['ccc', 3],
]);
let tempJson = mapToJson(testMap);    // {"aaa":1,"bbb":2,"ccc":3}
复制代码

  JSON数据 转为 Map数据结构:正常情况下,JSON数据所有键名都是字符串,则可以直接转为 Map数据结构。

复制代码
// 先将 JSON字符串 转成 JSON对象,然后将 对象实例转为 Map数据结构即可
function jsonToMap(obj) {
    let tempObj = JSON.parse(obj), keysList = Object.keys(tempObj), tempMap = new Map();
    for (let key of keysList) {
        tempMap.set(key, tempObj[key]);
    }
    return tempMap;
}

let tempJson = '{"aaa": 1, "bbb": 2, "ccc": 3}';
let tempMap = jsonToMap(tempJson);        // Map(3) {"aaa" => 1, "bbb" => 2, "ccc" => 3}
复制代码

Map 的克隆和合并

复制代码
// 克隆
let tempMap1 = new Map([
    ['aaa', 1],
    ['bbb', 2],
    ['ccc', 3]
]);
let tempMap2 = new Map(tempMap1);         // Map(3) {"aaa" => 1, "bbb" => 2, "ccc" => 3}
console.log(tempMap1 === tempMap2);       // false    证明克隆是 Map实例复制,不是引用地址复制
tempMap2.set('aaa', 123);
tempMap2.set('ddd', 'test');
console.log(tempMap1);                    // Map(3) {"aaa" => 1, "bbb" => 2, "ccc" => 3}
console.log(tempMap2);                    // Map(4) {"aaa" => 123, "bbb" => 2, "ccc" => 3, "ddd" => "test"}    两个 Map实例各自独立存在,互不影响

// 合并,如果实例内有重复且恒等的键名,则后面实例内的键值会覆盖前面实例内的键值
let tempMap3 = new Map([...tempMap1, ...tempMap2]);
console.log(tempMap3);                    // Map(4) {"aaa" => 123, "bbb" => 2, "ccc" => 3, "ddd" => "test"}
复制代码

WeakMap

WeakMap 弱引用的只是键名,而不是键值,键值依然是正常引用。

复制代码
let tempKey = {'aaa': 123};
let tempObj = 'ddd';
let testWeakMap = new WeakMap();
testWeakMap.set(tempKey, tempObj);

tempObj = null;
testWeakMap.get(tempKey);            // 'ddd'
// 键值tempObj 是正常引用,即使 WeakMap实例外部取消了对 tempObj的引用,WeakMap实例内部的引用依然存在。


转发 https://www.cnblogs.com/donghuang/p/12405005.html
posted @ 2020-03-08 00:01  前端老鸟  阅读(142)  评论(0编辑  收藏  举报