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