05.6 Spread u objektů
Výuka
Proč spread operátor?
Spread operátor ... u objektů "rozbalí" vlastnosti objektu do nového objektu. Je to moderní a elegantní způsob kopírování a spojování objektů.
Proč to potřebujeme?
- Kopírování objektu - Rychlá a čistá kopie bez mutace
- Spojování objektů - Sloučit více objektů do jednoho
- Přepsání vlastností - Aktualizuj některé vlastnosti
- Immutability - Vytvoř nový objekt místo změny originálu
Představ si to jako: Překopírování nálepek z jedné složky do druhé. Spread operátor ... vezme všechny nálepky (vlastnosti) a dá je do nové složky.
Jak to funguje?
Spread operátor u objektů (...obj):
1. "Rozbalí" vlastnosti objektu
2. { a: 1, b: 2 } → a: 1, b: 2
3. Používá se při vytváření nového objektu:
- Kopie: { ...obj }
- Spojení: { ...obj1, ...obj2 }
- Přepsání: { ...obj, key: newValue }
Klíčové koncepty
- Spread operátor
...- rozbalí vlastnosti objektu - Shallow copy - vytvoří kopii objektu (pozor u vnořených objektů!)
- Immutability - neměnný způsob práce s objekty
- Merging - spojování objektů
- Overriding - přepsání vlastností (poslední vyhrává)
- ES2018 feature - spread pro objekty od ES2018
JavaScript
Příklad 1: Kopírování objektu (shallow copy)
const original = {
name: 'Alice',
age: 25,
city: 'Praha'
};
// Kopie pomocí spread operátoru
const copy = { ...original };
console.log(copy);
// → { name: 'Alice', age: 25, city: 'Praha' }
// Je to NOVÝ objekt
console.log(copy === original);
// → false (různé objekty)
// Změna kopie neovlivní originál
copy.age = 26;
console.log(original.age); // → 25 (nezměněno)
console.log(copy.age); // → 26
Co se stalo?
{ ...original }vytvoří novou kopii objektu- Kopie je samostatný objekt (jiná reference)
- Změny v kopii neovlivní originál
- Pozor: Shallow copy - vnořené objekty se kopírují jako reference!
Příklad 2: Spojování objektů (merging)
const person = {
name: 'Bob',
age: 30
};
const contact = {
email: 'bob@example.com',
phone: '123456'
};
// Spojení dvou objektů
const user = { ...person, ...contact };
console.log(user);
// → { name: 'Bob', age: 30, email: 'bob@example.com', phone: '123456' }
// Můžeš spojit více objektů
const address = {
city: 'Brno',
zip: '60200'
};
const fullUser = { ...person, ...contact, ...address };
console.log(fullUser);
// → { name: 'Bob', age: 30, email: 'bob@example.com', phone: '123456', city: 'Brno', zip: '60200' }
Co se stalo?
{ ...obj1, ...obj2 }sloučí objekty do jednoho nového- Můžeš kombinovat více objektů
- Čitelnější než
Object.assign()
Příklad 3: Přepsání vlastností (override)
const defaults = {
theme: 'light',
fontSize: 14,
language: 'cs'
};
// Přepsání některých vlastností
const userSettings = {
...defaults,
theme: 'dark', // Přepíše theme
fontSize: 16 // Přepíše fontSize
// language zůstane 'cs'
};
console.log(userSettings);
// → { theme: 'dark', fontSize: 16, language: 'cs' }
// Pořadí záleží - poslední vyhrává
const config1 = { ...defaults, theme: 'dark' };
console.log(config1.theme); // → dark
const config2 = { theme: 'dark', ...defaults };
console.log(config2.theme); // → light (defaults přepsal dark!)
Co se stalo?
- Poslední hodnota vyhrává - pokud klíč existuje vícekrát
{ ...defaults, theme: 'dark' }-darkpřepíšelight{ theme: 'dark', ...defaults }-lightpřepíšedark- Pořadí záleží!
Příklad 4: Immutabilní update (React/Redux pattern)
const user = {
name: 'Charlie',
age: 35,
city: 'Ostrava'
};
// ❌ Mutace - mění originál
user.age = 36;
// ✅ Immutabilní update - vytvoří nový objekt
const updatedUser = { ...user, age: 36 };
console.log(user.age); // → 35 (nezměněno)
console.log(updatedUser.age); // → 36
// Praktický příklad - React state update
const state = {
user: { name: 'David', age: 40 },
isLoading: false
};
// ✅ Immutabilní update
const newState = {
...state,
isLoading: true
};
console.log(state.isLoading); // → false (originál nezměněn)
console.log(newState.isLoading); // → true
Co se stalo?
- Spread vytváří nové objekty bez mutace originálu
- Vhodné pro React/Redux (immutabilní state)
- Alternativa k mutaci objektu
Příklad 5: Shallow copy - pozor u vnořených objektů!
const user = {
name: 'Eve',
age: 28,
address: {
city: 'Praha',
zip: '11000'
}
};
// Shallow copy
const copy = { ...user };
// Změň primitivní vlastnost - OK
copy.name = 'Eva';
console.log(user.name); // → Eve (nezměněno)
console.log(copy.name); // → Eva
// Změň vnořený objekt - POZOR!
copy.address.city = 'Brno';
console.log(user.address.city); // → Brno (ZMĚNĚNO! ⚠️)
console.log(copy.address.city); // → Brno
// Důvod: address je reference (sdílená)
console.log(user.address === copy.address);
// → true (stejná reference!)
Co se stalo?
- Spread vytváří shallow copy - kopíruje jen první úroveň
- Vnořené objekty se kopírují jako reference
- Změna vnořeného objektu ovlivní originál!
Příklad 6: Deep copy - řešení pro vnořené objekty
const user = {
name: 'Frank',
age: 40,
address: {
city: 'Liberec',
zip: '46001'
}
};
// ❌ Shallow copy - vnořené objekty jsou reference
const shallowCopy = { ...user };
shallowCopy.address.city = 'Ústí nad Labem';
console.log(user.address.city); // → Ústí nad Labem (změněno!)
// ✅ Deep copy - vnořené objekty ručně
const deepCopy = {
...user,
address: { ...user.address } // Kopie vnořeného objektu
};
deepCopy.address.city = 'Plzeň';
console.log(user.address.city); // → Ústí nad Labem (nezměněno)
console.log(deepCopy.address.city); // → Plzeň
// Alternativa - JSON.parse/stringify (pozor na ztrátu funkcí!)
const jsonDeepCopy = JSON.parse(JSON.stringify(user));
jsonDeepCopy.address.city = 'Karlovy Vary';
console.log(user.address.city); // → Ústí nad Labem (nezměněno)
console.log(jsonDeepCopy.address.city); // → Karlovy Vary
Co se stalo?
- Pro deep copy musíš vnořené objekty ručně kopírovat
{ ...obj, nested: { ...obj.nested } }- kopie vnořeného objektuJSON.parse(JSON.stringify(obj))- deep copy, ale ztratíš funkce!
TypeScript
TypeScript přidává typovou kontrolu spread operátoru.
Stejné příklady s typy
// Interface pro spread
interface User {
name: string;
age: number;
city: string;
}
const user: User = {
name: 'Alice',
age: 25,
city: 'Praha'
};
// Kopie s typy
const copy: User = { ...user };
// Spojování s typy
interface Contact {
email: string;
phone: string;
}
const contact: Contact = {
email: 'alice@example.com',
phone: '123456'
};
// Spojení - TypeScript pozná nový typ
const userWithContact = { ...user, ...contact };
// Type: { name: string; age: number; city: string; email: string; phone: string }
// Přepsání s typovou kontrolou
const updated: User = {
...user,
age: 26 // ✅ OK - age je number
// age: 'twenty-six' // ❌ Error: Type 'string' is not assignable to type 'number'
};
// Partial update
function updateUser(user: User, updates: Partial<User>): User {
return { ...user, ...updates };
}
const newUser = updateUser(user, { age: 27 }); // ✅ OK
// updateUser(user, { age: 'invalid' }); // ❌ Error: Type 'string' is not assignable to type 'number'
// Readonly
interface ReadonlyUser {
readonly name: string;
readonly age: number;
}
const readonlyUser: ReadonlyUser = { name: 'Bob', age: 30 };
// Spread vytvoří nový objekt (můžeš změnit)
const mutableCopy = { ...readonlyUser };
mutableCopy.age = 31; // ✅ OK - kopie není readonly
// Nested types
interface Address {
city: string;
zip: string;
}
interface UserWithAddress {
name: string;
age: number;
address: Address;
}
const userWithAddress: UserWithAddress = {
name: 'Charlie',
age: 35,
address: { city: 'Brno', zip: '60200' }
};
// Deep copy s typy
const deepCopy: UserWithAddress = {
...userWithAddress,
address: { ...userWithAddress.address }
};
TypeScript přidává:
- ✅ Typovou kontrolu - spread musí odpovídat typu
- ✅ Inference typů - TypeScript pozná výsledný typ
- ✅ Partial<T> - pro částečné updaty
- ✅ Prevenci chyb - upozorní na špatné typy
Rozdíl JS vs TS
JavaScript:
- Spread funguje bez typové kontroly
- Můžeš omylem přepsat vlastnosti špatným typem
- Flexibilnější, ale nebezpečnější
TypeScript:
- Spread má typovou kontrolu
- TypeScript zkontroluje, že typy souhlasí
- Bezpečnější, prevence chyb
// JavaScript - projde, ale problematické
const user = { name: 'Alice', age: 25 };
const updated = { ...user, age: 'twenty-six' }; // Špatný typ!
// TypeScript - kontrola
interface User {
name: string;
age: number;
}
const user: User = { name: 'Alice', age: 25 };
// const updated: User = { ...user, age: 'twenty-six' }; // ❌ Error: Type 'string' is not assignable to type 'number'
Tip
💡 Používej spread pro immutabilní operace:
// ❌ Mutace originálu
const user = { name: 'Alice', age: 25 };
user.age = 26;
// ✅ Immutabilní update
const updatedUser = { ...user, age: 26 };
// ✅ Vhodné pro React state
setState({ ...state, isLoading: true });
💡 Spread je shallow copy - pozor u vnořených objektů:
const obj = { a: 1, nested: { b: 2 } };
// ❌ Shallow copy - nested je reference
const copy = { ...obj };
copy.nested.b = 3; // Změní i originál!
// ✅ Deep copy vnořených objektů
const deepCopy = {
...obj,
nested: { ...obj.nested }
};
💡 Pořadí záleží - poslední vyhrává:
// ❌ defaults přepíše user hodnoty
const config = { ...user, ...defaults };
// ✅ user hodnoty přepíší defaults
const config = { ...defaults, ...user };
Kvíz
Co vypíše tento kód?
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const result = { ...obj1, ...obj2 };
console.log(result.b);
❌ - To by bylo, kdyby obj2 byl první
✅ - - { ...obj1, ...obj2 } sloučí objekty
obj1má{ a: 1, b: 2 }obj2má{ b: 3, c: 4 }- Vlastnost
bexistuje v obou objektech - Poslední hodnota vyhrává:
obj2.b(=3) přepíšeobj1.b(=2) result={ a: 1, b: 3, c: 4 }
❌ - Spread nespojuje hodnoty do pole
❌ - Není to chyba, spread je validní syntaxe
Důležité: Při spojování objektů poslední hodnota vyhrává - pokud klíč existuje vícekrát!
Důležité: Při spojování objektů poslední hodnota vyhrává - pokud klíč existuje vícekrát!
🎯 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 →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
- 05.1 Vytvoření objektu
- 05.2 Vlastnosti
- 05.3 Metody objektu
- 05.4 This keyword
- 05.5 Destructuring objektů
- 05.6 Spread u objektů
- 05.7 Optional chaining
- 05.8 Nullish coalescing
- 05.9 Object.keys/values/entries
- 05.10 Computed properties
- 05.11 Getters a setters
- 05.12 Object.freeze/seal
Struktura lekcí (souborový strom)
- 1.1 Úvod do JavaScriptu a TypeScriptu
- 1.2 Nastavení prostředí
- 1.3 První program
- 1.4 Proměnné: var, let, const
- 1.5 Datové typy - přehled
- 1.6 String (řetězce)
- 1.7 Number (čísla)
- 1.8 Boolean (pravda/nepravda)
- 1.9 Null a Undefined
- 1.10 Type Inference vs Annotations
- 1.11 Aritmetické operátory
- 1.12 Porovnávací operátory
- 1.13 Logické operátory
- 1.14 Komentáře
- 1.15 Console metody
- 03.01 Deklarace funkce
- 03.02 Function Expression
- 03.03 Arrow Functions
- 03.04 Parametry a argumenty
- 03.05 Return hodnoty
- 03.06 Výchozí parametry
- 03.07 Rest parametry
- 03.08 Co je Scope
- 03.09 Lexikální Scope
- 03.10 Řetězec Scope
- 03.11 Globální Scope
- 03.12 Životní Cyklus Proměnných
- 03.13 Omezení Scope
- 03.14 Použití Closures
- 03.15 Callback funkce
- 03.16 Higher-order Functions
- 03.17 IIFE
- 03.18 Void funkce
- 03.19 Rekurze
- v přípravě
- v přípravě
- v přípravě
- v přípravě
- 01 — Co je Next.js
- 02 — Vytvoření projektu
- 03 — Struktura projektu (app/)
- 04 — Page komponenty (page.js / page.tsx)
- 05 — Layout komponenty (layout.js / layout.tsx)
- 06 — File-based routing
- 07 — Dynamické routy ([id]/page.js)
- 08 — Link komponenta (navigace)
- 09 — Image komponenta (next/image)
- 10 — Metadata (title, description, Open Graph)
- 11 — Loading UI (loading.js / loading.tsx)
- 12 — Error handling (error.js / error.tsx)
- 13 — Not Found (not-found.js / not-found.tsx)
- v přípravě
- v přípravě
- v přípravě