DvÄ nejpoužÃvanÄjšà datové struktury v JavaScriptu jsou objekty a pole.
- Objekty nám umožÅujà vytvoÅit jednoduchou entitu, v nÞ jsou datové prvky uloženy pod klÃÄi.
- Pole nám umožÅujà shromáždit datové prvky do seÅazeného seznamu.
Když je vÅ¡ak pÅedáváme nÄjaké funkci, nemusÃme je potÅebovat celé. Funkce může požadovat jen urÄité prvky nebo vlastnosti.
DestrukturaÄnà pÅiÅazenà je speciálnà syntaxe, která nám umožÅuje ârozbalitâ pole nebo objekty do svazku promÄnných, což bývá nÄkdy vhodnÄjÅ¡Ã.
Destrukturace také skvÄle funguje se složitými funkcemi, které majà spoustu parametrů, standardnà hodnoty a tak dále. Brzy to uvidÃme.
Destrukturace polÃ
Zde je pÅÃklad, jak je pole destrukturováno do promÄnných:
// máme pole obsahujÃcà jméno a pÅÃjmenÃ
let pole = ["Jan", "Novák"]
// destrukturaÄnà pÅiÅazenÃ
// nastavà kÅestnÃJméno = pole[0]
// a pÅÃjmenà = pole[1]
let [kÅestnÃJméno, pÅÃjmenÃ] = pole;
alert(kÅestnÃJméno); // Jan
alert(pÅÃjmenÃ); // Novák
Nynà můžeme mÃsto s prvky pole pracovat s promÄnnými.
Vypadá to výbornÄ, když to zkombinujeme se split nebo jinými metodami vracejÃcÃmi pole:
let [kÅestnÃJméno, pÅÃjmenÃ] = "Jan Novák".split(' ');
alert(kÅestnÃJméno); // Jan
alert(pÅÃjmenÃ); // Novák
Jak vidÃte, syntaxe je jednoduchá. Je tady vÅ¡ak nÄkolik zvláštnÃch detailů. PodÃváme se na dalšà pÅÃklady, abychom tomu lépe porozumÄli.
Tato technika se nazývá âdestrukturaÄnà pÅiÅazenÃâ, protože provádà âdestrukturaciâ kopÃrovánÃm prvků do promÄnných. Samotné pole se vÅ¡ak nemÄnÃ.
Je to jen kratšà způsob, jak napsat:
// let [kÅestnÃJméno, pÅÃjmenÃ] = pole;
let kÅestnÃJméno = pole[0];
let pÅÃjmenà = pole[1];
NechtÄné prvky pole můžeme zahodit pÅidánÃm Äárky:
// druhý prvek nepotÅebujeme
let [kÅestnÃJméno, , titul] = ["Julius", "Caesar", "Konzul", "ÅÃmské republiky"];
alert( titul ); // Konzul
V uvedeném kódu byl druhý prvek pole pÅeskoÄen, tÅetà pÅiÅazen do promÄnné titul a ostatnà prvky pole byly také pÅeskoÄeny (protože pro nÄ nejsou uvedeny žádné promÄnné).
â¦Ve skuteÄnosti můžeme destrukturaÄnà pÅiÅazenà použÃt na libovolný iterovatelný objekt, nejenom na pole:
let [a, b, c] = "abc"; // ["a", "b", "c"]
let [jedna, dvÄ, tÅi] = new Set([1, 2, 3]);
To funguje, protože vnitÅnÄ se destrukturaÄnà pÅiÅazenà vykonává iteracà nad hodnotou vpravo. Je to urÄitý druh syntaktického cukru pro volánà for..of nad hodnotou vpravo od = a pÅiÅazenà hodnot.
Na levé stranÄ můžeme použÃvat cokoli, do Äeho lze pÅiÅazovat.
NapÅÃklad vlastnost objektu:
let uživatel = {};
[uživatel.kÅestnÃJméno, uživatel.pÅÃjmenÃ] = "Jan Novák".split(' ');
alert(uživatel.kÅestnÃJméno); // Jan
alert(uživatel.pÅÃjmenÃ); // Novák
V pÅedchozà kapitole jsme vidÄli metodu Object.entries(obj).
Můžeme ji použÃvat spoleÄnÄ s destrukturacà k procházenà dvojic klÃÄů a hodnot objektu:
let uživatel = {
jméno: "Jan",
vÄk: 30
};
// cyklus nad dvojicemi klÃÄ-hodnota
for (let [klÃÄ, hodnota] of Object.entries(uživatel)) {
alert(`${klÃÄ}:${hodnota}`); // jméno:Jan, poté vÄk:30
}
Podobný kód pro Map je jednoduššÃ, protože mapa je iterovatelná:
let uživatel = new Map();
uživatel.set("jméno", "Jan");
uživatel.set("vÄk", "30");
// Map iteruje nad dvojicemi [klÃÄ, hodnota], což je velmi vhodné pro destrukturaci
for (let [klÃÄ, hodnota] of uživatel) {
alert(`${klÃÄ}:${hodnota}`); // jméno:Jan, poté vÄk:30
}
Existuje dobÅe známý trik pro výmÄnu hodnot dvou promÄnných použitÃm destrukturaÄnÃho pÅiÅazenÃ:
let host = "Jana";
let správce = "Petr";
// VymÄnÃme hodnoty: uÄinÃme host=Petr, správce=Jana
[host, správce] = [správce, host];
alert(`${host} ${správce}`); // Petr Jana (úspÄÅ¡nÄ vymÄnÄno!)
Zde jsme vytvoÅili doÄasné pole dvou promÄnných a okamžitÄ je destrukturovali v obráceném poÅadÃ.
TÃmto způsobem můžeme vymÄnit i vÃce než dvÄ promÄnné.
Zbytek ââ¦â
Jestliže je pole delšà než seznam nalevo, âpÅebývajÃcÃâ prvky jsou obvykle vypuÅ¡tÄny.
NapÅÃklad zde se vezmou jen prvnà dva prvky a ostatnà se jednoduÅ¡e ignorujÃ:
let [jméno1, jméno2] = ["Julius", "Caesar", "Konzul", "ÅÃmské republiky"];
alert(jméno1); // Julius
alert(jméno2); // Caesar
// Dalšà prvky již nejsou nikam pÅiÅazeny
Kdybychom chtÄli shromáždit i to, co následuje, můžeme pÅidat jeden dalšà parametr, do nÄhož se uložà âzbytekâ, pomocà tÅà teÄek "...":
let [jméno1, jméno2, ...zbytek] = ["Julius", "Caesar", "Konzul", "ÅÃmské republiky"];
// zbytek je pole prvků poÄÃnaje tÅetÃm
alert(zbytek[0]); // Konzul
alert(zbytek[1]); // ÅÃmské republiky
alert(zbytek.length); // 2
Hodnota promÄnné zbytek je pole zbývajÃcÃch prvků pole.
MÃsto zbytek můžeme použÃt jakékoli jméno promÄnné, jen musÃme zajistit, aby pÅed nÃm byly tÅi teÄky a aby bylo v destrukturaÄnÃm pÅiÅazenà uvedeno jako poslednÃ.
let [jméno1, jméno2, ...tituly] = ["Julius", "Caesar", "Konzul", "ÅÃmské republiky"];
// nynà tituly = ["Konzul", "ÅÃmské republiky"]
Standardnà hodnoty
Pokud je pole kratšà než seznam promÄnných nalevo, nedojde k chybÄ. Neuvedené hodnoty se považujà za nedefinované:
let [kÅestnÃJméno, pÅÃjmenÃ] = [];
alert(kÅestnÃJméno); // undefined
alert(pÅÃjmenÃ); // undefined
Chceme-li, aby chybÄjÃcà hodnoty nahradila nÄjaká âstandardnÃâ hodnota, můžeme ji uvést pomocà =:
// standardnà hodnoty
let [jméno = "Host", pÅÃjmenà = "Anonym"] = ["Julius"];
alert(jméno); // Julius (z pole)
alert(pÅÃjmenÃ); // Anonym (použita standardnà hodnota)
StandardnÃmi hodnotami mohou být i složitÄjšà výrazy nebo dokonce volánà funkcÃ. Vyhodnocujà se jen tehdy, když hodnota nenà poskytnuta.
NapÅÃklad zde použijeme pro dvÄ standardnà hodnoty funkci prompt:
// spustà prompt jen pro pÅÃjmenÃ
let [jméno = prompt('jméno?'), pÅÃjmenà = prompt('pÅÃjmenÃ?')] = ["Julius"];
alert(jméno); // Julius (z pole)
alert(pÅÃjmenÃ); // to, co vrátil prompt
ProsÃme vÅ¡imnÄte si: prompt se spustà jen pro chybÄjÃcà hodnotu (pÅÃjmenÃ).
Destrukturace objektů
DestrukturaÄnà pÅiÅazenà funguje i pro objekty.
Základnà syntaxe je:
let {promÄnná1, promÄnná2} = {promÄnná1:â¦, promÄnná2:â¦}
Na pravé stranÄ bychom mÄli mÃt existujÃcà objekt, který chceme rozdÄlit do promÄnných. Levá strana obsahuje objektu podobný âvzorâ pro odpovÃdajÃcà vlastnosti. V nejjednoduššÃm pÅÃpadÄ je to seznam názvů promÄnných v {...}.
PÅÃklad:
let možnosti = {
titulek: "Menu",
Å¡ÃÅka: 100,
výška: 200
};
let {titulek, Å¡ÃÅka, výška} = možnosti;
alert(titulek); // Menu
alert(Å¡ÃÅka); // 100
alert(výška); // 200
Vlastnosti možnosti.titulek, možnosti.Å¡ÃÅka a možnosti.výška jsou pÅiÅazeny do pÅÃsluÅ¡ných promÄnných.
Na poÅadà nezáležÃ. Tohle bude fungovat také:
// zmÄnÃme poÅadà v let {...}
let {výška, Å¡ÃÅka, titulek} = { titulek: "Menu", výška: 200, Å¡ÃÅka: 100 }
Vzor na levé stranÄ může být složitÄjšà a může specifikovat mapovánà mezi vlastnostmi a promÄnnými.
Chceme-li pÅiÅadit vlastnost do promÄnné s jiným názvem, napÅ. pÅiÅadit možnosti.Å¡ÃÅka do promÄnné jménem Å¡, pak můžeme nastavit jméno promÄnné za dvojteÄkou:
let možnosti = {
titulek: "Menu",
Å¡ÃÅka: 100,
výška: 200
};
// { zdrojováVlastnost: cÃlováPromÄnná }
let {Å¡ÃÅka: Å¡, výška: v, titulek} = možnosti;
// Å¡ÃÅka -> Å¡
// výška -> v
// titulek -> titulek
alert(titulek); // Menu
alert(Å¡); // 100
alert(v); // 200
DvojteÄka ukazuje, âco : jde kamâ. V uvedeném pÅÃkladu vlastnost Å¡ÃÅka jde do Å¡, vlastnost výška jde do v a titulek se pÅiÅadà do promÄnné se stejným názvem.
Pro vlastnosti, které mohou chybÄt, můžeme nastavit standardnà hodnoty pomocà "=" takto:
let možnosti = {
titulek: "Menu"
};
let {Å¡ÃÅka = 100, výška = 200, titulek} = možnosti;
alert(titulek); // Menu
alert(Å¡ÃÅka); // 100
alert(výška); // 200
StejnÄ jako u polà nebo parametrů funkcà mohou standardnà hodnoty být libovolné výrazy nebo dokonce volánà funkcÃ. Budou vyhodnoceny jen tehdy, když hodnota nebude poskytnuta.
V následujÃcÃm kódu se prompt zeptá na promÄnnou Å¡ÃÅka, ale ne na titulek:
let možnosti = {
titulek: "Menu"
};
let {Å¡ÃÅka = prompt("Å¡ÃÅka?"), titulek = prompt("titulek?")} = možnosti;
alert(titulek); // Menu
alert(Å¡ÃÅka); // (to, co vrátil prompt)
Můžeme také zkombinovat dvojteÄku a rovnÃtko:
let možnosti = {
titulek: "Menu"
};
let {Å¡ÃÅka: Å¡ = 100, výška: v = 200, titulek} = možnosti;
alert(titulek); // Menu
alert(Å¡); // 100
alert(v); // 200
Máme-li složitý objekt s mnoha vlastnostmi, můžeme vytáhnout jen ty, které potÅebujeme:
let možnosti = {
titulek: "Menu",
Å¡ÃÅka: 100,
výška: 200
};
// do promÄnné vyjmeme jen titulek
let { titulek } = možnosti;
alert(titulek); // Menu
Zbytkový vzor ââ¦â
Co když má objekt vÃce vlastnostÃ, než my máme promÄnných? Můžeme nÄkteré z nich vzÃt a âzbytekâ nÄkam pÅiÅadit?
Můžeme použÃt zbytkový vzor, stejnÄ jako jsme to udÄlali u polÃ. NÄkteré staršà prohlÞeÄe to nepodporujà (IE, jako polyfill použijte Babel), ale v modernÃch to funguje.
Vypadá to takto:
let možnosti = {
titulek: "Menu",
výška: 200,
Å¡ÃÅka: 100
};
// titulek = vlastnost nazvaná titulek
// zbytek = objekt s ostatnÃmi vlastnostmi
let {titulek, ...zbytek} = možnosti;
// nynà titulek="Menu", zbytek={výška: 200, Å¡ÃÅka: 100}
alert(zbytek.výška); // 200
alert(zbytek.Å¡ÃÅka); // 100
letVe výše uvedených pÅÃkladech jsme promÄnné deklarovali pÅÃmo pÅi pÅiÅazenÃ: let {â¦} = {â¦}. Můžeme samozÅejmÄ použÃt i existujÃcà promÄnné bez uvedenà let. Je tady vÅ¡ak chyták.
Tohle nebude fungovat:
let titulek, Å¡ÃÅka, výška;
// na tomto Åádku je chyba
{titulek, Å¡ÃÅka, výška} = {titulek: "Menu", Å¡ÃÅka: 200, výška: 100};
Problém je v tom, že JavaScript zacházà s {...} v hlavnÃm kódu (ne uvnitÅ jiného výrazu) jako s kódovým blokem. Takové kódové bloky můžeme použÃvat k seskupenà pÅÃkazů, napÅÃklad:
{
// kódový blok
let zpráva = "Ahoj";
// ...
alert( zpráva );
}
Zde tedy JavaScript pÅedpokládá, že máme kódový blok, což je důvod, proÄ nastane chyba. My mÃsto toho chceme destrukturaci.
Abychom sdÄlili JavaScriptu, že tohle nenà kódový blok, můžeme uzavÅÃt výraz do závorek (...):
let titulek, Å¡ÃÅka, výška;
// nynà je to v poÅádku
({titulek, Å¡ÃÅka, výška} = {titulek: "Menu", Å¡ÃÅka: 200, výška: 100});
alert( titulek ); // Menu
VnoÅená destrukturace
Jestliže objekt nebo pole obsahuje jiné vnoÅené objekty a pole, můžeme vyjmout hlubšà Äásti pomocà složitÄjÅ¡Ãch vzorů na levé stranÄ.
V následujÃcÃm kódu objekt možnosti obsahuje jiný objekt ve vlastnosti velikost a pole ve vlastnosti prvky. Vzor na levé stranÄ pÅiÅazenà má stejnou strukturu jako objekt, z nÄhož vybÃráme hodnoty:
let možnosti = {
velikost: {
Å¡ÃÅka: 100,
výška: 200
},
prvky: ["KoláÄ", "Vdolek"],
extra: true
};
// destrukturaÄnà pÅiÅazenÃ, pro Äitelnost rozdÄlené do vÃce Åádků
let {
velikost: { // zde uvedeme velikost
Å¡ÃÅka,
výška
},
prvky: [prvek1, prvek2], // zde pÅiÅadÃme prvky
titulek = "Menu" // v objektu nenà pÅÃtomen (použije se standardnà hodnota)
} = možnosti;
alert(titulek); // Menu
alert(Å¡ÃÅka); // 100
alert(výška); // 200
alert(prvek1); // KoláÄ
alert(prvek2); // Vdolek
Do pÅÃsluÅ¡ných promÄnných se pÅiÅadà vÅ¡echny vlastnosti objektu možnosti s výjimkou extra, která v levé Äásti chybÃ:
Nakonec tedy máme Å¡ÃÅka, výška, prvek1, prvek2 a titulek ze standardnà hodnoty.
VÅ¡imnÄte si, že zde nejsou žádné promÄnné pro velikost a prvky, jelikož jsme mÃsto nich vzali jejich obsah.
Chytré funkÄnà parametry
Stává se, že funkce má mnoho parametrů a vÄtÅ¡ina z nich je nepovinná. To platà zejména pro uživatelská rozhranÃ. PÅedstavte si funkci, která vytváÅà menu. Může obsahovat Å¡ÃÅku, výšku, titulek, seznam prvků a podobnÄ.
Zde je špatný způsob, jak takovou funkci napsat:
function zobrazMenu(titulek = "Bez názvu", Å¡ÃÅka = 200, výška = 100, prvky = []) {
// ...
}
Problém v reálném životÄ spoÄÃvá v tom, jak si pamatovat poÅadà argumentů. IDE se nám s tÃm obvykle snažà pomoci, zvláštÄ je-li kód dobÅe dokumentován, ale i tak⦠Dalšà problém je v tom, jak volat funkci, když u vÄtÅ¡iny parametrů chceme ponechat standardnà hodnoty.
Takhle?
// undefined tam, kde se má použÃt standardnà hodnota
zobrazMenu("Moje menu", undefined, undefined, ["Prvek1", "Prvek2"])
To je oÅ¡klivé. A když budeme pracovat s vÃce parametry, bude to neÄitelné.
Destrukturace nás pÅicházà zachránit!
Můžeme pÅedávat parametry jako objekt a funkce je okamžitÄ destrukturuje do promÄnných:
// pÅedáme objekt do funkce
let možnosti = {
titulek: "Moje menu",
prvky: ["Prvek1", "Prvek2"]
};
// ...a ta jej okamžitÄ rozdÄlà do promÄnných
function zobrazMenu({titulek = "Bez názvu", Å¡ÃÅka = 200, výška = 100, prvky = []}) {
// titulek, prvky â pÅevzaty z objektu možnosti,
// Å¡ÃÅka, výška â použity standardnà hodnoty
alert( `${titulek} ${Å¡ÃÅka} ${výška}` ); // Moje menu 200 100
alert( prvky ); // Prvek1,Prvek2
}
zobrazMenu(možnosti);
S vnoÅenými objekty a dvojteÄkovým mapovánÃm můžeme použÃt i složitÄjšà destrukturaci:
let možnosti = {
titulek: "Moje menu",
prvky: ["Prvek1", "Prvek2"]
};
function zobrazMenu({
titulek = "Bez názvu",
Å¡ÃÅka: Å¡ = 100, // Å¡ÃÅka jde do Å¡
výška: v = 200, // výška jde do v
prvky: [prvek1, prvek2] // prvnà prvek pole prvky jde do prvek1, druhý do prvek2
}) {
alert( `${titulek} ${Å¡} ${v}` ); // Moje menu 100 200
alert( prvek1 ); // Prvek1
alert( prvek2 ); // Prvek2
}
zobrazMenu(možnosti);
Ãplná syntaxe je stejná jako u destrukturaÄnÃho pÅiÅazenÃ:
function({
vstupujÃcÃVlastnost: názevPromÄnné = standardnÃHodnota
...
})
Pro objekt parametrů pak budeme mÃt pro vlastnost vstupujÃcÃVlastnost promÄnnou názevPromÄnné , jejÞ standardnà hodnotou bude standardnÃHodnota.
ProsÃme vÅ¡imnÄte si, že taková destrukturace pÅedpokládá, že zobrazMenu() má argument. Chceme-li vÅ¡echny hodnoty standardnÃ, mÄli bychom uvést prázdný objekt:
zobrazMenu({}); // ok, vÅ¡echny hodnoty jsou standardnÃ
zobrazMenu(); // tohle ohlásà chybu
To můžeme opravit tak, že uÄinÃme {} standardnà hodnotou celého objektu parametrů:
function zobrazMenu({ titulek = "Menu", Å¡ÃÅka = 100, výška = 200 } = {}) {
alert( `${titulek} ${Å¡ÃÅka} ${výška}` );
}
zobrazMenu(); // Menu 100 200
V uvedeném kódu je celý argumentový objekt standardnÄ {}, takže vždy bude co destrukturovat.
ShrnutÃ
-
DestrukturaÄnà pÅiÅazenà umožÅuje rychlé mapovánà objektu nebo pole do mnoha promÄnných.
-
Ãplná syntaxe pro objekt:
let {vlastnost : názevPromÄnné = standardnÃHodnota, ...zbytek} = objektTo znamená, že vlastnost
vlastnostmá pÅijÃt do promÄnnénázevPromÄnné, a pokud taková vlastnost neexistuje, mÄla by se použÃt hodnotastandardnÃHodnota.Objektové vlastnosti, pro které nenà uvedeno mapovánÃ, se zkopÃrujà do objektu
zbytek. -
Ãplná syntaxe pro pole:
let [prvek1 = standardnÃHodnota, prvek2, ...zbytek] = polePrvnà prvek se uložà do promÄnné
prvek1, druhý doprvek2, ze vÅ¡ech ostatnÃch prvků se vytvoÅà polezbytek. -
Je možné extrahovat data z vnoÅených polà nebo objektů. V tom pÅÃpadÄ musà mÃt levá strana stejnou strukturu jako pravá.
KomentáÅe
<code>, pro nÄkolik Åádků je obalte znaÄkou<pre>, pro vÃce než 10 Åádků vložte odkaz na pÃskoviÅ¡tÄ (plnkr, jsbin, codepenâ¦)