【JavaScript】WeakMap 和 WeakSet

Map

Map 用于存储键值对。

  1. 添加属性:
    使用 Map 的 set() 方法可以向 Map 对象中添加键值对。例如:

    const map = new Map();
    map.set('key1', 'value1');
    map.set('key2', 'value2');
    

    通过二维数组快速创建 map 键值对。

     let arr = [
         [1, 2],
         [2, 3],
         [3, 4]
     ]
     let map = new Map(arr)
     console.log(map)  // Map(3) { 1 => 2, 2 => 3, 3 => 4 }
    
    map.keys()  // MapIterator { 1, 2, 3 }
    map.entries() // MapIterator { 1 => 2, 2 => 3, 3 => 4 }
    map.values()  // MapIterator { 2, 3, 4 }
    
  2. 获取属性和长度:
    使用 Map 的 get() 方法可以根据键获取对应的值。使用 Map 的 size 属性可以获取 Map 对象中键值对的数量。例如:

    const map = new Map();
    map.set('key1', 'value1');
    map.set('key2', 'value2');
    const value1 = map.get('key1'); // 获取键为 'key1' 的值
    const size = map.size; // 获取 Map 对象中键值对的数量
    
     let obj = {
         a: 1,
         b: 2,
         c: 3
     }
     console.log(Object.keys(obj).length)
    
  3. 遍历 Map 对象:
    使用 Map 的 forEach() 方法可以遍历 Map 对象的键值对。可以传入一个回调函数,对每个键值对执行相应的操作。例如:

    const map = new Map();
    map.set('key1', 'value1');
    map.set('key2', 'value2');
    map.forEach((value, key) => {
      console.log(key, value); // 打印每个键值对
    });
    
     console.log(map)  // Map(3) { 1 => 2, 2 => 3, 3 => 4 }
     for (let mapElement of map) {
         console.log(mapElement)  // [ 1, 2 ] // [ 2, 3 ] // [ 3, 4 ]
     }
    
  4. 删除属性:
    使用 Map 的 delete() 方法可以根据键删除对应的键值对。例如:

    const map = new Map();
    map.set('key1', 'value1');
    map.set('key2', 'value2');
    map.delete('key1'); // 删除键为 'key1' 的键值对
    
  5. Map 和 Object 的区别:

    • 额外的键:Map 默认情况下不包含任何键,只包含插入的键;一个 Object 有一个原型,原型链上的键名可能和自己在对象上设置的键名冲突,可以使用 Object.create(null) 创建一个没有原型的对象
    • 键的类型:Map 的键可以使用任意类型的值,包括对象、函数、NaN 等,而 Object 的键只能是 String 或 Symbol 类型。
    • 插入顺序:Map 会按照插入顺序保存键值对,而 Object 并不保证属性的顺序(无序)。
    • 迭代和大小:Map 提供了内置的迭代器和方便的方法来获取大小(使用 size 属性),而 Object 需要手动处理迭代和计算大小。
    • 性能:在需要频繁添加、删除和查找键值对的场景中,Map 的性能通常优于 Object。

WeakMap

和 Map 很相似,但会有一些差异:

  1. 引用关联和垃圾回收:WeakMap中的键是弱引用,而Map中的键是强引用。当对象(键)被垃圾回收时, Map 对象将保持引用链接,而 WeakMap 对象将丢失链接,也就是说不会被计入垃圾回收策略。WeakMap 通常⽤于缓存或元数据,当对象不再被使⽤时,WeakMap 可以⾃动清除对应的数据,避免内存泄漏。

  2. 键类型限制:在Map中,键可以是任意类型的值,包括原始类型和对象。而在WeakMap中,键只能是对象类型。这是因为WeakMap的实现依赖于对象的引用。

  3. 迭代和大小:Map提供了迭代方法,如forEach、keys、values和entries,可以使用 for … of … 遍历Map中的键值对。而WeakMap没有提供直接的迭代方法,也没有办法获取WeakMap的大小(即键值对的数量)。

  4. 并非 Map 中所有方法都支持。WeakMap 支持的方法:delete、get、has、set。

  5. 性能:由于WeakMap中的键是弱引用,它的性能可能会受到一些限制。在大规模操作时,WeakMap的性能可能会比Map略差。此外,由于WeakMap不会保留对象的引用,它对垃圾回收的支持更好,有助于避免内存泄漏。

let obj: any = {name: 'xx'} // 1
let obj1 = obj // 2
let weakMap: WeakMap<any, any> = new WeakMap()
weakMap.set(obj, 'obj') // 不计入垃圾回收机制
obj = null
obj1 = null
console.log(weakMap)
console.log(weakMap.get(obj)) // 已经没有标记 为 undefined

在这里插入图片描述

在浏览器中查看这里有一个有意思的点。上面整体打印可以有值,但是下面单独打印属性却是没有值的。这是因为 V8 的垃圾回收机制(GC),这个机制执行的时间至少需要 200ms ,所以导致我们看到的一个几乎马上就要消失的值。

Set

Set 允许存储唯一的值,无论是原始值还是对象引用。

  1. 添加元素:

    • 使用 add(value) 方法向 Set 中添加元素。和 Map 一样,也是不允许添加重复值。如果该值已经存在于 Set 中,则不会重复添加。
  2. 遍历集合:

    • Set 没有提供直接访问元素的索引,因此无法通过索引来遍历。但可以使用迭代器来遍历 Set 中的元素。
    • 使用 forEach(callbackFn, thisArg) 方法迭代 Set 中的每个元素,其中 callbackFn 是回调函数,thisArg 是可选的上下文对象。
    • 使用 for...of 循环遍历 Set 中的元素。
  3. 删除元素:

    • 使用 delete(value) 方法从 Set 中删除指定的元素。如果成功删除该元素,返回 true;如果元素不存在,则返回 false
    • 使用 clear() 方法可以清空整个 Set。
  4. 应用场景:

    • 去重:Set 中的元素是唯一的,这使得它成为去除数组中重复元素的有效工具。
    let arr = [1,3,3,4,5,6,6,6]
    let unique = [...new Set(arr)]
    console.log(unique)
    
    • 并集、交集、差集
    const setA = new Set([1, 2, 3, 4]);
    const setB = new Set([3, 4, 5, 6]);
    
    // 交集
    const intersection = new Set([...setA].filter(x => setB.has(x)));
    console.log([...intersection]);  // 输出: [3, 4]
    
    // 差集
    const difference = new Set([...setA].filter(x => !setB.has(x)));
    console.log([...difference]);  // 输出: [1, 2]
    
    // 并集
    const union = new Set([...setA, ...setB]);
    console.log([...union]);  // 输出: [1, 2, 3, 4, 5, 6]
    

需要注意的是,Set 中的元素是根据其值的唯一性进行存储和比较的,因此对于对象类型的值,它们在 Set 中被视为引用而不是值本身。这意味着两个具有相同属性和值的不同对象将被视为两个不同的元素。

以下是使用 Set 的示例代码:

const set = new Set();

set.add(1);
set.add(2);
set.add(3);

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

set.forEach((value) => {
  console.log(value);
});

// 输出:
// 1
// 2
// 3

set.delete(2);
console.log(set.has(2));  // 输出: false

set.clear();
console.log(set.size);  // 输出: 0

WeakSet

WeakSet 和 Set 区别如下:

  • WeakSet 只能储存对象引用,不能存放值,而 Set 对象都可以
  • WeakSet 对象中储存的对象值都是被弱引用的,即垃圾回收机制不考虑 WeakSet 对该对象的引用,如果没有其他的变量或者属性引用这个对象值,则这个对象将会被垃圾回收掉。(不考虑该对象还存在于 WeakSet
    中),所以 WeakSet 对象里有多少个成员元素,取决于垃圾回收机制有没有运行,运行前后成员个数可能不
    一致,遍历结束之后,有的成员可能取不到,被垃圾回收了。因此ES6规定,WeakSet对象是无法被遍历的,
    也没有办法拿到它包含的所有元素。

WeakSet 能够使用的方法如下:add(), delete(), has(), clear()

如果被垃圾回收掉,WeakSet 将丢失对内部数据的访问链接。

总结

image.png

结合 ts:

let set: Set<number> = new Set([1, 1, 2])
let map: Map<Object, number> = new Map()
map.set({name: 'xx'}, 1)
console.log(set)
console.log(map)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秀秀_heo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值