ES6之 Map、Set 和 WeakMap、WeakSet

52 篇文章 8 订阅
21 篇文章 1 订阅


Map 和 Set 是 ES6 标准新增的数据结构,它们分别提供了键值对和唯一值的集合。


Map

Map是一组键值对的结构,具有极快的查找速度。

Map 对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者原始值)都可以作为一个键或一个值。

特点

  • 键值对集合
  • 键的顺序与插入顺序相同
  • 键可以是任何类型(对象、基本类型)
  • 键是唯一的

如果要实现一个“名字”-“年龄”的对照表,直接根据名字查找年龄,无论这个表有多大,查找速度都不会变慢

用JavaScript写一个Map如下:

let person = new Map([['张三', 20], ['李四', 22], ['王五', 24]]);

person.get('张三'); // 20

用法

let m = new Map(); // 空Map

// 设置键值对  
m.set('aaa', 111); 
m.set('bbb', 222);

// 检查键是否存在  
m.has('aaa'); // true

// 获取值 
m.get('aaa'); // 111

// 删除键值对  
m.delete('aaa'); // 'aaa'
m.get('aaa'); // undefined

// 由于一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值覆盖掉:
m.set('bbb', 333);
m.get('bbb'); // 333

// 获取大小  
console.log(m.size); // 1

// 遍历Map  
for (let [key, value] of m) {  
  console.log(key, value);  // bbb, 333
}

// 清除所有键值对
m.clear();  
console.log(m.size); // 0
m.has('bbb'); // false

举例

const userMap = new Map();  
userMap.set('Alice', { age: 25, country: 'USA' });  
userMap.set('Bob', { age: 30, country: 'Canada' });  
  
for (let [name, info] of userMap) {  
  console.log(`${name} is ${info.age} years old and from ${info.country}.`);  
}

注意

  • 当使用对象作为键时,JavaScript 会在内部使用对象的引用而不是对象的值。
    因此,即使两个对象的内容相同,它们也会被视为不同的键。

  • Map 的迭代顺序是插入顺序。

Map与Object

  • 存储方式:
    Map使用键值对的方式存储数据,其中键和值可以是任何类型,且键必须是唯一的。
    Object也使用键值对的方式存储数据,但其键通常是字符串或Symbol类型。

  • 排序:
    Map保持插入顺序,因此迭代时元素会按照插入的顺序出现。
    Object不保证属性的顺序。

  • 性能:
    当键是简单类型时,Object的键查找速度可能更快。
    但对于复杂类型或需要排序的场景,Map可能更有优势。

  • 使用场景:
    Map适用于需要存储键值对,且键类型多样或需要保持插入顺序的场景。
    Object更常用于表示具有属性的对象或数据结构。


Set

Set 和 Map 类似,也是一组 key 的集合,但不存储 value 。由于 key 不能重复,所以,在 Set 中,没有重复的 key。

Set 对象是一种值的集合,它的值都是唯一的,没有重复的值

特点

  • 值的集合
  • 值是唯一的,没有重复
  • 插入顺序是保持的(在某些实现中)

用法

要创建一个Set,需要提供一个Array作为输入,或者直接创建一个空Set:

var s1 = new Set(); // 空Set
var s2 = new Set([1, 2, 3]); // 含1, 2, 3

// 重复元素在Set中自动被过滤
var s = new Set([1, 2, 3, 3, '3']);
console.log(s); // Set {1, 2, 3, "3"}         注意数字`3`和字符串`'3'`是不同的元素

// 添加元素到 Set 中,可以重复添加,但不会有效果
s.add(4);
console.log(s); // Set {1, 2, 3, 4}
s.add(4);
console.log(s); // 仍然是 Set {1, 2, 3, 4}

// 删除元素
var s = new Set([1, 2, 3]);
console.log(s); // Set {1, 2, 3}
s.delete(3);
console.log(s); // Set {1, 2}

// 检查值是否存在
console.log(s.has(2)); // true 

// 获取大小
console.log(s.size);  // 2

// 遍历Set  
for (let value of s) {  
  console.log(value);  
}

// 清除所有元素
s.clear();  
console.log(s.size); // 0
s.has(1); // false

举例

由于key不能重复,所以常用作数组去重

var s = new Set([1, 2, 2, 3, 'x', 4, 3, 2, 1, 'x']);

// ES6拓展运算符
console.log([...s]); // [1, 2, 3, "x", 4]
// or
console.log(Array.from(s)); // [1, 2, 3, "x", 4]

注意

  • Set 中的值必须是唯一的。尝试添加重复的值不会有任何效果。

  • 在某些JavaScript引擎中(如V8),Set 的迭代顺序是插入顺序,但这并不是ECMAScript规范的要求。如果需要保证顺序,应使用其他方法,如数组。

  • 与 Map 一样,当使用对象作为 Set 的值时,对象的引用被用作唯一性的判断标准,而不是对象的内容。

Set与Array

  • 存储方式:
    Set是一个值的集合,它的成员值都是唯一的,没有重复的值。
    Array则是一个有序的元素序列,可以存储重复的值。

  • 排序:
    Set不保证元素的顺序。
    Array中的元素是有序的。

  • 操作方法:
    Set提供了一些特有的方法,如add()添加元素、delete()删除元素、has()检查元素是否存在等。
    Array则具有更多的操作方法,如push()、pop()、shift()、unshift()等用于添加和删除元素,以及sort()、reverse()等用于修改元素顺序。

  • 使用场景:
    Set适用于需要存储一组唯一值,且不关心顺序的场景。
    Array则更常用于存储和处理有序的数据集合。


总之,Map 和 Set 提供了对键值对和唯一值集合的有效管理,是JavaScript中非常有用的数据结构。



WeakMap

WeakMap是一个键值对的集合,其中的键是弱引用的。

这意味着,当键所指向的对象没有其他引用时,它会被垃圾回收器自动回收,同时WeakMap中对应的键值对也会被移除。

特点

  • 键只能是对象,不能是原始值(如字符串、数字等)。
  • 键是弱引用,会被垃圾回收
  • 键值对是不可枚举的,不能使用常规的遍历方法。
  • 可以有效防止内存泄漏。

用法

const wm = new WeakMap();  

let obj1 = { name: 'John' };  
let obj2 = { name: 'Jane' };  

// 设置键值对   key必须是对象,value可以是任意类型。如果key已经存在,则更新其对应的value。
wm.set(obj1, 10);  
wm.set(obj2, 20);  

// 获取值
wm.get(obj1); // 10  
wm.get(obj2); // 20  
wm.get({ name: 'Json' }) // undefined    如果key不存在,则返回undefined

// 检查键是否存在  
wm.has(obj1); // true
wm.has({ name: 'John' }) // false

// 删除键值对    如果删除成功,返回true;如果key不存在,返回false。
wm.delete(obj2); // 返回 true
wm.get(obj2); // undefined

obj1 = null; // 释放对obj1的引用   obj1将被垃圾回收,wm中对应的键值对也会被移除  
wm.get(obj1); // undefined

注意

  • 由于WeakMap的键是弱引用,因此不应该依赖于键的持久存在。
  • WeakMap不支持遍历,如果需要遍历,请考虑使用常规的Map。

WeakSet

WeakSet是一个值的集合,其中的值是弱引用的。
这意味着,当集合中的某个值没有其他引用时,它会被垃圾回收器自动回收

特点

  • 成员只能是对象,不能是原始值(如字符串、数字等)。
  • 成员是弱引用,会被垃圾回收。
  • 不支持遍历,也没有size属性。

用法

const ws = new WeakSet();  

let obj1 = { name: 'Alice' };  
let obj2 = { name: 'Bob' };  

// 设置一个新的对象   如果添加成功,返回WeakSet本身;如果value已经存在,则不会重复添加。
ws.add(obj1);  
ws.add(obj2);  

// 检查键是否存在  
ws.has(obj1); // true  
ws.has({ name: 'Alice' });  // false

// 删除     如果删除成功,返回true;如果value不存在,返回false。
ws.delete(obj2); // true  
ws.has(obj2);  // false

obj1 = null; // 释放对obj1的引用  
// obj1将被垃圾回收,ws中对应的值也会被移除  
ws.has(obj1); // false

注意

  • WeakSet主要用于存储对象,并且这些对象在其他地方没有强引用。

  • 由于WeakSet不支持遍历,因此不应用于需要频繁访问或修改集合成员的场景。

总的来说,WeakMap和WeakSet在处理垃圾回收和内存管理方面提供了更灵活的方式,特别适用于需要存储临时数据或避免内存泄漏的场景。但是,由于它们的特殊性质(如不支持遍历),使用时需要特别注意。


总结

Map、WeakMap、Set和WeakSet都是JavaScript中用于存储数据的结构,但它们之间存在一些关键的区别。

  • Map和Set都是普通的键值对或值的集合。

    Map是一个键值对的集合,其中的键和值可以是任何类型的对象,且键是唯一的。Map允许你通过键来存储和检索值,因此可以通过get方法获取值。同时,Map的键值对可以通过迭代器进行遍历。

    Set则是一个值的集合,它的值也是唯一的,因此可以用于数组去重。Set中的元素不可重复且会自动排序。

  • WeakMap和WeakSet是Map和Set的“弱”版本。它们的主要区别在于它们对对象的引用方式。

    在WeakMap中,键对对象的引用是弱引用,这意味着如果一个对象只被WeakMap引用,那么这个对象可以被垃圾回收。这有助于防止因长时间持有对象引用而导致的内存泄漏。另外,WeakMap的键是不可遍历的,因此它常被用来保存对象的私有数据。

    WeakSet只能存储对象,且这些对象也是弱引用关联的,即如果没有其他引用指向该对象,则该对象会被垃圾回收。但WeakSet的一个主要限制是它没有迭代器,因此不能遍历其中的元素。

总的来说,Map和Set提供了强大的键值对或值集合的存储和检索能力,而WeakMap和WeakSet则提供了对对象进行弱引用的机制,有助于更有效地管理内存和数据的私有性。选择使用哪种结构取决于你的具体需求,比如是否需要存储键值对、是否需要弱引用、是否需要遍历等。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

猫老板的豆

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

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

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

打赏作者

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

抵扣说明:

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

余额充值