Domů O mně Služby Portfolio Učím Blog Kontakt
← Zpět na učím

04.13 Map kolekce

Výuka

Proč Map?

Map je vestavěná datová struktura pro uložení párů klíč-hodnota. Na rozdíl od obyčejných objektů může mít klíče jakéhokoliv typu (ne jen stringy) a zachovává pořadí vložení.

Proč to potřebujeme?

  • Flexibilní klíče - Klíče mohou být čísla, objekty, funkce (ne jen stringy)
  • Zachování pořadí - Páry se iterují v pořadí vložení
  • Rychlé operace - get, set, has, delete jsou rychlé (O(1))
  • Lepší API - size, clear, forEach - pohodlnější než u objektů

Představ si to jako: Slovník. Máš slova (klíče) a jejich definice (hodnoty). Na rozdíl od obyčejného objektu může být "slovo" cokoli - číslo, jiný objekt, dokonce funkce!

Jak to funguje?

Map:
1. Ukládá páry klíč  hodnota
2. Klíč může být JAKÉHOKOLIV typu (číslo, string, objekt, funkce)
3. Zachovává pořadí vložení
4. Rychlé operace: set, get, has, delete (O(1) v průměru)
5. size - počet párů (ne length!)

Klíčové koncepty

  • Map - kolekce párů klíč-hodnota
  • Libovolné klíče - klíč může být jakýkoliv typ (ne jen string!)
  • size - počet párů (ne length!)
  • Metody: set(), get(), has(), delete(), clear()
  • Iterable - můžeš iterovat přes páry, klíče nebo hodnoty
  • Zachovává pořadí - iterace v pořadí vložení

JavaScript

Příklad 1: Vytvoření Map a základní operace

// Prázdná Map
const map1 = new Map();
console.log(map1);
// → Map(0) {}

// Map s počátečními hodnotami (z pole párů)
const map2 = new Map([
  ['name', 'Alice'],
  ['age', 25],
  ['city', 'Praha']
]);
console.log(map2);
// → Map(3) {'name' => 'Alice', 'age' => 25, 'city' => 'Praha'}

// Počet párů
console.log(map2.size);
// → 3

Co se stalo?

  • new Map() - vytvoří prázdnou Map
  • new Map([[k1, v1], [k2, v2]]) - vytvoří Map z pole párů
  • size - počet párů (ne length!)

Příklad 2: set() a get() - uložení a získání hodnoty

const map = new Map();

// Ulož páry klíč-hodnota
map.set('name', 'Bob');
map.set('age', 30);
map.set('active', true);
console.log(map);
// → Map(3) {'name' => 'Bob', 'age' => 30, 'active' => true}

// Získej hodnotu podle klíče
console.log(map.get('name'));
// → Bob

console.log(map.get('age'));
// → 30

// Neexistující klíč vrátí undefined
console.log(map.get('city'));
// → undefined

// Můžeš řetězit (chaining)
map.set('x', 1).set('y', 2).set('z', 3);
console.log(map.size);
// → 6

Co se stalo?

  • set(key, value) - uloží pár (nebo aktualizuje, pokud klíč existuje)
  • get(key) - vrací hodnotu (nebo undefined)
  • Vrací Map samotnou → můžeš řetězit: map.set(...).set(...)

Příklad 3: Klíče jakéhokoliv typu (ne jen stringy!)

const map = new Map();

// String jako klíč
map.set('text', 'hodnota');

// Číslo jako klíč
map.set(42, 'odpověď na všechno');

// Boolean jako klíč
map.set(true, 'pravda');

// Objekt jako klíč (!)
const obj = { id: 1 };
map.set(obj, 'metadata');

// Funkce jako klíč (!)
const fn = () => {};
map.set(fn, 'callback');

console.log(map.get(42));         // → odpověď na všechno
console.log(map.get(obj));        // → metadata
console.log(map.get(fn));         // → callback

// ⚠️ Pozor - různé objekty se stejným obsahem jsou RŮZNÉ klíče
const obj2 = { id: 1 };
console.log(map.get(obj2));
// → undefined (obj !== obj2, různé reference!)

Co se stalo?

  • Klíče můžou být cokoli: číslo, string, boolean, objekt, funkce
  • Objekty se porovnávají podle reference, ne obsahu
  • To je hlavní výhoda Map oproti obyčejným objektům!

Příklad 4: has() a delete() - kontrola a odstranění

const map = new Map([
  ['a', 1],
  ['b', 2],
  ['c', 3]
]);

// Kontrola existence klíče
console.log(map.has('b'));
// → true

console.log(map.has('z'));
// → false

// Odstranění páru
const removed = map.delete('b');
console.log(removed);
// → true (pár byl odstraněn)

console.log(map);
// → Map(2) {'a' => 1, 'c' => 3}

// Pokus o odstranění neexistujícího klíče
const notRemoved = map.delete('z');
console.log(notRemoved);
// → false (klíč tam nebyl)

// Vymazání celé Map
map.clear();
console.log(map.size);
// → 0

Co se stalo?

  • has(key) - vrací true/false
  • delete(key) - odstraní pár, vrací true/false
  • clear() - vymaže všechny páry

Příklad 5: Iterace přes Map

const map = new Map([
  ['name', 'Alice'],
  ['age', 25],
  ['city', 'Praha']
]);

// for...of přes páry (entries)
for (const [key, value] of map) {
  console.log(`${key}: ${value}`);
}
// → name: Alice
// → age: 25
// → city: Praha

// Iterace jen přes klíče
for (const key of map.keys()) {
  console.log(key);
}
// → name
// → age
// → city

// Iterace jen přes hodnoty
for (const value of map.values()) {
  console.log(value);
}
// → Alice
// → 25
// → Praha

// forEach
map.forEach((value, key) => {
  console.log(`${key} = ${value}`);
});
// → name = Alice
// → age = 25
// → city = Praha

Co se stalo?

  • Defaultní iterace: přes páry [key, value]
  • keys() - iterátor přes klíče
  • values() - iterátor přes hodnoty
  • entries() - iterátor přes páry (stejné jako defaultní)
  • Zachovává pořadí vložení!

Příklad 6: Map vs obyčejný objekt

// Obyčejný objekt - klíče jsou VŽDY stringy
const obj = {};
obj[1] = 'hodnota';      // klíč se převede na '1'
obj[true] = 'bool';      // klíč se převede na 'true'
console.log(Object.keys(obj));
// → ['1', 'true'] (stringy!)

// Map - klíče NEJSOU převáděny na stringy
const map = new Map();
map.set(1, 'hodnota');
map.set(true, 'bool');
console.log([...map.keys()]);
// → [1, true] (původní typy!)

// Objekt - size ručně
console.log(Object.keys(obj).length);
// → 2 (musíš spočítat)

// Map - size přímo
console.log(map.size);
// → 2 (vlastnost)

// Objekt - iterace složitější
for (const key in obj) {
  console.log(`${key}: ${obj[key]}`);
}

// Map - iterace jednodušší
for (const [key, value] of map) {
  console.log(`${key}: ${value}`);
}

Co se stalo?

  • Objekt: klíče vždy stringy, složitější API
  • Map: klíče libovolného typu, lepší API
  • Kdy použít Map:
    • Potřebuješ klíče jiného typu než string
    • Často přidáváš/odstraňuješ páry
    • Záleží ti na pořadí
  • Kdy použít objekt:
    • Potřebuješ JSON (Map se neserializuje)
    • Klíče jsou známé předem (statická struktura)

TypeScript

TypeScript přidává typovou kontrolu klíčů a hodnot.

Stejné příklady s typy

// Map s typy
const map1: Map<string, number> = new Map([
  ['age', 25],
  ['score', 100]
]);

// TypeScript inferuje typ z pole
const map2 = new Map([
  ['name', 'Alice'],
  ['city', 'Praha']
]);  // Map<string, string>

// Chybová kontrola - špatný typ klíče nebo hodnoty
map1.set('count', 50);  // ✅ OK
// map1.set('count', 'text');  // ❌ Error: Argument of type 'string' is not assignable to parameter of type 'number'
// map1.set(123, 50);  // ❌ Error: Argument of type 'number' is not assignable to parameter of type 'string'

// Objekty jako klíče s interface
interface User {
  id: number;
  name: string;
}

const userMap: Map<User, string> = new Map();
const user1: User = { id: 1, name: 'Alice' };
userMap.set(user1, 'metadata');

const meta: string | undefined = userMap.get(user1);

// Generická utility funkce
function mapFromEntries<K, V>(entries: [K, V][]): Map<K, V> {
  return new Map(entries);
}

const numMap = mapFromEntries([[1, 'one'], [2, 'two']]);  // Map<number, string>

// ReadonlyMap (TypeScript 3.4+)
const readonly: ReadonlyMap<string, number> = new Map([['a', 1]]);
// readonly.set('b', 2);  // ❌ Error: Property 'set' does not exist on type 'ReadonlyMap<string, number>'
console.log(readonly.get('a'));  // ✅ OK - čtení je povoleno

TypeScript přidává:

  • Typovou kontrolu klíčů a hodnot - nemůžeš uložit špatný typ
  • Inference typů - TypeScript pozná typ z pole
  • ReadonlyMap - neměnná Map (jen čtení)
  • Generické funkce - typově bezpečné utility funkce

Rozdíl JS vs TS

JavaScript:

  • Map funguje bez typové kontroly
  • Můžeš uložit jakýkoliv typ klíče a hodnoty
  • Flexibilnější, ale nebezpečnější

TypeScript:

  • Map má definované typy klíčů a hodnot
  • TypeScript zkontroluje, že ukládáš správné typy
  • Bezpečnější, prevence chyb
// JavaScript - projde, ale matoucí
const map = new Map();
map.set('text', 123);
map.set(456, 'hodnota');  // Smíšené typy klíčů a hodnot

// TypeScript - konzistentní typy
const map: Map<string, number> = new Map();
map.set('text', 123);
// map.set(456, 'hodnota');  // ❌ Error

Tip

💡 Kdy použít Map místo objektu:

// ✅ Používej Map když:
// - Klíče nejsou stringy
// - Často přidáváš/odstraňuješ páry
// - Záleží ti na pořadí
// - Potřebuješ size property

// ✅ Používej objekt když:
// - Potřebuješ JSON (Map se neserializuje)
// - Klíče jsou známé předem
// - Struktura je statická

💡 Prevence chyb s objektovými klíči:

const map = new Map();
const key1 = { id: 1 };
const key2 = { id: 1 };

map.set(key1, 'hodnota');

// ❌ Chyba - key2 !== key1 (různé reference)
console.log(map.get(key2));  // → undefined

// ✅ Používej stejnou referenci
console.log(map.get(key1));  // → hodnota

💡 Převod Map na objekt a zpět:

// Map → objekt
const map = new Map([['a', 1], ['b', 2]]);
const obj = Object.fromEntries(map);
console.log(obj);  // → { a: 1, b: 2 }

// Objekt → Map
const obj2 = { x: 10, y: 20 };
const map2 = new Map(Object.entries(obj2));
console.log(map2);  // → Map(2) {'x' => 10, 'y' => 20}

Kvíz

Co vypíše tento kód?

const map = new Map();
map.set('a', 1);
map.set('a', 2);
map.set('b', 3);
console.log(map.size);

- - map.set('a', 1) - přidá pár 'a' => 1 (size = 1)

  • map.set('a', 2) - aktualizuje hodnotu pro klíč 'a' na 2 (size = 1, stále jen 1 pár!)
  • map.set('b', 3) - přidá pár 'b' => 3 (size = 2)
  • Finální: Map(2) {'a' => 2, 'b' => 3}

- Zapomněl jsi, že druhý set('a', 2) aktualizuje, nepřidává

- Každý set nepřidává nový pár, může aktualizovat

- Chybný výpočet

Důležité: Když set() najde existující klíč, aktualizuje hodnotu, nepřidává nový pár!

Důležité: Když set() najde existující klíč, aktualizuje hodnotu, nepřidává nový pár!

🎯 Závěrečný projekt

Po dokončení všech 8 dílů vytvoříte jednoduchou Todо aplikaci v čistém JavaScriptu. Naučíte se, jak aplikovat vše, co jste se naučili, na reálný projekt.

Zobrazit podrobnosti projektu →

Připraveni začít?

Zaregistrujte se a získejte přístup ke všem dílům tohoto seriálu

Kontaktujte mě

Informace o seriálu

Obtížnost

Délka

Cca 480 minut

Počet videí

8 videí + projekty

Certifikát

Po dokončení obdržíte certifikát


Lekce v této sekci


Struktura lekcí (souborový strom)

06. Typescript specifika
  • v přípravě
08. Moduly tridy
  • v přípravě
09. React zaklady
  • v přípravě
10. React hooks
  • v přípravě
12. Nextjs server
  • v přípravě
13. Databaze auth
  • v přípravě
14. Nextjs pokrocile
  • v přípravě