diff --git a/1-js/04-object-basics/07-optional-chaining/article.md b/1-js/04-object-basics/07-optional-chaining/article.md index 2c33f081b..c2b7d7e54 100644 --- a/1-js/04-object-basics/07-optional-chaining/article.md +++ b/1-js/04-object-basics/07-optional-chaining/article.md @@ -1,232 +1,232 @@ -# Optional chaining '?.' +# Volitelné zřetězení „?.“ [recent browser="new"] -The optional chaining `?.` is a safe way to access nested object properties, even if an intermediate property doesn't exist. +Volitelné zřetězení `?.` je bezpečný způsob, jak přistupovat k vnořeným vlastnostem objektu, i když vlastnost nacházející se mezi nimi neexistuje. -## The "non-existing property" problem +## Problém „neexistující vlastnosti“ -If you've just started to read the tutorial and learn JavaScript, maybe the problem hasn't touched you yet, but it's quite common. +Pokud jste teprve začali číst tento tutoriál a učit se JavaScript, tento problém se vás možná ještě nedotkl, ale dochází k němu poměrně často. -As an example, let's say we have `user` objects that hold the information about our users. +Jako příklad mějme objekt `uživatel`, který obsahuje informace o našich uživatelích. -Most of our users have addresses in `user.address` property, with the street `user.address.street`, but some did not provide them. +Většina našich uživatelů má ve vlastnosti `uživatel.adresa` adresu s ulicí `uživatel.adresa.ulice`, ale někteří ji neuvedli. -In such case, when we attempt to get `user.address.street`, and the user happens to be without an address, we get an error: +Když se v takovém případě pokusíme získat `uživatel.adresa.ulice` a uživatel je bez adresy, dostaneme chybu: ```js run -let user = {}; // a user without "address" property +let uživatel = {}; // uživatel bez vlastnosti „adresa“ -alert(user.address.street); // Error! +alert(uživatel.adresa.ulice); // Chyba! ``` -That's the expected result. JavaScript works like this. As `user.address` is `undefined`, an attempt to get `user.address.street` fails with an error. +To je očekávaný výsledek. JavaScript takto funguje. Když `uživatel.adresa` je `undefined`, pokus o získání `uživatel.adresa.ulice` selže s chybou. -In many practical cases we'd prefer to get `undefined` instead of an error here (meaning "no street"). +V mnoha praktických případech bychom však zde raději získali `undefined` místo chyby (což znamená „žádná ulice“). -...and another example. In Web development, we can get an object that corresponds to a web page element using a special method call, such as `document.querySelector('.elem')`, and it returns `null` when there's no such element. +...A jiný příklad. Při vývoji webů můžeme pomocí speciálního volání metody, např. `document.querySelector('.elem')`, získat objekt, který odpovídá určitému prvku webové stránky. Když na stránce takový prvek není, metoda vrací `null`. ```js run -// document.querySelector('.elem') is null if there's no element -let html = document.querySelector('.elem').innerHTML; // error if it's null +// document.querySelector('.elem') je null, pokud tam žádný prvek není +let html = document.querySelector('.elem').innerHTML; // chyba, pokud je to null ``` -Once again, if the element doesn't exist, we'll get an error accessing `.innerHTML` property of `null`. And in some cases, when the absence of the element is normal, we'd like to avoid the error and just accept `html = null` as the result. +Opět platí, že pokud tento prvek neexistuje, při přístupu k vlastnosti `.innerHTML` z `null` dostaneme chybu. Ale v některých případech, kdy je nepřítomnost prvku normální, bychom se této chybě rádi vyhnuli a prostě přijali za výsledek `html = null`. -How can we do this? +Jak to můžeme udělat? -The obvious solution would be to check the value using `if` or the conditional operator `?`, before accessing its property, like this: +Očividným řešením by bylo zkontrolovat hodnotu pomocí `if` nebo podmíněného operátoru `?` před přístupem k její vlastnosti, například: ```js -let user = {}; +let uživatel = {}; -alert(user.address ? user.address.street : undefined); +alert(uživatel.adresa ? uživatel.adresa.ulice : undefined); ``` -It works, there's no error... But it's quite inelegant. As you can see, the `"user.address"` appears twice in the code. +Funguje to, nenastala žádná chyba... Ale není to příliš elegantní. Jak vidíme, `„uživatel.adresa“` se v kódu objevuje dvakrát. -Here's how the same would look for `document.querySelector`: +Takto by vypadalo totéž pro `document.querySelector`: ```js run let html = document.querySelector('.elem') ? document.querySelector('.elem').innerHTML : null; ``` -We can see that the element search `document.querySelector('.elem')` is actually called twice here. Not good. +Vidíme, že hledání prvku `document.querySelector('.elem')` se zde ve skutečnosti volá dvakrát. To není dobré. -For more deeply nested properties, it becomes even uglier, as more repetitions are required. +Pro hlouběji vnořené vlastnosti to bude ještě ošklivější, protože bude potřeba více opakování. -E.g. let's get `user.address.street.name` in a similar fashion. +Například zkusme podobným způsobem získat `uživatel.adresa.ulice.název`. ```js -let user = {}; // user has no address +let uživatel = {}; // uživatel nemá adresu -alert(user.address ? user.address.street ? user.address.street.name : null : null); +alert(uživatel.adresa ? uživatel.adresa.ulice ? uživatel.adresa.ulice.název : null : null); ``` -That's just awful, one may even have problems understanding such code. +Je to ošklivé a člověk může mít problémy takovému kódu porozumět. -There's a little better way to write it, using the `&&` operator: +Existuje trochu lepší způsob, jak to napsat, a to pomocí operátoru `&&`: ```js run -let user = {}; // user has no address +let uživatel = {}; // uživatel nemá adresu -alert( user.address && user.address.street && user.address.street.name ); // undefined (no error) +alert( uživatel.adresa && uživatel.adresa.ulice && uživatel.adresa.ulice.název ); // undefined (žádná chyba) ``` -AND'ing the whole path to the property ensures that all components exist (if not, the evaluation stops), but also isn't ideal. +Spojení celé cesty k vlastnosti ANDem sice zajistí, že všechny komponenty existují (pokud ne, vyhodnocení se zastaví), ale ani to není ideální. -As you can see, property names are still duplicated in the code. E.g. in the code above, `user.address` appears three times. +Jak vidíte, názvy vlastností jsou v kódu stále zdvojeny, tj. ve výše uvedeném kódu se `uživatel.adresa` objeví třikrát. -That's why the optional chaining `?.` was added to the language. To solve this problem once and for all! +Z tohoto důvodu bylo do jazyka přidáno volitelné zřetězení `?.`, aby tento problém vyřešilo jednou provždy! -## Optional chaining +## Volitelné zřetězení -The optional chaining `?.` stops the evaluation if the value before `?.` is `undefined` or `null` and returns `undefined`. +Volitelné zřetězení `?.` zastaví vyhodnocování, jestliže hodnota před `?.` je `undefined` nebo `null`, a vrátí `undefined`. -**Further in this article, for brevity, we'll be saying that something "exists" if it's not `null` and not `undefined`.** +**Dále v tomto článku budeme pro přehlednost říkat, že něco „existuje“, jestliže to není `null` ani `undefined`.** -In other words, `value?.prop`: -- works as `value.prop`, if `value` exists, -- otherwise (when `value` is `undefined/null`) it returns `undefined`. +Jinými slovy, `hodnota?.vlastnost`: +- funguje jako `hodnota.vlastnost`, jestliže `hodnota` existuje, +- v opačném případě (když `hodnota` je `undefined/null`) vrátí `undefined`. -Here's the safe way to access `user.address.street` using `?.`: +Toto je bezpečný způsob, jak přistoupit k `uživatel.adresa.ulice` pomocí `?.`: ```js run -let user = {}; // user has no address +let uživatel = {}; // uživatel nemá adresu -alert( user?.address?.street ); // undefined (no error) +alert( uživatel?.adresa?.ulice ); // undefined (bez chyby) ``` -The code is short and clean, there's no duplication at all. +Kód je krátký a jasný, není v něm žádné zdvojení. -Here's an example with `document.querySelector`: +Zde je příklad s `document.querySelector`: ```js run -let html = document.querySelector('.elem')?.innerHTML; // will be undefined, if there's no element +let html = document.querySelector('.elem')?.innerHTML; // není-li žádný prvek, bude undefined ``` -Reading the address with `user?.address` works even if `user` object doesn't exist: + +Načtení adresy pomocí `uživatel?.adresa` funguje i tehdy, když objekt `uživatel` neexistuje: ```js run -let user = null; +let uživatel = null; -alert( user?.address ); // undefined -alert( user?.address.street ); // undefined +alert( uživatel?.adresa ); // undefined +alert( uživatel?.adresa.ulice ); // undefined ``` -Please note: the `?.` syntax makes optional the value before it, but not any further. +Prosíme všimněte si: syntaxe `?.` umožňuje, aby volitelná byla hodnota před ní, ale žádná další. -E.g. in `user?.address.street.name` the `?.` allows `user` to safely be `null/undefined` (and returns `undefined` in that case), but that's only for `user`. Further properties are accessed in a regular way. If we want some of them to be optional, then we'll need to replace more `.` with `?.`. +Např. `?.` v `uživatel?.adresa.ulice.název` umožňuje, aby `uživatel` byl bezpečně `null/undefined` (a v takovém případě vrátí `undefined`), ale to platí jen pro objekt `uživatel`. K dalším vlastnostem se přistupuje obvyklým způsobem. Chceme-li, aby některá z nich byla volitelná, musíme nahradit další `.` za `?.`. -```warn header="Don't overuse the optional chaining" -We should use `?.` only where it's ok that something doesn't exist. +```warn header="Nepoužívejte volitelné zřetězení přehnaně často" +Měli bychom používat `?.` jen tehdy, když je v pořádku, že něco neexistuje. -For example, if according to our code logic `user` object must exist, but `address` is optional, then we should write `user.address?.street`, but not `user?.address?.street`. +Například pokud podle logiky našeho kódu musí objekt `uživatel` existovat, ale `adresa` je volitelná, pak bychom měli psát `uživatel.adresa?.ulice`, ale ne `uživatel?.adresa?.ulice`. -Then, if `user` happens to be undefined, we'll see a programming error about it and fix it. Otherwise, if we overuse `?.`, coding errors can be silenced where not appropriate, and become more difficult to debug. +Pak pokud se stane, že `uživatel` bude nedefinovaný, uvidíme programátorskou chybu a opravíme ji. Kdybychom však přehnaně používali `?.`, mohly by se chyby v kódu neohlásit i tehdy, když to není vhodné, a ladění by bylo obtížnější. ``` -````warn header="The variable before `?.` must be declared" -If there's no variable `user` at all, then `user?.anything` triggers an error: +````warn header="Proměnná před `?.` musí být deklarovaná" +Pokud proměnná `uživatel` vůbec neexistuje, pak `uživatel?.cokoli` ohlásí chybu: ```js run -// ReferenceError: user is not defined -user?.address; +// ReferenceError: uživatel není definován +uživatel?.adresa; ``` -The variable must be declared (e.g. `let/const/var user` or as a function parameter). The optional chaining works only for declared variables. +Proměnná musí být deklarovaná (tj. `let/const/var uživatel` nebo jako parametr funkce). Volitelné zřetězení funguje jen pro deklarované proměnné. ```` -## Short-circuiting +## Zkratování -As it was said before, the `?.` immediately stops ("short-circuits") the evaluation if the left part doesn't exist. +Jak bylo řečeno, `?.` okamžitě zastaví („vyzkratuje“) vyhodnocování, jestliže levá část neexistuje. -So, if there are any further function calls or operations to the right of `?.`, they won't be made. +Jestliže tedy vpravo za `?.` následují další volání funkcí nebo operace, nevykonají se. -For instance: +Například: ```js run -let user = null; +let uživatel = null; let x = 0; -user?.sayHi(x++); // no "user", so the execution doesn't reach sayHi call and x++ +uživatel?.řekniAhoj(x++); // „uživatel“ není, takže běh se nedostane k volání řekniAhoj a x++ -alert(x); // 0, value not incremented +alert(x); // 0, hodnota se nezvýšila ``` -## Other variants: ?.(), ?.[] +## Další varianty: ?.(), ?.[] -The optional chaining `?.` is not an operator, but a special syntax construct, that also works with functions and square brackets. +Volitelné zřetězení `?.` není operátor, ale speciální syntaktický konstrukt, který funguje i s funkcemi a hranatými závorkami. -For example, `?.()` is used to call a function that may not exist. +Například `?.()` se používá k volání funkce, která nemusí existovat. -In the code below, some of our users have `admin` method, and some don't: +V níže uvedeném kódu někteří z našich uživatelů mají metodu `správce` a někteří ne: ```js run -let userAdmin = { - admin() { - alert("I am admin"); +let uživatelSprávce = { + správce() { + alert("Jsem správce"); } }; -let userGuest = {}; +let uživatelHost = {}; *!* -userAdmin.admin?.(); // I am admin +uživatelSprávce.správce?.(); // Jsem správce */!* *!* -userGuest.admin?.(); // nothing happens (no such method) +uživatelHost.správce?.(); // nic se nestane (taková metoda není) */!* ``` -Here, in both lines we first use the dot (`userAdmin.admin`) to get `admin` property, because we assume that the `user` object exists, so it's safe read from it. +Zde na obou řádcích nejprve použijeme tečku (`uživatelSprávce.správce`) k získání vlastnosti `správce`, protože předpokládáme, že objekt `uživatel` existuje, takže je bezpečné z něj číst. -Then `?.()` checks the left part: if the `admin` function exists, then it runs (that's so for `userAdmin`). Otherwise (for `userGuest`) the evaluation stops without errors. +Pak `?.()` prověří levou stranu: jestliže funkce `správce` existuje, pak se spustí (tak tomu je pro `uživatelSprávce`). Jinak (pro `uživatelHost`) se vyhodnocování zastaví bez chyb. -The `?.[]` syntax also works, if we'd like to use brackets `[]` to access properties instead of dot `.`. Similar to previous cases, it allows to safely read a property from an object that may not exist. +Funguje také syntaxe `?.[]`, jestliže pro přístup k vlastnostem raději používáme hranaté závorky `[]` namísto tečky `.`. Podobně jako v předchozích případech nám umožňuje bezpečně načíst vlastnost z objektu, který nemusí existovat. ```js run -let key = "firstName"; +let klíč = "křestníJméno"; -let user1 = { - firstName: "John" +let uživatel1 = { + křestníJméno: "Jan" }; -let user2 = null; +let uživatel2 = null; -alert( user1?.[key] ); // John -alert( user2?.[key] ); // undefined +alert( uživatel1?.[klíč] ); // Jan +alert( uživatel2?.[klíč] ); // undefined ``` -Also we can use `?.` with `delete`: +Můžeme použít `?.` i s `delete`: ```js run -delete user?.name; // delete user.name if user exists +delete uživatel?.jméno; // delete uživatel.jméno, pokud uživatel existuje ``` -````warn header="We can use `?.` for safe reading and deleting, but not writing" -The optional chaining `?.` has no use on the left side of an assignment. +````warn header="Můžeme používat `?.` k bezpečnému čtení a mazání, ale ne k zápisu" +Volitelné zřetězení `?.` nelze použít na levé straně přiřazení. -For example: +Například: ```js run -let user = null; +let uživatel = null; -user?.name = "John"; // Error, doesn't work -// because it evaluates to: undefined = "John" +uživatel?.jméno = "Jan"; // Chyba, nefunguje to +// protože se to vyhodnotí jako: undefined = "Jan" ``` - ```` -## Summary +## Shrnutí -The optional chaining `?.` syntax has three forms: +Syntaxe volitelného zřetězení `?.` má tři podoby: -1. `obj?.prop` -- returns `obj.prop` if `obj` exists, otherwise `undefined`. -2. `obj?.[prop]` -- returns `obj[prop]` if `obj` exists, otherwise `undefined`. -3. `obj.method?.()` -- calls `obj.method()` if `obj.method` exists, otherwise returns `undefined`. +1. `obj?.vlastnost` -- jestliže `obj` existuje, vrátí `obj.vlastnost`, jinak vrátí `undefined`. +2. `obj?.[vlastnost]` -- jestliže `obj` existuje, vrátí `obj[vlastnost]`, jinak vrátí `undefined`. +3. `obj.metoda?.()` -- jestliže `obj.metoda` existuje, zavolá `obj.metoda()`, jinak vrátí `undefined`. -As we can see, all of them are straightforward and simple to use. The `?.` checks the left part for `null/undefined` and allows the evaluation to proceed if it's not so. +Jak vidíme, všechny jsou srozumitelné a snadno se používají. `?.` ověří, zda levá strana je `null/undefined`, a pokud není, umožní pokračovat ve vyhodnocování. -A chain of `?.` allows to safely access nested properties. +Řetězec více `?.` nám umožňuje bezpečný přístup k vnořeným vlastnostem. -Still, we should apply `?.` carefully, only where it's acceptable, according to our code logic, that the left part doesn't exist. So that it won't hide programming errors from us, if they occur. +Přesto bychom měli používat `?.` opatrně a jen tehdy, když je podle logiky našeho kódu přijatelné, aby levá strana skutečně neexistovala. Tak se před námi neukryjí programátorské chyby, jestliže k nim dojde.