Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между Set и Map в JavaScript
Set и Map - это две важные коллекции данных в современном JavaScript, введенные в стандарт ES6. Хотя они похожи по структуре, они служат разным целям и имеют существенные различия. Давайте разберемся в деталях.
Set
Set - это коллекция уникальных значений. Каждое значение может появиться в Set только один раз.
// Создание Set
const numbers = new Set([1, 2, 3, 3, 4, 4, 5]);
console.log(numbers); // Set { 1, 2, 3, 4, 5 }
// Дубликаты автоматически удалены
const fruits = new Set();
fruits.add("яблоко");
fruits.add("банан");
fruits.add("яблоко"); // Не добавится, уже есть
console.log(fruits); // Set { яблоко, банан }
console.log(fruits.size); // 2
Характеристики Set
1. Хранит только значения
const set = new Set();
set.add("значение");
// Set хранит только значение, без ключа
2. Значения должны быть уникальными
const set = new Set([1, 2, 2, 3, 3, 3]);
console.log(set.size); // 3, а не 6
// Дубликаты игнорируются
3. Сравнение по значению (строгое сравнение)
const set = new Set();
set.add(1);
set.add("1");
console.log(set.size); // 2, так как 1 !== "1" (разные типы)
const obj1 = { id: 1 };
const obj2 = { id: 1 };
const set2 = new Set([obj1, obj2]);
console.log(set2.size); // 2, так как это разные объекты
4. Методы Set
const set = new Set([1, 2, 3]);
// add(value) - добавить элемент
set.add(4);
// has(value) - проверить наличие
console.log(set.has(2)); // true
// delete(value) - удалить элемент
set.delete(2);
console.log(set.has(2)); // false
// clear() - очистить все элементы
set.clear();
console.log(set.size); // 0
// Итерация
for (const value of set) {
console.log(value);
}
Map
Map - это коллекция пар ключ-значение. Похож на объект, но с дополнительными возможностями.
// Создание Map
const userMap = new Map();
userMap.set("user1", { name: "Иван", age: 30 });
userMap.set("user2", { name: "Мария", age: 25 });
console.log(userMap);
// Map {
// user1 => { name: Иван, age: 30 },
// user2 => { name: Мария, age: 25 }
// }
console.log(userMap.size); // 2
Характеристики Map
1. Хранит пары ключ-значение
const map = new Map();
map.set("name", "Иван");
map.set("age", 30);
map.set("city", "Москва");
// Каждый ключ связан с значением
2. Ключ может быть любого типа
const map = new Map();
// String как ключ
map.set("name", "Иван");
// Number как ключ
map.set(1, "первый");
// Object как ключ (!)
const obj = { id: 1 };
map.set(obj, "значение");
// Function как ключ
const func = () => {};
map.set(func, "функция");
console.log(map.size); // 4
3. Это очень важное отличие от объектов!
// С объектом
const obj = {};
obj[{ id: 1 }] = "значение1";
obj[{ id: 1 }] = "значение2"; // Перезапишет
console.log(Object.keys(obj)); // ["[object Object]"] - потеря информации
// С Map
const map = new Map();
const key1 = { id: 1 };
const key2 = { id: 1 };
map.set(key1, "значение1");
map.set(key2, "значение2"); // Оба сохранены!
console.log(map.size); // 2
4. Методы Map
const map = new Map();
map.set("a", 1);
map.set("b", 2);
map.set("c", 3);
// get(key) - получить значение
console.log(map.get("a")); // 1
// has(key) - проверить наличие ключа
console.log(map.has("b")); // true
// delete(key) - удалить пару
map.delete("b");
// clear() - очистить все
map.clear();
// Итерация по ключам
for (const key of map.keys()) {
console.log(key);
}
// Итерация по значениям
for (const value of map.values()) {
console.log(value);
}
// Итерация по парам
for (const [key, value] of map.entries()) {
console.log(key, value);
}
Сравнительная таблица
| Характеристика | Set | Map |
|---|---|---|
| Хранит | Значения | Пары ключ-значение |
| Уникальность | Значения уникальны | Ключи уникальны |
| Тип ключа | N/A | Любой тип |
| Методы | add, has, delete, clear | set, get, has, delete, clear |
| Итерация | for...of, forEach | for...of, forEach |
| Размер | .size | .size |
| Приоритет использования | Уникальные значения | Связанные данные |
Практические примеры
Пример 1: Set для удаления дубликатов
// Задача: удалить дубликаты из массива
const numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5];
const unique = [...new Set(numbers)];
console.log(unique); // [1, 2, 3, 4, 5]
// Работает с любыми типами
const words = ["яблоко", "банан", "яблоко", "груша"];
const uniqueWords = [...new Set(words)];
console.log(uniqueWords); // [яблоко, банан, груша]
Пример 2: Set для проверки членства
// Вместо: array.includes() который O(n)
const allowedRoles = ["admin", "moderator", "user"];
function checkOld(role) {
return allowedRoles.includes(role); // O(n)
}
// Используем Set - O(1)
const allowedRolesSet = new Set(allowedRoles);
function checkNew(role) {
return allowedRolesSet.has(role); // O(1), намного быстрее
}
// На миллионе элементов разница ощутима
Пример 3: Set для отслеживания посещений
class WebsiteAnalytics {
constructor() {
this.visitedUsers = new Set();
}
trackVisit(userId) {
this.visitedUsers.add(userId);
}
getUniqueVisitors() {
return this.visitedUsers.size;
}
hasVisited(userId) {
return this.visitedUsers.has(userId);
}
}
const analytics = new WebsiteAnalytics();
analytics.trackVisit("user1");
analytics.trackVisit("user2");
analytics.trackVisit("user1"); // Не считается дважды
console.log(analytics.getUniqueVisitors()); // 2
Пример 4: Map для кэширования
class UserService {
constructor() {
this.cache = new Map();
}
getUser(userId) {
// Проверяем кэш
if (this.cache.has(userId)) {
console.log("Из кэша");
return this.cache.get(userId);
}
// Получаем из БД
const user = this.fetchFromDB(userId);
// Сохраняем в кэш
this.cache.set(userId, user);
return user;
}
fetchFromDB(userId) {
// Имитация запроса к БД
return { id: userId, name: "Иван" };
}
}
const service = new UserService();
console.log(service.getUser(1)); // Из БД
console.log(service.getUser(1)); // Из кэша
Пример 5: Map для связей один-ко-многим
const groupMembers = new Map();
// Группа "frontend"
groupMembers.set("frontend", new Set(["Иван", "Мария", "Петр"]));
// Группа "backend"
groupMembers.set("backend", new Set(["Сергей", "Анна"]));
// Получить всех членов группы
console.log(groupMembers.get("frontend")); // Set { Иван, Мария, Петр }
// Проверить членство
const frontendMembers = groupMembers.get("frontend");
console.log(frontendMembers.has("Иван")); // true
// Добавить нового члена
frontendMembers.add("Александр");
Пример 6: Map для графов
class Graph {
constructor() {
this.adjacencyList = new Map();
}
addVertex(vertex) {
if (!this.adjacencyList.has(vertex)) {
this.adjacencyList.set(vertex, new Set());
}
}
addEdge(vertex1, vertex2) {
this.addVertex(vertex1);
this.addVertex(vertex2);
this.adjacencyList.get(vertex1).add(vertex2);
this.adjacencyList.get(vertex2).add(vertex1);
}
getConnections(vertex) {
return this.adjacencyList.get(vertex);
}
}
const graph = new Graph();
graph.addEdge("A", "B");
graph.addEdge("B", "C");
graph.addEdge("A", "C");
console.log(graph.getConnections("A")); // Set { B, C }
Когда использовать Set
- Нужны уникальные значения
- Нужна быстрая проверка membershipа - O(1)
- Нужно удалять дубликаты из массива
- Отслеживание посещений, событий
- Реализация множеств (union, intersection)
Когда использовать Map
- Нужны связи ключ-значение
- Ключи - не только строки (объекты, функции)
- Нужно хранить мета-информацию о элементах
- Кэширование данных
- Реализация графов, деревьев, таблиц
Производительность
// Set: проверка membershipа
const set = new Set(Array.from({length: 1000000}, (_, i) => i));
console.time("Set has");
set.has(500000);
console.timeEnd("Set has"); // ~0.1ms - O(1)
// Array: проверка membershipа
const arr = Array.from({length: 1000000}, (_, i) => i);
console.time("Array includes");
arr.includes(500000);
console.timeEnd("Array includes"); // ~2-5ms - O(n)
// Set намного быстрее для больших коллекций!
Заключение
Set - это коллекция уникальных значений, идеальная для удаления дубликатов и быстрой проверки membershipа.
Map - это коллекция пар ключ-значение, идеальная для связи данных и кэширования.
Выбирай Set, когда нужны только значения. Выбирай Map, когда нужны связи между данными. Комбинируй их для сложных структур данных.