Set 和 Map 使用与介绍

172 阅读4分钟

Set 和 Map区别:

元素存储方式

Set :存储唯一的值,每个值只能出现一次,类似于一个值的集合。

Map :存储键值对,键和值可以是任何类型的值(包括对象)。

迭代方式

Set :可以通过 for...of 循环直接迭代其值。

Map :可以通过 for...of 循环迭代其键值对。

方法

Set :具有 add (添加元素)、delete (删除元素)、has (检查是否存在元素)等方法。

Map :具有 set (设置键值对)、get (获取值)、delete (删除键值对)、has (检查是否存在键)等方法。

大小获取

Set :使用 size 属性获取元素数量。

Map :使用 size 属性获取键值对数量。

键的比较

Set :判断元素是否重复是基于值的严格相等(=== )。

Map :键的比较基于 Object.is ,更准确地处理特殊值,如 NaN 。

以下是示例代码展示它们的用法:

// Set 示例
let mySet = new Set();
mySet.add(1);
mySet.add(2);
mySet.add(2); // 重复添加,不会有效果
console.log(mySet.size); 
mySet.delete(1);
console.log(mySet.has(2)); 

// Map 示例
let myMap = new Map();
myMap.set('key1', 10);
myMap.set('key2', 20);
console.log(myMap.size); 
console.log(myMap.get('key1')); 
myMap.delete('key1');
console.log(myMap.has('key2')); 

总之,Set 适合存储不重复的值集合,而 Map 适合存储键值对形式的数据。

Set 使用场景:

去重操作

当需要从一个数组或其他可迭代对象中去除重复的元素时,可以将其转换为 Set ,然后再转换回数组。

集合运算

可以方便地进行集合的并集、交集、差集等运算。

快速查找

检查一个元素是否在集合中存在的时间复杂度为 O(1),效率很高。

存储唯一的对象引用

例如,在处理一组具有唯一标识的对象时,可以使用 Set 来确保不会有重复的对象。

事件处理

存储已注册的事件处理函数,确保不会重复注册相同的函数。

缓存数据

用于缓存一些唯一的数据,以提高查找和操作的效率。

以下是一些示例代码展示上述场景的应用:

// 去重
let array = [1, 2, 2, 3, 3, 3];
let uniqueArray = Array.from(new Set(array));

// 集合运算
let setA = new Set([1, 2, 3]);
let setB = new Set([2, 3, 4]);

// 并集
let union = new Set([...setA,...setB]);

// 交集
let intersection = new Set([...setA].filter(x => setB.has(x)));

// 差集
let difference = new Set([...setA].filter(x =>!setB.has(x)));

// 快速查找
let mySet = new Set([10, 20, 30]);
console.log(mySet.has(20)); 

// 存储唯一的对象引用
let obj1 = { id: 1 };
let obj2 = { id: 2 };
let setOfObjects = new Set([obj1, obj2]);

// 事件处理
let eventHandlers = new Set();
function registerHandler(handler) {
  eventHandlers.add(handler);
}

Map 使用场景:

键值对数据存储

当需要以非字符串类型(如对象、函数等)作为键来存储和获取相关值时,Map 比使用对象作为键值对存储更合适,因为对象的键只能是字符串或符号。

缓存数据

可以将计算结果或从外部获取的数据以特定的键进行缓存,以避免重复计算或请求。

关联数据

例如,将用户 ID 与用户详细信息关联起来,通过用户 ID 快速获取用户信息。

数据转换

对一组数据进行基于键的转换和处理。

维护状态

在一些复杂的应用中,Map 可以用于维护特定的状态信息,根据不同的键来跟踪和更新相关状态。

以下是一些示例代码展示上述场景的应用:

// 键值对数据存储(使用对象作为键)
let key = { name: 'John' };
let myMap = new Map();
myMap.set(key, 25);
console.log(myMap.get(key));

// 缓存数据
let cacheMap = new Map();
function expensiveComputation(key) {
  if (!cacheMap.has(key)) {
    let result = // 复杂计算
    cacheMap.set(key, result);
  }
  return cacheMap.get(key);
}

// 关联数据
let userMap = new Map();
userMap.set(1, { name: 'Alice', age: 20 });
userMap.set(2, { name: 'Bob', age: 25 });
console.log(userMap.get(1));

// 数据转换
let data = [
  { id: 1, value: 10 },
  { id: 2, value: 20 },
  { id: 3, value: 30 }
];
let transformedMap = new Map();
data.forEach(item => transformedMap.set(item.id, item.value * 2));

// 维护状态
let stateMap = new Map();
stateMap.set('isLoading', false);
stateMap.set('errorMessage', '');

map 与 Object 的区别

键的类型

Map 的键可以是任何类型的值,包括对象、函数、基本数据类型等。

Object 的键通常被限制为字符串或符号(在 ES6 中引入)。

键的顺序

Map 会保留键值对的插入顺序。

Object 的属性顺序是不确定的,特别是在不同的浏览器和 JavaScript 引擎中可能不同。

键的唯一性

在 Map 中,键是唯一的。如果尝试设置相同的键两次,新的值将覆盖旧的值。

Object 中,如果使用相同的字符串作为属性名多次,后面的属性值会覆盖前面的。

尺寸获取

Map 可以通过 size 属性直接获取元素数量。

Object 需要手动计算属性数量。

迭代方式

Map 提供了 forEach 方法以及 entries 、keys 、values 等迭代器方法,更方便进行迭代操作。

Object 需要通过 for...in 循环来遍历属性,但这可能会遍历到继承的属性。

原生支持方法

Map 具有一些特定的方法,如 set 、get 、delete 、has 等,用于操作键值对。

Object 则通过属性访问操作符( . 和 [] )来进行类似的操作。

以下是示例代码展示它们的区别:

// Map
let myMap = new Map();
myMap.set(1, 'One');
myMap.set('two', 2);
myMap.set({ key: 'value' }, 'Object as key');

console.log(myMap.size); 

// Object
let myObject = {};
myObject[1] = 'One';
myObject['two'] = 2;
myObject[{ key: 'value' }] = 'Object as key';

// 计算对象属性数量的函数
function countProperties(obj) {
  return Object.keys(obj).length;
}

console.log(countProperties(myObject));