Set和Map 数据结构

  • SetMap是数据结构,不是数据类型

    • 引入数学上集合的概念:集合的三个性质——确定性、互异性、无序性
      • SetMap算是一个集合,但是他们是有序的,只满足集合的确定性和互异性

        Set

        Set的介绍

  • ES6 提供了新的数据结构 Set。它类似于数组,但Set里的值都是唯一的

    • Set本身是一个构造函数,用来生成 Set 数据结构
  • Set的实例(myset)的属性和方法
    • 属性
      • myset.size:返回 Set 结构的成员总数
    • 方法
      • myset.add(val):添加某个值,返回 Set 结构本身
      • myset.delete(val):删除某个值,返回一个布尔值,表示删除是否成功
      • myset.has(val):返回一个布尔值,表示该值是否为Set的成员
      • myset.clear():清除所有成员,没有返回值
      • myset.forEach((val, key, set) => {}):使用回调函数遍历每个成员
        • 第一二个的参数val 和 key是一样的,set是set集合本身
      • myset.keys():返回键名的遍历器
      • myset.values():返回键值的遍历器
      • myset.entries():返回键值对的遍历器 ```javascript // 案例一 const myset = new Set();

let s1 = Symbol();

// 增加元素 myset.add(1); myset.add(1); // 重复了,自动过滤 myset.add({}).add(s1); console.log(myset.size); // 3

// 删除元素 myset.delete(1); console.log(myset.has(s1)); // true

// 清空元素 myset.clear();

  1. ```javascript
  2. // 案例二:new Set() 如何传参
  3. // 参数是带有[Symbol.iterator]属性的对象即可
  4. let s1 = new Set([4, 5, 6]);
  5. let s2 = new Set(document.childNodes);
  6. (function () {
  7. let s3 = new Set(arguments);
  8. })(4, 5, 6)
  1. // 案例三:关于set的遍历
  2. let set = new Set(['red', 'green', 'blue']);
  3. for (let item of set.keys()) {
  4. console.log(item);
  5. }
  6. // red
  7. // green
  8. // blue
  9. for (let item of set.values()) {
  10. console.log(item);
  11. }
  12. // red
  13. // green
  14. // blue
  15. for (let item of set.entries()) {
  16. console.log(item);
  17. }
  18. // ["red", "red"]
  19. // ["green", "green"]
  20. // ["blue", "blue"]
  21. // Set 结构的实例默认可遍历,它的默认遍历器生成函数就是它的values方法
  22. Set.prototype[Symbol.iterator] === Set.prototype.values // true
  23. // 所以有
  24. for (let item of set) {
  25. console.log(item)
  26. }
  27. // red
  28. // green
  29. // blue

Set的简单应用

  1. // 数组去重
  2. let arr = [1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 7];
  3. arr = [...new Set(arr)]; // [1,2,3,4,5,6,7]
  4. // 实现交、并、差
  5. let a = new Set([1, 2, 3]);
  6. let b = new Set([4, 3, 2]);
  7. // 交集
  8. let intersect = new Set([...a].filter(item => b.has(item)))
  9. // 并集
  10. let union = new Set([...a, ...b]);
  11. // (a 相对于 b 的)差集
  12. let difference = new Set([...a].filter(item => !b.has(item)))

WeakSet

  • WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别
    • WeakSet 的成员只能是对象,不能是其他类型的值
    • WeakSet 中的对象(非值类型)都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用
  • WeakSet的实例(myweakSet)的属性和方法
    • 属性
      • myweakSet没有myweakSet.size这个属性
    • 方法
      • myweakSet.add(val):添加某个值,返回 Set 结构本身
      • myweakSet.delete(val):删除某个值,返回一个布尔值,表示删除是否成功
      • myweakSet.has(val):返回一个布尔值,表示该值是否为Set的成员
    • 应用
      • WeakSet 的一个用处,是储存 DOM 节点,而不用担心这些节点从文档移除时,会引发内存泄漏 ```javascript // 案例一:成员只能是对象 let myweakSet = new WeakSet(); let arr = [1, 2, 3]; let obj = { name: ‘foo’ }; let str2 = new String(‘good’); myweakSet.add(arr); // 通过 myweakSet.add(obj); // 通过 myweakSet.add(str1); // 报错 myweakSet.add(str2); // 通过

myweakSet.delete(arr)

console.log(myweakSet);

  1. ```javascript
  2. // 案例二:弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用
  3. let myweakSet = new WeakSet();
  4. myweakSet.add([1, 2, 3]);
  5. myweakSet.add({ name: 'foo' });
  6. myweakSet.add(new String('good'));
  7. console.log(myweakSet); // 空的Set。[[Entries]]里面什么都没有
  8. /**
  9. * 由于[1, 2, 3]、{ name: 'foo' }、new String('good')
  10. * 没有像案例一,赋值给一个变量,没有被某个变量引用
  11. * 执行完add函数后,由于没有被变量引用。浏览器的垃圾回收机制又不考虑WeakSet的引用
  12. * 根据浏览器的垃圾回收机制,内存被回收了
  13. * 所以myweakSet里面的东西,就找不到了
  14. */

Map

Map的介绍

  • ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键
    • 如果需要“键值对”的数据结构,Map 比 Object 更合适
  • Map的实例(myMap)的属性和方法
    • 属性
      • myMap.size:返回 Map 结构的成员总数
    • 方法
      • myMap.set(key,value):该方法设置键名key对应的键值为value,然后返回整个 Map 结构
        • 如果key已经有值,则键值会被更新,否则就新生成该键
      • myMap.get(key):该方法读取key对应的键值,如果找不到key,返回undefined
      • myMap.has(key):该方法返回一个布尔值,表示某个键是否在当前 Map 对象之中
      • myMap.delete(key):该方法删除某个键,返回true。如果删除失败,返回false
      • myMap.clear():该方法清除所有成员,没有返回值
      • myMap.keys():返回键名的遍历器
      • myMap.values():返回键值的遍历器
      • myMap.entries():返回所有成员的遍历器
      • myMap.forEach():遍历 Map 的所有成员 ```javascript // 案例一 let myMap = new Map();

let obj = { name: 2 }; let sym = Symbol(); // 添加键值对 myMap.set(‘good’, true) myMap.set(obj, { age: 18 }).set(sym, 456);

// 获取key对应value myMap.get(sym); // 456

// 判断是否含有obj这个key myMap.has(obj); // true

// 找到对应的key,删除key-value myMap.delete(sym); // true

console.log(myMap.size); // 2

// 清空所有成员 myMap.clear();

console.log(myMap.size); // 0

  1. ```javascript
  2. // 案例二:new Map() 如何传参
  3. // 参数可以是任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构
  4. // 传参:数组
  5. let m1 = new Map([
  6. [{ name: 'Kery' }, { age: 18 }],
  7. [456, 'good-one'],
  8. [Symbol(), 'pointSystem']
  9. ])
  10. // 传参:set集合
  11. let set = new Set();
  12. document.head.childNodes.forEach((item, index) => set.add([index, item]))
  13. let m2 = new Map(set);
  14. // 传参:map集合
  15. let m3 = new Map(m1);
  1. // 案例三:关于Map的遍历
  2. let map = new Map([
  3. [1, 55],
  4. ['good', 123],
  5. [{}, 555]
  6. ])

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

  • Map 与 数组 ```javascript // 数组 转 Map let map = new Map([ [1, 55], [‘good’, 123], [{}, 555] ])

// Map 转 数组 let arr = […map]; // [[1, 55], [‘good, 123], [{}, 555]]

  1. - Map 对象
  2. ```javascript
  3. // 对象 转为 Map
  4. // 可以通过Object.entries()
  5. let obj = { a: 1, b: 2 };
  6. let map = new Map(Object.entries(obj));
  7. // Map 转为 对象
  8. function strMapToObj(strMap) {
  9. let obj = Object.create(null);
  10. for (let [k,v] of strMap) {
  11. obj[k] = v;
  12. }
  13. return obj;
  14. }
  15. let obj2 = strMapToObj(map);
  • Map 与 JSON
    • Map 转 JSON
      • 一种情况是,Map 的键名都是字符串,这时可以选择转为对象 JSON。
      • 另一种情况是,Map 的键名有非字符串,这时可以选择转为数组 JSON
    • JSON 转 Map
      • 一种情况是,所有键名都是字符串
      • 另一种情况是,整个 JSON 就是一个数组,且每个数组成员本身,又是一个有两个成员的数组 ```javascript // JSON 转成 Map let json1 = JSON.stringify({ a: [456], b: 2 }); let json2 = JSON.stringify([[true, 123], [{ foo: 3 }, [‘abc’]]]);

function jsonToMap(json) { let tmp = JSON.parse(json); let type = Object.prototype.toString.call(tmp).slice(8, -1); let map = null; if (type === ‘Object’) { map = new Map(Object.entries(tmp)); } else if (type === ‘Array’) { map = new Map(tmp); } return map }

let map = jsonToMap(json1);

// Map 转 JSON let map1 = new Map([ [‘a’, 123], [13, { name: ‘jack’ }] ]);

let map2 = new Map([ [new Date(), 1], [{ age: 18 }, 55], [Symbol(), 66] ])

function mapToJSON(map) { let keys = […map.keys()]; let check = keys.every(key => [‘Number’, ‘String’].includes(Object.prototype.toString.call(key).slice(8, -1)) ) if (check) { let obj = Object.create(null); map.forEach((val, key) => { obj[key] = val }) return JSON.stringify(obj); } return JSON.stringify([…map]); }

let json = mapToJSON(map2); ```

WeakMap

  • WeakMap结构与Map结构类似,也是用于生成键值对的集合。但,它与**Map**有两个区别
    • WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名
    • WeakMap 中的对象(非值类型)都是弱引用,即垃圾回收机制不考虑 WeakMap 对该对象的引用
  • WeakMap的实例(myweakMap)的属性和方法
    • 属性
      • myweakMap没有myweakMap.size这个属性
    • 方法
      • myweakMap.set(key, val):添加键值对,返回 Map 结构本身
      • myweakMap.has(key):返回一个布尔值,表示该值是否为 Map的成员
      • myweakMap.get(key):返回 key 对应的值
      • myweakMap.delete(key):删除 key 那个键值对
    • 应用
      • 是储存 DOM 节点,而不用担心这些节点从文档移除时,会引发内存泄漏