← Назад к вопросам

Что такое Map?

1.0 Junior🔥 211 комментариев
#Node.js и JavaScript#Алгоритмы и структуры данных

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Map в JavaScript/TypeScript — структура данных и применение

Map — это встроенная структура данных в JavaScript, которая позволяет хранить пары ключ-значение. Это мощный инструмент, особенно полезный в Node.js разработке.

Что такое Map?

Map — это упорядоченная коллекция пар [ключ, значение], где ключ и значение могут быть любого типа. В отличие от обычного объекта, Map имеет много преимуществ.

const map = new Map();
const map2 = new Map([['key1', 'value1'], ['key2', 'value2']]);
const userMap: Map<string, User> = new Map();

Основные методы Map

1. set() — добавление/обновление

map.set('count', 1).set('b', 2);

2. get() — получение значения

const value = map.get('count'); // 1

3. has() — проверка наличия ключа

if (map.has('count')) { ... }

4. delete() — удаление элемента

map.delete('count'); // true

5. clear() — очистка Map

map.clear();

6. size — количество элементов

console.log(map.size);

7. Итерация

for (const [key, value] of map.entries()) { ... }
for (const key of map.keys()) { ... }
for (const value of map.values()) { ... }
map.forEach((value, key) => { ... });

Map vs Object — сравнение

// ✅ Map — ключи любого типа
const mapWithObjKey = new Map();
const key = { id: 1 };
mapWithObjKey.set(key, 'value');

// ❌ Object — только строки и символы
const obj = {};
obj[{ id: 1 }] = 'value'; // Преобразует в "[object Object]"

// ✅ Map — итерация в порядке добавления
const map = new Map([['a', 1], ['b', 2]]);

// ✅ Map — встроенные методы
map.size;
map.has('a');
map.clear();

Практические примеры использования Map

1. Кеширование данных

@Injectable()
export class CacheService {
  private cache: Map<string, { value: any; expiresAt: number }> = new Map();
  
  set(key: string, value: any, ttlSeconds: number = 60) {
    this.cache.set(key, {
      value,
      expiresAt: Date.now() + ttlSeconds * 1000,
    });
  }
  
  get(key: string): any | null {
    const cached = this.cache.get(key);
    if (!cached) return null;
    
    if (Date.now() > cached.expiresAt) {
      this.cache.delete(key);
      return null;
    }
    
    return cached.value;
  }
}

2. Подсчёт частоты элементов

function countFrequency(arr: string[]): Map<string, number> {
  const frequency = new Map<string, number>();
  
  for (const item of arr) {
    frequency.set(item, (frequency.get(item) ?? 0) + 1);
  }
  
  return frequency;
}

const result = countFrequency(['apple', 'banana', 'apple']);
// Map { 'apple' => 2, 'banana' => 1 }

3. Управление зависимостями (DI контейнер)

@Injectable()
export class ServiceContainer {
  private services: Map<string | symbol, any> = new Map();
  private singletons: Map<string | symbol, any> = new Map();
  
  register(key: string | symbol, factory: () => any, singleton = false) {
    this.services.set(key, { factory, singleton });
  }
  
  resolve(key: string | symbol): any {
    const service = this.services.get(key);
    if (!service) throw new Error(`Service not found`);
    
    if (service.singleton) {
      if (!this.singletons.has(key)) {
        this.singletons.set(key, service.factory());
      }
      return this.singletons.get(key);
    }
    
    return service.factory();
  }
}

4. Группировка данных

interface User {
  id: number;
  role: 'admin' | 'user';
  name: string;
}

function groupUsersByRole(users: User[]): Map<string, User[]> {
  const grouped = new Map<string, User[]>();
  
  for (const user of users) {
    if (!grouped.has(user.role)) {
      grouped.set(user.role, []);
    }
    grouped.get(user.role)!.push(user);
  }
  
  return grouped;
}

5. Отслеживание активных сессий

@Injectable()
export class SessionService {
  private sessions: Map<string, Session> = new Map();
  
  createSession(userId: string, data: any): string {
    const sessionId = generateUUID();
    this.sessions.set(sessionId, {
      userId,
      data,
      createdAt: new Date(),
      lastActivityAt: new Date(),
    });
    return sessionId;
  }
  
  getSession(sessionId: string): Session | null {
    return this.sessions.get(sessionId) ?? null;
  }
  
  deleteSession(sessionId: string): void {
    this.sessions.delete(sessionId);
  }
  
  cleanupExpiredSessions(maxAgeMinutes: number = 30): void {
    const now = new Date();
    for (const [sessionId, session] of this.sessions) {
      const ageMinutes = (now.getTime() - session.lastActivityAt.getTime()) / (1000 * 60);
      if (ageMinutes > maxAgeMinutes) {
        this.sessions.delete(sessionId);
      }
    }
  }
}

6. WeakMap для приватных данных

class User {
  private privateData: WeakMap<User, any> = new WeakMap();
  
  setPrivate(key: any) {
    this.privateData.set(this, key);
  }
  
  getPrivate() {
    return this.privateData.get(this);
  }
}

Производительность Map vs Object

Для больших наборов данных Map часто быстрее благодаря оптимизированной работе движка JavaScript.

Выводы

Map — это мощная структура данных, которая превосходит обычные объекты по гибкости. Основные преимущества:

  • Ключи любого типа (не только строки)
  • Гарантированный порядок элементов
  • Встроенные методы (set, get, has, delete, clear, size)
  • Лучшая производительность для больших наборов данных

Map широко используется для кеширования, группировки данных, управления состоянием, отслеживания сессий и в DI контейнерах. Это один из основных инструментов опытного Node.js разработчика.