diff --git a/1-js/02-first-steps/07-type-conversions/article.md b/1-js/02-first-steps/07-type-conversions/article.md index 57f4cd364..b8cf5b179 100644 --- a/1-js/02-first-steps/07-type-conversions/article.md +++ b/1-js/02-first-steps/07-type-conversions/article.md @@ -146,4 +146,4 @@ Většinu těchto pravidel je snadné pochopit a zapamatovat si. Významné výj - `undefined` převedené na číslo je `NaN`, ne `0`. - `"0"` a řetězce obsahující jen mezery, např. `" "`, jsou po převodu na boolean vyhodnoceny jako true. -O objektech se zde nezmiňujeme. Později, až se v JavaScriptu naučíme všechny potřebné základy, se k nim vrátíme v kapitole , která je věnována výlučně objektům. +O objektech se zde nezmiňujeme. Později, až se v JavaScriptu naučíme všechny potřebné základy, se k nim vrátíme v kapitole , která je věnována výlučně objektům. \ No newline at end of file diff --git a/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2.svg b/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2.svg index fb567c1c1..050264a37 100644 --- a/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2.svg +++ b/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2.svg @@ -1 +1 @@ -ZačátekVy to nevíte? “ECMAScript”!Správně!What's the "oficiální" název JavaScript?JinéECMAScript \ No newline at end of file +ZačátekVy to nevíte? “ECMAScript”!Správně!Jaký je "oficiální" název JavaScriptu?JinéECMAScript \ No newline at end of file diff --git a/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task.svg b/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task.svg index 9e4caf654..9f3d967ac 100644 --- a/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task.svg +++ b/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task.svg @@ -1 +1 @@ -ZačátekZrušenoZrušenoVítejte!Neznám vásChybné hesloKdo je tam?Heslo?ZrušenoZrušenoAdminMistrJinéJiné \ No newline at end of file +ZačátekZrušenoZrušenoVítejte!Neznám vásChybné hesloKdo je tam?Heslo?ZrušenoZrušenoSprávceMistrJinéJiné \ No newline at end of file diff --git a/1-js/03-code-quality/01-debugging-chrome/chrome-sources-breakpoint.svg b/1-js/03-code-quality/01-debugging-chrome/chrome-sources-breakpoint.svg index 63bf4966e..9cccdfb03 100644 --- a/1-js/03-code-quality/01-debugging-chrome/chrome-sources-breakpoint.svg +++ b/1-js/03-code-quality/01-debugging-chrome/chrome-sources-breakpoint.svg @@ -1 +1 @@ -here's the listbreakpoints \ No newline at end of file +zde je seznamzarážky \ No newline at end of file diff --git a/1-js/03-code-quality/01-debugging-chrome/chrome-sources-debugger-pause.svg b/1-js/03-code-quality/01-debugging-chrome/chrome-sources-debugger-pause.svg index 0147c2e0a..6835bfaa4 100644 --- a/1-js/03-code-quality/01-debugging-chrome/chrome-sources-debugger-pause.svg +++ b/1-js/03-code-quality/01-debugging-chrome/chrome-sources-debugger-pause.svg @@ -1 +1 @@ -213see the outer call detailswatch expressionscurrent variables \ No newline at end of file +213viz detaily vnějšího volánísledování výrazůaktuální proměnné \ No newline at end of file diff --git a/1-js/03-code-quality/01-debugging-chrome/chrome-sources-debugger-trace-1.svg b/1-js/03-code-quality/01-debugging-chrome/chrome-sources-debugger-trace-1.svg index 9fa1b3b8c..cea51b5b5 100644 --- a/1-js/03-code-quality/01-debugging-chrome/chrome-sources-debugger-trace-1.svg +++ b/1-js/03-code-quality/01-debugging-chrome/chrome-sources-debugger-trace-1.svg @@ -1 +1 @@ -nested calls \ No newline at end of file +vnořená volání \ No newline at end of file diff --git a/1-js/03-code-quality/04-ninja-code/article.md b/1-js/03-code-quality/04-ninja-code/article.md index 20901b22a..c6b65574c 100644 --- a/1-js/03-code-quality/04-ninja-code/article.md +++ b/1-js/03-code-quality/04-ninja-code/article.md @@ -135,7 +135,7 @@ Přidejte novou proměnnou jen tehdy, když je to absolutně nezbytné. Jinak místo toho opakovaně používejte již existující názvy. Jen do nich zapisujte nové hodnoty. -Ve funkci se snažte používat jedině proměnné, které byly předány jako argumenty. +Ve funkci se snažte používat jedině proměnné, které byly předány jako parametry. Díky tomu je opravdu těžké poznat, co vlastně proměnná obsahuje *právě teď*. A také, odkud to přišlo. Cílem je procvičit intuici a paměť člověka, který čte kód. Osoba se slabou intuicí bude muset analyzovat kód řádek po řádku a stopovat změny v každé větvi. @@ -171,6 +171,7 @@ Dejte každému vědět, jak úžasné jsou vaše entity! Názvy jako `superElem Jistě, na jednu stranu musíte něco napsat: `super..`, `mega..`, `pěkný..`. Ale na druhou stranu to neposkytuje žádné detaily. Čtenář se může rozhodnout hledat jejich skrytý význam a strávit meditací hodinu nebo dvě své placené pracovní doby. +Dejte každému vědět, jak úžasné jsou vaše entity! Názvy jako `superElement`, `megaRámec` nebo `pěknýPrvek` čtenáře zaručeně osvítí. ## Překrývejte vnější proměnné diff --git a/1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/solution.md b/1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/solution.md index 4d0571b9d..fc2fe8146 100644 --- a/1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/solution.md +++ b/1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/solution.md @@ -1,50 +1,50 @@ -The test demonstrates one of the temptations a developer meets when writing tests. +Tento test ukazuje jedno z pokušení, kterým vývojář při psaní testů čelí. -What we have here is actually 3 tests, but layed out as a single function with 3 asserts. +To, co zde máme, jsou ve skutečnosti 3 testy, ale jsou vytvořeny jako jediná funkce se 3 kontrolami. -Sometimes it's easier to write this way, but if an error occurs, it's much less obvious what went wrong. +Někdy je jednodušší psát takto, ale když nastane chyba, je mnohem méně zřejmé, co bylo špatně. -If an error happens in the middle of a complex execution flow, then we'll have to figure out the data at that point. We'll actually have to *debug the test*. +Nastane-li chyba uprostřed složitého provádění, musíme v té chvíli zjišťovat, jaká byla data. Vlastně musíme *ladit test*. -It would be much better to break the test into multiple `it` blocks with clearly written inputs and outputs. +Bylo by mnohem lepší rozdělit test do několika `it` bloků s jasně uvedenými vstupy a výstupy. -Like this: +Například takto: ```js -describe("Raises x to power n", function() { - it("5 in the power of 1 equals 5", function() { - assert.equal(pow(5, 1), 5); +describe("Umocní x na n-tou", function() { + it("5 na 1 se rovná 5", function() { + assert.equal(mocnina(5, 1), 5); }); - it("5 in the power of 2 equals 25", function() { - assert.equal(pow(5, 2), 25); + it("5 na 2 se rovná 25", function() { + assert.equal(mocnina(5, 2), 25); }); - it("5 in the power of 3 equals 125", function() { - assert.equal(pow(5, 3), 125); + it("5 na 3 se rovná 125", function() { + assert.equal(mocnina(5, 3), 125); }); }); ``` -We replaced the single `it` with `describe` and a group of `it` blocks. Now if something fails we would see clearly what the data was. +Nahradili jsme jediné `it` za `describe` a skupinu `it` bloků. Když nyní něco selže, jasně uvidíme, jaká byla data. -Also we can isolate a single test and run it in standalone mode by writing `it.only` instead of `it`: +Nyní můžeme také izolovat jediný test a spustit jej samostatně. To uděláme tak, že napíšeme `it.only` místo `it`: ```js -describe("Raises x to power n", function() { - it("5 in the power of 1 equals 5", function() { - assert.equal(pow(5, 1), 5); +describe("Umocní x na n-tou", function() { + it("5 na 1 se rovná 5", function() { + assert.equal(mocnina(5, 1), 5); }); *!* - // Mocha will run only this block - it.only("5 in the power of 2 equals 25", function() { - assert.equal(pow(5, 2), 25); + // Mocha spustí pouze tento blok + it.only("5 na 2 se rovná 25", function() { + assert.equal(mocnina(5, 2), 25); }); */!* - it("5 in the power of 3 equals 125", function() { - assert.equal(pow(5, 3), 125); + it("5 na 3 se rovná 125", function() { + assert.equal(mocnina(5, 3), 125); }); }); ``` diff --git a/1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/task.md b/1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/task.md index 66fece09a..41b26df3a 100644 --- a/1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/task.md +++ b/1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/task.md @@ -2,23 +2,23 @@ importance: 5 --- -# What's wrong in the test? +# Co je na tomto testu špatně? -What's wrong in the test of `pow` below? +Co je špatně na níže uvedeném testu funkce `mocnina`? ```js -it("Raises x to the power n", function() { +it("Umocní x na n-tou", function() { let x = 5; - let result = x; - assert.equal(pow(x, 1), result); + let výsledek = x; + assert.equal(mocnina(x, 1), výsledek); - result *= x; - assert.equal(pow(x, 2), result); + výsledek *= x; + assert.equal(mocnina(x, 2), výsledek); - result *= x; - assert.equal(pow(x, 3), result); + výsledek *= x; + assert.equal(mocnina(x, 3), výsledek); }); ``` -P.S. Syntactically the test is correct and passes. +P.S. Syntakticky je tento test korektní a projde. diff --git a/1-js/03-code-quality/05-testing-mocha/article.md b/1-js/03-code-quality/05-testing-mocha/article.md index 4c2b1aa5e..d35aafd1c 100644 --- a/1-js/03-code-quality/05-testing-mocha/article.md +++ b/1-js/03-code-quality/05-testing-mocha/article.md @@ -1,279 +1,279 @@ -# Automated testing with Mocha +# Automatické testování pomocí Mochy -Automated testing will be used in further tasks, and it's also widely used in real projects. +Automatické testování bude používáno v dalších úlohách a široce se používá i ve skutečných projektech. -## Why do we need tests? +## K čemu potřebujeme testy? -When we write a function, we can usually imagine what it should do: which parameters give which results. +Když píšeme funkci, můžeme si obvykle představit, co by měla dělat: jaké parametry by měly dávat jaké výsledky. -During development, we can check the function by running it and comparing the outcome with the expected one. For instance, we can do it in the console. +Během vývoje můžeme tuto funkci zkontrolovat tak, že ji spustíme a porovnáme její výsledek s očekávaným. Můžeme to udělat například na konzoli. -If something is wrong -- then we fix the code, run again, check the result -- and so on till it works. +Jestliže je něco špatně -- pak opravíme kód, znovu spustíme funkci, zkontrolujeme výsledek -- a tak dále, dokud to nebude fungovat. -But such manual "re-runs" are imperfect. +Avšak takové ruční „znovuspouštění“ není dokonalé. -**When testing a code by manual re-runs, it's easy to miss something.** +**Když testujeme kód tím, že ho znovu ručně spouštíme, můžeme snadno něco přehlédnout.** -For instance, we're creating a function `f`. Wrote some code, testing: `f(1)` works, but `f(2)` doesn't work. We fix the code and now `f(2)` works. Looks complete? But we forgot to re-test `f(1)`. That may lead to an error. +Například vytváříme funkci `f`. Napíšeme kód a testujeme: `f(1)` funguje, ale `f(2)` ne. Opravíme kód a nyní `f(2)` funguje. Vypadá to kompletně? Ale zapomněli jsme znovu otestovat `f(1)`. To může vést k chybě. -That's very typical. When we develop something, we keep a lot of possible use cases in mind. But it's hard to expect a programmer to check all of them manually after every change. So it becomes easy to fix one thing and break another one. +To je velmi typické. Když něco vyvíjíme, máme na paměti mnoho možných případů použití. Těžko však očekávat od programátora, že je po každé změně všechny znovu ručně prověří. Lehce se tedy stává, že opravíme jednu věc a rozbijeme jinou. -**Automated testing means that tests are written separately, in addition to the code. They run our functions in various ways and compare results with the expected.** +**Automatické testování znamená, že testy jsou psány odděleně navíc ke kódu. Různými způsoby spouštějí naše funkce a porovnávají jejich výsledky s očekávanými.** -## Behavior Driven Development (BDD) +## Vývoj řízený chováním (BDD) -Let's start with a technique named [Behavior Driven Development](http://en.wikipedia.org/wiki/Behavior-driven_development) or, in short, BDD. +Začněme technikou nazývanou *Vývoj řízený chováním*, anglicky [Behavior Driven Development](http://en.wikipedia.org/wiki/Behavior-driven_development), zkráceně BDD. -**BDD is three things in one: tests AND documentation AND examples.** +**BDD jsou tři věci v jedné: testy A dokumentace A příklady.** -To understand BDD, we'll examine a practical case of development. +Abychom BDD pochopili, prozkoumáme praktický příklad vývoje. -## Development of "pow": the spec +## Vývoj funkce „mocnina“: specifikace -Let's say we want to make a function `pow(x, n)` that raises `x` to an integer power `n`. We assume that `n≥0`. +Řekněme, že chceme vytvořit funkci `mocnina(x, n)`, která umocní `x` na celočíselný exponent `n`. Předpokládáme, že `n≥0`. -That task is just an example: there's the `**` operator in JavaScript that can do that, but here we concentrate on the development flow that can be applied to more complex tasks as well. +Tato úloha je jenom příklad: v JavaScriptu je operátor `**`, který to umí, ale zde se soustředíme na proces vývoje, který může být aplikován i na složitější úlohy. -Before creating the code of `pow`, we can imagine what the function should do and describe it. +Před vytvořením kódu funkce `mocnina` si představíme, co by tato funkce měla dělat, a popíšeme to. -Such description is called a *specification* or, in short, a spec, and contains descriptions of use cases together with tests for them, like this: +Takový popis se nazývá *specifikace* a obsahuje popisy případů použití společně s jejich testy, například takto: ```js -describe("pow", function() { +describe("mocnina", function() { - it("raises to n-th power", function() { - assert.equal(pow(2, 3), 8); + it("umocní na n-tou", function() { + assert.equal(mocnina(2, 3), 8); }); }); ``` -A spec has three main building blocks that you can see above: +Specifikace má tři hlavní stavební bloky, které vidíte výše: -`describe("title", function() { ... })` -: What functionality we're describing? In our case we're describing the function `pow`. Used to group "workers" -- the `it` blocks. +`describe("název", function() { ... })` +: Jakou funkcionalitu popisujeme? V našem případě popisujeme funkci `mocnina`. Používá se k seskupení „pracovníků“ -- bloků `it`. -`it("use case description", function() { ... })` -: In the title of `it` we *in a human-readable way* describe the particular use case, and the second argument is a function that tests it. +`it("popis případu použití", function() { ... })` +: V titulku `it` popíšeme *lidsky čitelným způsobem* konkrétní případ použití. Druhým argumentem je funkce, která jej otestuje. -`assert.equal(value1, value2)` -: The code inside `it` block, if the implementation is correct, should execute without errors. +`assert.equal(hodnota1, hodnota2)` +: Je-li implementace korektní, kód uvnitř bloku `it` by se měl spustit bez chyb. - Functions `assert.*` are used to check whether `pow` works as expected. Right here we're using one of them -- `assert.equal`, it compares arguments and yields an error if they are not equal. Here it checks that the result of `pow(2, 3)` equals `8`. There are other types of comparisons and checks, that we'll add later. +Funkce `assert.*` se používají k ověření, zda `mocnina` funguje tak, jak očekáváme. Právě zde používáme jednu z nich -- `assert.equal`, která porovná argumenty a vyvolá chybu, pokud si nejsou rovny. Zde zkontroluje, zda výsledek `mocnina(2, 3)` se rovná `8`. Existují i jiné druhy porovnání a kontrol, které přidáme později. -The specification can be executed, and it will run the test specified in `it` block. We'll see that later. +Specifikaci můžeme spustit a ta pak spustí test specifikovaný v bloku `it`. To uvidíme později. -## The development flow +## Proces vývoje -The flow of development usually looks like this: +Proces vývoje obvykle vypadá takto: -1. An initial spec is written, with tests for the most basic functionality. -2. An initial implementation is created. -3. To check whether it works, we run the testing framework [Mocha](https://mochajs.org/) (more details soon) that runs the spec. While the functionality is not complete, errors are displayed. We make corrections until everything works. -4. Now we have a working initial implementation with tests. -5. We add more use cases to the spec, probably not yet supported by the implementations. Tests start to fail. -6. Go to 3, update the implementation till tests give no errors. -7. Repeat steps 3-6 till the functionality is ready. +1. Napíše se úvodní specifikace s testy pro většinu základní funkcionality. +2. Vytvoří se úvodní implementace. +3. Abychom prověřili, zda funguje, spustíme testovací rámec [Mocha](https://mochajs.org/) (více později), který spustí specifikaci. Dokud funkcionalita není úplná, budou se zobrazovat chyby. Provádíme opravy, dokud nebude vše fungovat. +4. Nyní máme funkční úvodní implementaci s testy. +5. Do specifikace přidáváme další případy použití, které implementace pravděpodobně ještě nepodporuje. Testy začnou selhávat. +6. Vrátíme se ke kroku 3 a vylepšujeme implementaci, dokud testy nepřestanou vydávat chyby. +7. Opakujeme kroky 3-6, dokud nebude funkcionalita připravena. -So, the development is *iterative*. We write the spec, implement it, make sure tests pass, then write more tests, make sure they work etc. At the end we have both a working implementation and tests for it. +Vývoj je tedy *iterativní*. Napíšeme specifikaci, implementujeme ji, ujistíme se, že testy projdou, napíšeme další testy, ujistíme se, že projdou, atd. Nakonec máme funkční implementaci i její testy. -Let's see this development flow in our practical case. +Podívejme se na tento proces vývoje v praxi. -The first step is already complete: we have an initial spec for `pow`. Now, before making the implementation, let's use a few JavaScript libraries to run the tests, just to see that they are working (they will all fail). +První krok je již téměř hotov: máme úvodní specifikaci funkce `mocnina`. Nyní před vytvořením implementace použijeme několik JavaScriptových knihoven ke spuštění testů, abychom viděli, zda fungují (všechny testy selžou). -## The spec in action +## Specifikace v akci -Here in the tutorial we'll be using the following JavaScript libraries for tests: +V tomto tutoriálu budeme pro testy používat následující JavaScriptové knihovny: -- [Mocha](https://mochajs.org/) -- the core framework: it provides common testing functions including `describe` and `it` and the main function that runs tests. -- [Chai](https://www.chaijs.com/) -- the library with many assertions. It allows to use a lot of different assertions, for now we need only `assert.equal`. -- [Sinon](https://sinonjs.org/) -- a library to spy over functions, emulate built-in functions and more, we'll need it much later. +- [Mocha](https://mochajs.org/) -- jádro rámce: poskytuje běžné testovací funkce včetně `describe` a `it` a hlavní funkci, která spouští testy. +- [Chai](https://www.chaijs.com/) -- knihovna s mnoha kontrolami. Umožňuje nám použít spoustu různých kontrol, ale nyní budeme potřebovat jen `assert.equal`. +- [Sinon](https://sinonjs.org/) -- knihovna k prozkoumávání funkcí, emulování vestavěných funkcí a podobně. Budeme ji potřebovat až mnohem později. -These libraries are suitable for both in-browser and server-side testing. Here we'll consider the browser variant. +Tyto knihovny jsou vhodné pro testování v prohlížeči i na straně serveru. Zde budeme uvažovat prohlížečovou variantu. -The full HTML page with these frameworks and `pow` spec: +Celá HTML stránka s těmito rámci a specifikací funkce `mocnina`: ```html src="https://github.com/index.html" ``` -The page can be divided into five parts: +Tuto stránku lze rozdělit do pěti částí: -1. The `` -- add third-party libraries and styles for tests. -2. The ` - + - + - +
- + diff --git a/1-js/03-code-quality/05-testing-mocha/index.html b/1-js/03-code-quality/05-testing-mocha/index.html index 28a2ea62b..c78960f52 100644 --- a/1-js/03-code-quality/05-testing-mocha/index.html +++ b/1-js/03-code-quality/05-testing-mocha/index.html @@ -1,17 +1,17 @@ - + - + - + @@ -19,18 +19,18 @@ - + - +
- + diff --git a/1-js/03-code-quality/05-testing-mocha/pow-1.view/index.html b/1-js/03-code-quality/05-testing-mocha/pow-1.view/index.html index e48a8d3a2..7a268de82 100644 --- a/1-js/03-code-quality/05-testing-mocha/pow-1.view/index.html +++ b/1-js/03-code-quality/05-testing-mocha/pow-1.view/index.html @@ -1,18 +1,18 @@ - + - + - + @@ -20,18 +20,18 @@ - + - +
- + diff --git a/1-js/03-code-quality/05-testing-mocha/pow-2.view/index.html b/1-js/03-code-quality/05-testing-mocha/pow-2.view/index.html index e8d6be23d..956b6fbb3 100644 --- a/1-js/03-code-quality/05-testing-mocha/pow-2.view/index.html +++ b/1-js/03-code-quality/05-testing-mocha/pow-2.view/index.html @@ -1,18 +1,18 @@ - + - + - + @@ -20,18 +20,18 @@ - + - +
- + diff --git a/1-js/03-code-quality/05-testing-mocha/pow-3.view/index.html b/1-js/03-code-quality/05-testing-mocha/pow-3.view/index.html index c71b0d5d5..4773a9ff9 100644 --- a/1-js/03-code-quality/05-testing-mocha/pow-3.view/index.html +++ b/1-js/03-code-quality/05-testing-mocha/pow-3.view/index.html @@ -1,18 +1,18 @@ - + - + - + @@ -20,24 +20,24 @@ - + - +
- + diff --git a/1-js/03-code-quality/05-testing-mocha/pow-4.view/index.html b/1-js/03-code-quality/05-testing-mocha/pow-4.view/index.html index c71b0d5d5..4773a9ff9 100644 --- a/1-js/03-code-quality/05-testing-mocha/pow-4.view/index.html +++ b/1-js/03-code-quality/05-testing-mocha/pow-4.view/index.html @@ -1,18 +1,18 @@ - + - + - + @@ -20,24 +20,24 @@ - + - +
- + diff --git a/1-js/03-code-quality/05-testing-mocha/pow-full.view/index.html b/1-js/03-code-quality/05-testing-mocha/pow-full.view/index.html index 076b1e5a9..f41da18fc 100644 --- a/1-js/03-code-quality/05-testing-mocha/pow-full.view/index.html +++ b/1-js/03-code-quality/05-testing-mocha/pow-full.view/index.html @@ -1,18 +1,18 @@ - + - + - + @@ -20,25 +20,25 @@ - + - +
- + diff --git a/1-js/03-code-quality/05-testing-mocha/pow-min.view/index.html b/1-js/03-code-quality/05-testing-mocha/pow-min.view/index.html index d82a79dca..8b88e32d3 100644 --- a/1-js/03-code-quality/05-testing-mocha/pow-min.view/index.html +++ b/1-js/03-code-quality/05-testing-mocha/pow-min.view/index.html @@ -1,18 +1,18 @@ - + - + - + @@ -20,21 +20,21 @@ - + - +
- + - + \ No newline at end of file diff --git a/1-js/03-code-quality/05-testing-mocha/pow-nan.view/index.html b/1-js/03-code-quality/05-testing-mocha/pow-nan.view/index.html index 523ae25ec..4773a9ff9 100644 --- a/1-js/03-code-quality/05-testing-mocha/pow-nan.view/index.html +++ b/1-js/03-code-quality/05-testing-mocha/pow-nan.view/index.html @@ -1,18 +1,18 @@ - + - + - + @@ -20,22 +20,24 @@ - + - +
- + diff --git a/1-js/03-code-quality/06-polyfills/article.md b/1-js/03-code-quality/06-polyfills/article.md index 5ca123908..f8e0b5c59 100644 --- a/1-js/03-code-quality/06-polyfills/article.md +++ b/1-js/03-code-quality/06-polyfills/article.md @@ -1,89 +1,89 @@ -# Polyfills and transpilers +# Polyfilly a transpilátory -The JavaScript language steadily evolves. New proposals to the language appear regularly, they are analyzed and, if considered worthy, are appended to the list at and then progress to the [specification](https://www.ecma-international.org/publications-and-standards/standards/ecma-262/). +Jazyk JavaScript se neustále vyvíjí. Pravidelně se pro tento jazyk objevují nové návrhy, ty jsou analyzovány a jsou-li shledány užitečnými, přidají se na seznam na a pak pokračují do [specifikace](https://www.ecma-international.org/publications-and-standards/standards/ecma-262/). -Teams behind JavaScript engines have their own ideas about what to implement first. They may decide to implement proposals that are in draft and postpone things that are already in the spec, because they are less interesting or just harder to do. +Týmy vyvíjející JavaScriptové motory mají své vlastní nápady ohledně toho, co implementovat jako první. Mohou se rozhodnout implementovat návrhy, které jsou teprve načrtnuty, a odložit věci, které jsou už ve specifikaci, protože jsou méně zajímavé nebo prostě jen těžší na implementaci. -So it's quite common for an engine to implement only part of the standard. +Je tedy poměrně běžné, že motor implementuje pouze část standardu. -A good page to see the current state of support for language features is (it's big, we have a lot to study yet). +Dobrá stránka, na které uvidíte aktuální stav podpory vlastností jazyka, je (je to velká tabulka, máme ještě hodně co studovat). -As programmers, we'd like to use most recent features. The more good stuff - the better! +Jako programátoři rádi používáme nejnovější vlastnosti. Čím více dobrých věcí, tím lépe! -On the other hand, how to make our modern code work on older engines that don't understand recent features yet? +Na druhou stranu, jak přimět náš moderní kód, aby fungoval na starších motorech, které ještě nerozumějí vlastnostem přidaným teprve nedávno? -There are two tools for that: +Jsou dva druhy nástrojů, které to zajistí: -1. Transpilers. -2. Polyfills. +1. Transpilátory. +2. Polyfilly. -Here, in this chapter, our purpose is to get the gist of how they work, and their place in web development. +V této kapitole je naším cílem získat náhled na to, jak fungují a jaké je jejich místo při vývoji webů. -## Transpilers +## Transpilátory -A [transpiler](https://en.wikipedia.org/wiki/Source-to-source_compiler) is a special piece of software that translates source code to another source code. It can parse ("read and understand") modern code and rewrite it using older syntax constructs, so that it'll also work in outdated engines. +[Transpilátor](https://cs.wikipedia.org/wiki/Transpiler) neboli transpiler je zvláštní druh softwaru, který překládá zdrojový kód do jiného zdrojového kódu. Umí parsovat („přečíst a pochopit“) moderní kód a přepsat jej pomocí starších syntaktických konstrukcí tak, aby kód fungoval i na zastaralých motorech. -E.g. JavaScript before year 2020 didn't have the "nullish coalescing operator" `??`. So, if a visitor uses an outdated browser, it may fail to understand the code like `height = height ?? 100`. +Například JavaScript před rokem 2020 neměl „operátor koalescence“ `??`. Jestliže tedy návštěvník používá zastaralý prohlížeč, nemusí porozumět kódu `výška = výška ?? 100`. -A transpiler would analyze our code and rewrite `height ?? 100` into `(height !== undefined && height !== null) ? height : 100`. +Transpilátor analyzuje náš kód a přepíše `výška ?? 100` na `(výška !== undefined && výška !== null) ? výška : 100`. ```js -// before running the transpiler -height = height ?? 100; +// před spuštěním transpilátoru +výška = výška ?? 100; -// after running the transpiler -height = (height !== undefined && height !== null) ? height : 100; +// po spuštění transpilátoru +výška = (výška !== undefined && výška !== null) ? výška : 100; ``` -Now the rewritten code is suitable for older JavaScript engines. +Nyní je přepsaný kód vhodný i pro starší JavaScriptové motory. -Usually, a developer runs the transpiler on their own computer, and then deploys the transpiled code to the server. +Vývojář si obvykle spustí transpilátor na svém vlastním počítači a pak zveřejní transpilovaný kód na serveru. -Speaking of names, [Babel](https://babeljs.io) is one of the most prominent transpilers out there. +Když hovoříme o názvech, jedním z nejvýznamnějších transpilátorů je [Babel](https://babeljs.io). -Modern project build systems, such as [webpack](https://webpack.js.org/), provide a means to run a transpiler automatically on every code change, so it's very easy to integrate into the development process. +Moderní systémy pro vytváření projektů, například [webpack](https://webpack.js.org/), poskytují způsoby, jak spouštět transpilátor automaticky při každé změně kódu, takže je velmi jednoduché jej integrovat do procesu vývoje. -## Polyfills +## Polyfilly -New language features may include not only syntax constructs and operators, but also built-in functions. +Mezi nové vlastnosti jazyka mohou patřit nejenom syntaktické konstrukce a operátory, ale také vestavěné funkce. -For example, `Math.trunc(n)` is a function that "cuts off" the decimal part of a number, e.g `Math.trunc(1.23)` returns `1`. +Například `Math.trunc(n)` je funkce, která „odřízne“ desetinnou část čísla, např. `Math.trunc(1.23)` vrátí `1`. -In some (very outdated) JavaScript engines, there's no `Math.trunc`, so such code will fail. +V některých (velmi zastaralých) JavaScriptových motorech není funkce `Math.trunc`, takže takový kód selže. -As we're talking about new functions, not syntax changes, there's no need to transpile anything here. We just need to declare the missing function. +Protože hovoříme o nových funkcích a ne o syntaktických změnách, není tady potřeba nic transpilovat. Potřebujeme jenom deklarovat chybějící funkci. -A script that updates/adds new functions is called "polyfill". It "fills in" the gap and adds missing implementations. +Skript, který vylepšuje nebo přidává nové funkce, se nazývá „polyfill“. „Vyplní“ (anglicky „fill in“) mezeru a přidá chybějící implementace. -For this particular case, the polyfill for `Math.trunc` is a script that implements it, like this: +V tomto konkrétním případě je polyfill pro `Math.trunc` skript, který ji implementuje, například takto: ```js -if (!Math.trunc) { // if no such function - // implement it - Math.trunc = function(number) { - // Math.ceil and Math.floor exist even in ancient JavaScript engines - // they are covered later in the tutorial - return number < 0 ? Math.ceil(number) : Math.floor(number); +if (!Math.trunc) { // není-li taková funkce + // implementuje ji + Math.trunc = function(číslo) { + // Math.ceil a Math.floor existují i v nejstarších JavaScriptových motorech + // budou vysvětleny později v tomto tutoriálu + return číslo < 0 ? Math.ceil(číslo) : Math.floor(číslo); }; } ``` -JavaScript is a highly dynamic language. Scripts may add/modify any function, even built-in ones. +JavaScript je vysoce dynamický jazyk. Skripty mohou přidávat nebo modifikovat libovolné funkce, dokonce i vestavěné. -One interesting polyfill library is [core-js](https://github.com/zloirock/core-js), which supports a wide range of features and allows you to include only the ones you need. +Zajímavá knihovna polyfillů je [core js](https://github.com/zloirock/core-js), která podporuje širokou škálu vlastností a umožňuje vám přidat jen ty, které potřebujete. -## Summary +## Shrnutí -In this chapter we'd like to motivate you to study modern and even "bleeding-edge" language features, even if they aren't yet well-supported by JavaScript engines. +V této kapitole jsme vás chtěli motivovat k prostudování moderních vlastností jazyka, včetně těch „za hranou“, i když ještě nejsou příliš podporovány v motorech JavaScriptu. -Just don't forget to use a transpiler (if using modern syntax or operators) and polyfills (to add functions that may be missing). They'll ensure that the code works. +Jen nezapomínejte používat transpilátor (používáte-li moderní syntaxi nebo operátory) a polyfilly (abyste přidali funkce, které mohou chybět). Ty zajistí, že váš kód bude fungovat. -For example, later when you're familiar with JavaScript, you can setup a code build system based on [webpack](https://webpack.js.org/) with the [babel-loader](https://github.com/babel/babel-loader) plugin. +Například později, až budete JavaScript dobře znát, si můžete nastavit systém pro vytváření kódu založený na [webpacku](https://webpack.js.org/) s pluginem [babel-loader](https://github.com/babel/babel-loader). -Good resources that show the current state of support for various features: -- - for pure JavaScript. -- - for browser-related functions. +Dobré zdroje, které ukazují aktuální stav podpory různých vlastností: +- - pro čistý JavaScript. +- - pro funkce vztahující se k prohlížeči. -P.S. Google Chrome is usually the most up-to-date with language features, try it if a tutorial demo fails. Most tutorial demos work with any modern browser though. +P.S. Pokud se týká vlastností jazyka, obvykle je nejaktuálnější Google Chrome. Pokud vám některé demo v tomto tutoriálu selže, zkuste ho. Většina dem v tutoriálu však funguje na kterémkoli moderním prohlížeči. diff --git a/1-js/03-code-quality/index.md b/1-js/03-code-quality/index.md index 2ef64fa69..78218ce6a 100644 --- a/1-js/03-code-quality/index.md +++ b/1-js/03-code-quality/index.md @@ -1,3 +1,3 @@ -# Code quality +# Kvalita kódu -This chapter explains coding practices that we'll use further in the development. +Tato kapitola vysvětluje programovací praktiky, které budeme používat nadále při vývoji. diff --git a/1-js/04-object-basics/01-object/2-hello-object/solution.md b/1-js/04-object-basics/01-object/2-hello-object/solution.md index 60083b963..9c53460bf 100644 --- a/1-js/04-object-basics/01-object/2-hello-object/solution.md +++ b/1-js/04-object-basics/01-object/2-hello-object/solution.md @@ -1,10 +1,10 @@ ```js -let user = {}; -user.name = "John"; -user.surname = "Smith"; -user.name = "Pete"; -delete user.name; +let uživatel = {}; +uživatel.jméno = "Jan"; +uživatel.příjmení = "Novák"; +uživatel.jméno = "Petr"; +delete uživatel.jméno; ``` diff --git a/1-js/04-object-basics/01-object/2-hello-object/task.md b/1-js/04-object-basics/01-object/2-hello-object/task.md index 2841a058f..48a2d6808 100644 --- a/1-js/04-object-basics/01-object/2-hello-object/task.md +++ b/1-js/04-object-basics/01-object/2-hello-object/task.md @@ -2,13 +2,12 @@ importance: 5 --- -# Hello, object +# Ahoj, objekte -Write the code, one line for each action: - -1. Create an empty object `user`. -2. Add the property `name` with the value `John`. -3. Add the property `surname` with the value `Smith`. -4. Change the value of the `name` to `Pete`. -5. Remove the property `name` from the object. +Napište tento kód, pro každou akci jeden řádek: +1. Vytvořte prázdný objekt `uživatel`. +2. Přidejte vlastnost `jméno` s hodnotou `Jan`. +3. Přidejte vlastnost `příjmení` s hodnotou `Novák`. +4. Změňte hodnotu vlastnosti `jméno` na `Petr`. +5. Odstraňte vlastnost `jméno` z objektu. \ No newline at end of file diff --git a/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js b/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js index db3283e49..7e8287b43 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js +++ b/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js @@ -1,6 +1,6 @@ -function isEmpty(obj) { - for (let key in obj) { - // if the loop has started, there is a property +function jePrázdný(obj) { + for (let klíč in obj) { + // pokud cyklus začal, je tam nějaká vlastnost return false; } return true; diff --git a/1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js b/1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js index 4db5efabe..cc5956948 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js +++ b/1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js @@ -1,11 +1,11 @@ -describe("isEmpty", function() { - it("returns true for an empty object", function() { - assert.isTrue(isEmpty({})); +describe("jePrázdný", function() { + it("vrátí true pro prázdný objekt", function() { + assert.isTrue(jePrázdný({})); }); - it("returns false if a property exists", function() { - assert.isFalse(isEmpty({ - anything: false + it("vrátí false, jestliže existuje nějaká vlastnost", function() { + assert.isFalse(jePrázdný({ + cokoli: false })); }); }); \ No newline at end of file diff --git a/1-js/04-object-basics/01-object/3-is-empty/solution.md b/1-js/04-object-basics/01-object/3-is-empty/solution.md index b876973b5..c63abc9a5 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/solution.md +++ b/1-js/04-object-basics/01-object/3-is-empty/solution.md @@ -1 +1 @@ -Just loop over the object and `return false` immediately if there's at least one property. +Prostě proveďte cyklus nad objektem, a má-li aspoň jednu vlastnost, okamžitě proveďte `return false`. diff --git a/1-js/04-object-basics/01-object/3-is-empty/task.md b/1-js/04-object-basics/01-object/3-is-empty/task.md index c438d36a2..7f4375bd8 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/task.md +++ b/1-js/04-object-basics/01-object/3-is-empty/task.md @@ -2,19 +2,19 @@ importance: 5 --- -# Check for emptiness +# Ověření prázdnoty -Write the function `isEmpty(obj)` which returns `true` if the object has no properties, `false` otherwise. +Napište funkci `jePrázdný(obj)`, která vrátí `true`, jestliže objekt nemá žádné vlastnosti, a `false` jinak. -Should work like that: +Měla by fungovat takto: ```js -let schedule = {}; +let rozvrh = {}; -alert( isEmpty(schedule) ); // true +alert( jePrázdný(rozvrh) ); // true -schedule["8:30"] = "get up"; +rozvrh["8:30"] = "vstát"; -alert( isEmpty(schedule) ); // false +alert( jePrázdný(rozvrh) ); // false ``` diff --git a/1-js/04-object-basics/01-object/5-sum-object/solution.md b/1-js/04-object-basics/01-object/5-sum-object/solution.md index 63df87849..d1b1c7616 100644 --- a/1-js/04-object-basics/01-object/5-sum-object/solution.md +++ b/1-js/04-object-basics/01-object/5-sum-object/solution.md @@ -1,16 +1,16 @@ ```js run -let salaries = { - John: 100, - Ann: 160, - Pete: 130 +let platy = { + Jan: 100, + Anna: 160, + Petr: 130 }; -let sum = 0; -for (let key in salaries) { - sum += salaries[key]; +let součet = 0; +for (let klíč in platy) { + součet += platy[klíč]; } -alert(sum); // 390 +alert(součet); // 390 ``` diff --git a/1-js/04-object-basics/01-object/5-sum-object/task.md b/1-js/04-object-basics/01-object/5-sum-object/task.md index 7e3e048d0..72323466e 100644 --- a/1-js/04-object-basics/01-object/5-sum-object/task.md +++ b/1-js/04-object-basics/01-object/5-sum-object/task.md @@ -2,18 +2,18 @@ importance: 5 --- -# Sum object properties +# Sečtěte vlastnosti objektu -We have an object storing salaries of our team: +Máme objekt, v němž jsou uloženy platy našeho týmu: ```js -let salaries = { - John: 100, - Ann: 160, - Pete: 130 +let platy = { + Jan: 100, + Anna: 160, + Petr: 130 } ``` -Write the code to sum all salaries and store in the variable `sum`. Should be `390` in the example above. +Napište kód, který všechny platy sečte a uloží do proměnné `součet`. Ve výše uvedeném příkladu by mělo vyjít `390`. -If `salaries` is empty, then the result must be `0`. \ No newline at end of file +Je-li objekt `platy` prázdný, výsledek musí být `0`. \ No newline at end of file diff --git a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/solution.js b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/solution.js index 4668c1dc0..c91ab0f43 100644 --- a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/solution.js +++ b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/solution.js @@ -1,7 +1,7 @@ -function multiplyNumeric(obj) { - for (let key in obj) { - if (typeof obj[key] == 'number') { - obj[key] *= 2; +function vynásobČísla(obj) { + for (let klíč in obj) { + if (typeof obj[klíč] == 'number') { + obj[klíč] *= 2; } } } \ No newline at end of file diff --git a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js index a02b1e1cb..a7e7b52ee 100644 --- a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js +++ b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js @@ -1,17 +1,17 @@ let menu = { - width: 200, - height: 300, - title: "My menu" + šířka: 200, + výška: 300, + titulek: "Moje menu" }; -function multiplyNumeric(obj) { +function vynásobČísla(obj) { - /* your code */ + /* váš kód */ } -multiplyNumeric(menu); +vynásobČísla(menu); -alert( "menu width=" + menu.width + " height=" + menu.height + " title=" + menu.title ); +alert( "menu šířka=" + menu.šířka + " výška=" + menu.výška + " titulek=" + menu.titulek ); diff --git a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js index 064e5414f..34f2434ab 100644 --- a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js +++ b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js @@ -1,18 +1,18 @@ -describe("multiplyNumeric", function() { - it("multiplies all numeric properties by 2", function() { +describe("vynásobČísla", function() { + it("vynásobí všechny číselné vlastnosti dvěma", function() { let menu = { - width: 200, - height: 300, - title: "My menu" + šířka: 200, + výška: 300, + titulek: "Moje menu" }; - let result = multiplyNumeric(menu); - assert.equal(menu.width, 400); - assert.equal(menu.height, 600); - assert.equal(menu.title, "My menu"); + let výsledek = vynásobČísla(menu); + assert.equal(menu.šířka, 400); + assert.equal(menu.výška, 600); + assert.equal(menu.titulek, "Moje menu"); }); - it("returns nothing", function() { - assert.isUndefined( multiplyNumeric({}) ); + it("nevrátí nic", function() { + assert.isUndefined( vynásobČísla({}) ); }); }); diff --git a/1-js/04-object-basics/01-object/8-multiply-numeric/task.md b/1-js/04-object-basics/01-object/8-multiply-numeric/task.md index 6878ca088..41e57cf09 100644 --- a/1-js/04-object-basics/01-object/8-multiply-numeric/task.md +++ b/1-js/04-object-basics/01-object/8-multiply-numeric/task.md @@ -2,32 +2,32 @@ importance: 3 --- -# Multiply numeric property values by 2 +# Vynásobte hodnoty číselných vlastností dvěma -Create a function `multiplyNumeric(obj)` that multiplies all numeric property values of `obj` by `2`. +Vytvořte funkci `vynásobČísla(obj)`, která vynásobí hodnoty všech číselných vlastností objektu `obj` dvěma. -For instance: +Například: ```js -// before the call +// před voláním let menu = { - width: 200, - height: 300, - title: "My menu" + šířka: 200, + výška: 300, + titulek: "Moje menu" }; -multiplyNumeric(menu); +vynásobČísla(menu); -// after the call +// po volání menu = { - width: 400, - height: 600, - title: "My menu" + šířka: 400, + výška: 600, + titulek: "Moje menu" }; ``` -Please note that `multiplyNumeric` does not need to return anything. It should modify the object in-place. +Prosíme všimněte si, že `vynásobČísla` nemusí nic vracet. Měla by modifikovat samotný objekt. -P.S. Use `typeof` to check for a number here. +P.S. Pro kontrolu, zda hodnota je číslo, použijte `typeof`. diff --git a/1-js/04-object-basics/01-object/article.md b/1-js/04-object-basics/01-object/article.md index 0fe5979fa..841dd000e 100644 --- a/1-js/04-object-basics/01-object/article.md +++ b/1-js/04-object-basics/01-object/article.md @@ -1,263 +1,263 @@ -# Objects +# Objekty -As we know from the chapter , there are eight data types in JavaScript. Seven of them are called "primitive", because their values contain only a single thing (be it a string or a number or whatever). +Jak víme z kapitoly , JavaScript obsahuje osm datových typů. Sedm z nich se nazývá „primitivní typy“ nebo „primitivy“, protože jejich hodnoty obsahují pouze jednu věc (ať už je to řetězec, číslo nebo něco jiného). -In contrast, objects are used to store keyed collections of various data and more complex entities. In JavaScript, objects penetrate almost every aspect of the language. So we must understand them first before going in-depth anywhere else. +Naproti tomu objekty se používají k uložení kolekcí různých dat pod klíči a složitějších entit. V JavaScriptu objekty pronikají do téměř všech aspektů jazyka. Musíme jim tedy porozumět předtím, než půjdeme do hloubky v něčem jiném. -An object can be created with figure brackets `{…}` with an optional list of *properties*. A property is a "key: value" pair, where `key` is a string (also called a "property name"), and `value` can be anything. +Objekt můžeme vytvořit pomocí složených závorek `{…}` obsahujících nepovinný seznam *vlastností*. Vlastnost je dvojice „klíč: hodnota“, v níž `klíč` je řetězec (nazývá se také „název vlastnosti“) a `hodnota` může být cokoli. -We can imagine an object as a cabinet with signed files. Every piece of data is stored in its file by the key. It's easy to find a file by its name or add/remove a file. +Objekt si můžeme představit jako skříň s označenými spisy. Každý kousek dat je uložen podle klíče ve svém spisu. Je pak lehké najít spis podle jeho názvu nebo spis přidat či odstranit. ![](object.svg) -An empty object ("empty cabinet") can be created using one of two syntaxes: +Prázdný objekt („prázdná skříň“) může být vytvořen pomocí jedné ze dvou syntaxí: ```js -let user = new Object(); // "object constructor" syntax -let user = {}; // "object literal" syntax +let uživatel = new Object(); // syntaxe „konstruktor objektu“ +let uživatel = {}; // syntaxe „objektový literál“ ``` ![](object-user-empty.svg) -Usually, the figure brackets `{...}` are used. That declaration is called an *object literal*. +Obvykle se používají složené závorky `{...}`. Tato deklarace se nazývá *objektový literál*. -## Literals and properties +## Literály a vlastnosti -We can immediately put some properties into `{...}` as "key: value" pairs: +Do `{...}` můžeme rovnou umístit vlastnosti jako dvojice „klíč: hodnota“: ```js -let user = { // an object - name: "John", // by key "name" store value "John" - age: 30 // by key "age" store value 30 +let uživatel = { // objekt + jméno: "Jan", // pod klíčem „jméno“ uložíme hodnotu „Jan“ + věk: 30 // pod klíčem „věk“ uložíme hodnotu 30 }; ``` -A property has a key (also known as "name" or "identifier") before the colon `":"` and a value to the right of it. +Vlastnost má klíč (nazývaný také „jméno“, „název“ nebo „identifikátor“) před dvojtečkou `":"` a hodnotu napravo od ní. -In the `user` object, there are two properties: +V objektu `uživatel` se nacházejí dvě vlastnosti: -1. The first property has the name `"name"` and the value `"John"`. -2. The second one has the name `"age"` and the value `30`. +1. První vlastnost má název `"jméno"` a hodnotu `"Jan"`. +2. Druhá vlastnost má název `"věk"` a hodnotu `30`. -The resulting `user` object can be imagined as a cabinet with two signed files labeled "name" and "age". +Výsledný objekt `uživatel` si můžeme představit jako skříň se dvěma spisy označenými „jméno“ a „věk“. ![user object](object-user.svg) -We can add, remove and read files from it at any time. +Kdykoli do ní můžeme přidávat, odebírat a číst z ní spisy. -Property values are accessible using the dot notation: +Hodnoty vlastností jsou dostupné pomocí tečkové notace: ```js -// get property values of the object: -alert( user.name ); // John -alert( user.age ); // 30 +// vrátí hodnoty vlastností objektu: +alert( uživatel.jméno ); // Jan +alert( uživatel.věk ); // 30 ``` -The value can be of any type. Let's add a boolean one: +Hodnota může být libovolného typu. Přidejme hodnotu typu boolean: ```js -user.isAdmin = true; +uživatel.jeSprávce = true; ``` ![user object 2](object-user-isadmin.svg) -To remove a property, we can use the `delete` operator: +K odstranění vlastnosti můžeme použít operátor `delete`: ```js -delete user.age; +delete uživatel.věk; ``` ![user object 3](object-user-delete.svg) -We can also use multiword property names, but then they must be quoted: +Můžeme použít i víceslovné názvy vlastností, ale pak je musíme dát do uvozovek: ```js -let user = { - name: "John", - age: 30, - "likes birds": true // multiword property name must be quoted +let uživatel = { + jméno: "Jan", + věk: 30, + "má rád ptáky": true // víceslovný název vlastnosti musí být v uvozovkách }; ``` ![](object-user-props.svg) -The last property in the list may end with a comma: +Poslední vlastnost v seznamu může končit čárkou: ```js -let user = { - name: "John", - age: 30*!*,*/!* +let uživatel = { + jméno: "Jan", + věk: 30*!*,*/!* } ``` -That is called a "trailing" or "hanging" comma. Makes it easier to add/remove/move around properties, because all lines become alike. +Tato čárka se nazývá „vlečná“. Díky ní je jednodušší přidávat, odebírat nebo přesunovat vlastnosti, protože všechny řádky budou vypadat podobně. -## Square brackets +## Hranaté závorky -For multiword properties, the dot access doesn't work: +U víceslovných vlastností tečkový přístup nefunguje: ```js run -// this would give a syntax error -user.likes birds = true +// toto způsobí syntaktickou chybu +uživatel.má rád ptáky = true ``` -JavaScript doesn't understand that. It thinks that we address `user.likes`, and then gives a syntax error when comes across unexpected `birds`. +JavaScript tomu nerozumí. Myslí si, že adresujeme `uživatel.má`, a pak oznámí syntaktickou chybu, když narazí na nečekané `rád`. -The dot requires the key to be a valid variable identifier. That implies: contains no spaces, doesn't start with a digit and doesn't include special characters (`$` and `_` are allowed). +Tečka vyžaduje, aby klíč byl platný identifikátor proměnné. To znamená, že neobsahuje žádné mezery, nezačíná číslicí a neobsahuje speciální znaky (`$` a `_` jsou povoleny). -There's an alternative "square bracket notation" that works with any string: +Existuje alternativní „notace hranatých závorek“, která funguje s libovolným řetězcem: ```js run -let user = {}; +let uživatel = {}; -// set -user["likes birds"] = true; +// nastavit +uživatel["má rád ptáky"] = true; -// get -alert(user["likes birds"]); // true +// načíst +alert(uživatel["má rád ptáky"]); // true -// delete -delete user["likes birds"]; +// smazat +delete uživatel["má rád ptáky"]; ``` -Now everything is fine. Please note that the string inside the brackets is properly quoted (any type of quotes will do). +Nyní je všechno v pořádku. Všimněte si, že řetězec uvnitř hranatých závorek je správně ohraničen uvozovkami (lze použít jakýkoli druh uvozovek). -Square brackets also provide a way to obtain the property name as the result of any expression -- as opposed to a literal string -- like from a variable as follows: +Hranaté závorky také poskytují způsob, jak získat název vlastnosti jako výsledek jakéhokoli výrazu -- na rozdíl od literálního řetězce -- například z proměnné následovně: ```js -let key = "likes birds"; +let klíč = "má rád ptáky"; -// same as user["likes birds"] = true; -user[key] = true; +// totéž jako uživatel["má rád ptáky"] = true; +uživatel[klíč] = true; ``` -Here, the variable `key` may be calculated at run-time or depend on the user input. And then we use it to access the property. That gives us a great deal of flexibility. +Zde může být proměnná `klíč` vypočtena za běhu skriptu nebo záviset na uživatelském vstupu. A pak ji použijeme k přístupu k vlastnosti. To nám dává velké množství flexibility. -For instance: +Například: ```js run -let user = { - name: "John", - age: 30 +let uživatel = { + jméno: "Jan", + věk: 30 }; -let key = prompt("What do you want to know about the user?", "name"); +let klíč = prompt("Co chcete vědět o uživateli?", "jméno"); -// access by variable -alert( user[key] ); // John (if enter "name") +// přístup pomocí proměnné +alert( uživatel[klíč] ); // Jan (pokud bylo zadáno "jméno") ``` -The dot notation cannot be used in a similar way: +Tečkovou notaci nelze podobným způsobem použít: ```js run -let user = { - name: "John", - age: 30 +let uživatel = { + jméno: "Jan", + věk: 30 }; -let key = "name"; -alert( user.key ) // undefined +let klíč = "jméno"; +alert( uživatel.klíč ) // undefined ``` -### Computed properties +### Vypočítávané vlastnosti -We can use square brackets in an object literal, when creating an object. That's called *computed properties*. +Když vytváříme objekt, můžeme použít hranaté závorky v objektovém literálu. Takové vlastnosti se nazývají *vypočítávané*. -For instance: +Například: ```js run -let fruit = prompt("Which fruit to buy?", "apple"); +let ovoce = prompt("Jaké ovoce koupit?", "jablko"); -let bag = { +let taška = { *!* - [fruit]: 5, // the name of the property is taken from the variable fruit + [ovoce]: 5, // název vlastnosti se získá z proměnné ovoce */!* }; -alert( bag.apple ); // 5 if fruit="apple" +alert( taška.jablko ); // 5, je-li ovoce=="jablko" ``` -The meaning of a computed property is simple: `[fruit]` means that the property name should be taken from `fruit`. +Význam vypočítávané vlastnosti je jednoduchý: `[ovoce]` znamená, že název vlastnosti by měl být převzat z proměnné `ovoce`. -So, if a visitor enters `"apple"`, `bag` will become `{apple: 5}`. +Jestliže tedy návštěvník zadá `"jablko"`, `taška` bude `{jablko: 5}`. -Essentially, that works the same as: +V zásadě to funguje stejně jako: ```js run -let fruit = prompt("Which fruit to buy?", "apple"); -let bag = {}; +let ovoce = prompt("Jaké ovoce koupit?", "jablko"); +let taška = {}; -// take property name from the fruit variable -bag[fruit] = 5; +// vezmeme název vlastnosti z proměnné ovoce +taška[ovoce] = 5; ``` -...But looks nicer. +...Ale vypadá to lépe. -We can use more complex expressions inside square brackets: +Uvnitř hranatých závorek můžeme používat i složitější výrazy: ```js -let fruit = 'apple'; -let bag = { - [fruit + 'Computers']: 5 // bag.appleComputers = 5 +let ovoce = 'apple'; // anglicky „jablko“ (pozn. překl.) +let taška = { + [ovoce + 'Computers']: 5 // taška.appleComputers = 5 }; ``` -Square brackets are much more powerful than dot notation. They allow any property names and variables. But they are also more cumbersome to write. +Hranaté závorky jsou mnohem silnější než tečková notace. Umožňují libovolné názvy vlastností a proměnné. Je však také pracnější je napsat. -So most of the time, when property names are known and simple, the dot is used. And if we need something more complex, then we switch to square brackets. +Většinou se tedy používá tečka, jsou-li názvy vlastností známé a jednoduché. Teprve když potřebujeme něco složitějšího, přejdeme k hranatým závorkám. -## Property value shorthand +## Zkratka hodnoty vlastnosti -In real code, we often use existing variables as values for property names. +Ve skutečném kódu často používáme jako hodnoty vlastností již existující proměnné. -For instance: +Například: ```js run -function makeUser(name, age) { +function vytvořUživatele(jméno, věk) { return { - name: name, - age: age, - // ...other properties + jméno: jméno, + věk: věk, + // ...další vlastnosti }; } -let user = makeUser("John", 30); -alert(user.name); // John +let uživatel = vytvořUživatele("Jan", 30); +alert(uživatel.jméno); // Jan ``` -In the example above, properties have the same names as variables. The use-case of making a property from a variable is so common, that there's a special *property value shorthand* to make it shorter. +Ve výše uvedeném příkladu mají vlastnosti stejné názvy jako proměnné. Vytvoření vlastnosti z proměnné se provádí natolik často, že pro něj existuje speciální *zkratka hodnoty vlastnosti*, která jej zkracuje. -Instead of `name:name` we can just write `name`, like this: +Místo `jméno:jméno` můžeme napsat jen `jméno`, například takto: ```js -function makeUser(name, age) { +function vytvořUživatele(jméno, věk) { *!* return { - name, // same as name: name - age, // same as age: age + jméno, // totéž jako jméno: jméno + věk, // totéž jako věk: věk // ... }; */!* } ``` -We can use both normal properties and shorthands in the same object: +Ve stejném objektu můžeme použít běžné vlastnosti i zkratky: ```js -let user = { - name, // same as name:name - age: 30 +let uživatel = { + jméno, // totéž jako jméno: jméno + věk: 30 }; ``` -## Property names limitations +## Omezení názvů vlastností -As we already know, a variable cannot have a name equal to one of the language-reserved words like "for", "let", "return" etc. +Jak už víme, proměnná nemůže mít stejný název jako některé z rezervovaných slov, např. „for“, „let“, „return“ atd. -But for an object property, there's no such restriction: +Pro vlastnost objektu však toto omezení neplatí: ```js run -// these properties are all right +// všechny tyto vlastnosti jsou správně let obj = { for: 1, let: 2, @@ -267,237 +267,237 @@ let obj = { alert( obj.for + obj.let + obj.return ); // 6 ``` -In short, there are no limitations on property names. They can be any strings or symbols (a special type for identifiers, to be covered later). +Krátce řečeno, názvy vlastností nejsou nijak omezeny. Mohou to být libovolné řetězce nebo symboly (speciální typ identifikátorů, který bude objasněn později). -Other types are automatically converted to strings. +Ostatní typy se automaticky konvertují na řetězce. -For instance, a number `0` becomes a string `"0"` when used as a property key: +Například když je jako klíč vlastnosti použito číslo `0`, stane se řetězcem `0`: ```js run let obj = { - 0: "test" // same as "0": "test" + 0: "test" // totéž jako "0": "test" }; -// both alerts access the same property (the number 0 is converted to string "0") +// oba alerty přistupují ke stejné vlastnosti (číslo 0 se převede na řetězec "0") alert( obj["0"] ); // test -alert( obj[0] ); // test (same property) +alert( obj[0] ); // test (stejná vlastnost) ``` -There's a minor gotcha with a special property named `__proto__`. We can't set it to a non-object value: +Je tady drobné úskalí se speciální vlastností jménem `__proto__`. Tu nemůžeme nastavit na neobjektovou hodnotu: ```js run let obj = {}; -obj.__proto__ = 5; // assign a number -alert(obj.__proto__); // [object Object] - the value is an object, didn't work as intended +obj.__proto__ = 5; // přiřadíme číslo +alert(obj.__proto__); // [object Object] - hodnota je objekt, nefungovalo to tak, jak jsme zamýšleli ``` -As we see from the code, the assignment to a primitive `5` is ignored. +Jak vidíme z kódu, přiřazení primitivu `5` se ignoruje. -We'll cover the special nature of `__proto__` in [subsequent chapters](info:prototype-inheritance), and suggest the [ways to fix](info:prototype-methods) such behavior. +V [dalších kapitolách](info:prototype-inheritance) vysvětlíme zvláštní povahu `__proto__` a naznačíme [způsoby](info:prototype-methods), jak takové chování opravit. -## Property existence test, "in" operator +## Test existence vlastnosti, operátor „in“ -A notable feature of objects in JavaScript, compared to many other languages, is that it's possible to access any property. There will be no error if the property doesn't exist! +Pozoruhodnou vlastností objektů v JavaScriptu, na rozdíl od mnoha jiných jazyků, je možnost přistupovat k libovolné vlastnosti. Pokud vlastnost nebude existovat, nenastane chyba! -Reading a non-existing property just returns `undefined`. So we can easily test whether the property exists: +Načtení neexistující vlastnosti jednoduše vrátí `undefined`. Můžeme tedy snadno otestovat, zda vlastnost existuje: ```js run -let user = {}; +let uživatel = {}; -alert( user.noSuchProperty === undefined ); // true means "no such property" +alert( uživatel.takováVlastnostNení === undefined ); // true znamená „taková vlastnost neexistuje“ ``` -There's also a special operator `"in"` for that. +K tomuto účelu existuje i speciální operátor `"in"`. -The syntax is: +Jeho syntaxe je: ```js -"key" in object +"klíč" in objekt ``` -For instance: +Například: ```js run -let user = { name: "John", age: 30 }; +let uživatel = { jméno: "Jan", věk: 30 }; -alert( "age" in user ); // true, user.age exists -alert( "blabla" in user ); // false, user.blabla doesn't exist +alert( "věk" in uživatel ); // true, uživatel.věk existuje +alert( "blabla" in uživatel ); // false, uživatel.blabla neexistuje ``` -Please note that on the left side of `in` there must be a *property name*. That's usually a quoted string. +Prosíme všimněte si, že na levé straně `in` musí být *název vlastnosti*, což je obvykle řetězec v uvozovkách. -If we omit quotes, that means a variable should contain the actual name to be tested. For instance: +Vypustíme-li uvozovky, znamená to proměnnou, která by měla obsahovat skutečný název, který bude prověřen. Například: ```js run -let user = { age: 30 }; +let uživatel = { věk: 30 }; -let key = "age"; -alert( *!*key*/!* in user ); // true, property "age" exists +let klíč = "věk"; +alert( *!*klíč*/!* in uživatel ); // true, vlastnost „věk“ existuje ``` -Why does the `in` operator exist? Isn't it enough to compare against `undefined`? +Proč vůbec existuje operátor `in`? Nestačilo by porovnávat s `undefined`? -Well, most of the time the comparison with `undefined` works fine. But there's a special case when it fails, but `"in"` works correctly. +Ve většině případů porovnání s `undefined` funguje správně. Existuje však speciální případ, kdy selže, ale operátor `"in"` funguje korektně. -It's when an object property exists, but stores `undefined`: +Je to tehdy, když vlastnost objektu existuje, ale je v ní uloženo `undefined`: ```js run let obj = { test: undefined }; -alert( obj.test ); // it's undefined, so - no such property? +alert( obj.test ); // je undefined, takže - taková vlastnost neexistuje? -alert( "test" in obj ); // true, the property does exist! +alert( "test" in obj ); // true, vlastnost existuje! ``` -In the code above, the property `obj.test` technically exists. So the `in` operator works right. +Ve výše uvedeném kódu vlastnost `obj.test` technicky existuje, takže operátor `in` funguje správně. -Situations like this happen very rarely, because `undefined` should not be explicitly assigned. We mostly use `null` for "unknown" or "empty" values. So the `in` operator is an exotic guest in the code. +Takové situace nastávají velmi zřídka, jelikož `undefined` by nemělo být výslovně přiřazováno. Pro „neznámé“ nebo „prázdné“ hodnoty většinou používáme `null`. Proto je operátor `in` v kódu exotickým hostem. -## The "for..in" loop [#forin] +## Cyklus „for..in“ [#forin] -To walk over all keys of an object, there exists a special form of the loop: `for..in`. This is a completely different thing from the `for(;;)` construct that we studied before. +Pro procházení všemi klíči objektu existuje speciální forma cyklu: `for..in`. Je to úplně něco jiného než konstrukce `for(;;)`, kterou jsme již prostudovali. -The syntax: +Syntaxe: ```js -for (key in object) { - // executes the body for each key among object properties +for (klíč in objekt) { + // tělo se spustí pro každý klíč mezi vlastnostmi objektu } ``` -For instance, let's output all properties of `user`: +Vypišme například všechny vlastnosti objektu `uživatel`: ```js run -let user = { - name: "John", - age: 30, - isAdmin: true +let uživatel = { + jméno: "Jan", + věk: 30, + jeSprávce: true }; -for (let key in user) { - // keys - alert( key ); // name, age, isAdmin - // values for the keys - alert( user[key] ); // John, 30, true +for (let klíč in uživatel) { + // klíče + alert( klíč ); // jméno, věk, jeSprávce + // hodnoty klíčů + alert( uživatel[klíč] ); // Jan, 30, true } ``` -Note that all "for" constructs allow us to declare the looping variable inside the loop, like `let key` here. +Všimněte si, že všechny konstrukce „for“ nám umožňují deklarovat uvnitř cyklu smyčkovou proměnnou, jako zde `let klíč`. -Also, we could use another variable name here instead of `key`. For instance, `"for (let prop in obj)"` is also widely used. +Můžeme zde použít i jiný název proměnné namísto `klíč`. Například hojně se používá `"for (let vlastnost in obj)"`. -### Ordered like an object +### Seřazené jako objekt -Are objects ordered? In other words, if we loop over an object, do we get all properties in the same order they were added? Can we rely on this? +Jsou objekty seřazené? Jinými slovy: když cyklus prochází nad objektem, obdržíme všechny vlastnosti ve stejném pořadí, v jakém byly přidány? Můžeme se na to spolehnout? -The short answer is: "ordered in a special fashion": integer properties are sorted, others appear in creation order. The details follow. +Krátká odpověď je: „seřazeny speciálním způsobem“: celočíselné vlastnosti jsou seřazeny, ostatní se objeví v pořadí vytvoření. Následují podrobnosti. -As an example, let's consider an object with the phone codes: +Uvažujme například objekt s telefonními předvolbami států: ```js run -let codes = { - "49": "Germany", - "41": "Switzerland", - "44": "Great Britain", +let předvolby = { + "49": "Německo", + "41": "Švýcarsko", + "44": "Velká Británie", // .., "1": "USA" }; *!* -for (let code in codes) { - alert(code); // 1, 41, 44, 49 +for (let předvolba in předvolby) { + alert(předvolba); // 1, 41, 44, 49 } */!* ``` -The object may be used to suggest a list of options to the user. If we're making a site mainly for a German audience then we probably want `49` to be the first. +Objekt můžeme použít, abychom uživateli navrhli seznam možností. Například vytváříme-li stránku zejména pro návštěvníky z Německa, budeme pravděpodobně chtít, aby jako první bylo `49`. -But if we run the code, we see a totally different picture: +Jenže když kód spustíme, uvidíme úplně jiný obrázek: -- USA (1) goes first -- then Switzerland (41) and so on. +- jako první bude USA (1) +- pak Švýcarsko (41) a tak dále. -The phone codes go in the ascending sorted order, because they are integers. So we see `1, 41, 44, 49`. +Telefonní předvolby jsou seřazeny vzestupně, protože jsou to celá čísla. Uvidíme tedy `1, 41, 44, 49`. -````smart header="Integer properties? What's that?" -The "integer property" term here means a string that can be converted to-and-from an integer without a change. +````smart header="Celočíselné vlastnosti? K čemu to je?" +Pojem „celočíselná vlastnost“ zde znamená řetězec, který může být konvertován na celé číslo a zpět beze změny. -So, `"49"` is an integer property name, because when it's transformed to an integer number and back, it's still the same. But `"+49"` and `"1.2"` are not: +Takže `"49"` je název celočíselné vlastnosti, protože když se převede na celé číslo a zpět, zůstane stejný. Ale `"+49"` a `"1.2"` nejsou: ```js run -// Number(...) explicitly converts to a number -// Math.trunc is a built-in function that removes the decimal part -alert( String(Math.trunc(Number("49"))) ); // "49", same, integer property -alert( String(Math.trunc(Number("+49"))) ); // "49", not same "+49" ⇒ not integer property -alert( String(Math.trunc(Number("1.2"))) ); // "1", not same "1.2" ⇒ not integer property +// Number(...) explicitně konvertuje na číslo +// Math.trunc je vestavěná funkce, která odstraní desetinnou část +alert( String(Math.trunc(Number("49"))) ); // "49", totéž, celočíselná vlastnost +alert( String(Math.trunc(Number("+49"))) ); // "49", není totéž jako "+49" ⇒ není to celočíselná vlastnost +alert( String(Math.trunc(Number("1.2"))) ); // "1", není totéž jako "1.2" ⇒ není to celočíselná vlastnost ``` ```` -...On the other hand, if the keys are non-integer, then they are listed in the creation order, for instance: +...Na druhou stranu nejsou-li klíče celá čísla, budou seřazeny v tomtéž pořadí, v jakém byly vytvořeny, například: ```js run -let user = { - name: "John", - surname: "Smith" +let uživatel = { + jméno: "Jan", + příjmení: "Novák" }; -user.age = 25; // add one more +uživatel.věk = 25; // přidáme další *!* -// non-integer properties are listed in the creation order +// jiné než celočíselné vlastnosti jsou seřazeny v pořadí, v němž byly vytvořeny */!* -for (let prop in user) { - alert( prop ); // name, surname, age +for (let vlastnost in uživatel) { + alert( vlastnost ); // jméno, příjmení, věk } ``` -So, to fix the issue with the phone codes, we can "cheat" by making the codes non-integer. Adding a plus `"+"` sign before each code is enough. +Abychom tedy vyřešili problém s telefonními předvolbami, můžeme „podvádět“ tak, že předvolby učiníme neceločíselnými. Postačí přidat znaménko plus `"+"` před každou předvolbu. -Like this: +Například: ```js run -let codes = { - "+49": "Germany", - "+41": "Switzerland", - "+44": "Great Britain", +let předvolby = { + "+49": "Německo", + "+41": "Švýcarsko", + "+44": "Velká Británie", // .., "+1": "USA" }; -for (let code in codes) { - alert( +code ); // 49, 41, 44, 1 +for (let předvolba in předvolby) { + alert( +předvolba ); // 49, 41, 44, 1 } ``` -Now it works as intended. +Nyní to funguje tak, jak jsme zamýšleli. -## Summary +## Shrnutí -Objects are associative arrays with several special features. +Objekty jsou asociativní pole s několika speciálními vlastnostmi. -They store properties (key-value pairs), where: -- Property keys must be strings or symbols (usually strings). -- Values can be of any type. +Ukládají se do nich vlastnosti (dvojice klíč-hodnota), v nichž: +- Klíče vlastností musejí být řetězce nebo symboly (obvykle to jsou řetězce). +- Hodnoty mohou být jakéhokoli typu. -To access a property, we can use: -- The dot notation: `obj.property`. -- Square brackets notation `obj["property"]`. Square brackets allow taking the key from a variable, like `obj[varWithKey]`. +Pro přístup k vlastnosti můžeme použít: +- Tečkovou notaci: `obj.vlastnost`. +- Notaci hranatých závorek `obj["vlastnost"]`. Hranaté závorky nám umožňují převzít klíč z proměnné, např. `obj[proměnnáSKlíčem]`. -Additional operators: -- To delete a property: `delete obj.prop`. -- To check if a property with the given key exists: `"key" in obj`. -- To iterate over an object: `for (let key in obj)` loop. +Další operátory: +- K vymazání vlastnosti: `delete obj.vlastnost`. +- K ověření, zda vlastnost se zadaným klíčem existuje: `"klíč" in obj`. +- K iteraci nad objektem: cyklus `for (let klíč in obj)`. -What we've studied in this chapter is called a "plain object", or just `Object`. +To, co jsme prostudovali v této kapitole, se nazývá „planý objekt“ nebo jen `Object`. -There are many other kinds of objects in JavaScript: +V JavaScriptu však existuje i mnoho dalších druhů objektů: -- `Array` to store ordered data collections, -- `Date` to store the information about the date and time, -- `Error` to store the information about an error. -- ...And so on. +- `Array` (pole) k ukládání seřazených kolekcí dat, +- `Date` (datum) k ukládání informací o datu a času, +- `Error` (chyba) k ukládání informací o chybě, +- ...a tak dále. -They have their special features that we'll study later. Sometimes people say something like "Array type" or "Date type", but formally they are not types of their own, but belong to a single "object" data type. And they extend it in various ways. +Mají své speciální vlastnosti, které prostudujeme později. Někdy lidé říkají „typ Array“ nebo „typ Date“, ale formálně to nejsou samostatné typy, nýbrž patří k jednoduchému datovému typu „objekt“ a různými způsoby jej rozšiřují. -Objects in JavaScript are very powerful. Here we've just scratched the surface of a topic that is really huge. We'll be closely working with objects and learning more about them in further parts of the tutorial. +Objekty v JavaScriptu jsou velmi silné. Tady jsme jen lehce nakousli téma, které je opravdu obrovské. V dalších částech tohoto tutoriálu budeme s objekty pracovat blíže a dozvíme se o nich víc. diff --git a/1-js/04-object-basics/01-object/object-user-delete.svg b/1-js/04-object-basics/01-object/object-user-delete.svg index c5af7e7af..51401681b 100644 --- a/1-js/04-object-basics/01-object/object-user-delete.svg +++ b/1-js/04-object-basics/01-object/object-user-delete.svg @@ -1 +1 @@ -nameisAdminuser \ No newline at end of file +jménojeSprávceuživatel \ No newline at end of file diff --git a/1-js/04-object-basics/01-object/object-user-empty.svg b/1-js/04-object-basics/01-object/object-user-empty.svg index 99edb0269..fb8de8597 100644 --- a/1-js/04-object-basics/01-object/object-user-empty.svg +++ b/1-js/04-object-basics/01-object/object-user-empty.svg @@ -1 +1 @@ -emptyuser \ No newline at end of file +prázdnýuživatel \ No newline at end of file diff --git a/1-js/04-object-basics/01-object/object-user-isadmin.svg b/1-js/04-object-basics/01-object/object-user-isadmin.svg index e2cc0eaf1..ba4f86683 100644 --- a/1-js/04-object-basics/01-object/object-user-isadmin.svg +++ b/1-js/04-object-basics/01-object/object-user-isadmin.svg @@ -1 +1 @@ -nameageisAdminuser \ No newline at end of file +jménověkjeSprávceuživatel \ No newline at end of file diff --git a/1-js/04-object-basics/01-object/object-user-props.svg b/1-js/04-object-basics/01-object/object-user-props.svg index b3d5c9b71..e713dc382 100644 --- a/1-js/04-object-basics/01-object/object-user-props.svg +++ b/1-js/04-object-basics/01-object/object-user-props.svg @@ -1 +1 @@ -nameagelikes birdsuser \ No newline at end of file +jménověkmá rád ptákyuživatel \ No newline at end of file diff --git a/1-js/04-object-basics/01-object/object-user.svg b/1-js/04-object-basics/01-object/object-user.svg index f499fbc10..6e690275e 100644 --- a/1-js/04-object-basics/01-object/object-user.svg +++ b/1-js/04-object-basics/01-object/object-user.svg @@ -1 +1 @@ -nameageuser \ No newline at end of file +jménověkuživatel \ No newline at end of file diff --git a/1-js/04-object-basics/01-object/object.svg b/1-js/04-object-basics/01-object/object.svg index 47431a6e1..20c7695e4 100644 --- a/1-js/04-object-basics/01-object/object.svg +++ b/1-js/04-object-basics/01-object/object.svg @@ -1 +1 @@ -key1key2key3 \ No newline at end of file +klíč1klíč2klíč3 \ No newline at end of file diff --git a/1-js/04-object-basics/02-object-copy/article.md b/1-js/04-object-basics/02-object-copy/article.md index e80f748ab..6589108dc 100644 --- a/1-js/04-object-basics/02-object-copy/article.md +++ b/1-js/04-object-basics/02-object-copy/article.md @@ -1,325 +1,324 @@ -# Object references and copying +# Odkazy na objekty a kopírování objektů -One of the fundamental differences of objects versus primitives is that objects are stored and copied "by reference", whereas primitive values: strings, numbers, booleans, etc -- are always copied "as a whole value". +Jeden ze základních rozdílů mezi objekty a primitivními typy je, že objekty se ukládají a kopírují jako „odkazy“, zatímco primitivní hodnoty: řetězce, čísla, booleany atd. -- se kopírují vždy „jako celá hodnota“. -That's easy to understand if we look a bit under the hood of what happens when we copy a value. +Snadno tomu porozumíme, jestliže se podíváme trochu více pod kapuci toho, co se děje, když kopírujeme hodnotu. -Let's start with a primitive, such as a string. +Začněme primitivním typem, třeba řetězcem. -Here we put a copy of `message` into `phrase`: +Do proměnné `věta` zkopírujeme proměnnou `zpráva`: ```js -let message = "Hello!"; -let phrase = message; +let zpráva = "Ahoj!"; +let věta = zpráva; ``` -As a result we have two independent variables, each one storing the string `"Hello!"`. +Výsledkem budou dvě nezávislé proměnné, v každé bude uložen řetězec `"Ahoj!"`. ![](variable-copy-value.svg) -Quite an obvious result, right? +Vcelku zjevný výsledek, že? -Objects are not like that. +Objekty se takhle nechovají. -**A variable assigned to an object stores not the object itself, but its "address in memory" -- in other words "a reference" to it.** +**V proměnné, do níž je přiřazen objekt, není uložen samotný objekt, ale jeho „adresa v paměti“ -- jinými slovy „odkaz“ na objekt.** -Let's look at an example of such a variable: +Podívejme se na příklad takové proměnné: ```js -let user = { - name: "John" +let uživatel = { + jméno: "Jan" }; ``` -And here's how it's actually stored in memory: +A takto je ve skutečnosti uložen v paměti: ![](variable-contains-reference.svg) -The object is stored somewhere in memory (at the right of the picture), while the `user` variable (at the left) has a "reference" to it. +Objekt je uložen někde v paměti (na obrázku vpravo), zatímco proměnná `uživatel` (vlevo) obsahuje „odkaz“ na něj. -We may think of an object variable, such as `user`, like a sheet of paper with the address of the object on it. +Můžeme se dívat na objektovou proměnnou, např. `uživatel`, jako na kus papíru, na němž je napsána adresa objektu. -When we perform actions with the object, e.g. take a property `user.name`, the JavaScript engine looks at what's at that address and performs the operation on the actual object. +Když provádíme akci nad objektem, např. zjišťujeme vlastnost `uživatel.jméno`, motor JavaScriptu se podívá na to, co je na této adrese, a provede operaci nad skutečným objektem. -Now here's why it's important. +Teď vysvětlíme, proč je to důležité. -**When an object variable is copied, the reference is copied, but the object itself is not duplicated.** +**Když je kopírována objektová proměnná, zkopíruje se odkaz, ale samotný objekt se nezdvojí.** -For instance: +Například: ```js no-beautify -let user = { name: "John" }; +let uživatel = { jméno: "Jan" }; -let admin = user; // copy the reference +let správce = uživatel; // kopírování odkazu ``` -Now we have two variables, each storing a reference to the same object: +Nyní máme dvě proměnné, v obou jsou uloženy odkazy na tentýž objekt: ![](variable-copy-reference.svg) -As you can see, there's still one object, but now with two variables that reference it. +Jak vidíte, objekt je stále jen jeden, ale nyní se na něj odkazují dvě proměnné. -We can use either variable to access the object and modify its contents: +Obě proměnné můžeme používat k přístupu k objektu a modifikaci jeho obsahu: ```js run -let user = { name: 'John' }; +let uživatel = { jméno: 'Jan' }; -let admin = user; +let správce = uživatel; *!* -admin.name = 'Pete'; // changed by the "admin" reference +správce.jméno = 'Petr'; // změna pomocí odkazu „správce“ */!* -alert(*!*user.name*/!*); // 'Pete', changes are seen from the "user" reference +alert(*!*uživatel.jméno*/!*); // 'Petr', změny jsou vidět i z odkazu „uživatel“ ``` -It's as if we had a cabinet with two keys and used one of them (`admin`) to get into it and make changes. Then, if we later use another key (`user`), we are still opening the same cabinet and can access the changed contents. +Je to, jako kdybychom měli skříň se dvěma klíči a použili jeden z nich (`správce`) k tomu, abychom se do ní dostali a provedli změny. Když poté použijeme druhý klíč (`uživatel`), budeme stále otevírat stejnou skříň a můžeme přistupovat ke změněnému obsahu. -## Comparison by reference +## Porovnání pomocí odkazů -Two objects are equal only if they are the same object. +Dva objekty jsou si rovny, jen když je to jeden a tentýž objekt. -For instance, here `a` and `b` reference the same object, thus they are equal: +Například zde `a` a `b` jsou odkazy na tentýž objekt, takže jsou si rovny: ```js run let a = {}; -let b = a; // copy the reference +let b = a; // kopírování odkazu -alert( a == b ); // true, both variables reference the same object +alert( a == b ); // true, obě proměnné se odkazují na tentýž objekt alert( a === b ); // true ``` -And here two independent objects are not equal, even though they look alike (both are empty): +A zde si dva nezávislé objekty nejsou rovny, přestože vypadají podobně (oba jsou prázdné): ```js run let a = {}; -let b = {}; // two independent objects +let b = {}; // dva nezávislé objekty alert( a == b ); // false ``` -For comparisons like `obj1 > obj2` or for a comparison against a primitive `obj == 5`, objects are converted to primitives. We'll study how object conversions work very soon, but to tell the truth, such comparisons are needed very rarely -- usually they appear as a result of a programming mistake. +Při porovnání typu `obj1 > obj2` nebo při porovnání s primitivním typem `obj == 5` se objekty převádějí na primitivy. Jak funguje porovnávání objektů, prostudujeme velmi brzy, ale upřímně řečeno, taková porovnání jsou zapotřebí jen velmi zřídka -- obvykle se objevují v důsledku programátorské chyby. -````smart header="Const objects can be modified" -An important side effect of storing objects as references is that an object declared as `const` *can* be modified. +````smart header="Konstantní objekty můžeme modifikovat" +Důležitým vedlejším efektem ukládání objektů jako odkazů je, že objekt deklarovaný jako `const` *může* být modifikován. -For instance: +Například: ```js run -const user = { - name: "John" +const uživatel = { + jméno: "Jan" }; *!* -user.name = "Pete"; // (*) +uživatel.jméno = "Petr"; // (*) */!* -alert(user.name); // Pete +alert(uživatel.jméno); // Petr ``` -It might seem that the line `(*)` would cause an error, but it does not. The value of `user` is constant, it must always reference the same object, but properties of that object are free to change. +Může se zdát, že na řádku `(*)` bude ohlášena chyba, ale nestane se tak. Hodnota objektu `uživatel` je konstantní a musí pořád odkazovat na stejný objekt, ale vlastnosti tohoto objektu lze libovolně měnit. -In other words, the `const user` gives an error only if we try to set `user=...` as a whole. +Jinými slovy, `const uživatel` vyvolá chybu, jen pokud se pokusíme nastavit `uživatel=...` jako celek. -That said, if we really need to make constant object properties, it's also possible, but using totally different methods. We'll mention that in the chapter . +Jestliže ovšem skutečně potřebujeme učinit vlastnosti objektů konstantní, je to rovněž možné, ale úplně jiným způsobem. Zmíníme se o tom v kapitole . ```` -## Cloning and merging, Object.assign [#cloning-and-merging-object-assign] +## Klonování a slučování, Object.assign [#cloning-and-merging-object-assign] -So, copying an object variable creates one more reference to the same object. +Kopírování objektové proměnné tedy vytvoří další odkaz na tentýž objekt. -But what if we need to duplicate an object? +Co když však potřebujeme duplikovat objekt? -We can create a new object and replicate the structure of the existing one, by iterating over its properties and copying them on the primitive level. +Můžeme vytvořit nový objekt a replikovat strukturu existujícího objektu tím, že budeme iterovat nad jeho vlastnostmi a kopírovat je na úrovni primitivů. -Like this: +Například: ```js run -let user = { - name: "John", - age: 30 +let uživatel = { + jméno: "Jan", + věk: 30 }; *!* -let clone = {}; // the new empty object +let klon = {}; // nový prázdný objekt -// let's copy all user properties into it -for (let key in user) { - clone[key] = user[key]; +// zkopírujme do něj všechny uživatelské vlastnosti +for (let klíč in uživatel) { + klon[klíč] = uživatel[klíč]; } */!* -// now clone is a fully independent object with the same content -clone.name = "Pete"; // changed the data in it +// nyní je klon plně nezávislý objekt se stejným obsahem +klon.jméno = "Petr"; // změníme data uvnitř -alert( user.name ); // still John in the original object +alert( uživatel.jméno ); // v původním objektu je stále Jan ``` -We can also use the method [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign). +Můžeme také použít metodu [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign). -The syntax is: +Její syntaxe je: ```js -Object.assign(dest, ...sources) +Object.assign(cíl, ...zdroje]) ``` -- The first argument `dest` is a target object. -- Further arguments is a list of source objects. +- První argument `cíl` je cílový objekt. +- Další argumenty jsou seznam zdrojů. -It copies the properties of all source objects into the target `dest`, and then returns it as the result. +Metoda zkopíruje vlastnosti všech zdrojových objektů do cíle `cíl` a ten pak vrátí jako svůj výsledek. -For example, we have `user` object, let's add a couple of permissions to it: +Například máme objekt `uživatel`. Přidejme do něj několik oprávnění: -```js run -let user = { name: "John" }; +```js +let uživatel = { jméno: "Jan" }; -let permissions1 = { canView: true }; -let permissions2 = { canEdit: true }; +let oprávnění1 = { můžeProhlížet: true }; +let oprávnění2 = { můžeEditovat: true }; *!* -// copies all properties from permissions1 and permissions2 into user -Object.assign(user, permissions1, permissions2); +// zkopíruje všechny vlastnosti z objektů oprávnění1 a oprávnění2 do objektu uživatel +Object.assign(uživatel, oprávnění1, oprávnění2); */!* -// now user = { name: "John", canView: true, canEdit: true } -alert(user.name); // John -alert(user.canView); // true -alert(user.canEdit); // true +// nyní uživatel = { jméno: "Jan", můžeProhlížet: true, můžeEditovat: true } +alert(uživatel.jméno); // John +alert(uživatel.můžeProhlížet); // true +alert(uživatel.můžeEditovat); // true ``` -If the copied property name already exists, it gets overwritten: +Jestliže vlastnost s kopírovaným názvem již existuje, bude přepsána: ```js run -let user = { name: "John" }; +let uživatel = { jméno: "Jan" }; -Object.assign(user, { name: "Pete" }); +Object.assign(uživatel, { jméno: "Petr" }); -alert(user.name); // now user = { name: "Pete" } +alert(uživatel.jméno); // nyní uživatel = { jméno: "Petr" } ``` -We also can use `Object.assign` to perform a simple object cloning: +Můžeme také využít `Object.assign` k provedení jednoduchého klonování objektu: -```js run -let user = { - name: "John", - age: 30 +```js +let uživatel = { + jméno: "Jan", + věk: 30 }; *!* -let clone = Object.assign({}, user); +let klon = Object.assign({}, uživatel); */!* alert(clone.name); // John alert(clone.age); // 30 ``` -Here it copies all properties of `user` into the empty object and returns it. +Zde metoda zkopíruje všechny vlastnosti objektu `uživatel` do prázdného objektu a ten pak vrátí. -There are also other methods of cloning an object, e.g. using the [spread syntax](info:rest-parameters-spread) `clone = {...user}`, covered later in the tutorial. +Existují i jiné metody klonování objektu, např. použitím [rozšířené syntaxe](info:rest-parameters-spread) `klon = {...uživatel}`, kterou vysvětlíme později v tomto tutoriálu. -## Nested cloning +## Vnořené klonování -Until now we assumed that all properties of `user` are primitive. But properties can be references to other objects. +Až dosud jsme předpokládali, že všechny vlastnosti objektu `uživatel` jsou primitivní. Ale vlastnosti mohou být i odkazy na jiné objekty. -Like this: +Například: ```js run -let user = { - name: "John", - sizes: { - height: 182, - width: 50 +let uživatel = { + jméno: "Jan", + míry: { + výška: 182, + šířka: 50 } }; -alert( user.sizes.height ); // 182 +alert( uživatel.míry.výška ); // 182 ``` -Now it's not enough to copy `clone.sizes = user.sizes`, because `user.sizes` is an object, and will be copied by reference, so `clone` and `user` will share the same sizes: +Teď nestačí kopírovat `klon.míry = uživatel.míry`, protože `uživatel.míry` je objekt a bude zkopírován odkazem, takže `klon` a `uživatel` budou sdílet stejné míry: ```js run -let user = { - name: "John", - sizes: { - height: 182, - width: 50 +let uživatel = { + jméno: "Jan", + míry: { + výška: 182, + šířka: 50 } }; -let clone = Object.assign({}, user); +let klon = Object.assign({}, uživatel); -alert( user.sizes === clone.sizes ); // true, same object +alert( uživatel.míry === klon.míry ); // true, stejný objekt -// user and clone share sizes -user.sizes.width = 60; // change a property from one place -alert(clone.sizes.width); // 60, get the result from the other one +// uživatel a klon sdílejí tytéž míry +uživatel.míry.šířka = 60; // změníme vlastnost na jednom místě +alert(klon.míry.šířka); // 60, získáme výsledek z jiného místa ``` -To fix that and make `user` and `clone` truly separate objects, we should use a cloning loop that examines each value of `user[key]` and, if it's an object, then replicate its structure as well. That is called a "deep cloning" or "structured cloning". There's [structuredClone](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) method that implements deep cloning. - +Abychom to opravili a učinili objekty `uživatel` a `klon` skutečně oddělenými, měli bychom použít klonovací cyklus, který prozkoumá každou hodnotu `uživatel[klíč]`, a pokud je to objekt, replikuje i jeho strukturu. Toto klonování se nazývá „hloubkové“ („hluboké“) anebo „strukturované“. Existuje metoda `structuredClone`, která implementuje hloubkové klonování. ### structuredClone -The call `structuredClone(object)` clones the `object` with all nested properties. +Volání `structuredClone(objekt)` vytvoří klon objektu `objekt` se všemi vnořenými vlastnostmi. -Here's how we can use it in our example: +V našem příkladu ji můžeme použít následovně: ```js run -let user = { - name: "John", - sizes: { - height: 182, - width: 50 +let uživatel = { + jméno: "Jan", + míry: { + výška: 182, + šířka: 50 } }; *!* -let clone = structuredClone(user); +let klon = structuredClone(uživatel); */!* -alert( user.sizes === clone.sizes ); // false, different objects +alert( uživatel.míry === klon.míry ); // false, různé objekty -// user and clone are totally unrelated now -user.sizes.width = 60; // change a property from one place -alert(clone.sizes.width); // 50, not related +// uživatel a klon nyní nejsou nijak propojeny +uživatel.míry.šířka = 60; // změníme vlastnost na jednom místě +alert(klon.míry.šířka); // 50, nemělo to vliv ``` -The `structuredClone` method can clone most data types, such as objects, arrays, primitive values. +Metoda `structuredClone` může klonovat většinu datových typů, např. objekty, pole, primitivní hodnoty. -It also supports circular references, when an object property references the object itself (directly or via a chain or references). +Podporuje i kruhové odkazy, kdy vlastnost nějakého objektu odkazuje na tento objekt samotný (přímo nebo skrz řetězec odkazů). -For instance: +Příklad: ```js run -let user = {}; -// let's create a circular reference: -// user.me references the user itself -user.me = user; +let uživatel = {}; +// vytvořme kruhový odkaz: +// uživatel.já odkazuje na samotného uživatele +uživatel.já = uživatel; -let clone = structuredClone(user); -alert(clone.me === clone); // true +let klon = structuredClone(uživatel); +alert(klon.já === klon); // true ``` -As you can see, `clone.me` references the `clone`, not the `user`! So the circular reference was cloned correctly as well. +Jak vidíte, `klon.já` odkazuje na `klon`, ne na `uživatel`! Kruhový odkaz byl tedy rovněž správně naklonován. -Although, there are cases when `structuredClone` fails. +Existují však případy, kdy `structuredClone` selhává. -For instance, when an object has a function property: +Například když objekt má funkční vlastnost: ```js run -// error +// chyba structuredClone({ f: function() {} }); ``` -Function properties aren't supported. +Funkční vlastnosti nejsou podporovány. -To handle such complex cases we may need to use a combination of cloning methods, write custom code or, to not reinvent the wheel, take an existing implementation, for instance [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) from the JavaScript library [lodash](https://lodash.com). +Abychom zvládli tak složité příklady, možná budeme muset použít kombinaci klonovacích metod, napsat si vlastní kód nebo, abychom znovu nevynalézali kolo, použít existující implementaci, například [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) z JavaScriptové knihovny [lodash](https://lodash.com). -## Summary +## Shrnutí -Objects are assigned and copied by reference. In other words, a variable stores not the "object value", but a "reference" (address in memory) for the value. So copying such a variable or passing it as a function argument copies that reference, not the object itself. +Objekty se přiřazují a kopírují odkazem. Jinými slovy, v proměnné není uložena „hodnota objektu“, ale „odkaz“ (adresa v paměti) na tuto hodnotu. Zkopírování této hodnoty nebo její předání do funkce jako argument tedy zkopíruje tento odkaz, ne objekt samotný. -All operations via copied references (like adding/removing properties) are performed on the same single object. +Všechny operace na zkopírovaných odkazech (např. přidávání nebo odebírání vlastností) jsou prováděny na jednom a tomtéž objektu. -To make a "real copy" (a clone) we can use `Object.assign` for the so-called "shallow copy" (nested objects are copied by reference) or a "deep cloning" function `structuredClone` or use a custom cloning implementation, such as [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). +Abychom vytvořili „skutečnou kopii“ (klon), můžeme použít `Object.assign` pro tzv. „mělkou kopii“ (vnořené objekty se kopírují odkazem) nebo funkci `structuredClone` pro „hloubkové klonování“, nebo zákaznickou implementaci klonování, např. [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). diff --git a/1-js/04-object-basics/02-object-copy/variable-contains-reference.svg b/1-js/04-object-basics/02-object-copy/variable-contains-reference.svg index 267f04578..f8e4a062e 100644 --- a/1-js/04-object-basics/02-object-copy/variable-contains-reference.svg +++ b/1-js/04-object-basics/02-object-copy/variable-contains-reference.svg @@ -1 +1 @@ -username \ No newline at end of file +uživateljméno \ No newline at end of file diff --git a/1-js/04-object-basics/02-object-copy/variable-copy-reference.svg b/1-js/04-object-basics/02-object-copy/variable-copy-reference.svg index a847fb200..5efaf54d6 100644 --- a/1-js/04-object-basics/02-object-copy/variable-copy-reference.svg +++ b/1-js/04-object-basics/02-object-copy/variable-copy-reference.svg @@ -1 +1 @@ -useradminname \ No newline at end of file +uživatelsprávcejméno \ No newline at end of file diff --git a/1-js/04-object-basics/02-object-copy/variable-copy-value.svg b/1-js/04-object-basics/02-object-copy/variable-copy-value.svg index 0d6ca67bc..aeed3c394 100644 --- a/1-js/04-object-basics/02-object-copy/variable-copy-value.svg +++ b/1-js/04-object-basics/02-object-copy/variable-copy-value.svg @@ -1 +1 @@ -"Hello!"message"Hello!"phrase \ No newline at end of file +"Ahoj!"zpráva"Ahoj!"věta \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/article.md b/1-js/04-object-basics/03-garbage-collection/article.md index 1b576d629..baad7962d 100644 --- a/1-js/04-object-basics/03-garbage-collection/article.md +++ b/1-js/04-object-basics/03-garbage-collection/article.md @@ -1,212 +1,212 @@ -# Garbage collection +# Sběr odpadků -Memory management in JavaScript is performed automatically and invisibly to us. We create primitives, objects, functions... All that takes memory. +Správa paměti v JavaScriptu se provádí automaticky a pro nás neviditelně. Vytváříme primitivy, objekty, funkce... To všechno zabírá paměť. -What happens when something is not needed any more? How does the JavaScript engine discover it and clean it up? +Co se stane, když něco už není potřeba? Jak to JavaScriptový motor odhalí a vyčistí? -## Reachability +## Dosažitelnost -The main concept of memory management in JavaScript is *reachability*. +Hlavním konceptem správy paměti v JavaScriptu je *dosažitelnost*. -Simply put, "reachable" values are those that are accessible or usable somehow. They are guaranteed to be stored in memory. +Jednoduše řečeno, „dosažitelné“ hodnoty jsou ty, které jsou odněkud přístupné nebo použitelné. U nich je zaručeno, že budou uloženy v paměti. -1. There's a base set of inherently reachable values, that cannot be deleted for obvious reasons. +1. Existuje základní sada zaručeně dosažitelných hodnot, které nelze smazat z pochopitelných důvodů. - For instance: + Například: - - The currently executing function, its local variables and parameters. - - Other functions on the current chain of nested calls, their local variables and parameters. - - Global variables. - - (there are some other, internal ones as well) + - Právě prováděná funkce, její lokální proměnné a parametry. + - Další funkce v právě prováděném řetězci vnořených volání, jejich lokální proměnné a parametry. + - Globální proměnné. + - (existují i některé další, stejně jako interní) - These values are called *roots*. + Tyto hodnoty se nazývají *kořenové hodnoty* nebo *kořeny*. -2. Any other value is considered reachable if it's reachable from a root by a reference or by a chain of references. +2. Jakákoli jiná hodnota se považuje za dosažitelnou, je-li dosažitelná z kořene nějakým odkazem nebo řetězcem odkazů. - For instance, if there's an object in a global variable, and that object has a property referencing another object, *that* object is considered reachable. And those that it references are also reachable. Detailed examples to follow. + Například obsahuje-li globální proměnná nějaký objekt a tento objekt má vlastnost, která se odkazuje na další objekt, pak *onen další* objekt se považuje za dosažitelný. I ty, na které se odkazuje on, jsou dosažitelné. Podrobné příklady budou následovat. -There's a background process in the JavaScript engine that is called [garbage collector](https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)). It monitors all objects and removes those that have become unreachable. +V JavaScriptovém motoru v pozadí probíhá proces, který se nazývá [sběrač odpadků](https://cs.wikipedia.org/wiki/Garbage_collection) (garbage collector). Monitoruje všechny objekty a odstraňuje ty, které se staly nedosažitelnými. -## A simple example +## Jednoduchý příklad -Here's the simplest example: +Uveďme nejjednodušší příklad: ```js -// user has a reference to the object -let user = { - name: "John" +// uživatel obsahuje odkaz na objekt +let uživatel = { + jméno: "Jan" }; ``` ![](memory-user-john.svg) -Here the arrow depicts an object reference. The global variable `"user"` references the object `{name: "John"}` (we'll call it John for brevity). The `"name"` property of John stores a primitive, so it's painted inside the object. +Zde šipka představuje odkaz na objekt. Globální proměnná `"uživatel"` odkazuje na objekt `{jméno: "Jan"}` (pro zjednodušení mu budeme říkat Jan). Vlastnost `"jméno"` objektu Jan obsahuje primitiv, proto je zobrazena uvnitř objektu. -If the value of `user` is overwritten, the reference is lost: +Je-li hodnota proměnné `uživatel` přepsána, odkaz je ztracen: ```js -user = null; +uživatel = null; ``` ![](memory-user-john-lost.svg) -Now John becomes unreachable. There's no way to access it, no references to it. Garbage collector will junk the data and free the memory. +Nyní se Jan stal nedosažitelným. Není žádný způsob, jak k němu přistoupit, neexistují na něj žádné odkazy. Sběrač odpadků odstraní jeho data a uvolní paměť. -## Two references +## Dva odkazy -Now let's imagine we copied the reference from `user` to `admin`: +Nyní si představme, že zkopírujeme odkaz z objektu `uživatel` do objektu `správce`: ```js -// user has a reference to the object -let user = { - name: "John" +// uživatel obsahuje odkaz na objekt +let uživatel = { + jméno: "Jan" }; *!* -let admin = user; +let správce = uživatel; */!* ``` ![](memory-user-john-admin.svg) -Now if we do the same: +Když nyní uděláme totéž: ```js -user = null; +uživatel = null; ``` -...Then the object is still reachable via `admin` global variable, so it must stay in memory. If we overwrite `admin` too, then it can be removed. +...Pak bude objekt stále dosažitelný z globální proměnné `správce`, a tedy musí zůstat v paměti. Jestliže přepíšeme i `správce`, bude možné jej odstranit. -## Interlinked objects +## Propojené objekty -Now a more complex example. The family: +Nyní složitější příklad. Rodina: ```js -function marry(man, woman) { - woman.husband = man; - man.wife = woman; +function svatba(muž, žena) { + žena.manžel = muž; + muž.manželka = žena; return { - father: man, - mother: woman + otec: muž, + matka: žena } } -let family = marry({ - name: "John" +let rodina = svatba({ + jméno: "Jan" }, { - name: "Ann" + jméno: "Anna" }); ``` -Function `marry` "marries" two objects by giving them references to each other and returns a new object that contains them both. +Funkce `svatba` „oddá“ dva objekty tak, že jim předá odkazy na sebe navzájem a vytvoří nový objekt, který je oba bude obsahovat. -The resulting memory structure: +Výsledná struktura paměti: ![](family.svg) -As of now, all objects are reachable. +V této chvíli jsou všechny objekty dosažitelné. -Now let's remove two references: +Nyní odstraňme dva odkazy: ```js -delete family.father; -delete family.mother.husband; +delete rodina.otec; +delete rodina.matka.manžel; ``` ![](family-delete-refs.svg) -It's not enough to delete only one of these two references, because all objects would still be reachable. +Nestačí smazat jen jeden z těchto dvou odkazů, jelikož všechny objekty by stále byly dosažitelné. -But if we delete both, then we can see that John has no incoming reference any more: +Jestliže však smažeme oba, vidíme, že Jan již nemá žádné „příchozí“ odkazy, které by směřovaly k němu: ![](family-no-father.svg) -Outgoing references do not matter. Only incoming ones can make an object reachable. So, John is now unreachable and will be removed from the memory with all its data that also became unaccessible. +„Odchozí“ odkazy (směřující od Jana) nejsou podstatné. Objekt mohou učinit dosažitelným jedině příchozí odkazy. Jan je tedy nyní nedosažitelný a bude odstraněn z paměti i se všemi svými daty, která se také stala nedosažitelnými. -After garbage collection: +Po provedení sběru odpadků: ![](family-no-father-2.svg) -## Unreachable island +## Nedosažitelný ostrov -It is possible that the whole island of interlinked objects becomes unreachable and is removed from the memory. +Může se stát, že se celý ostrov navzájem propojených objektů stane nedosažitelným a bude odstraněn z paměti. -The source object is the same as above. Then: +Zdrojový objekt je stejný jako ten uvedený výše. Pak: ```js -family = null; +rodina = null; ``` -The in-memory picture becomes: +Obrázek paměti bude vypadat takto: ![](family-no-family.svg) -This example demonstrates how important the concept of reachability is. +Tento příklad demonstruje, jak důležitý je koncept dosažitelnosti. -It's obvious that John and Ann are still linked, both have incoming references. But that's not enough. +Je vidět, že Jan a Anna jsou stále spojeni a k oběma směřují nějaké odkazy. To ale nestačí. -The former `"family"` object has been unlinked from the root, there's no reference to it any more, so the whole island becomes unreachable and will be removed. +Bývalý objekt `"rodina"` byl odpojen od kořene, neexistuje na něj už žádný odkaz, takže se celý tento ostrov objektů stal nedosažitelným a bude odstraněn. -## Internal algorithms +## Interní algoritmy -The basic garbage collection algorithm is called "mark-and-sweep". +Základní algoritmus sběru odpadků se nazývá „označ a zameť“ („mark-and-sweep“). -The following "garbage collection" steps are regularly performed: +Pravidelně se provádějí následující kroky „sběru odpadků“: -- The garbage collector takes roots and "marks" (remembers) them. -- Then it visits and "marks" all references from them. -- Then it visits marked objects and marks *their* references. All visited objects are remembered, so as not to visit the same object twice in the future. -- ...And so on until every reachable (from the roots) references are visited. -- All objects except marked ones are removed. +- Sběrač odpadků vezme kořeny a „označí“ (zapamatuje) si je. +- Pak navštíví a „označí“ všechny odkazy z nich. +- Pak navštíví označené objekty a označí *jejich* odkazy. Všechny navštívené objekty si pamatuje, aby v budoucnu nenavštívil stejný objekt dvakrát. +- ...A tak dále, dokud nebudou navštíveny všechny (z kořenů) dosažitelné odkazy. +- Všechny objekty, které nejsou označeny, se odstraní. -For instance, let our object structure look like this: +Například nechť naše objektová struktura vypadá takto: ![](garbage-collection-1.svg) -We can clearly see an "unreachable island" to the right side. Now let's see how "mark-and-sweep" garbage collector deals with it. +Jasně vidíme „nedosažitelný ostrov“ na pravé straně. Nyní se podívejme, jak si s ním poradí sběrač odpadků typu „označ a zameť“. -The first step marks the roots: +První krok označí kořeny: ![](garbage-collection-2.svg) -Then we follow their references and mark referenced objects: +Pak budeme následovat jejich odkazy a označíme odkazované objekty: ![](garbage-collection-3.svg) -...And continue to follow further references, while possible: +...A budeme dále následovat další odkazy, dokud to bude možné: ![](garbage-collection-4.svg) -Now the objects that could not be visited in the process are considered unreachable and will be removed: +Nyní se objekty, které nemohly být v tomto procesu navštíveny, budou považovat za nedosažitelné a budou odstraněny: ![](garbage-collection-5.svg) -We can also imagine the process as spilling a huge bucket of paint from the roots, that flows through all references and marks all reachable objects. The unmarked ones are then removed. +Můžeme si tento proces představit i jako rozlití velkého kbelíku s barvou na kořenech. Barva teče všemi odkazy a dostane se ke všem dosažitelným objektům. Neoznačené objekty jsou poté odstraněny. -That's the concept of how garbage collection works. JavaScript engines apply many optimizations to make it run faster and not introduce any delays into the code execution. +Toto je koncept fungování sbírání odpadků. JavaScriptové motory aplikují mnoho optimalizací, které způsobí, že se jeho běh urychlí a nebude při běhu kódu způsobovat prodlevy. -Some of the optimizations: +Některé z nich: -- **Generational collection** -- objects are split into two sets: "new ones" and "old ones". In typical code, many objects have a short life span: they appear, do their job and die fast, so it makes sense to track new objects and clear the memory from them if that's the case. Those that survive for long enough, become "old" and are examined less often. -- **Incremental collection** -- if there are many objects, and we try to walk and mark the whole object set at once, it may take some time and introduce visible delays in the execution. So the engine splits the whole set of existing objects into multiple parts. And then clear these parts one after another. There are many small garbage collections instead of a total one. That requires some extra bookkeeping between them to track changes, but we get many tiny delays instead of a big one. -- **Idle-time collection** -- the garbage collector tries to run only while the CPU is idle, to reduce the possible effect on the execution. +- **Generační sběr** -- objekty se rozdělí na dvě skupiny: „nové“ a „staré“. V obvyklém kódu má mnoho objektů jen krátký život: objeví se, vykonají svou práci a rychle zemřou, takže má smysl stopovat nové objekty a pokud nastane tento případ, vyčistit je z paměti. Ty, které přežijí dostatečně dlouho, se stanou „starými“ a budou prozkoumávány méně často. +- **Inkrementální sběr** -- jestliže máme mnoho objektů a snažíme se projít a označit celou jejich sadu najednou, může to zabrat nějakou dobu a způsobit znatelné prodlevy při běhu skriptu. Motor tedy rozdělí celou sadu existujících objektů do více částí. A pak čistí tyto části jednu po druhé. Nastane tedy více malých sběrů odpadků místo jednoho celkového. To vyžaduje určitou další administraci mezi nimi, aby se zaznamenaly změny, ale pak získáme mnoho drobných prodlev místo jedné velké. +- **Sběr v čase nečinnosti** -- sběrač odpadků se snaží běžet jen tehdy, když je CPU nečinná, aby zmenšil svůj vliv na běh. -There exist other optimizations and flavours of garbage collection algorithms. As much as I'd like to describe them here, I have to hold off, because different engines implement different tweaks and techniques. And, what's even more important, things change as engines develop, so studying deeper "in advance", without a real need is probably not worth that. Unless, of course, it is a matter of pure interest, then there will be some links for you below. +Existují i jiné optimalizace a doplňky algoritmů sběru odpadků. Jakkoli rád bych je zde popsal, musím se toho vzdát, jelikož různé motory implementují různá vylepšení a techniky. Co je ještě důležitější, během vývoje motorů se vše mění, takže studovat je hlouběji „dopředu“, aniž bychom je opravdu potřebovali, pravděpodobně nemá smysl. Pokud to ovšem není věc čistého zájmu, v kterémžto případě najdete některé odkazy níže. -## Summary +## Shrnutí -The main things to know: +Hlavní věci, které máme vědět: -- Garbage collection is performed automatically. We cannot force or prevent it. -- Objects are retained in memory while they are reachable. -- Being referenced is not the same as being reachable (from a root): a pack of interlinked objects can become unreachable as a whole, as we've seen in the example above. +- Sběr odpadků se provádí automaticky. Nemůžeme si jej vynutit nebo mu zabránit. +- Objekty zůstávají v paměti, dokud jsou dosažitelné. +- Být odkazován není totéž jako být dosažitelný (z kořene): sada vzájemně propojených objektů se může jako celek stát nedosažitelnou, jak jsme viděli ve výše uvedeném příkladu. -Modern engines implement advanced algorithms of garbage collection. +Moderní motory implementují pokročilé algoritmy sběru odpadků. -A general book "The Garbage Collection Handbook: The Art of Automatic Memory Management" (R. Jones et al) covers some of them. +Některé z nich jsou probrány v obecné knize „The Garbage Collection Handbook: The Art of Automatic Memory Management“ (R. Jones a kolektiv). -If you are familiar with low-level programming, more detailed information about V8's garbage collector is in the article [A tour of V8: Garbage Collection](https://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection). +Pokud jste obeznámeni s programováním na nízké úrovni, podrobnější informace o sběrači odpadků V8 najdete v článku [A tour of V8: Garbage Collection](https://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection). -The [V8 blog](https://v8.dev/) also publishes articles about changes in memory management from time to time. Naturally, to learn more about garbage collection, you'd better prepare by learning about V8 internals in general and read the blog of [Vyacheslav Egorov](https://mrale.ph) who worked as one of the V8 engineers. I'm saying: "V8", because it is best covered by articles on the internet. For other engines, many approaches are similar, but garbage collection differs in many aspects. +Rovněž [blog V8](https://v8.dev/) občas publikuje články o změnách ve správě paměti. Přirozeně, chcete-li se naučit o sběru odpadků víc, nejlépe se na to připravíte tak, že se poučíte o interních záležitostech V8 obecně a přečtete si blog [Vjačeslava Jegorova](https://mrale.ph), který pracoval jako jeden z tvůrců V8. Říkám „V8“, protože ten je nejlépe pokryt články na internetu. V jiných motorech jsou mnohé přístupy podobné, ale sběrače odpadků se v mnoha aspektech liší. -In-depth knowledge of engines is good when you need low-level optimizations. It would be wise to plan that as the next step after you're familiar with the language. +Hloubková znalost motorů se hodí, když potřebujete optimalizaci na nízké úrovni. Bylo by moudré naplánovat si to jako další krok poté, co se seznámíte s jazykem. diff --git a/1-js/04-object-basics/03-garbage-collection/family-delete-refs.svg b/1-js/04-object-basics/03-garbage-collection/family-delete-refs.svg index a582ca64b..e938375ca 100644 --- a/1-js/04-object-basics/03-garbage-collection/family-delete-refs.svg +++ b/1-js/04-object-basics/03-garbage-collection/family-delete-refs.svg @@ -1 +1 @@ -<global variable>ObjectObjectwifefamilyname: "John"name: "Ann"motherObjectfatherhusband \ No newline at end of file +<globální proměnná>ObjectObjectmanželkarodinajméno: "Jan"jméno: "Anna"matkaObjectotecmanžel \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/family-no-family.svg b/1-js/04-object-basics/03-garbage-collection/family-no-family.svg index c73dd6a48..1629c26e0 100644 --- a/1-js/04-object-basics/03-garbage-collection/family-no-family.svg +++ b/1-js/04-object-basics/03-garbage-collection/family-no-family.svg @@ -1 +1 @@ -<global>ObjectObjectfatherwifename: "John"name: "Ann"motherObjecthusbandfamily: null \ No newline at end of file +<globální>ObjectObjectotecmanželkajméno: "Jan"jméno: "Anna"matkaObjectmanželrodina: null \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/family-no-father-2.svg b/1-js/04-object-basics/03-garbage-collection/family-no-father-2.svg index 6bd13c0e8..fc6b1e6b2 100644 --- a/1-js/04-object-basics/03-garbage-collection/family-no-father-2.svg +++ b/1-js/04-object-basics/03-garbage-collection/family-no-father-2.svg @@ -1 +1 @@ -Objectfamilyname: "Ann"motherObject<global> \ No newline at end of file +Objectrodinajméno: "Anna"matkaObject<globální> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/family-no-father.svg b/1-js/04-object-basics/03-garbage-collection/family-no-father.svg index fd1f20607..85d60c7ff 100644 --- a/1-js/04-object-basics/03-garbage-collection/family-no-father.svg +++ b/1-js/04-object-basics/03-garbage-collection/family-no-father.svg @@ -1 +1 @@ -ObjectObjectwifefamilyname: "John"name: "Ann"motherObject<global> \ No newline at end of file +ObjectObjectmanželkarodinajméno: "Jan"jméno: "Anna"matkaObject<globální> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/family.svg b/1-js/04-object-basics/03-garbage-collection/family.svg index fd0534874..780d0e214 100644 --- a/1-js/04-object-basics/03-garbage-collection/family.svg +++ b/1-js/04-object-basics/03-garbage-collection/family.svg @@ -1 +1 @@ -ObjectObjectfatherwifefamilyname: "John"name: "Ann"motherObjecthusband<global variable> \ No newline at end of file +ObjectObjectotecmanželkarodinajméno: "Jan"jméno: "Anna"matkaObjectmanžel<globální proměnná> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/garbage-collection-1.svg b/1-js/04-object-basics/03-garbage-collection/garbage-collection-1.svg index 5cac52e9a..8a5bfbdbc 100644 --- a/1-js/04-object-basics/03-garbage-collection/garbage-collection-1.svg +++ b/1-js/04-object-basics/03-garbage-collection/garbage-collection-1.svg @@ -1 +1 @@ -<global> \ No newline at end of file +<globální> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/garbage-collection-2.svg b/1-js/04-object-basics/03-garbage-collection/garbage-collection-2.svg index 7dd3a693a..60edf0917 100644 --- a/1-js/04-object-basics/03-garbage-collection/garbage-collection-2.svg +++ b/1-js/04-object-basics/03-garbage-collection/garbage-collection-2.svg @@ -1 +1 @@ -<global> \ No newline at end of file +<globální> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/garbage-collection-3.svg b/1-js/04-object-basics/03-garbage-collection/garbage-collection-3.svg index 106057787..c18c27c85 100644 --- a/1-js/04-object-basics/03-garbage-collection/garbage-collection-3.svg +++ b/1-js/04-object-basics/03-garbage-collection/garbage-collection-3.svg @@ -1 +1 @@ -<global> \ No newline at end of file +<globální> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/garbage-collection-4.svg b/1-js/04-object-basics/03-garbage-collection/garbage-collection-4.svg index bd485adee..7949c1ba9 100644 --- a/1-js/04-object-basics/03-garbage-collection/garbage-collection-4.svg +++ b/1-js/04-object-basics/03-garbage-collection/garbage-collection-4.svg @@ -1 +1 @@ -<global> \ No newline at end of file +<globální> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/garbage-collection-5.svg b/1-js/04-object-basics/03-garbage-collection/garbage-collection-5.svg index 2d85432bc..3d47483ae 100644 --- a/1-js/04-object-basics/03-garbage-collection/garbage-collection-5.svg +++ b/1-js/04-object-basics/03-garbage-collection/garbage-collection-5.svg @@ -1 +1 @@ -<global>unreachables \ No newline at end of file +<globální>nedosažitelné \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/memory-user-john-admin.svg b/1-js/04-object-basics/03-garbage-collection/memory-user-john-admin.svg index 191324354..006c5241f 100644 --- a/1-js/04-object-basics/03-garbage-collection/memory-user-john-admin.svg +++ b/1-js/04-object-basics/03-garbage-collection/memory-user-john-admin.svg @@ -1 +1 @@ -username: "John"Objectadmin<global> \ No newline at end of file +uživateljméno: "Jan"Objectsprávce<globální> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/memory-user-john-lost.svg b/1-js/04-object-basics/03-garbage-collection/memory-user-john-lost.svg index 07914a9ca..e56526608 100644 --- a/1-js/04-object-basics/03-garbage-collection/memory-user-john-lost.svg +++ b/1-js/04-object-basics/03-garbage-collection/memory-user-john-lost.svg @@ -1 +1 @@ -name: "John"Objectuser: null<global> \ No newline at end of file +jméno: "Jan"Objectuživatel: null<globální> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/memory-user-john.svg b/1-js/04-object-basics/03-garbage-collection/memory-user-john.svg index 15bd51afb..a481aa24e 100644 --- a/1-js/04-object-basics/03-garbage-collection/memory-user-john.svg +++ b/1-js/04-object-basics/03-garbage-collection/memory-user-john.svg @@ -1 +1 @@ -username: "John"Object<global> \ No newline at end of file +uživateljméno: "Jan"Object<globální> \ No newline at end of file diff --git a/1-js/04-object-basics/04-object-methods/4-object-property-this/solution.md b/1-js/04-object-basics/04-object-methods/4-object-property-this/solution.md index f33c9310e..d40185f5b 100644 --- a/1-js/04-object-basics/04-object-methods/4-object-property-this/solution.md +++ b/1-js/04-object-basics/04-object-methods/4-object-property-this/solution.md @@ -1,55 +1,55 @@ -**Answer: an error.** +**Odpověď: chyba.** -Try it: +Zkuste to: ```js run -function makeUser() { +function vytvořUživatele() { return { - name: "John", - ref: this + jméno: "Jan", + odkaz: this }; } -let user = makeUser(); +let uživatel = vytvořUživatele(); -alert( user.ref.name ); // Error: Cannot read property 'name' of undefined +alert( uživatel.odkaz.jméno ); // Chyba: Nelze načíst vlastnost 'jméno' objektu undefined ``` -That's because rules that set `this` do not look at object definition. Only the moment of call matters. +Je to proto, že pravidla, která nastavují `this`, se nedívají do definice objektu. Záleží jen na okamžiku volání. -Here the value of `this` inside `makeUser()` is `undefined`, because it is called as a function, not as a method with "dot" syntax. +Zde je hodnota `this` uvnitř `vytvořUživatele()` `undefined`, protože tato funkce je volána jako funkce, ne jako metoda „tečkovou“ syntaxí. -The value of `this` is one for the whole function, code blocks and object literals do not affect it. +Hodnota `this` je stejná pro celou funkci, bloky kódu a objektové literály ji neovlivňují. -So `ref: this` actually takes current `this` of the function. +Takže `odkaz: this` vezme ve skutečnosti aktuální `this` této funkce. -We can rewrite the function and return the same `this` with `undefined` value: +Můžeme funkci přepsat a vrátit stejné `this` s hodnotou `undefined`: ```js run -function makeUser(){ - return this; // this time there's no object literal +function vytvořUživatele(){ + return this; // tentokrát tady není objektový literál } -alert( makeUser().name ); // Error: Cannot read property 'name' of undefined +alert( vytvořUživatele().jméno ); // Chyba: Nelze načíst vlastnost 'jméno' objektu undefined ``` -As you can see the result of `alert( makeUser().name )` is the same as the result of `alert( user.ref.name )` from the previous example. +Jak vidíte, výsledek `alert( vytvořUživatele().jméno )` je stejný jako výsledek `alert( uživatel.odkaz.jméno )` z předchozího příkladu. -Here's the opposite case: +Toto je opačný příklad: ```js run -function makeUser() { +function vytvořUživatele() { return { - name: "John", + jméno: "Jan", *!* - ref() { + odkaz() { return this; } */!* }; } -let user = makeUser(); +let uživatel = vytvořUživatele(); -alert( user.ref().name ); // John +alert( uživatel.odkaz().jméno ); // Jan ``` -Now it works, because `user.ref()` is a method. And the value of `this` is set to the object before dot `.`. +Teď to funguje, protože `uživatel.odkaz()` je metoda. A hodnota `this` se nastaví na objekt před tečkou `.`. \ No newline at end of file diff --git a/1-js/04-object-basics/04-object-methods/4-object-property-this/task.md b/1-js/04-object-basics/04-object-methods/4-object-property-this/task.md index c6f8f9658..20bdcde72 100644 --- a/1-js/04-object-basics/04-object-methods/4-object-property-this/task.md +++ b/1-js/04-object-basics/04-object-methods/4-object-property-this/task.md @@ -2,22 +2,22 @@ importance: 5 --- -# Using "this" in object literal +# Použití „this“ v objektovém literálu -Here the function `makeUser` returns an object. +Zde funkce `vytvořUživatele` vrátí objekt. -What is the result of accessing its `ref`? Why? +Jaký je výsledek přístupu k jeho vlastnosti `odkaz`? Proč? ```js -function makeUser() { +function vytvořUživatele() { return { - name: "John", - ref: this + jméno: "Jan", + odkaz: this }; } -let user = makeUser(); +let uživatel = vytvořUživatele(); -alert( user.ref.name ); // What's the result? +alert( uživatel.odkaz.jméno ); // Jaký je výsledek? ``` diff --git a/1-js/04-object-basics/04-object-methods/7-calculator/_js.view/solution.js b/1-js/04-object-basics/04-object-methods/7-calculator/_js.view/solution.js index 9ccbe43a1..892c060a4 100644 --- a/1-js/04-object-basics/04-object-methods/7-calculator/_js.view/solution.js +++ b/1-js/04-object-basics/04-object-methods/7-calculator/_js.view/solution.js @@ -1,13 +1,13 @@ -let calculator = { - sum() { +let kalkulátor = { + součet() { return this.a + this.b; }, - mul() { + součin() { return this.a * this.b; }, - read() { + načti() { this.a = +prompt('a?', 0); this.b = +prompt('b?', 0); } diff --git a/1-js/04-object-basics/04-object-methods/7-calculator/_js.view/test.js b/1-js/04-object-basics/04-object-methods/7-calculator/_js.view/test.js index 4decb76dc..e5c76fe2b 100644 --- a/1-js/04-object-basics/04-object-methods/7-calculator/_js.view/test.js +++ b/1-js/04-object-basics/04-object-methods/7-calculator/_js.view/test.js @@ -1,32 +1,31 @@ - -describe("calculator", function() { +describe("kalkulátor", function() { - context("when 2 and 3 entered", function() { + context("když zadáme 2 a 3", function() { beforeEach(function() { sinon.stub(window, "prompt"); prompt.onCall(0).returns("2"); prompt.onCall(1).returns("3"); - calculator.read(); + kalkulátor.načti(); }); afterEach(function() { prompt.restore(); }); - it('the read get two values and saves them as object properties', function () { - assert.equal(calculator.a, 2); - assert.equal(calculator.b, 3); + it('funkce načti načte dvě hodnoty a uloží je jako vlastnosti objektu', function () { + assert.equal(kalkulátor.a, 2); + assert.equal(kalkulátor.b, 3); }); - it("the sum is 5", function() { - assert.equal(calculator.sum(), 5); + it("součet je 5", function() { + assert.equal(kalkulátor.součet(), 5); }); - it("the multiplication product is 6", function() { - assert.equal(calculator.mul(), 6); + it("součin je 6", function() { + assert.equal(kalkulátor.součin(), 6); }); }); diff --git a/1-js/04-object-basics/04-object-methods/7-calculator/solution.md b/1-js/04-object-basics/04-object-methods/7-calculator/solution.md index 459997624..0925287b8 100644 --- a/1-js/04-object-basics/04-object-methods/7-calculator/solution.md +++ b/1-js/04-object-basics/04-object-methods/7-calculator/solution.md @@ -1,21 +1,21 @@ ```js run demo solution -let calculator = { - sum() { +let kalkulátor = { + součet() { return this.a + this.b; }, - mul() { + součin() { return this.a * this.b; }, - read() { + načti() { this.a = +prompt('a?', 0); this.b = +prompt('b?', 0); } }; -calculator.read(); -alert( calculator.sum() ); -alert( calculator.mul() ); +kalkulátor.načti(); +alert( kalkulátor.součet() ); +alert( kalkulátor.součin() ); ``` diff --git a/1-js/04-object-basics/04-object-methods/7-calculator/task.md b/1-js/04-object-basics/04-object-methods/7-calculator/task.md index 82d0da030..b6b51a1b4 100644 --- a/1-js/04-object-basics/04-object-methods/7-calculator/task.md +++ b/1-js/04-object-basics/04-object-methods/7-calculator/task.md @@ -2,22 +2,22 @@ importance: 5 --- -# Create a calculator +# Vytvořte kalkulátor -Create an object `calculator` with three methods: +Vytvořte objekt `kalkulátor` se třemi metodami: -- `read()` prompts for two values and saves them as object properties with names `a` and `b` respectively. -- `sum()` returns the sum of saved values. -- `mul()` multiplies saved values and returns the result. +- `načti()` se zeptá na dvě hodnoty a uloží je jako vlastnosti objektu pod názvy po řadě `a` a `b`. +- `součet()` vrátí součet uložených hodnot. +- `součin()` vynásobí uložené hodnoty mezi sebou a vrátí výsledek. ```js -let calculator = { - // ... your code ... +let kalkulátor = { + // ... váš kód ... }; -calculator.read(); -alert( calculator.sum() ); -alert( calculator.mul() ); +kalkulátor.načti(); +alert( kalkulátor.součet() ); +alert( kalkulátor.součin() ); ``` [demo] diff --git a/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/solution.js b/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/solution.js index a35c009cc..577cda7d8 100644 --- a/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/solution.js +++ b/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/solution.js @@ -1,16 +1,21 @@ -let ladder = { - step: 0, - up: function() { - this.step++; +let žebřík = { + stupeň: 0, + nahoru: function() { + this.stupeň++; return this; }, - down: function() { - this.step--; + dolů: function() { + this.stupeň--; return this; }, +<<<<<<< HEAD + zobrazStupeň: function() { + alert(this.stupeň); +======= showStep: function() { alert(this.step); return this; +>>>>>>> 71da17e5960f1c76aad0d04d21f10bc65318d3f6 } }; \ No newline at end of file diff --git a/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/test.js b/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/test.js index b4f2459b7..b6e514e0f 100644 --- a/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/test.js +++ b/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/test.js @@ -1,36 +1,36 @@ -describe('Ladder', function() { +describe('Žebřík', function() { before(function() { window.alert = sinon.stub(window, "alert"); }); beforeEach(function() { - ladder.step = 0; + žebřík.stupeň = 0; }); - it('up() should return this', function() { - assert.equal(ladder.up(), ladder); + it('nahoru() by mělo vrátit this', function() { + assert.equal(žebřík.nahoru(), žebřík); }); - it('down() should return this', function() { - assert.equal(ladder.down(), ladder); + it('dolů() by mělo vrátit this', function() { + assert.equal(žebřík.dolů(), žebřík); }); - it('showStep() should call alert', function() { - ladder.showStep(); + it('zobrazStupeň() by mělo volat alert', function() { + žebřík.zobrazStupeň(); assert(alert.called); }); - it('up() should increase step', function() { - assert.equal(ladder.up().up().step, 2); + it('nahoru() by mělo zvýšit stupeň', function() { + assert.equal(žebřík.nahoru().nahoru().stupeň, 2); }); - it('down() should decrease step', function() { - assert.equal(ladder.down().step, -1); + it('dolů() by mělo snížit stupeň', function() { + assert.equal(žebřík.dolů().stupeň, -1); }); - it('down().up().up().up() ', function() { - assert.equal(ladder.down().up().up().up().step, 2); + it('dolů().nahoru().nahoru().nahoru() ', function() { + assert.equal(žebřík.dolů().nahoru().nahoru().nahoru().stupeň, 2); }); it('showStep() should return this', function() { @@ -42,7 +42,7 @@ describe('Ladder', function() { }); after(function() { - ladder.step = 0; + žebřík.stupeň = 0; alert.restore(); }); }); diff --git a/1-js/04-object-basics/04-object-methods/8-chain-calls/solution.md b/1-js/04-object-basics/04-object-methods/8-chain-calls/solution.md index f215461dd..1e7ee3170 100644 --- a/1-js/04-object-basics/04-object-methods/8-chain-calls/solution.md +++ b/1-js/04-object-basics/04-object-methods/8-chain-calls/solution.md @@ -1,39 +1,39 @@ -The solution is to return the object itself from every call. +Řešením je v každém volání vrátit tento objekt samotný. ```js run demo -let ladder = { - step: 0, - up() { - this.step++; +let žebřík = { + stupeň: 0, + nahoru() { + this.stupeň++; *!* return this; */!* }, - down() { - this.step--; + dolů() { + this.stupeň--; *!* return this; */!* }, - showStep() { - alert( this.step ); + zobrazStupeň() { + alert( this.stupeň ); *!* return this; */!* } }; -ladder.up().up().down().showStep().down().showStep(); // shows 1 then 0 +žebřík.nahoru().nahoru().dolů().zobrazStupeň().dolů().zobrazStupeň(); // zobrazí 1, pak 0 ``` -We also can write a single call per line. For long chains it's more readable: +Můžeme také psát každé volání na nový řádek. U delšího zřetězení je to čitelnější: ```js -ladder - .up() - .up() - .down() - .showStep() // 1 - .down() - .showStep(); // 0 +žebřík + .nahoru() + .nahoru() + .dolů() + .zobrazStupeň() // 1 + .dolů() + .zobrazStupeň(); // 0 ``` diff --git a/1-js/04-object-basics/04-object-methods/8-chain-calls/task.md b/1-js/04-object-basics/04-object-methods/8-chain-calls/task.md index 7d2ef8c15..6056342f4 100644 --- a/1-js/04-object-basics/04-object-methods/8-chain-calls/task.md +++ b/1-js/04-object-basics/04-object-methods/8-chain-calls/task.md @@ -2,40 +2,40 @@ importance: 2 --- -# Chaining +# Zřetězení -There's a `ladder` object that allows you to go up and down: +Máme objekt `žebřík`, který nám umožňuje chodit nahoru a dolů: ```js -let ladder = { - step: 0, - up() { - this.step++; +let žebřík = { + stupeň: 0, + nahoru() { + this.stupeň++; }, - down() { - this.step--; + dolů() { + this.stupeň--; }, - showStep: function() { // shows the current step - alert( this.step ); + zobrazStupeň: function() { // zobrazí aktuální stupeň + alert( this.stupeň ); } }; ``` -Now, if we need to make several calls in sequence, we can do it like this: +Když nyní potřebujeme učinit několik volání po sobě, můžeme to udělat takto: ```js -ladder.up(); -ladder.up(); -ladder.down(); -ladder.showStep(); // 1 -ladder.down(); -ladder.showStep(); // 0 +žebřík.nahoru(); +žebřík.nahoru(); +žebřík.dolů(); +žebřík.zobrazStupeň(); // 1 +žebřík.dolů(); +žebřík.zobrazStupeň(); // 0 ``` -Modify the code of `up`, `down`, and `showStep` to make the calls chainable, like this: +Upravte kód funkcí `nahoru`, `dolů` a `zobrazStupeň` tak, aby bylo možné volání zřetězit takto: ```js -ladder.up().up().down().showStep().down().showStep(); // shows 1 then 0 +žebřík.nahoru().nahoru().dolů().zobrazStupeň().dolů().zobrazStupeň(); // zobrazí 1, pak 0 ``` -Such an approach is widely used across JavaScript libraries. +Takový přístup se zeširoka používá v JavaScriptových knihovnách. diff --git a/1-js/04-object-basics/04-object-methods/article.md b/1-js/04-object-basics/04-object-methods/article.md index cea2b6a70..7effbc17b 100644 --- a/1-js/04-object-basics/04-object-methods/article.md +++ b/1-js/04-object-basics/04-object-methods/article.md @@ -1,270 +1,270 @@ -# Object methods, "this" +# Objektové metody, „this“ -Objects are usually created to represent entities of the real world, like users, orders and so on: +Objekty se obvykle vytvářejí tak, aby představovaly entity ze skutečného světa, například uživatele, objednávky a podobně: ```js -let user = { - name: "John", - age: 30 +let uživatel = { + jméno: "Jan", + věk: 30 }; ``` -And, in the real world, a user can *act*: select something from the shopping cart, login, logout etc. +A ve skutečném světě může uživatel *konat* nějakou akci: vybrat si něco z nákupního vozíku, přihlásit se, odhlásit se atd. -Actions are represented in JavaScript by functions in properties. +V JavaScriptu jsou tyto akce reprezentovány funkcemi ve vlastnostech. -## Method examples +## Příklady metod -For a start, let's teach the `user` to say hello: +Pro začátek naučme objekt `uživatel` říci ahoj: ```js run -let user = { - name: "John", - age: 30 +let uživatel = { + jméno: "Jan", + věk: 30 }; *!* -user.sayHi = function() { - alert("Hello!"); +uživatel.řekniAhoj = function() { + alert("Ahoj!"); }; */!* -user.sayHi(); // Hello! +uživatel.řekniAhoj(); // Ahoj! ``` -Here we've just used a Function Expression to create a function and assign it to the property `user.sayHi` of the object. +Právě jsme použili funkční výraz, kterým jsme vytvořili funkci a přiřadili ji do vlastnosti objektu `uživatel.řekniAhoj`. -Then we can call it as `user.sayHi()`. The user can now speak! +Pak ji můžeme volat pomocí `uživatel.řekniAhoj()`. Uživatel nyní umí mluvit! -A function that is a property of an object is called its *method*. +Funkce, která je vlastností objektu, se nazývá jeho *metoda*. -So, here we've got a method `sayHi` of the object `user`. +Zde tedy máme metodu `řekniAhoj` objektu `uživatel`. -Of course, we could use a pre-declared function as a method, like this: +Samozřejmě můžeme použít jako metodu předem deklarovanou funkci, například takto: ```js run -let user = { +let uživatel = { // ... }; *!* -// first, declare -function sayHi() { - alert("Hello!"); -} +// nejprve ji deklarujeme +function řekniAhoj() { + alert("Ahoj!"); +}; -// then add as a method -user.sayHi = sayHi; +// pak přidáme jako metodu +uživatel.řekniAhoj = řekniAhoj; */!* -user.sayHi(); // Hello! +uživatel.řekniAhoj(); // Ahoj! ``` -```smart header="Object-oriented programming" -When we write our code using objects to represent entities, that's called [object-oriented programming](https://en.wikipedia.org/wiki/Object-oriented_programming), in short: "OOP". +```smart header="Objektově orientované programování" +Způsob programování, při kterém píšeme kód, který používá objekty představující entity, se nazývá [objektově orientované programování](https://cs.wikipedia.org/wiki/Objektově_orientované_programování), zkráceně „OOP“. -OOP is a big thing, an interesting science of its own. How to choose the right entities? How to organize the interaction between them? That's architecture, and there are great books on that topic, like "Design Patterns: Elements of Reusable Object-Oriented Software" by E. Gamma, R. Helm, R. Johnson, J. Vissides or "Object-Oriented Analysis and Design with Applications" by G. Booch, and more. +OOP je velká věc a samo o sobě je zajímavou vědou. Jak zvolit správné entity? Jak zorganizovat interakci mezi nimi? To je architektura a o tomto tématu existují skvělé knihy, např. „Design Patterns: Elements of Reusable Object-Oriented Software“ od E. Gammy, R. Helma, R. Johnsona a J. Vissidese, nebo „Object-Oriented Analysis and Design with Applications“ od G. Booche a další. ``` -### Method shorthand +### Zkratky metod -There exists a shorter syntax for methods in an object literal: +V objektovém literálu existuje i kratší syntaxe metod: ```js -// these objects do the same +// tyto objekty dělají totéž -user = { - sayHi: function() { - alert("Hello"); +uživatel = { + řekniAhoj: function() { + alert("Ahoj"); } }; -// method shorthand looks better, right? -user = { +// zkratka metody vypadá lépe, že? +uživatel = { *!* - sayHi() { // same as "sayHi: function(){...}" + řekniAhoj() { // totéž jako „řekniAhoj: function(){...}“ */!* - alert("Hello"); + alert("Ahoj"); } }; ``` -As demonstrated, we can omit `"function"` and just write `sayHi()`. +Jak vidíme, můžeme vypustit slovo `"function"` a napsat jen `řekniAhoj()`. -To tell the truth, the notations are not fully identical. There are subtle differences related to object inheritance (to be covered later), but for now they do not matter. In almost all cases, the shorter syntax is preferred. +Upřímně řečeno, tyto notace nejsou zcela identické. Jsou v nich drobné rozdíly týkající se objektové dědičnosti (která bude vysvětlena později), ale na nich nám prozatím nezáleží. Téměř ve všech případech se dává přednost kratší syntaxi. -## "this" in methods +## „this“ v metodách -It's common that an object method needs to access the information stored in the object to do its job. +Běžně se stává, že objektová metoda potřebuje přístup k informaci uložené v objektu, aby mohla vykonat svou práci. -For instance, the code inside `user.sayHi()` may need the name of the `user`. +Například kód uvnitř `uživatel.řekniAhoj()` může potřebovat jméno objektu `uživatel`. -**To access the object, a method can use the `this` keyword.** +**K přístupu do objektu může metoda používat klíčové slovo `this`.** -The value of `this` is the object "before dot", the one used to call the method. +Hodnota `this` je objekt „před tečkou“, tedy ten, který byl použit k volání metody. -For instance: +Například: ```js run -let user = { - name: "John", - age: 30, +let uživatel = { + jméno: "Jan", + věk: 30, - sayHi() { + řekniAhoj() { *!* - // "this" is the "current object" - alert(this.name); + // „this“ je „aktuální objekt“ + alert(this.jméno); */!* } }; -user.sayHi(); // John +uživatel.řekniAhoj(); // Jan ``` -Here during the execution of `user.sayHi()`, the value of `this` will be `user`. +Zde během výkonu `uživatel.řekniAhoj()` hodnota `this` bude `uživatel`. -Technically, it's also possible to access the object without `this`, by referencing it via the outer variable: +Technicky je možné přistupovat k objektu i bez `this` tak, že se na něj odkážeme přes vnější proměnnou: ```js -let user = { - name: "John", - age: 30, +let uživatel = { + jméno: "Jan", + věk: 30, - sayHi() { + řekniAhoj() { *!* - alert(user.name); // "user" instead of "this" + alert(uživatel.jméno); // „uživatel“ namísto „this“ */!* } }; ``` -...But such code is unreliable. If we decide to copy `user` to another variable, e.g. `admin = user` and overwrite `user` with something else, then it will access the wrong object. +...Takový kód je však nespolehlivý. Pokud se rozhodneme zkopírovat objekt `uživatel` do jiné proměnné, např. `správce = uživatel`, a přepsat proměnnou `uživatel` něčím jiným, pak budeme přistupovat k nesprávnému objektu. -That's demonstrated below: +To je ukázáno zde: ```js run -let user = { - name: "John", - age: 30, +let uživatel = { + jméno: "Jan", + věk: 30, - sayHi() { + řekniAhoj() { *!* - alert( user.name ); // leads to an error + alert( uživatel.jméno ); // povede k chybě */!* } }; -let admin = user; -user = null; // overwrite to make things obvious +let správce = uživatel; +uživatel = null; // přepíšeme, aby to bylo zřejmé *!* -admin.sayHi(); // TypeError: Cannot read property 'name' of null +správce.řekniAhoj(); // TypeError: Cannot read property 'jméno' of null */!* ``` -If we used `this.name` instead of `user.name` inside the `alert`, then the code would work. +Kdybychom uvnitř `alert` použili `this.jméno` namísto `uživatel.jméno`, kód by fungoval. -## "this" is not bound +## „this“ není vázané -In JavaScript, keyword `this` behaves unlike most other programming languages. It can be used in any function, even if it's not a method of an object. +V JavaScriptu se klíčové slovo `this` chová jinak než ve většině ostatních programovacích jazyků. Může být použito v libovolné funkci, i když to není metoda objektu. -There's no syntax error in the following example: +V následujícím příkladu není žádná syntaktická chyba: ```js -function sayHi() { - alert( *!*this*/!*.name ); +function řekniAhoj() { + alert( *!*this*/!*.jméno ); } ``` -The value of `this` is evaluated during the run-time, depending on the context. +Hodnota `this` se vyhodnocuje za běhu skriptu v závislosti na kontextu. -For instance, here the same function is assigned to two different objects and has different "this" in the calls: +Například zde bude stejná funkce přiřazena dvěma různým objektům a ve voláních bude mít různá „this“: ```js run -let user = { name: "John" }; -let admin = { name: "Admin" }; +let uživatel = { jméno: "Jan" }; +let správce = { jméno: "Správce" }; -function sayHi() { - alert( this.name ); +function řekniAhoj() { + alert( this.jméno ); } *!* -// use the same function in two objects -user.f = sayHi; -admin.f = sayHi; +// použijeme stejnou funkci ve dvou objektech +uživatel.f = řekniAhoj; +správce.f = řekniAhoj; */!* -// these calls have different this -// "this" inside the function is the object "before the dot" -user.f(); // John (this == user) -admin.f(); // Admin (this == admin) +// tato volání mají různá this +// „this“ uvnitř funkce je objekt „před tečkou“ +uživatel.f(); // Jan (this == uživatel) +správce.f(); // Správce (this == správce) -admin['f'](); // Admin (dot or square brackets access the method – doesn't matter) +správce['f'](); // Správce (k metodě přistupuje tečka nebo hranaté závorky - na tom nezáleží) ``` -The rule is simple: if `obj.f()` is called, then `this` is `obj` during the call of `f`. So it's either `user` or `admin` in the example above. +Platí jednoduché pravidlo: je-li volána `obj.f()`, pak `this` během volání `f` je `obj`. Ve výše uvedeném příkladu je to tedy `uživatel` anebo `správce`. -````smart header="Calling without an object: `this == undefined`" -We can even call the function without an object at all: +````smart header="Volání bez objektu: `this == undefined`" +Můžeme tuto funkci volat dokonce zcela bez objektu: ```js run -function sayHi() { +function řekniAhoj() { alert(this); } -sayHi(); // undefined +řekniAhoj(); // undefined ``` -In this case `this` is `undefined` in strict mode. If we try to access `this.name`, there will be an error. +Ve striktním režimu je `this` v tomto případě `undefined`. Pokud se pokusíme přistoupit k `this.jméno`, nastane chyba. -In non-strict mode the value of `this` in such case will be the *global object* (`window` in a browser, we'll get to it later in the chapter [](info:global-object)). This is a historical behavior that `"use strict"` fixes. +V nestriktním režimu bude hodnota `this` v takovém případě *globální objekt* (v prohlížeči `window`, dostaneme se k tomu později v kapitole [](info:global-object)). To je historické chování, které `"use strict"` opravuje. -Usually such call is a programming error. If there's `this` inside a function, it expects to be called in an object context. +Takové volání je obvykle programovací chyba. Jestliže je `this` uvnitř funkce, očekává se, že funkce bude volána v kontextu objektu. ```` -```smart header="The consequences of unbound `this`" -If you come from another programming language, then you are probably used to the idea of a "bound `this`", where methods defined in an object always have `this` referencing that object. +```smart header="Důsledky nevázaného `this`" +Pokud přicházíte z jiného programovacího jazyka, pak jste pravděpodobně zvyklí na myšlenku „vázaného `this`“, kdy v metodách definovaných v nějakém objektu `this` vždy odkazuje na tento objekt. -In JavaScript `this` is "free", its value is evaluated at call-time and does not depend on where the method was declared, but rather on what object is "before the dot". +V JavaScriptu je `this` „volné“, jeho hodnota se vypočítává až při volání a není závislá na tom, kde byla metoda deklarována, ale jen na tom, jaký objekt je „před tečkou“. -The concept of run-time evaluated `this` has both pluses and minuses. On the one hand, a function can be reused for different objects. On the other hand, the greater flexibility creates more possibilities for mistakes. +Koncept vyhodnocování `this` za běhu má své výhody i nevýhody. Na jednu stranu můžeme tutéž funkci použít opakovaně pro různé objekty. Na druhou stranu větší flexibilita vytváří více prostoru pro chyby. -Here our position is not to judge whether this language design decision is good or bad. We'll understand how to work with it, how to get benefits and avoid problems. +Zde nám nepřísluší soudit, zda je toto rozhodnutí návrhářů jazyka dobré nebo špatné. Porozumíme tomu, jak s ním pracovat, jak využít jeho výhody a vyhnout se problémům. ``` -## Arrow functions have no "this" +## Šipkové funkce nemají „this“ -Arrow functions are special: they don't have their "own" `this`. If we reference `this` from such a function, it's taken from the outer "normal" function. +Šipkové funkce jsou zvláštní: nemají „své vlastní“ `this`. Pokud se v takové funkci odkážeme na `this`, bude převzato z vnější „normální“ funkce. -For instance, here `arrow()` uses `this` from the outer `user.sayHi()` method: +Například zde `šipka()` používá `this` z vnější metody `uživatel.řekniAhoj()`: ```js run -let user = { - firstName: "Ilya", - sayHi() { - let arrow = () => alert(this.firstName); - arrow(); +let uživatel = { + křestníJméno: "Ilja", + řekniAhoj() { + let šipka = () => alert(this.křestníJméno); + šipka(); } }; -user.sayHi(); // Ilya +uživatel.řekniAhoj(); // Ilja ``` -That's a special feature of arrow functions, it's useful when we actually do not want to have a separate `this`, but rather to take it from the outer context. Later in the chapter we'll go more deeply into arrow functions. +To je speciální vlastnost šipkových funkcí. Je užitečná, když ve skutečnosti nechceme mít oddělené `this`, ale chceme je převzít z vnějšího kontextu. Později v kapitole prozkoumáme šipkové funkce více do hloubky. -## Summary +## Shrnutí -- Functions that are stored in object properties are called "methods". -- Methods allow objects to "act" like `object.doSomething()`. -- Methods can reference the object as `this`. +- Funkce uložené ve vlastnostech objektu se nazývají „metody“. +- Metody umožňují objektům „konat akce“, např. `objekt.dělejNěco()`. +- Metody se na tento objekt mohou odkazovat klíčovým slovem `this`. -The value of `this` is defined at run-time. -- When a function is declared, it may use `this`, but that `this` has no value until the function is called. -- A function can be copied between objects. -- When a function is called in the "method" syntax: `object.method()`, the value of `this` during the call is `object`. +Hodnota `this` je definována za běhu skriptu. +- Když je funkce deklarována, může používat `this`, ale toto `this` nemá žádnou hodnotu, dokud není funkce volána. +- Funkce může být kopírována mezi objekty. +- Když je funkce volána „metodovou“ syntaxí `objekt.metoda()`, hodnota `this` během tohoto volání je `objekt`. -Please note that arrow functions are special: they have no `this`. When `this` is accessed inside an arrow function, it is taken from outside. +Prosíme všimněte si, že šipkové funkce jsou zvláštní: nemají `this`. Když uvnitř šipkové funkce přistoupíme k `this`, převezme se zvnějšku. diff --git a/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/solution.md b/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/solution.md index 7d8edd7ca..8f23cac8d 100644 --- a/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/solution.md +++ b/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/solution.md @@ -1,8 +1,8 @@ -Yes, it's possible. +Ano, je to možné. -If a function returns an object then `new` returns it instead of `this`. +Jestliže funkce vrací objekt, pak jej `new` vrátí místo `this`. -So they can, for instance, return the same externally defined object `obj`: +Mohou tedy například vrátit stejný externě definovaný objekt `obj`: ```js run no-beautify let obj = {}; diff --git a/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md b/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md index e932a201a..f4cff1f19 100644 --- a/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md +++ b/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md @@ -2,9 +2,9 @@ importance: 2 --- -# Two functions – one object +# Dvě funkce – jeden objekt -Is it possible to create functions `A` and `B` so that `new A() == new B()`? +Je možné vytvořit funkce `A` a `B` tak, aby `new A() == new B()`? ```js no-beautify function A() { ... } @@ -16,4 +16,4 @@ let b = new B(); alert( a == b ); // true ``` -If it is, then provide an example of their code. +Pokud ano, uveďte příklad jejich kódu. diff --git a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/_js.view/solution.js b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/_js.view/solution.js index 3b51b2e69..ef30542f2 100644 --- a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/_js.view/solution.js +++ b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/_js.view/solution.js @@ -1,15 +1,15 @@ -function Calculator() { +function Kalkulátor() { - this.read = function() { + this.načti = function() { this.a = +prompt('a?', 0); this.b = +prompt('b?', 0); }; - this.sum = function() { + this.součet = function() { return this.a + this.b; }; - this.mul = function() { + this.součin = function() { return this.a * this.b; }; } \ No newline at end of file diff --git a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/_js.view/test.js b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/_js.view/test.js index bba80e5c2..19afc9dbe 100644 --- a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/_js.view/test.js +++ b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/_js.view/test.js @@ -1,27 +1,27 @@ -describe("calculator", function() { - let calculator; +describe("kalkulátor", function() { + let kalkulátor; before(function() { sinon.stub(window, "prompt") prompt.onCall(0).returns("2"); prompt.onCall(1).returns("3"); - calculator = new Calculator(); - calculator.read(); + kalkulátor = new Kalkulátor(); + kalkulátor.read(); }); - it("the read method asks for two values using prompt and remembers them in object properties", function() { - assert.equal(calculator.a, 2); - assert.equal(calculator.b, 3); + it("funkce načti se zeptá na dvě hodnoty pomocí prompt a zapamatuje si je jako vlastnosti objektu", function() { + assert.equal(kalkulátor.a, 2); + assert.equal(kalkulátor.b, 3); }); - it("when 2 and 3 are entered, the sum is 5", function() { - assert.equal(calculator.sum(), 5); + it("když zadáme 2 a 3, součet je 5", function() { + assert.equal(kalkulátor.součet(), 5); }); - it("when 2 and 3 are entered, the product is 6", function() { - assert.equal(calculator.mul(), 6); + it("když zadáme 2 a 3, součin je 6", function() { + assert.equal(kalkulátor.součin(), 6); }); after(function() { diff --git a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/solution.md b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/solution.md index 86bb65416..8a7a577bb 100644 --- a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/solution.md +++ b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/solution.md @@ -1,23 +1,23 @@ ```js run demo -function Calculator() { +function Kalkulátor() { - this.read = function() { + this.načti = function() { this.a = +prompt('a?', 0); this.b = +prompt('b?', 0); }; - this.sum = function() { + this.součet = function() { return this.a + this.b; }; - this.mul = function() { + this.součin = function() { return this.a * this.b; }; } -let calculator = new Calculator(); -calculator.read(); +let kalkulátor = new Kalkulátor(); +kalkulátor.načti(); -alert( "Sum=" + calculator.sum() ); -alert( "Mul=" + calculator.mul() ); +alert( "Součet=" + kalkulátor.součet() ); +alert( "Součin=" + kalkulátor.součin() ); ``` diff --git a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md index c862bec40..4ceaa62c2 100644 --- a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md +++ b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md @@ -2,22 +2,22 @@ importance: 5 --- -# Create new Calculator +# Vytvořte nový Kalkulátor -Create a constructor function `Calculator` that creates objects with 3 methods: +Vytvořte konstruktor `Kalkulátor`, který bude vytvářet objekty se třemi metodami: -- `read()` prompts for two values and saves them as object properties with names `a` and `b` respectively. -- `sum()` returns the sum of these properties. -- `mul()` returns the multiplication product of these properties. +- `načti()` se funkcí `prompt` zeptá na dvě hodnoty a uloží je jako vlastnosti objektu s názvy po řadě `a` a `b`. +- `součet()` vrátí součet těchto hodnot. +- `součin()` vrátí součin těchto hodnot. -For instance: +Například: ```js -let calculator = new Calculator(); -calculator.read(); +let kalkulátor = new Kalkulátor(); +kalkulátor.načti(); -alert( "Sum=" + calculator.sum() ); -alert( "Mul=" + calculator.mul() ); +alert( "Součet=" + kalkulátor.součet() ); +alert( "Součin=" + kalkulátor.součin() ); ``` [demo] diff --git a/1-js/04-object-basics/06-constructor-new/3-accumulator/_js.view/solution.js b/1-js/04-object-basics/06-constructor-new/3-accumulator/_js.view/solution.js index 585287c54..066d71ac6 100644 --- a/1-js/04-object-basics/06-constructor-new/3-accumulator/_js.view/solution.js +++ b/1-js/04-object-basics/06-constructor-new/3-accumulator/_js.view/solution.js @@ -1,8 +1,8 @@ -function Accumulator(startingValue) { - this.value = startingValue; +function Akumulátor(počátečníHodnota) { + this.hodnota = počátečníHodnota; - this.read = function() { - this.value += +prompt('How much to add?', 0); + this.načti = function() { + this.hodnota += +prompt('Kolik přičíst?', 0); }; -} +} \ No newline at end of file diff --git a/1-js/04-object-basics/06-constructor-new/3-accumulator/_js.view/test.js b/1-js/04-object-basics/06-constructor-new/3-accumulator/_js.view/test.js index a719cf45c..116b77da5 100644 --- a/1-js/04-object-basics/06-constructor-new/3-accumulator/_js.view/test.js +++ b/1-js/04-object-basics/06-constructor-new/3-accumulator/_js.view/test.js @@ -1,4 +1,4 @@ -describe("Accumulator", function() { +describe("Akumulátor", function() { beforeEach(function() { sinon.stub(window, "prompt") @@ -8,23 +8,23 @@ describe("Accumulator", function() { prompt.restore(); }); - it("initial value is the argument of the constructor", function() { - let accumulator = new Accumulator(1); + it("úvodní hodnota je argument konstruktoru", function() { + let akumulátor = new Akumulátor(1); - assert.equal(accumulator.value, 1); + assert.equal(akumulátor.hodnota, 1); }); - it("after reading 0, the value is 1", function() { - let accumulator = new Accumulator(1); + it("po načtení 0 je hodnota 1", function() { + let akumulátor = new Akumulátor(1); prompt.returns("0"); - accumulator.read(); - assert.equal(accumulator.value, 1); + akumulátor.načti(); + assert.equal(akumulátor.hodnota, 1); }); - it("after reading 1, the value is 2", function() { - let accumulator = new Accumulator(1); + it("po načtení 1 je hodnota 2", function() { + let akumulátor = new Akumulátor(1); prompt.returns("1"); - accumulator.read(); - assert.equal(accumulator.value, 2); + akumulátor.načti(); + assert.equal(akumulátor.hodnota, 2); }); }); diff --git a/1-js/04-object-basics/06-constructor-new/3-accumulator/solution.md b/1-js/04-object-basics/06-constructor-new/3-accumulator/solution.md index eb145e79d..ddde781f9 100644 --- a/1-js/04-object-basics/06-constructor-new/3-accumulator/solution.md +++ b/1-js/04-object-basics/06-constructor-new/3-accumulator/solution.md @@ -1,17 +1,17 @@ ```js run demo -function Accumulator(startingValue) { - this.value = startingValue; +function Akumulátor(počátečníHodnota) { + this.hodnota = počátečníHodnota; - this.read = function() { - this.value += +prompt('How much to add?', 0); + this.načti = function() { + this.hodnota += +prompt('Kolik přičíst?', 0); }; } -let accumulator = new Accumulator(1); -accumulator.read(); -accumulator.read(); -alert(accumulator.value); +let akumulátor = new Akumulátor(1); +akumulátor.načti(); +akumulátor.načti(); +alert(akumulátor.hodnota); ``` diff --git a/1-js/04-object-basics/06-constructor-new/3-accumulator/task.md b/1-js/04-object-basics/06-constructor-new/3-accumulator/task.md index c2c44881e..5ef5469d6 100644 --- a/1-js/04-object-basics/06-constructor-new/3-accumulator/task.md +++ b/1-js/04-object-basics/06-constructor-new/3-accumulator/task.md @@ -2,26 +2,26 @@ importance: 5 --- -# Create new Accumulator +# Vytvořte nový Akumulátor -Create a constructor function `Accumulator(startingValue)`. +Vytvořte konstruktor `Akumulátor(počátečníHodnota)`. -Object that it creates should: +Objekt, který je tímto konstruktorem vytvořen, by měl: -- Store the "current value" in the property `value`. The starting value is set to the argument of the constructor `startingValue`. -- The `read()` method should use `prompt` to read a new number and add it to `value`. +- Ukládat „aktuální hodnotu“ do vlastnosti `hodnota`. Počáteční hodnota se nastaví na argument konstruktoru `počátečníHodnota`. +- Metoda `načti()` by se měla pomocí `prompt` zeptat na nové číslo a přičíst je k vlastnosti `hodnota`. -In other words, the `value` property is the sum of all user-entered values with the initial value `startingValue`. +Jinými slovy, vlastnost `hodnota` bude součet všech uživatelem zadaných hodnot a úvodní hodnoty `počátečníHodnota`. -Here's the demo of the code: +Zde je ukázka kódu: ```js -let accumulator = new Accumulator(1); // initial value 1 +let akumulátor = new Akumulátor(1); // počáteční hodnota 1 -accumulator.read(); // adds the user-entered value -accumulator.read(); // adds the user-entered value +akumulátor.načti(); // přičte uživatelem zadanou hodnotu +akumulátor.načti(); // přičte uživatelem zadanou hodnotu -alert(accumulator.value); // shows the sum of these values +alert(akumulátor.hodnota); // zobrazí součet těchto hodnot ``` [demo] diff --git a/1-js/04-object-basics/06-constructor-new/article.md b/1-js/04-object-basics/06-constructor-new/article.md index a335464f1..564183bba 100644 --- a/1-js/04-object-basics/06-constructor-new/article.md +++ b/1-js/04-object-basics/06-constructor-new/article.md @@ -1,231 +1,231 @@ -# Constructor, operator "new" +# Konstruktor, operátor „new“ -The regular `{...}` syntax allows us to create one object. But often we need to create many similar objects, like multiple users or menu items and so on. +Obvyklá syntaxe `{...}` nám umožňuje vytvořit jeden objekt. Často však potřebujeme vytvořit mnoho podobných objektů, např. více uživatelů, položek menu a podobně. -That can be done using constructor functions and the `"new"` operator. +To můžeme učinit pomocí konstruktorů a operátoru `"new"`. -## Constructor function +## Konstruktor -Constructor functions technically are regular functions. There are two conventions though: +Konstruktory jsou z technického hlediska obvyklé funkce. Platí pro ně však dvě konvence: -1. They are named with capital letter first. -2. They should be executed only with `"new"` operator. +1. Jejich název začíná velkým písmenem. +2. Měly by být volány jen pomocí operátoru `„new“`. -For instance: +Například: ```js run -function User(name) { - this.name = name; - this.isAdmin = false; +function Uživatel(jméno) { + this.jméno = jméno; + this.jeSprávce = false; } *!* -let user = new User("Jack"); +let uživatel = new Uživatel("Kuba"); */!* -alert(user.name); // Jack -alert(user.isAdmin); // false +alert(uživatel.jméno); // Kuba +alert(uživatel.jeSprávce); // false ``` -When a function is executed with `new`, it does the following steps: +Když je funkce volána pomocí `new`, provedou se následující kroky: -1. A new empty object is created and assigned to `this`. -2. The function body executes. Usually it modifies `this`, adds new properties to it. -3. The value of `this` is returned. +1. Vytvoří se nový prázdný objekt a přiřadí se do `this`. +2. Vykoná se tělo funkce. To obvykle modifikuje `this`, do něhož přidá nové vlastnosti. +3. Vrátí se hodnota `this`. -In other words, `new User(...)` does something like: +Jinými slovy, `new Uživatel(...)` udělá něco jako: ```js -function User(name) { +function Uživatel(jméno) { *!* - // this = {}; (implicitly) + // this = {}; (implicitně) */!* - // add properties to this - this.name = name; - this.isAdmin = false; + // přidá vlastnosti do this + this.jméno = jméno; + this.jeSprávce = false; *!* - // return this; (implicitly) + // return this; (implicitně) */!* } ``` -So `let user = new User("Jack")` gives the same result as: +Takže `let uživatel = new Uživatel("Kuba")` vydá stejný výsledek jako: ```js -let user = { - name: "Jack", - isAdmin: false +let uživatel = { + jméno: "Kuba", + jeSprávce: false }; ``` -Now if we want to create other users, we can call `new User("Ann")`, `new User("Alice")` and so on. Much shorter than using literals every time, and also easy to read. +Když nyní budeme chtít vytvořit jiné uživatele, můžeme volat `new Uživatel("Anna")`, `new Uživatel("Alice")` a tak dále. Je to mnohem kratší než pokaždé používat literály a je to i snadno čitelné. -That's the main purpose of constructors -- to implement reusable object creation code. +To je hlavní smysl konstruktorů -- implementovat opakovaně použitelný kód pro vytváření objektů. -Let's note once again -- technically, any function (except arrow functions, as they don't have `this`) can be used as a constructor. It can be run with `new`, and it will execute the algorithm above. The "capital letter first" is a common agreement, to make it clear that a function is to be run with `new`. +Znovu poznamenejme, že technicky může být libovolná funkce (s výjimkou šipkových funkcí, jelikož ty nemají `this`) použita jako konstruktor. Může být volána pomocí `new` a pak se vykoná výše uvedený algoritmus. „Velké první písmeno“ je obvyklá úmluva, aby bylo zřejmé, že funkce má být volána pomocí `new`. ````smart header="new function() { ... }" -If we have many lines of code all about creation of a single complex object, we can wrap them in an immediately called constructor function, like this: +Máme-li mnoho řádků kódu a všechny se týkají vytvoření jediného složitého objektu, můžeme je zapouzdřit do konstruktoru, který okamžitě zavoláme, například: ```js -// create a function and immediately call it with new -let user = new function() { - this.name = "John"; - this.isAdmin = false; - - // ...other code for user creation - // maybe complex logic and statements - // local variables etc +// vytvoříme funkci a okamžitě ji zavoláme pomocí new +let uživatel = new function() { + this.jméno = "Jan"; + this.jeSprávce = false; + + // ...další kód pro vytváření uživatele + // možná složitá logika a příkazy + // lokální proměnné atd. }; ``` -This constructor can't be called again, because it is not saved anywhere, just created and called. So this trick aims to encapsulate the code that constructs the single object, without future reuse. +Tento konstruktor nemůžeme volat znovu, protože není nikde uložen, bude pouze vytvořen a zavolán. Smyslem tohoto triku je tedy zapouzdřit kód, který vytvoří jediný objekt a dále se nepoužívá. ```` -## Constructor mode test: new.target +## Test režimu konstruktoru: new.target -```smart header="Advanced stuff" -The syntax from this section is rarely used, skip it unless you want to know everything. +```smart header="Pokročilá záležitost" +Syntaxe z této části se používá málokdy. Pokud nechcete znát opravdu všechno, můžete ji přeskočit. ``` -Inside a function, we can check whether it was called with `new` or without it, using a special `new.target` property. +Uvnitř funkce můžeme ověřit, zda byla volána pomocí `new` nebo bez něj, pomocí speciální vlastnosti `new.target`. -It is undefined for regular calls and equals the function if called with `new`: +Ta je při běžném volání `undefined`, ale pokud je funkce volána pomocí `new`, je rovna této funkci: ```js run -function User() { +function Uživatel() { alert(new.target); } -// without "new": +// bez „new“: *!* -User(); // undefined +Uživatel(); // undefined */!* -// with "new": +// s „new“: *!* -new User(); // function User { ... } +new Uživatel(); // function Uživatel { ... } */!* ``` -That can be used inside the function to know whether it was called with `new`, "in constructor mode", or without it, "in regular mode". +Můžeme ji použít uvnitř funkce, abychom se dozvěděli, zda byla volána „v režimu konstruktoru“ pomocí `new` nebo „v běžném režimu“ bez něj. -We can also make both `new` and regular calls to do the same, like this: +Můžeme také funkci přimět, aby při volání pomocí `new` a při běžném volání prováděla totéž, například takto: ```js run -function User(name) { - if (!new.target) { // if you run me without new - return new User(name); // ...I will add new for you +function Uživatel(jméno) { + if (!new.target) { // pokud mě spustíte bez new + return new Uživatel(jméno); // ...přidám new pro vás } - this.name = name; + this.jméno = jméno; } -let john = User("John"); // redirects call to new User -alert(john.name); // John +let jan = Uživatel("Jan"); // přesměruje volání na new Uživatel +alert(jan.jméno); // Jan ``` -This approach is sometimes used in libraries to make the syntax more flexible. So that people may call the function with or without `new`, and it still works. +Tento přístup se někdy používá v knihovnách, aby byla syntaxe flexibilnější. Lidé pak mohou volat funkci s `new` nebo bez něj a funkce pokaždé funguje. -Probably not a good thing to use everywhere though, because omitting `new` makes it a bit less obvious what's going on. With `new` we all know that the new object is being created. +Pravděpodobně však není dobré používat jej všude, protože bez uvedení `new` je trochu méně zřejmé, co se děje. Když je uvedeno `new`, všichni víme, že se vytváří nový objekt. -## Return from constructors +## Návrat z konstruktorů -Usually, constructors do not have a `return` statement. Their task is to write all necessary stuff into `this`, and it automatically becomes the result. +Konstruktory obvykle nemají příkaz `return`. Jejich úkolem je zapsat všechno potřebné do `this` a to se pak automaticky stane výsledkem. -But if there is a `return` statement, then the rule is simple: +Jestliže však je příkaz `return` přítomen, platí jednoduché pravidlo: -- If `return` is called with an object, then the object is returned instead of `this`. -- If `return` is called with a primitive, it's ignored. +- Je-li `return` volán s objektem, vrátí se namísto `this` tento objekt. +- Je-li `return` volán s primitivem, tento primitiv se ignoruje. -In other words, `return` with an object returns that object, in all other cases `this` is returned. +Jinými slovy, `return` s objektem vrátí onen objekt, ve všech ostatních případech se vrátí `this`. -For instance, here `return` overrides `this` by returning an object: +Například zde `return` přepisuje `this` vrácením objektu: ```js run -function BigUser() { +function VelkýUživatel() { - this.name = "John"; + this.jméno = "Jan"; - return { name: "Godzilla" }; // <-- returns this object + return { jméno: "Godzilla" }; // <-- vrátí tento objekt } -alert( new BigUser().name ); // Godzilla, got that object +alert( new VelkýUživatel().jméno ); // Godzilla, získali jsme onen objekt ``` -And here's an example with an empty `return` (or we could place a primitive after it, doesn't matter): +A zde je příklad s prázdným `return` (nebo za něj můžeme umístit primitiv, na tom nezáleží): ```js run -function SmallUser() { +function MalýUživatel() { - this.name = "John"; + this.jméno = "Jan"; - return; // <-- returns this + return; // <-- vrátí this } -alert( new SmallUser().name ); // John +alert( new MalýUživatel().jméno ); // Jan ``` -Usually constructors don't have a `return` statement. Here we mention the special behavior with returning objects mainly for the sake of completeness. +Konstruktory obvykle příkaz `return` neobsahují. Speciální chování s vracením objektů zde zmiňujeme zejména pro úplnost. -````smart header="Omitting parentheses" -By the way, we can omit parentheses after `new`: +````smart header="Vypuštění závorek" +Mimochodem, závorky za `new` můžeme vypustit: ```js -let user = new User; // <-- no parentheses -// same as -let user = new User(); +let uživatel = new Uživatel; // <-- bez závorek +// totéž jako +let uživatel = new Uživatel(); ``` -Omitting parentheses here is not considered a "good style", but the syntax is permitted by specification. +Vypouštění závorek zde se nepovažuje za „dobrý styl“, ale specifikace tuto syntaxi povoluje. ```` -## Methods in constructor +## Metody v konstruktoru -Using constructor functions to create objects gives a great deal of flexibility. The constructor function may have parameters that define how to construct the object, and what to put in it. +Používání konstruktorů k vytváření objektů nám dává velké množství flexibility. Konstruktor může mít parametry, které definují, jak objekt zkonstruovat a co do něj uložit. -Of course, we can add to `this` not only properties, but methods as well. +Samozřejmě do `this` můžeme přidávat nejen vlastnosti, ale také metody. -For instance, `new User(name)` below creates an object with the given `name` and the method `sayHi`: +Například níže uvedené `new Uživatel(jméno)` vytvoří objekt se zadanou vlastností `jméno` a metodou `řekniAhoj`: ```js run -function User(name) { - this.name = name; +function Uživatel(jméno) { + this.jméno = jméno; - this.sayHi = function() { - alert( "My name is: " + this.name ); + this.řekniAhoj = function() { + alert( "Jmenuji se: " + this.jméno ); }; } *!* -let john = new User("John"); +let jan = new Uživatel("Jan"); -john.sayHi(); // My name is: John +jan.řekniAhoj(); // Jmenuji se: Jan */!* /* -john = { - name: "John", - sayHi: function() { ... } +jan = { + jméno: "Jan", + řekniAhoj: function() { ... } } */ ``` -To create complex objects, there's a more advanced syntax, [classes](info:classes), that we'll cover later. +K vytváření složitých objektů existuje i pokročilejší syntaxe -- [třídy](info:classes), kterou probereme později. -## Summary +## Shrnutí -- Constructor functions or, briefly, constructors, are regular functions, but there's a common agreement to name them with capital letter first. -- Constructor functions should only be called using `new`. Such a call implies a creation of empty `this` at the start and returning the populated one at the end. +- Konstruktory jsou obvyklé funkce, avšak panuje běžná úmluva, že jejich název by měl mít velké první písmeno. +- Konstruktory by měly být volány jedině pomocí `new`. Takové volání způsobí, že se na začátku vytvoří prázdné `this` a to se pak na konci vrátí naplněné. -We can use constructor functions to make multiple similar objects. +Konstruktory můžeme používat k vytváření více podobných objektů. -JavaScript provides constructor functions for many built-in language objects: like `Date` for dates, `Set` for sets and others that we plan to study. +JavaScript poskytuje konstruktory pro mnoho vestavěných jazykových objektů: např. `Date` pro data, `Set` pro množiny a jiné, které máme v plánu prostudovat. -```smart header="Objects, we'll be back!" -In this chapter we only cover the basics about objects and constructors. They are essential for learning more about data types and functions in the next chapters. +```smart header="Objekty, vrátíme se!" +V této kapitole probíráme ohledně objektů a konstruktorů jen základy, které jsou podstatné pro pochopení dalších věcí ohledně datových typů a funkcí v dalších kapitolách. -After we learn that, we return to objects and cover them in-depth in the chapters and . +Až se je naučíme, vrátíme se k objektům a probereme je do hloubky v kapitolách a . ``` 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. diff --git a/1-js/04-object-basics/08-symbol/article.md b/1-js/04-object-basics/08-symbol/article.md index 10a98af0a..42c99b1f0 100644 --- a/1-js/04-object-basics/08-symbol/article.md +++ b/1-js/04-object-basics/08-symbol/article.md @@ -1,37 +1,38 @@ -# Symbol type +# Typ symbol -By specification, only two primitive types may serve as object property keys: +Podle specifikace mohou jako klíče vlastností objektů sloužit pouze dva primitivní typy: -- string type, or -- symbol type. +- typ řetězec, nebo +- typ symbol. -Otherwise, if one uses another type, such as number, it's autoconverted to string. So that `obj[1]` is the same as `obj["1"]`, and `obj[true]` is the same as `obj["true"]`. +Pokud použijeme jiný typ, například číslo, je automaticky převeden na řetězec. Takže `obj[1]` je totéž jako `obj["1"]` a `obj[true]` je totéž jako `obj["true"]`. -Until now we've been using only strings. +Doposud jsme používali pouze řetězce. -Now let's explore symbols, see what they can do for us. +Nyní prozkoumejme symboly a podívejme se, co pro nás mohou udělat. -## Symbols +## Symboly -A "symbol" represents a unique identifier. +„Symbol“ představuje unikátní identifikátor. -A value of this type can be created using `Symbol()`: +Hodnotu tohoto typu můžeme vytvořit pomocí `Symbol()`: ```js +// id je nový symbol let id = Symbol(); ``` -Upon creation, we can give symbols a description (also called a symbol name), mostly useful for debugging purposes: +Po vytvoření můžeme symbolu dát nějaký popis (nazývaný také název symbolu), což je užitečné zejména pro účely ladění: ```js -// id is a symbol with the description "id" +// id je symbol s popisem "id" let id = Symbol("id"); ``` -Symbols are guaranteed to be unique. Even if we create many symbols with exactly the same description, they are different values. The description is just a label that doesn't affect anything. +U symbolů je zaručeno, že jsou unikátní. I když vytvoříme mnoho symbolů s naprosto stejným popisem, budou představovat různé hodnoty. Popis je jenom štítek, který nemá na nic vliv. -For instance, here are two symbols with the same description -- they are not equal: +Například zde jsou dva symboly se stejným popisem -- přesto si nejsou rovny: ```js run let id1 = Symbol("id"); @@ -42,34 +43,34 @@ alert(id1 == id2); // false */!* ``` -If you are familiar with Ruby or another language that also has some sort of "symbols" -- please don't be misguided. JavaScript symbols are different. +Jestliže znáte Ruby nebo jiný jazyk, který také obsahuje nějaký druh „symbolů“ -- prosíme, nenechte se zmást. Symboly v JavaScriptu jsou jiné. -So, to summarize, a symbol is a "primitive unique value" with an optional description. Let's see where we can use them. +Když to tedy shrneme, symbol je „primitivní unikátní hodnota“ s nepovinným popisem. Podívejme se, kde je můžeme použít. -````warn header="Symbols don't auto-convert to a string" -Most values in JavaScript support implicit conversion to a string. For instance, we can `alert` almost any value, and it will work. Symbols are special. They don't auto-convert. +````warn header="Symboly se automaticky nekonvertují na řetězce" +Většina hodnot v JavaScriptu podporuje implicitní konverzi na řetězec. Například můžeme použít `alert` na téměř jakoukoli hodnotu a bude fungovat. Symboly jsou zvláštní. Ty se automaticky nekonvertují. -For instance, this `alert` will show an error: +Například tento `alert` ohlásí chybu: ```js run let id = Symbol("id"); *!* -alert(id); // TypeError: Cannot convert a Symbol value to a string +alert(id); // TypeError: Nelze převést hodnotu Symbol na řetězec */!* ``` -That's a "language guard" against messing up, because strings and symbols are fundamentally different and should not accidentally convert one into another. +Je to „jazyková stráž“ proti nepořádku, jelikož řetězce a symboly jsou naprosto odlišné a neměly by se neúmyslně konvertovat jedny na druhé. -If we really want to show a symbol, we need to explicitly call `.toString()` on it, like here: +Jestliže opravdu chceme zobrazit symbol, musíme na něm explicitně zavolat `.toString()`, např. zde: ```js run let id = Symbol("id"); *!* -alert(id.toString()); // Symbol(id), now it works +alert(id.toString()); // Symbol(id), nyní to funguje */!* ``` -Or get `symbol.description` property to show the description only: +Nebo načíst vlastnost `symbol.description`, aby se zobrazil jen popis: ```js run let id = Symbol("id"); @@ -80,210 +81,209 @@ alert(id.description); // id ```` -## "Hidden" properties +## „Skryté“ vlastnosti +Symboly nám umožňují vytvářet „skryté“ vlastnosti objektu, k nimž žádná jiná část kódu nemůže neúmyslně přistoupit nebo je přepsat. -Symbols allow us to create "hidden" properties of an object, that no other part of code can accidentally access or overwrite. +Například pracujeme s objekty `uživatel`, které patří do kódu třetí strany, a my bychom do nich rádi přidali identifikátory. -For instance, if we're working with `user` objects, that belong to a third-party code. We'd like to add identifiers to them. - -Let's use a symbol key for it: +Použijeme pro ně symbolický klíč: ```js run -let user = { // belongs to another code - name: "John" +let uživatel = { // patří do jiného kódu + jméno: "Jan" }; let id = Symbol("id"); -user[id] = 1; +uživatel[id] = 1; -alert( user[id] ); // we can access the data using the symbol as the key +alert( uživatel[id] ); // můžeme přistupovat k datům pomocí tohoto symbolu jako klíče ``` -What's the benefit of using `Symbol("id")` over a string `"id"`? +Jaká je výhoda používání `Symbol("id")` oproti řetězci `"id"`? -As `user` objects belong to another codebase, it's unsafe to add fields to them, since we might affect pre-defined behavior in that other codebase. However, symbols cannot be accessed accidentally. The third-party code won't be aware of newly defined symbols, so it's safe to add symbols to the `user` objects. +Protože objekt `uživatel` patří do jiného kódu, není bezpečné do něj přidávat nějaká pole, protože bychom mohli ovlivnit předdefinované chování v onom jiném kódu. Avšak k symbolu nelze neúmyslně přistoupit. Kód třetí strany se o nově definovaných symbolech nedozví, takže přidávat do objektu `uživatel` symboly je bezpečné. -Also, imagine that another script wants to have its own identifier inside `user`, for its own purposes. +Představte si také, že jiný skript bude chtít uvnitř objektu `uživatel` mít svůj vlastní identifikátor pro své účely. -Then that script can create its own `Symbol("id")`, like this: +Pak tento skript může vytvořit svůj vlastní `Symbol("id")`, například takto: ```js // ... let id = Symbol("id"); -user[id] = "Their id value"; +uživatel[id] = "Jejich hodnota id"; ``` -There will be no conflict between our and their identifiers, because symbols are always different, even if they have the same name. +Nenastane žádný konflikt mezi našimi a jeho identifikátory, protože symboly jsou vždy různé, i když mají stejný název. -...But if we used a string `"id"` instead of a symbol for the same purpose, then there *would* be a conflict: +...Kdybychom však ke stejnému účelu místo symbolu použili řetězec `"id"`, pak by konflikt *nastal*: ```js -let user = { name: "John" }; +let uživatel = { jméno: "Jan" }; -// Our script uses "id" property -user.id = "Our id value"; +// Náš skript používá vlastnost „id“ +uživatel.id = "Naše hodnota id"; -// ...Another script also wants "id" for its purposes... +// ...Jiný skript chce také „id“ pro své vlastní účely... -user.id = "Their id value" -// Boom! overwritten by another script! +uživatel.id = "Jejich hodnota id" +// Bum! cizí skript nám ji přepsal! ``` -### Symbols in an object literal +### Symboly v objektovém literálu -If we want to use a symbol in an object literal `{...}`, we need square brackets around it. +Chceme-li použít symbol v objektovém literálu `{...}`, musíme jej uzavřít do hranatých závorek. -Like this: +Například: ```js let id = Symbol("id"); -let user = { - name: "John", +let uživatel = { + jméno: "Jan", *!* - [id]: 123 // not "id": 123 + [id]: 123 // ne "id": 123 */!* }; ``` -That's because we need the value from the variable `id` as the key, not the string "id". +Je to proto, že jako klíč potřebujeme hodnotu proměnné `id`, ne řetězec `"id"`. -### Symbols are skipped by for..in +### Cyklus for..in symboly přeskakuje -Symbolic properties do not participate in `for..in` loop. +Symbolické vlastnosti se neúčastní cyklu `for..in`. -For instance: +Například: ```js run let id = Symbol("id"); -let user = { - name: "John", - age: 30, +let uživatel = { + jméno: "Jan", + věk: 30, [id]: 123 }; *!* -for (let key in user) alert(key); // name, age (no symbols) +for (let klíč in uživatel) alert(klíč); // jméno, věk (žádné symboly) */!* -// the direct access by the symbol works -alert( "Direct: " + user[id] ); // Direct: 123 +// přímý přístup k symbolu funguje +alert( "Přímo: " + uživatel[id] ); // Přímo: 123 ``` -[Object.keys(user)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys) also ignores them. That's a part of the general "hiding symbolic properties" principle. If another script or a library loops over our object, it won't unexpectedly access a symbolic property. +Ignoruje je i metoda [Object.keys(uživatel)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys). To je součást obecného principu „skrývání symbolických vlastností“. Jestliže jiný skript nebo knihovna provádí cyklus nad naším objektem, nepřistoupí nečekaně k symbolické vlastnosti. -In contrast, [Object.assign](mdn:js/Object/assign) copies both string and symbol properties: +Naproti tomu [Object.assign](mdn:js/Object/assign) zkopíruje řetězcové i symbolické vlastnosti: ```js run let id = Symbol("id"); -let user = { +let uživatel = { [id]: 123 }; -let clone = Object.assign({}, user); +let klon = Object.assign({}, uživatel); -alert( clone[id] ); // 123 +alert( klon[id] ); // 123 ``` -There's no paradox here. That's by design. The idea is that when we clone an object or merge objects, we usually want *all* properties to be copied (including symbols like `id`). +Není to žádný paradox. Je to tak podle designu. Myšlenka je, že když klonujeme objekt nebo slučujeme objekty, chceme obvykle zkopírovat *všechny* vlastnosti (včetně symbolických, jako `id`). -## Global symbols +## Globální symboly -As we've seen, usually all symbols are different, even if they have the same name. But sometimes we want same-named symbols to be same entities. For instance, different parts of our application want to access symbol `"id"` meaning exactly the same property. +Jak jsme viděli, všechny symboly jsou zpravidla různé, i když mají stejný název. Někdy však chceme, aby symboly se stejným názvem byly stejnými entitami. Například různé části naší aplikace chtějí přistupovat k symbolu `"id"`, který má znamenat stále tutéž vlastnost. -To achieve that, there exists a *global symbol registry*. We can create symbols in it and access them later, and it guarantees that repeated accesses by the same name return exactly the same symbol. +K tomu, abychom toho mohli dosáhnout, existuje *globální registr symbolů*. V něm můžeme symboly vytvořit a později k nim přistupovat. Registr nám zaručuje, že opakovaný přístup stejným názvem vrátí přesně stejný symbol. -In order to read (create if absent) a symbol from the registry, use `Symbol.for(key)`. +K načtení (vytvoření, pokud neexistuje) symbolu z registru použijeme `Symbol.for(klíč)`. -That call checks the global registry, and if there's a symbol described as `key`, then returns it, otherwise creates a new symbol `Symbol(key)` and stores it in the registry by the given `key`. +Tato metoda zkontroluje globální registr, a jestliže je v něm symbol popsaný jako `klíč`, vrátí jej, v opačném případě vytvoří nový symbol `Symbol(klíč)` a uloží ho do registru pod zadaným `klíč`em. -For instance: +Například: ```js run -// read from the global registry -let id = Symbol.for("id"); // if the symbol did not exist, it is created +// načtení z globálního registru +let id = Symbol.for("id"); // jestliže symbol neexistoval, bude vytvořen -// read it again (maybe from another part of the code) -let idAgain = Symbol.for("id"); +// načteme ho znovu (třeba z jiné části kódu) +let idZnovu = Symbol.for("id"); -// the same symbol -alert( id === idAgain ); // true +// tentýž symbol +alert( id === idZnovu ); // true ``` -Symbols inside the registry are called *global symbols*. If we want an application-wide symbol, accessible everywhere in the code -- that's what they are for. +Symboly v tomto registru se nazývají *globální symboly*. Chceme-li symbol pro celou aplikaci, který bude dostupný všude v kódu -- k tomuto účelu nám registr slouží. -```smart header="That sounds like Ruby" -In some programming languages, like Ruby, there's a single symbol per name. +```smart header="To zní jako Ruby" +V některých programovacích jazycích, např. Ruby, existuje jediný symbol pro každý název. -In JavaScript, as we can see, that's true for global symbols. +V JavaScriptu, jak vidíme, to platí pro globální symboly. ``` ### Symbol.keyFor -We have seen that for global symbols, `Symbol.for(key)` returns a symbol by name. To do the opposite -- return a name by global symbol -- we can use: `Symbol.keyFor(sym)`: +Viděli jsme, že pro globální symboly metoda `Symbol.for(klíč)` vrátí symbol podle názvu. Chceme-li udělat opak -- vrátit název podle globálního symbolu -- můžeme použít `Symbol.keyFor(sym)`: -For instance: +Například: ```js run -// get symbol by name -let sym = Symbol.for("name"); +// načteme symbol podle názvu +let sym = Symbol.for("jméno"); let sym2 = Symbol.for("id"); -// get name by symbol -alert( Symbol.keyFor(sym) ); // name +// načteme název podle symbolu +alert( Symbol.keyFor(sym) ); // jméno alert( Symbol.keyFor(sym2) ); // id ``` -The `Symbol.keyFor` internally uses the global symbol registry to look up the key for the symbol. So it doesn't work for non-global symbols. If the symbol is not global, it won't be able to find it and returns `undefined`. +Metoda `Symbol.keyFor` interně používá globální registr symbolů k vyhledání klíče pro symbol. Pro neglobální symboly tedy nefunguje. Není-li symbol globální, nebude ho schopna najít a vrátí `undefined`. -That said, all symbols have the `description` property. +Když o tom mluvíme, všechny symboly mají vlastnost `description`. -For instance: +Například: ```js run -let globalSymbol = Symbol.for("name"); -let localSymbol = Symbol("name"); +let globálníSymbol = Symbol.for("jméno"); +let lokálníSymbol = Symbol("jméno"); -alert( Symbol.keyFor(globalSymbol) ); // name, global symbol -alert( Symbol.keyFor(localSymbol) ); // undefined, not global +alert( Symbol.keyFor(globálníSymbol) ); // jméno, globální symbol +alert( Symbol.keyFor(lokálníSymbol) ); // undefined, není globální -alert( localSymbol.description ); // name +alert( lokálníSymbol.description ); // jméno ``` -## System symbols +## Systémové symboly -There exist many "system" symbols that JavaScript uses internally, and we can use them to fine-tune various aspects of our objects. +V JavaScriptu existuje mnoho „systémových“ symbolů, které JavaScript interně využívá a my je můžeme použít k vyladění různých aspektů našich objektů. -They are listed in the specification in the [Well-known symbols](https://tc39.github.io/ecma262/#sec-well-known-symbols) table: +Jsou uvedeny ve specifikaci v tabulce [Dobře známé symboly](https://tc39.github.io/ecma262/#sec-well-known-symbols): - `Symbol.hasInstance` - `Symbol.isConcatSpreadable` - `Symbol.iterator` - `Symbol.toPrimitive` -- ...and so on. +- ...a tak dále. -For instance, `Symbol.toPrimitive` allows us to describe object to primitive conversion. We'll see its use very soon. +Například `Symbol.toPrimitive` nám umožňuje popsat konverzi objektu na primitiv. Jeho použití uvidíme velmi brzy. -Other symbols will also become familiar when we study the corresponding language features. +Až prostudujeme příslušné vlastnosti jazyka, seznámíme se i s jinými symboly. -## Summary +## Shrnutí -`Symbol` is a primitive type for unique identifiers. +`Symbol` je primitivní typ pro unikátní identifikátory. -Symbols are created with `Symbol()` call with an optional description (name). +Symboly se vytvářejí voláním `Symbol()` s nepovinným popisem (názvem). -Symbols are always different values, even if they have the same name. If we want same-named symbols to be equal, then we should use the global registry: `Symbol.for(key)` returns (creates if needed) a global symbol with `key` as the name. Multiple calls of `Symbol.for` with the same `key` return exactly the same symbol. +Symboly jsou vždy různé hodnoty, i když mají stejný název. Jestliže chceme, aby si symboly se stejným názvem byly rovny, měli bychom použít globální registr: `Symbol.for(klíč)` vrátí (vytvoří, je-li potřeba) globální symbol, jehož název bude `klíč`. Více volání `Symbol.for` se stejnou hodnotou `klíč` vrátí přesně tentýž symbol. -Symbols have two main use cases: +Symboly mají dvě hlavní použití: -1. "Hidden" object properties. +1. „Skryté“ vlastnosti objektů. - If we want to add a property into an object that "belongs" to another script or a library, we can create a symbol and use it as a property key. A symbolic property does not appear in `for..in`, so it won't be accidentally processed together with other properties. Also it won't be accessed directly, because another script does not have our symbol. So the property will be protected from accidental use or overwrite. + Chceme-li přidat vlastnost do objektu, který „patří“ do jiného skriptu nebo knihovny, můžeme vytvořit symbol a použít jej jako klíč vlastnosti. Symbolická vlastnost se neobjeví ve `for..in`, takže nebude neúmyslně zpracována společně s ostatními vlastnostmi. Nikdo jiný k ní také nebude přímo přistupovat, jelikož žádný jiný skript nebude mít náš symbol. Vlastnost tedy bude chráněna před náhodným použitím nebo přepsáním. - So we can "covertly" hide something into objects that we need, but others should not see, using symbolic properties. + Pomocí symbolických vlastností tedy můžeme „utajeně“ ukrýt do objektů něco, co potřebujeme, ale jiní by to neměli vidět. -2. There are many system symbols used by JavaScript which are accessible as `Symbol.*`. We can use them to alter some built-in behaviors. For instance, later in the tutorial we'll use `Symbol.iterator` for [iterables](info:iterable), `Symbol.toPrimitive` to setup [object-to-primitive conversion](info:object-toprimitive) and so on. +2. JavaScript používá mnoho systémových symbolů, které jsou dostupné pomocí `Symbol.*`. Můžeme je používat, abychom změnili vestavěné chování. Například později v tomto tutoriálu budeme používat `Symbol.iterator` pro [iterovatelné objekty](info:iterable), `Symbol.toPrimitive` k nastavení [konverze objektů na primitivy](info:object-toprimitive) a tak dále. -Technically, symbols are not 100% hidden. There is a built-in method [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) that allows us to get all symbols. Also there is a method named [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) that returns *all* keys of an object including symbolic ones. But most libraries, built-in functions and syntax constructs don't use these methods. +Z technického hlediska nejsou symboly na 100% skryté. Existuje vestavěná metoda [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols), která nám umožňuje získat všechny symboly. Existuje i metoda [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys), která vrátí *všechny* klíče objektu včetně symbolických. Většina knihoven, vestavěných funkcí a syntaktických konstruktů však tyto metody nepoužívá. diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index fa68da583..c32d38394 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -1,250 +1,250 @@ -# Object to primitive conversion +# Konverze objektů na primitivní typy -What happens when objects are added `obj1 + obj2`, subtracted `obj1 - obj2` or printed using `alert(obj)`? +Co se stane, když se objekty sečtou `obj1 + obj2`, odečtou `obj1 - obj2` nebo zobrazí pomocí `alert(obj)`? -JavaScript doesn't allow you to customize how operators work on objects. Unlike some other programming languages, such as Ruby or C++, we can't implement a special object method to handle addition (or other operators). +JavaScript neumožňuje přesně nastavit způsob, jakým operátory fungují nad objekty. Na rozdíl od některých jiných programovacích jazyků, např. Ruby nebo C++, nemůžeme implementovat speciální objektovou metodu, která bude zpracovávat sčítání (nebo jiné operátory). -In case of such operations, objects are auto-converted to primitives, and then the operation is carried out over these primitives and results in a primitive value. +Při takovýchto operacích se objekty automaticky konvertují na primitivy a pak se nad těmito primitivy vykoná operace, jejímž výsledkem je primitivní hodnota. -That's an important limitation: the result of `obj1 + obj2` (or another math operation) can't be another object! +To je důležité omezení: výsledkem `obj1 + obj2` (nebo jiné matematické operace) nemůže být jiný objekt! -E.g. we can't make objects representing vectors or matrices (or achievements or whatever), add them and expect a "summed" object as the result. Such architectural feats are automatically "off the board". +Například nemůžeme vytvořit objekty představující vektory nebo matice (nebo výsledky či cokoli jiného), sečíst je a jako výsledek očekávat „sečtený“ objekt. Takové architektonické výkony jsou automaticky „mimo mísu“. -So, because we can't technically do much here, there's no maths with objects in real projects. When it happens, with rare exceptions, it's because of a coding mistake. +Protože zde toho technicky nemůžeme mnoho udělat, v reálných projektech nebývají žádné matematické operace s objekty. Když se objeví, je to až na vzácné výjimky důsledkem chyby v kódu. -In this chapter we'll cover how an object converts to primitive and how to customize it. +V této kapitole probereme, jak převést objekt na primitiv a jak si to přizpůsobit. -We have two purposes: +Má to dva účely: -1. It will allow us to understand what's going on in case of coding mistakes, when such an operation happened accidentally. -2. There are exceptions, where such operations are possible and look good. E.g. subtracting or comparing dates (`Date` objects). We'll come across them later. +1. Umožní nám to porozumět, co se děje v případě chyby v kódu, když k takové operaci neúmyslně dojde. +2. Existují výjimky, kdy jsou takové operace možné a vypadají dobře. Například odečítání nebo porovnávání dat (objekty `Date`). Narazíme na ně později. -## Conversion rules +## Pravidla konverze -In the chapter we've seen the rules for numeric, string and boolean conversions of primitives. But we left a gap for objects. Now, as we know about methods and symbols it becomes possible to fill it. +V kapitole jsme viděli pravidla číselných, řetězcových a booleanových konverzí primitivů. Objekty jsme však vynechali. Nyní, když známe metody a symboly, můžeme tuto mezeru zaplnit. -1. There's no conversion to boolean. All objects are `true` in a boolean context, as simple as that. There exist only numeric and string conversions. -2. The numeric conversion happens when we subtract objects or apply mathematical functions. For instance, `Date` objects (to be covered in the chapter ) can be subtracted, and the result of `date1 - date2` is the time difference between two dates. -3. As for the string conversion -- it usually happens when we output an object with `alert(obj)` and in similar contexts. +1. Neexistuje žádná konverze na boolean. V booleovském kontextu jsou všechny objekty prostě a jednoduše `true`. Existují jen konverze na číslo a na řetězec. +2. Konverze na číslo se odehrává, když objekty odečítáme nebo na nich provádíme matematické funkce. Například objekty `Date` (vysvětlíme je v kapitole ) můžeme od sebe odečíst a výsledkem `datum1 - datum2` je časový rozdíl mezi těmito dvěma daty. +3. Co se týče konverze na řetězec -- ta se zpravidla odehrává, když pošleme objekt na výstup, např. `alert(obj)`, a v podobných kontextech. -We can implement string and numeric conversion by ourselves, using special object methods. +Konverzi na řetězec a na číslo si můžeme implementovat sami použitím speciálních objektových metod. -Now let's get into technical details, because it's the only way to cover the topic in-depth. +Podívejme se nyní na technické podrobnosti, protože to je jediný způsob, jak toto téma pokrýt do hloubky. -## Hints +## Náznaky -How does JavaScript decide which conversion to apply? +Podle čeho se JavaScript rozhoduje, kterou konverzi použít? -There are three variants of type conversion, that happen in various situations. They're called "hints", as described in the [specification](https://tc39.github.io/ecma262/#sec-toprimitive): +Existují tři varianty typové konverze, k nimž dochází v různých situacích. Nazývají se „náznaky“ („hinty“) a jsou popsány ve [specifikaci](https://tc39.github.io/ecma262/#sec-toprimitive): `"string"` -: For an object-to-string conversion, when we're doing an operation on an object that expects a string, like `alert`: +: Pro konverzi objektu na řetězec, když nad objektem provádíme operaci, která očekává řetězec, např. `alert`: ```js - // output + // výstup alert(obj); - // using object as a property key - anotherObj[obj] = 123; + // použití objektu jako klíče vlastnosti + dalšíObj[obj] = 123; ``` `"number"` -: For an object-to-number conversion, like when we're doing maths: +: Pro konverzi objektu na číslo, např. když provádíme matematické výpočty: ```js - // explicit conversion - let num = Number(obj); + // explicitní konverze + let číslo = Number(obj); - // maths (except binary plus) - let n = +obj; // unary plus - let delta = date1 - date2; + // matematika (kromě binárního plus) + let n = +obj; // unární plus + let delta = datum1 - datum2; - // less/greater comparison - let greater = user1 > user2; + // porovnání menší/větší než + let větší = uživatel1 > uživatel2; ``` - - Most built-in mathematical functions also include such conversion. + + Takovou konverzi obsahuje také většina vestavěných matematických funkcí. `"default"` -: Occurs in rare cases when the operator is "not sure" what type to expect. +: Nastává ve vzácných případech, když si operátor „není jist“, jaký typ má očekávat. - For instance, binary plus `+` can work both with strings (concatenates them) and numbers (adds them). So if a binary plus gets an object as an argument, it uses the `"default"` hint to convert it. + Například binární plus `+` může pracovat jak s řetězci (spojuje je), tak s čísly (sčítá je). Jestliže tedy binární plus obdrží objekt jako argument, použije k jeho konverzi náznak `"default"`. - Also, if an object is compared using `==` with a string, number or a symbol, it's also unclear which conversion should be done, so the `"default"` hint is used. + Rovněž je-li objekt porovnáván s řetězcem, číslem nebo symbolem pomocí `==`, není jisté, která konverze by se měla provést, takže je použit náznak `"default"`. ```js - // binary plus uses the "default" hint - let total = obj1 + obj2; + // binární plus používá náznak "default" + let celkem = obj1 + obj2; - // obj == number uses the "default" hint - if (user == 1) { ... }; + // obj == číslo používá náznak "default" + if (uživatel == 1) { ... }; ``` - The greater and less comparison operators, such as `<` `>`, can work with both strings and numbers too. Still, they use the `"number"` hint, not `"default"`. That's for historical reasons. + Také operátory porovnání větší než a menší než, např. `<` `>`, mohou pracovat s řetězci i s čísly. Ty však používají náznak `"number"`, ne `"default"`. Je tomu tak z historických důvodů. -In practice though, things are a bit simpler. +V praxi je to však o něco jednodušší. -All built-in objects except for one case (`Date` object, we'll learn it later) implement `"default"` conversion the same way as `"number"`. And we probably should do the same. +Všechny vestavěné objekty až na jednu výjimku (objekt `Date`, dozvíme se o něm později) implementují konverzi `"default"` stejným způsobem jako `"number"`. A my bychom asi měli dělat totéž. -Still, it's important to know about all 3 hints, soon we'll see why. +Stále je však důležité znát všechny 3 náznaky. Brzy uvidíme proč. -**To do the conversion, JavaScript tries to find and call three object methods:** +**Když JavaScript provádí konverzi, snaží se najít a zavolat tři objektové metody:** -1. Call `obj[Symbol.toPrimitive](hint)` - the method with the symbolic key `Symbol.toPrimitive` (system symbol), if such method exists, -2. Otherwise if hint is `"string"` - - try calling `obj.toString()` or `obj.valueOf()`, whatever exists. -3. Otherwise if hint is `"number"` or `"default"` - - try calling `obj.valueOf()` or `obj.toString()`, whatever exists. +1. Zavolá `obj[Symbol.toPrimitive](náznak)` -- metodu se symbolickým klíčem `Symbol.toPrimitive` (systémový symbol), jestliže taková metoda existuje. +2. V opačném případě, je-li náznak `"string"`: + - pokusí se zavolat `obj.toString()` nebo `obj.valueOf()`, první z nich, která existuje. +3. V opačném případě, je-li náznak `"number"` nebo `"default"`: + - pokusí se zavolat `obj.valueOf()` nebo `obj.toString()`, první z nich, která existuje. ## Symbol.toPrimitive -Let's start from the first method. There's a built-in symbol named `Symbol.toPrimitive` that should be used to name the conversion method, like this: +Začněme první metodou. V JavaScriptu je vestavěný symbol jménem `Symbol.toPrimitive`, který by měl být použit k pojmenování konverzní metody, např. takto: ```js -obj[Symbol.toPrimitive] = function(hint) { - // here goes the code to convert this object to a primitive - // it must return a primitive value - // hint = one of "string", "number", "default" +obj[Symbol.toPrimitive] = function(náznak) { + // sem přijde kód, který převede tento objekt na primitiv + // musí vrátit primitivní hodnotu + // náznak = jeden ze "string", "number", "default" }; ``` -If the method `Symbol.toPrimitive` exists, it's used for all hints, and no more methods are needed. +Jestliže metoda `Symbol.toPrimitive` existuje, bude použita pro všechny náznaky a žádné další metody nejsou zapotřebí. -For instance, here `user` object implements it: +Například zde ji implementuje objekt `uživatel`: ```js run -let user = { - name: "John", - money: 1000, +let uživatel = { + jméno: "Jan", + peníze: 1000, - [Symbol.toPrimitive](hint) { - alert(`hint: ${hint}`); - return hint == "string" ? `{name: "${this.name}"}` : this.money; + [Symbol.toPrimitive](náznak) { + alert(`náznak: ${náznak}`); + return náznak == "string" ? `{jméno: "${this.jméno}"}` : this.peníze; } }; -// conversions demo: -alert(user); // hint: string -> {name: "John"} -alert(+user); // hint: number -> 1000 -alert(user + 500); // hint: default -> 1500 +// demo konverzí: +alert(uživatel); // náznak: string -> {jméno: "Jan"} +alert(+uživatel); // náznak: number -> 1000 +alert(uživatel + 500); // náznak: default -> 1500 ``` -As we can see from the code, `user` becomes a self-descriptive string or a money amount, depending on the conversion. The single method `user[Symbol.toPrimitive]` handles all conversion cases. +Jak vidíme z kódu, `uživatel` se stane sebepopisujícím řetězcem nebo peněžní částkou v závislosti na druhu konverze. Všechny případy konverze obstarává jediná metoda `uživatel[Symbol.toPrimitive]`. ## toString/valueOf -If there's no `Symbol.toPrimitive` then JavaScript tries to find methods `toString` and `valueOf`: +Neexistuje-li `Symbol.toPrimitive`, pak se JavaScript pokusí najít metody `toString` a `valueOf`: -- For the `"string"` hint: call `toString` method, and if it doesn't exist or if it returns an object instead of a primitive value, then call `valueOf` (so `toString` has the priority for string conversions). -- For other hints: call `valueOf`, and if it doesn't exist or if it returns an object instead of a primitive value, then call `toString` (so `valueOf` has the priority for maths). +- Pro náznak `"string"`: volá se metoda `toString`, a jestliže neexistuje nebo vrátí objekt místo primitivní hodnoty, pak se volá `valueOf` (při konverzi na řetězec má tedy přednost `toString`). +- Pro jiné náznaky: volá se `valueOf`, a jestliže neexistuje nebo vrátí objekt místo primitivní hodnoty, pak se volá `toString` (při matematických výpočtech má tedy přednost `valueOf`). -Methods `toString` and `valueOf` come from ancient times. They are not symbols (symbols did not exist that long ago), but rather "regular" string-named methods. They provide an alternative "old-style" way to implement the conversion. +Metody `toString` a `valueOf` pocházejí z dávné minulosti. Nejsou to symboly (symboly tak dávno ještě neexistovaly), ale „obvyklé“ metody s řetězcovým názvem. Poskytují alternativní způsob „ve starém stylu“, jak implementovat konverzi. -These methods must return a primitive value. If `toString` or `valueOf` returns an object, then it's ignored (same as if there were no method). +Tyto metody musejí vracet primitivní hodnotu. Jestliže `toString` nebo `valueOf` vrátí objekt, jsou ignorovány (stejně, jako by taková metoda neexistovala). -By default, a plain object has following `toString` and `valueOf` methods: +Výchozí planý objekt obsahuje následující metody `toString` a `valueOf`: -- The `toString` method returns a string `"[object Object]"`. -- The `valueOf` method returns the object itself. +- Metoda `toString` vrací řetězec `"[object Object]"`. +- Metoda `valueOf` vrací objekt samotný. -Here's the demo: +Zde je příklad: ```js run -let user = {name: "John"}; +let uživatel = {jméno: "Jan"}; -alert(user); // [object Object] -alert(user.valueOf() === user); // true +alert(uživatel); // [object Object] +alert(uživatel.valueOf() === uživatel); // true ``` -So if we try to use an object as a string, like in an `alert` or so, then by default we see `[object Object]`. +Jestliže se tedy pokusíme použít objekt jako řetězec, např. ve volání `alert` nebo podobně, pak standardně uvidíme `[object Object]`. -The default `valueOf` is mentioned here only for the sake of completeness, to avoid any confusion. As you can see, it returns the object itself, and so is ignored. Don't ask me why, that's for historical reasons. So we can assume it doesn't exist. +Výchozí `valueOf` je zde zmíněna jen pro úplnost, abychom se vyhnuli zmatkům. Jak vidíte, vrací objekt samotný, a proto je ignorována. Neptejte se mě proč, je tomu tak z historických důvodů. Můžeme tedy předpokládat, že ani neexistuje. -Let's implement these methods to customize the conversion. +Implementujme tyto metody, abychom si konverzi přizpůsobili. -For instance, here `user` does the same as above using a combination of `toString` and `valueOf` instead of `Symbol.toPrimitive`: +Například zde `uživatel` dělá totéž jako výše pomocí kombinace `toString` a `valueOf` namísto `Symbol.toPrimitive`: ```js run -let user = { - name: "John", - money: 1000, +let uživatel = { + jméno: "Jan", + peníze: 1000, - // for hint="string" + // pro náznak="string" toString() { - return `{name: "${this.name}"}`; + return `{jméno: "${this.jméno}"}`; }, - // for hint="number" or "default" + // pro náznak="number" nebo "default" valueOf() { - return this.money; + return this.peníze; } }; -alert(user); // toString -> {name: "John"} -alert(+user); // valueOf -> 1000 -alert(user + 500); // valueOf -> 1500 +alert(uživatel); // toString -> {jméno: "Jan"} +alert(+uživatel); // valueOf -> 1000 +alert(uživatel + 500); // valueOf -> 1500 ``` -As we can see, the behavior is the same as the previous example with `Symbol.toPrimitive`. +Jak vidíme, chování je stejné jako v předchozím příkladu se `Symbol.toPrimitive`. -Often we want a single "catch-all" place to handle all primitive conversions. In this case, we can implement `toString` only, like this: +Často chceme, aby všechny konverze na primitivy obsloužilo jediné „vše zachytávající“ místo. V tom případě můžeme implementovat jen `toString`, např. takto: ```js run -let user = { - name: "John", +let uživatel = { + jméno: "Jan", toString() { - return this.name; + return this.jméno; } }; -alert(user); // toString -> John -alert(user + 500); // toString -> John500 +alert(uživatel); // toString -> Jan +alert(uživatel + 500); // toString -> Jan500 ``` -In the absence of `Symbol.toPrimitive` and `valueOf`, `toString` will handle all primitive conversions. +Nejsou-li přítomny metody `Symbol.toPrimitive` a `valueOf`, obstará všechny konverze na primitivy metoda `toString`. -### A conversion can return any primitive type +### Konverze může vrátit jakýkoli primitivní typ -The important thing to know about all primitive-conversion methods is that they do not necessarily return the "hinted" primitive. +O všech metodách konverze na primitivy je důležité vědět, že nemusejí nutně vracet „naznačený“ primitiv. -There is no control whether `toString` returns exactly a string, or whether `Symbol.toPrimitive` method returns a number for the hint `"number"`. +Nekontroluje se, zda metoda `toString` opravdu vrátila řetězec nebo zda metoda `Symbol.toPrimitive` pro náznak `"number"` vrátila opravdu číslo. -The only mandatory thing: these methods must return a primitive, not an object. +Jediné, co je povinné: tyto metody musejí vracet primitiv, ne objekt. -```smart header="Historical notes" -For historical reasons, if `toString` or `valueOf` returns an object, there's no error, but such value is ignored (like if the method didn't exist). That's because in ancient times there was no good "error" concept in JavaScript. +```smart header="Historické poznámky" +Z historických důvodů platí, že jestliže `toString` nebo `valueOf` vrátí objekt, nenastane chyba, ale taková hodnota se ignoruje (jako by tato metoda neexistovala). Je to proto, že v dávné minulosti nebyl v JavaScriptu žádný dobrý „chybový“ koncept. -In contrast, `Symbol.toPrimitive` is stricter, it *must* return a primitive, otherwise there will be an error. +Naproti tomu `Symbol.toPrimitive` je striktnější a *musí* vrátit primitiv, jinak nastane chyba. ``` -## Further conversions +## Další konverze -As we know already, many operators and functions perform type conversions, e.g. multiplication `*` converts operands to numbers. +Jak již víme, typovou konverzi provádí mnoho operátorů a funkcí, např. násobení `*` převádí operandy na čísla. -If we pass an object as an argument, then there are two stages of calculations: -1. The object is converted to a primitive (using the rules described above). -2. If necessary for further calculations, the resulting primitive is also converted. +Jestliže předáme objekt jako argument, provedou se dva kroky výpočtu: +1. Objekt se konvertuje na primitiv (podle výše uvedených pravidel). +2. Je-li to nezbytné pro další výpočty, výsledný primitiv se také konvertuje. -For instance: +Například: ```js run let obj = { - // toString handles all conversions in the absence of other methods + // při nepřítomnosti ostatních metod provádí toString všechny konverze toString() { return "2"; } }; -alert(obj * 2); // 4, object converted to primitive "2", then multiplication made it a number +alert(obj * 2); // 4, objekt se konvertoval na primitiv "2", pak z něj násobení učinilo číslo ``` -1. The multiplication `obj * 2` first converts the object to primitive (that's a string `"2"`). -2. Then `"2" * 2` becomes `2 * 2` (the string is converted to number). +1. Násobení `obj * 2` nejprve převede objekt na primitiv (tedy na řetězec `"2"`). +2. Pak se ze `"2" * 2` stane `2 * 2` (řetězec se konvertuje na číslo). -Binary plus will concatenate strings in the same situation, as it gladly accepts a string: +Binární plus ve stejné situaci spojí řetězce, jelikož ochotně přijme řetězec: ```js run let obj = { @@ -253,28 +253,28 @@ let obj = { } }; -alert(obj + 2); // "22" ("2" + 2), conversion to primitive returned a string => concatenation +alert(obj + 2); // "22" ("2" + 2), konverze na primitiv vrátila řetězec => zřetězení ``` -## Summary - -The object-to-primitive conversion is called automatically by many built-in functions and operators that expect a primitive as a value. +## Shrnutí -There are 3 types (hints) of it: -- `"string"` (for `alert` and other operations that need a string) -- `"number"` (for maths) -- `"default"` (few operators, usually objects implement it the same way as `"number"`) +Konverze objektu na primitiv je volána automaticky mnoha vestavěnými funkcemi a operátory, které očekávají primitiv jako hodnotu. -The specification describes explicitly which operator uses which hint. +Dělí se na 3 druhy (náznaky): +- `"string"` (pro `alert` a jiné operace, které vyžadují řetězec) +- `"number"` (pro matematické výpočty) +- `"default"` (jen málo operátorů, obvykle ji objekty implementují stejným způsobem jako `"number"`) -The conversion algorithm is: +Specifikace výslovně popisuje, který operátor používá který náznak. -1. Call `obj[Symbol.toPrimitive](hint)` if the method exists, -2. Otherwise if hint is `"string"` - - try calling `obj.toString()` or `obj.valueOf()`, whatever exists. -3. Otherwise if hint is `"number"` or `"default"` - - try calling `obj.valueOf()` or `obj.toString()`, whatever exists. +Algoritmus konverze je: -All these methods must return a primitive to work (if defined). +1. Zavolá `obj[Symbol.toPrimitive](náznak)`, jestliže tato metoda existuje. +2. V opačném případě, je-li náznak `"string"`: + - pokusí se zavolat `obj.toString()` nebo `obj.valueOf()`, první z nich, která existuje. +3. V opačném případě, je-li náznak `"number"` nebo `"default"`: + - pokusí se zavolat `obj.valueOf()` nebo `obj.toString()`, první z nich, která existuje. + +Všechny tyto metody musejí vracet primitiv, aby fungovaly (jsou-li definovány). -In practice, it's often enough to implement only `obj.toString()` as a "catch-all" method for string conversions that should return a "human-readable" representation of an object, for logging or debugging purposes. +V praxi často postačí implementovat jen `obj.toString()` jako „vše zachytávající“ metodu pro konverzi na řetězec, která by měla vracet „lidsky čitelnou“ reprezentaci objektu, pro účely logování nebo ladění. diff --git a/1-js/04-object-basics/index.md b/1-js/04-object-basics/index.md index d2387aafa..7855038e9 100644 --- a/1-js/04-object-basics/index.md +++ b/1-js/04-object-basics/index.md @@ -1 +1 @@ -# Objects: the basics +# Objekty: základy diff --git a/1-js/05-data-types/01-primitives-methods/1-string-new-property/solution.md b/1-js/05-data-types/01-primitives-methods/1-string-new-property/solution.md index fd22a4653..25c78339e 100644 --- a/1-js/05-data-types/01-primitives-methods/1-string-new-property/solution.md +++ b/1-js/05-data-types/01-primitives-methods/1-string-new-property/solution.md @@ -1,24 +1,24 @@ -Try running it: +Zkuste si to spustit: ```js run -let str = "Hello"; +let řetězec = "Ahoj"; -str.test = 5; // (*) +řetězec.test = 5; // (*) -alert(str.test); +alert(řetězec.test); ``` -Depending on whether you have `use strict` or not, the result may be: -1. `undefined` (no strict mode) -2. An error (strict mode). +Podle toho, zda máte `use strict` nebo ne, výsledek může být: +1. `undefined` (nestriktní režim). +2. Chyba (striktní režim). -Why? Let's replay what's happening at line `(*)`: +Proč? Přehrajme si, co se děje na řádku `(*)`: -1. When a property of `str` is accessed, a "wrapper object" is created. -2. In strict mode, writing into it is an error. -3. Otherwise, the operation with the property is carried on, the object gets the `test` property, but after that the "wrapper object" disappears, so in the last line `str` has no trace of the property. +1. Když přistoupíme k vlastnosti proměnné `řetězec`, vytvoří se „obal“. +2. Ve striktním režimu zápis do něj znamená chybu. +3. V nestriktním režimu bude operace s touto vlastností provedena, objekt získá vlastnost `test`, ale poté „obal“ zmizí, takže na posledním řádku nemá `řetězec` po této vlastnosti ani stopu. -**This example clearly shows that primitives are not objects.** +**Tento příklad jednoznačně dokazuje, že primitivy nejsou objekty.** -They can't store additional data. +Nelze do nich ukládat další data. diff --git a/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md b/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md index 208f84cc7..b02f16daa 100644 --- a/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md +++ b/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md @@ -2,17 +2,17 @@ importance: 5 --- -# Can I add a string property? +# Mohu přidat vlastnost do řetězce? -Consider the following code: +Uvažujme následující kód: ```js -let str = "Hello"; +let řetězec = "Ahoj"; -str.test = 5; +řetězec.test = 5; -alert(str.test); +alert(řetězec.test); ``` -What do you think, will it work? What will be shown? +Co myslíte, bude to fungovat? Co se zobrazí? diff --git a/1-js/05-data-types/01-primitives-methods/article.md b/1-js/05-data-types/01-primitives-methods/article.md index 69e7196e9..0965701be 100644 --- a/1-js/05-data-types/01-primitives-methods/article.md +++ b/1-js/05-data-types/01-primitives-methods/article.md @@ -1,76 +1,76 @@ -# Methods of primitives +# Metody primitivů -JavaScript allows us to work with primitives (strings, numbers, etc.) as if they were objects. They also provide methods to call as such. We will study those soon, but first we'll see how it works because, of course, primitives are not objects (and here we will make it even clearer). +JavaScript nám umožňuje pracovat s primitivy (řetězci, čísly atd.), jako by to byly objekty. Poskytuje i metody, které na nich můžeme volat jako na objektech. V dalších kapitolách je prostudujeme, ale nejprve se podíváme, jak to funguje, protože primitivy samozřejmě nejsou objekty (a zde to ještě více ozřejmíme). -Let's look at the key distinctions between primitives and objects. +Podíváme se na klíčové rozdíly mezi primitivy a objekty. -A primitive +Primitiv: -- Is a value of a primitive type. -- There are 7 primitive types: `string`, `number`, `bigint`, `boolean`, `symbol`, `null` and `undefined`. +- Je hodnota primitivního typu. +- Existuje 7 primitivních typů: `string`, `number`, `bigint`, `boolean`, `symbol`, `null` a `undefined`. -An object +Objekt: -- Is capable of storing multiple values as properties. -- Can be created with `{}`, for instance: `{name: "John", age: 30}`. There are other kinds of objects in JavaScript: functions, for example, are objects. +- Dokáže obsahovat více hodnot uložených ve svých vlastnostech. +- Může být vytvořen pomocí `{}`, např. `{jméno: "Jan", věk: 30}`. V JavaScriptu jsou i jiné druhy objektů, například funkce jsou objekty. -One of the best things about objects is that we can store a function as one of its properties. +Jedna z nejlepších věcí na objektech je, že jako jejich vlastnost můžeme uložit funkci. ```js run -let john = { - name: "John", - sayHi: function() { - alert("Hi buddy!"); +let jan = { + jméno: "Jan", + řekniAhoj: function() { + alert("Ahoj kámo!"); } }; -john.sayHi(); // Hi buddy! +jan.řekniAhoj(); // Ahoj kámo! ``` -So here we've made an object `john` with the method `sayHi`. +Zde jsme tedy vytvořili objekt `jan` s metodou `řekniAhoj`. -Many built-in objects already exist, such as those that work with dates, errors, HTML elements, etc. They have different properties and methods. +JavaScript obsahuje mnoho vestavěných objektů, například ty, které pracují s daty, chybami, HTML prvky a podobně. Mají různé vlastnosti a metody. -But, these features come with a cost! +Tyto vlastnosti však mají svou cenu! -Objects are "heavier" than primitives. They require additional resources to support the internal machinery. +Objekty jsou „těžší“ než primitivy. Vyžadují více zdrojů, které zatěžují vnitřní stroj. -## A primitive as an object +## Primitiv jako objekt -Here's the paradox faced by the creator of JavaScript: +Tvůrci JavaScriptu čelili následujícímu paradoxu: -- There are many things one would want to do with a primitive, like a string or a number. It would be great to access them using methods. -- Primitives must be as fast and lightweight as possible. +- Existuje mnoho věcí, které člověk chce dělat s primitivy, jakými jsou řetězec nebo číslo. Bylo by skvělé přistupovat k nim pomocí metod. +- Primitivy musejí být co nejrychlejší a co nejmenší. -The solution looks a little bit awkward, but here it is: +Řešení vypadá trochu těžkopádně, ale je zde: -1. Primitives are still primitive. A single value, as desired. -2. The language allows access to methods and properties of strings, numbers, booleans and symbols. -3. In order for that to work, a special "object wrapper" that provides the extra functionality is created, and then is destroyed. +1. Primitiv je pořád primitiv. Jednoduchá hodnota, po jaké toužíme. +2. Jazyk umožňuje přístup k metodám a vlastnostem řetězců, čísel, booleanů a symbolů. +3. Aby to fungovalo, vytvoří se speciální objekt zvaný „obal“ neboli „wrapper“, který tuto přídavnou funkcionalitu poskytne a pak bude zničen. -The "object wrappers" are different for each primitive type and are called: `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. Thus, they provide different sets of methods. +Tyto „objektové obaly“ jsou pro každý primitivní typ jiné a nazývají se: `String`, `Number`, `Boolean`, `Symbol` a `BigInt`. Poskytují tedy různé sady metod. -For instance, there exists a string method [str.toUpperCase()](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) that returns a capitalized `str`. +Například existuje řetězcová metoda [řetězec.toUpperCase()](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase), která vrací `řetězec` zapsaný velkými písmeny. -Here's how it works: +Funguje následovně: ```js run -let str = "Hello"; +let řetězec = "Ahoj"; -alert( str.toUpperCase() ); // HELLO +alert( řetězec.toUpperCase() ); // AHOJ ``` -Simple, right? Here's what actually happens in `str.toUpperCase()`: +Jednoduché, že? Ve skutečnosti se v `řetězec.toUpperCase()` děje následující: -1. The string `str` is a primitive. So in the moment of accessing its property, a special object is created that knows the value of the string, and has useful methods, like `toUpperCase()`. -2. That method runs and returns a new string (shown by `alert`). -3. The special object is destroyed, leaving the primitive `str` alone. +1. Řetězec `řetězec` je primitiv. V okamžiku přístupu k jeho vlastnosti se tedy vytvoří speciální objekt, který zná hodnotu tohoto řetězce a obsahuje užitečné metody, např. `toUpperCase()`. +2. Tato metoda se spustí a vrátí nový řetězec (který je zobrazen funkcí `alert`). +3. Speciální objekt se zničí a zůstane samotný primitiv `řetězec`. -So primitives can provide methods, but they still remain lightweight. +Primitivy tedy mohou poskytovat metody, ale samy zůstávají malé. -The JavaScript engine highly optimizes this process. It may even skip the creation of the extra object at all. But it must still adhere to the specification and behave as if it creates one. +JavaScriptový motor tento proces značně optimalizuje. Může dokonce úplně vynechat vytvoření nového objektu. Stále však musí dodržovat specifikaci a chovat se tak, jako by jej vytvořil. -A number has methods of its own, for instance, [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) rounds the number to the given precision: +I čísla mají své vlastní metody, například [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) zaokrouhluje číslo se zadanou přesností: ```js run let n = 1.23456; @@ -78,15 +78,15 @@ let n = 1.23456; alert( n.toFixed(2) ); // 1.23 ``` -We'll see more specific methods in chapters and . +Další specifické metody uvidíme v kapitolách a . -````warn header="Constructors `String/Number/Boolean` are for internal use only" -Some languages like Java allow us to explicitly create "wrapper objects" for primitives using a syntax like `new Number(1)` or `new Boolean(false)`. +````warn header="Konstruktory `String/Number/Boolean` jsou jen pro interní použití" +Některé jazyky, např. Java, nám umožňují explicitně vytvářet „obaly“ pro primitivy pomocí syntaxe typu `new Number(1)` nebo `new Boolean(false)`. -In JavaScript, that's also possible for historical reasons, but highly **unrecommended**. Things will go crazy in several places. +V JavaScriptu je to z historických důvodů také možné, ale důrazně **nedoporučované**. Skript se začne chovat bláznivě hned na několika místech. -For instance: +Například: ```js run alert( typeof 0 ); // "number" @@ -94,36 +94,36 @@ alert( typeof 0 ); // "number" alert( typeof new Number(0) ); // "object"! ``` -Objects are always truthy in `if`, so here the alert will show up: +Objekty jsou v `if` vždy pravdivé, takže zde se zobrazí hlášení: ```js run -let zero = new Number(0); +let nula = new Number(0); -if (zero) { // zero is true, because it's an object - alert( "zero is truthy!?!" ); +if (nula) { // nula je pravdivá, protože je to objekt + alert( "nula je pravdivá!?!" ); } ``` -On the other hand, using the same functions `String/Number/Boolean` without `new` is totally fine and useful thing. They convert a value to the corresponding type: to a string, a number, or a boolean (primitive). +Naproti tomu použití stejné funkce `String/Number/Boolean` bez `new` je zcela správná a užitečná věc. Funkce převede hodnotu na odpovídající typ: na řetězec, na číslo nebo na boolean (na primitiv). -For example, this is entirely valid: +Například tohle je zcela v pořádku: ```js -let num = Number("123"); // convert a string to number +let číslo = Number("123"); // převede řetězec na číslo ``` ```` -````warn header="null/undefined have no methods" -The special primitives `null` and `undefined` are exceptions. They have no corresponding "wrapper objects" and provide no methods. In a sense, they are "the most primitive". +````warn header="null/undefined nemají žádné metody" +Speciální primitivy `null` a `undefined` představují výjimky. Nemají odpovídající „obaly“ a neposkytují žádné metody. V určitém smyslu slova jsou vlastně „ty nejprimitivnější“. -An attempt to access a property of such value would give the error: +Pokus o přístup k vlastnosti takové hodnoty ohlásí chybu: ```js run -alert(null.test); // error +alert(null.test); // chyba ```` -## Summary +## Shrnutí -- Primitives except `null` and `undefined` provide many helpful methods. We will study those in the upcoming chapters. -- Formally, these methods work via temporary objects, but JavaScript engines are well tuned to optimize that internally, so they are not expensive to call. +- Primitivy s výjimkou `null` a `undefined` poskytují mnoho užitečných metod. Prostudujeme je v následujících kapitolách. +- Formálně tyto metody pracují na dočasných objektech, ale JavaScriptové motory jsou dobře vyladěny, aby je vnitřně optimalizovaly, takže jejich volání není nákladné. \ No newline at end of file diff --git a/1-js/05-data-types/02-number/1-sum-interface/solution.md b/1-js/05-data-types/02-number/1-sum-interface/solution.md index f2c81437d..7d1604200 100644 --- a/1-js/05-data-types/02-number/1-sum-interface/solution.md +++ b/1-js/05-data-types/02-number/1-sum-interface/solution.md @@ -1,12 +1,12 @@ ```js run demo -let a = +prompt("The first number?", ""); -let b = +prompt("The second number?", ""); +let a = +prompt("První číslo?", ""); +let b = +prompt("Druhé číslo?", ""); alert( a + b ); ``` -Note the unary plus `+` before `prompt`. It immediately converts the value to a number. +Všimněte si unárního plus `+` před `prompt`, které okamžitě konvertuje hodnotu na číslo. -Otherwise, `a` and `b` would be string their sum would be their concatenation, that is: `"1" + "2" = "12"`. \ No newline at end of file +Jinak by `a` a `b` byly řetězce a součtem by bylo jejich zřetězení, tedy: `"1" + "2" = "12"`. \ No newline at end of file diff --git a/1-js/05-data-types/02-number/1-sum-interface/task.md b/1-js/05-data-types/02-number/1-sum-interface/task.md index 780126640..1f34794e4 100644 --- a/1-js/05-data-types/02-number/1-sum-interface/task.md +++ b/1-js/05-data-types/02-number/1-sum-interface/task.md @@ -2,10 +2,10 @@ importance: 5 --- -# Sum numbers from the visitor +# Sečtěte čísla od návštěvníka -Create a script that prompts the visitor to enter two numbers and then shows their sum. +Vytvořte skript, který vyzve návštěvníka, aby zadal dvě čísla, a pak zobrazí jejich součet. [demo] -P.S. There is a gotcha with types. +P.S. Je tam chyták s typy. diff --git a/1-js/05-data-types/02-number/2-why-rounded-down/solution.md b/1-js/05-data-types/02-number/2-why-rounded-down/solution.md index 4bcd74512..0971031e6 100644 --- a/1-js/05-data-types/02-number/2-why-rounded-down/solution.md +++ b/1-js/05-data-types/02-number/2-why-rounded-down/solution.md @@ -1,33 +1,33 @@ -Internally the decimal fraction `6.35` is an endless binary. As always in such cases, it is stored with a precision loss. +Interně je desetinné číslo `6.35` nekonečné binární číslo. Jako vždy v takových případech je uloženo se ztrátou přesnosti. -Let's see: +Podívejme se: ```js run alert( 6.35.toFixed(20) ); // 6.34999999999999964473 ``` -The precision loss can cause both increase and decrease of a number. In this particular case the number becomes a tiny bit less, that's why it rounded down. +Ztrátou přesnosti se číslo může zvýšit i snížit. V tomto konkrétním případě se číslo o něco málo sníží, proto bude zaokrouhleno dolů. -And what's for `1.35`? +A co `1.35`? ```js run alert( 1.35.toFixed(20) ); // 1.35000000000000008882 ``` -Here the precision loss made the number a little bit greater, so it rounded up. +Zde ztráta přesnosti číslo trošičku zvýšila, takže se zaokrouhlilo nahoru. -**How can we fix the problem with `6.35` if we want it to be rounded the right way?** +**Jak můžeme problém s `6.35` vyřešit, chceme-li, aby se zaokrouhlilo správně?** -We should bring it closer to an integer prior to rounding: +Měli bychom je před zaokrouhlením přiblížit k celému číslu: ```js run alert( (6.35 * 10).toFixed(20) ); // 63.50000000000000000000 ``` -Note that `63.5` has no precision loss at all. That's because the decimal part `0.5` is actually `1/2`. Fractions divided by powers of `2` are exactly represented in the binary system, now we can round it: +Všimněte si, že `63.5` nemá vůbec žádnou ztrátu přesnosti. Je to proto, že desetinná část `0.5` je ve skutečnosti `1/2`. Zlomky s mocninou `2` ve jmenovateli jsou v binární soustavě reprezentovány přesně, takže je nyní můžeme zaokrouhlit: ```js run -alert( Math.round(6.35 * 10) / 10 ); // 6.35 -> 63.5 -> 64(rounded) -> 6.4 +alert( Math.round(6.35 * 10) / 10 ); // 6.35 -> 63.5 -> 64(zaokrouhleno) -> 6.4 ``` diff --git a/1-js/05-data-types/02-number/2-why-rounded-down/task.md b/1-js/05-data-types/02-number/2-why-rounded-down/task.md index 568c26480..d85f27c93 100644 --- a/1-js/05-data-types/02-number/2-why-rounded-down/task.md +++ b/1-js/05-data-types/02-number/2-why-rounded-down/task.md @@ -2,21 +2,21 @@ importance: 4 --- -# Why 6.35.toFixed(1) == 6.3? +# Proč 6.35.toFixed(1) == 6.3? -According to the documentation `Math.round` and `toFixed` both round to the nearest number: `0..4` lead down while `5..9` lead up. +Podle dokumentace `Math.round` a `toFixed` zaokrouhlují obě na nejbližší číslo: `0..4` se zaokrouhluje dolů, zatímco `5..9` nahoru. -For instance: +Například: ```js run alert( 1.35.toFixed(1) ); // 1.4 ``` -In the similar example below, why is `6.35` rounded to `6.3`, not `6.4`? +Proč se v podobném níže uvedeném příkladu `6.35` zaokrouhlí na `6.3` a ne na `6.4`? ```js run alert( 6.35.toFixed(1) ); // 6.3 ``` -How to round `6.35` the right way? +Jak zaokrouhlit `6.35` správně? diff --git a/1-js/05-data-types/02-number/3-repeat-until-number/_js.view/solution.js b/1-js/05-data-types/02-number/3-repeat-until-number/_js.view/solution.js index a8c30c010..6324c12b9 100644 --- a/1-js/05-data-types/02-number/3-repeat-until-number/_js.view/solution.js +++ b/1-js/05-data-types/02-number/3-repeat-until-number/_js.view/solution.js @@ -1,12 +1,12 @@ -function readNumber() { - let num; +function načtiČíslo() { + let číslo; do { - num = prompt("Enter a number please?", 0); - } while ( !isFinite(num) ); + číslo = prompt("Zadejte číslo, prosím:", 0); + } while ( !isFinite(číslo) ); - if (num === null || num === '') return null; + if (číslo === null || číslo === '') return null; - return +num; + return +číslo; } \ No newline at end of file diff --git a/1-js/05-data-types/02-number/3-repeat-until-number/_js.view/test.js b/1-js/05-data-types/02-number/3-repeat-until-number/_js.view/test.js index 6bd0123db..6d0727970 100644 --- a/1-js/05-data-types/02-number/3-repeat-until-number/_js.view/test.js +++ b/1-js/05-data-types/02-number/3-repeat-until-number/_js.view/test.js @@ -6,33 +6,33 @@ afterEach(function() { prompt.restore(); }); -describe("readNumber", function() { +describe("načtiČíslo", function() { - it("if a number, returns it", function() { + it("je-li to číslo, vrátí je", function() { prompt.returns("123"); - assert.strictEqual(readNumber(), 123); + assert.strictEqual(načtiČíslo(), 123); }); - it("if 0, returns it", function() { + it("je-li to 0, vrátí ji", function() { prompt.returns("0"); - assert.strictEqual(readNumber(), 0); + assert.strictEqual(načtiČíslo(), 0); }); - it("continues the loop until meets a number", function() { - prompt.onCall(0).returns("not a number"); - prompt.onCall(1).returns("not a number again"); + it("pokračuje ve smyčce, dokud nenajde číslo", function() { + prompt.onCall(0).returns("to není číslo"); + prompt.onCall(1).returns("to taky není číslo"); prompt.onCall(2).returns("1"); - assert.strictEqual(readNumber(), 1); + assert.strictEqual(načtiČíslo(), 1); }); - it("if an empty line, returns null", function() { + it("je-li zadán prázdný řádek, vrátí null", function() { prompt.returns(""); - assert.isNull(readNumber()); + assert.isNull(načtiČíslo()); }); - it("if cancel, returns null", function() { + it("je-li stisknuto Storno, vrátí null", function() { prompt.returns(null); - assert.isNull(readNumber()); + assert.isNull(načtiČíslo()); }); }); diff --git a/1-js/05-data-types/02-number/3-repeat-until-number/solution.md b/1-js/05-data-types/02-number/3-repeat-until-number/solution.md index 005116d17..effc4a45b 100644 --- a/1-js/05-data-types/02-number/3-repeat-until-number/solution.md +++ b/1-js/05-data-types/02-number/3-repeat-until-number/solution.md @@ -1,23 +1,23 @@ ```js run demo -function readNumber() { - let num; +function načtiČíslo() { + let číslo; do { - num = prompt("Enter a number please?", 0); - } while ( !isFinite(num) ); + číslo = prompt("Zadejte číslo, prosím:", 0); + } while ( !isFinite(číslo) ); - if (num === null || num === '') return null; + if (číslo === null || číslo === '') return null; - return +num; + return +číslo; } -alert(`Read: ${readNumber()}`); +alert(`Načteno: ${načtiČíslo()}`); ``` -The solution is a little bit more intricate that it could be because we need to handle `null`/empty lines. +Řešení je trochu složitější, než by mohlo být, protože si musíme poradit s `null`/prázdnými řádky. -So we actually accept the input until it is a "regular number". Both `null` (cancel) and empty line also fit that condition, because in numeric form they are `0`. +Ve skutečnosti tedy přijímáme vstup tak dlouho, dokud to není „skutečné číslo“. Tuto podmínku splňují i `null` (storno) a prázdný řádek, protože v číselné podobě jsou obě `0`. -After we stopped, we need to treat `null` and empty line specially (return `null`), because converting them to a number would return `0`. +Po skončení musíme zacházet s `null` a s prázdným řádkem speciálně (vrátit `null`), jelikož jejich konverze na číslo by vrátila `0`. diff --git a/1-js/05-data-types/02-number/3-repeat-until-number/task.md b/1-js/05-data-types/02-number/3-repeat-until-number/task.md index 9b172fa8a..5835988eb 100644 --- a/1-js/05-data-types/02-number/3-repeat-until-number/task.md +++ b/1-js/05-data-types/02-number/3-repeat-until-number/task.md @@ -2,13 +2,13 @@ importance: 5 --- -# Repeat until the input is a number +# Opakování, dokud na vstupu nebude číslo -Create a function `readNumber` which prompts for a number until the visitor enters a valid numeric value. +Vytvořte funkci `načtiČíslo`, která se bude ptát na číslo tak dlouho, až návštěvník zadá platnou číselnou hodnotu. -The resulting value must be returned as a number. +Výslednou hodnotu funkce musí vrátit jako číslo. -The visitor can also stop the process by entering an empty line or pressing "CANCEL". In that case, the function should return `null`. +Návštěvník může tento proces ukončit i zadáním prázdného řádku nebo stisknutím „Storno“. V takovém případě by funkce měla vrátit `null`. [demo] diff --git a/1-js/05-data-types/02-number/4-endless-loop-error/solution.md b/1-js/05-data-types/02-number/4-endless-loop-error/solution.md index 8bc55bd02..4640285cb 100644 --- a/1-js/05-data-types/02-number/4-endless-loop-error/solution.md +++ b/1-js/05-data-types/02-number/4-endless-loop-error/solution.md @@ -1,6 +1,6 @@ -That's because `i` would never equal `10`. +Protože `i` nikdy nebude rovno `10`. -Run it to see the *real* values of `i`: +Spusťme si jej, abychom viděli *skutečné* hodnoty `i`: ```js run let i = 0; @@ -10,8 +10,8 @@ while (i < 11) { } ``` -None of them is exactly `10`. +Žádná z nich není přesně `10`. -Such things happen because of the precision losses when adding fractions like `0.2`. +Takové věci se dějí kvůli ztrátám přesnosti při přičítání desetinných čísel jako `0.2`. -Conclusion: evade equality checks when working with decimal fractions. \ No newline at end of file +Důsledek: když pracujete s desetinnými čísly, vyvarujte se testů rovnosti. \ No newline at end of file diff --git a/1-js/05-data-types/02-number/4-endless-loop-error/task.md b/1-js/05-data-types/02-number/4-endless-loop-error/task.md index 592ece31c..96b31061e 100644 --- a/1-js/05-data-types/02-number/4-endless-loop-error/task.md +++ b/1-js/05-data-types/02-number/4-endless-loop-error/task.md @@ -2,9 +2,9 @@ importance: 4 --- -# An occasional infinite loop +# Občasná nekonečná smyčka -This loop is infinite. It never ends. Why? +Tento cyklus je nekonečný. Nikdy neskončí. Proč? ```js let i = 0; diff --git a/1-js/05-data-types/02-number/8-random-min-max/solution.md b/1-js/05-data-types/02-number/8-random-min-max/solution.md index 8736c3d56..049b87003 100644 --- a/1-js/05-data-types/02-number/8-random-min-max/solution.md +++ b/1-js/05-data-types/02-number/8-random-min-max/solution.md @@ -1,11 +1,11 @@ -We need to "map" all values from the interval 0..1 into values from `min` to `max`. +Musíme „namapovat“ všechny hodnoty z intervalu 0..1 na hodnoty od `min` do `max`. -That can be done in two stages: +To můžeme udělat ve dvou krocích: -1. If we multiply a random number from 0..1 by `max-min`, then the interval of possible values increases `0..1` to `0..max-min`. -2. Now if we add `min`, the possible interval becomes from `min` to `max`. +1. Když vynásobíme náhodné číslo z 0..1 číslem `max-min`, pak se interval možných hodnot zvětší z `0..1` na `0..max-min`. +2. Když nyní přičteme `min`, možný interval se změní na interval od `min` do `max`. -The function: +Funkce: ```js run function random(min, max) { diff --git a/1-js/05-data-types/02-number/8-random-min-max/task.md b/1-js/05-data-types/02-number/8-random-min-max/task.md index 7037cfcbb..aa861fd11 100644 --- a/1-js/05-data-types/02-number/8-random-min-max/task.md +++ b/1-js/05-data-types/02-number/8-random-min-max/task.md @@ -2,13 +2,13 @@ importance: 2 --- -# A random number from min to max +# Náhodné číslo od min do max -The built-in function `Math.random()` creates a random value from `0` to `1` (not including `1`). +Vestavěná funkce `Math.random()` vytváří náhodnou hodnotu od `0` do `1` (kromě `1`). -Write the function `random(min, max)` to generate a random floating-point number from `min` to `max` (not including `max`). +Napište funkci `random(min, max)`, která bude generovat náhodné číslo s pohyblivou řádovou čárkou od `min` do `max` (kromě `max`). -Examples of its work: +Příklady, jak má fungovat: ```js alert( random(1, 5) ); // 1.2345623452 diff --git a/1-js/05-data-types/02-number/9-random-int-min-max/solution.md b/1-js/05-data-types/02-number/9-random-int-min-max/solution.md index 0950ff812..48e7922cb 100644 --- a/1-js/05-data-types/02-number/9-random-int-min-max/solution.md +++ b/1-js/05-data-types/02-number/9-random-int-min-max/solution.md @@ -1,66 +1,66 @@ -# The simple but wrong solution +# Jednoduché, ale nesprávné řešení -The simplest, but wrong solution would be to generate a value from `min` to `max` and round it: +Jednoduchým, ale nesprávným řešením by bylo generovat hodnotu od `min` do `max` a zaokrouhlit ji: ```js run function randomInteger(min, max) { - let rand = min + Math.random() * (max - min); - return Math.round(rand); + let náhodnéČíslo = min + Math.random() * (max - min); + return Math.round(náhodnéČíslo); } alert( randomInteger(1, 3) ); ``` -The function works, but it is incorrect. The probability to get edge values `min` and `max` is two times less than any other. +Tato funkce funguje, ale nekorektně. Pravděpodobnost, že získáme krajní hodnoty `min` a `max`, je dvakrát nižší, než u ostatních hodnot. -If you run the example above many times, you would easily see that `2` appears the most often. +Jestliže si spustíte výše uvedený příklad mnohokrát po sobě, brzy uvidíte, že nejčastěji se objevuje `2`. -That happens because `Math.round()` gets random numbers from the interval `1..3` and rounds them as follows: +Děje se to proto, že `Math.round()` získává náhodná čísla z intervalu `1..3` a zaokrouhluje je následovně: ```js no-beautify -values from 1 ... to 1.4999999999 become 1 -values from 1.5 ... to 2.4999999999 become 2 -values from 2.5 ... to 2.9999999999 become 3 +hodnoty od 1 ... do 1.4999999999 se zaokrouhlí na 1 +hodnoty od 1.5 ... do 2.4999999999 se zaokrouhlí na 2 +hodnoty od 2.5 ... do 2.9999999999 se zaokrouhlí na 3 ``` -Now we can clearly see that `1` gets twice less values than `2`. And the same with `3`. +Nyní jasně vidíme, že `1` má dvakrát méně hodnot než `2`. Totéž platí pro `3`. -# The correct solution +# Správné řešení -There are many correct solutions to the task. One of them is to adjust interval borders. To ensure the same intervals, we can generate values from `0.5 to 3.5`, thus adding the required probabilities to the edges: +Tato úloha má mnoho správných řešení. Jedno z nich je přizpůsobit hranice intervalu. Abychom zajistili stejné intervaly, můžeme generovat hodnoty od `0.5` do `3.5` a tím zvýšit požadované pravděpodobnosti krajních hodnot: ```js run *!* function randomInteger(min, max) { - // now rand is from (min-0.5) to (max+0.5) - let rand = min - 0.5 + Math.random() * (max - min + 1); - return Math.round(rand); + // nyní náhodnéČíslo je od (min-0.5) do (max+0.5) + let náhodnéČíslo = min - 0.5 + Math.random() * (max - min + 1); + return Math.round(náhodnéČíslo); } */!* alert( randomInteger(1, 3) ); ``` -An alternative way could be to use `Math.floor` for a random number from `min` to `max+1`: +Alternativním způsobem by bylo použít `Math.floor` pro náhodné číslo od `min` do `max+1`: ```js run *!* function randomInteger(min, max) { - // here rand is from min to (max+1) - let rand = min + Math.random() * (max + 1 - min); - return Math.floor(rand); + // zde náhodnéČíslo je od min do (max+1) + let náhodnéČíslo = min + Math.random() * (max + 1 - min); + return Math.floor(náhodnéČíslo); } */!* alert( randomInteger(1, 3) ); ``` -Now all intervals are mapped this way: +Nyní jsou všechny intervaly mapovány tímto způsobem: ```js no-beautify -values from 1 ... to 1.9999999999 become 1 -values from 2 ... to 2.9999999999 become 2 -values from 3 ... to 3.9999999999 become 3 +hodnoty od 1 ... do 1.9999999999 se zaokrouhlí na 1 +hodnoty od 2 ... do 2.9999999999 se zaokrouhlí na 2 +hodnoty od 3 ... do 3.9999999999 se zaokrouhlí na 3 ``` -All intervals have the same length, making the final distribution uniform. +Všechny intervaly mají stejnou délku, takže konečné rozložení je rovnoměrné. diff --git a/1-js/05-data-types/02-number/9-random-int-min-max/task.md b/1-js/05-data-types/02-number/9-random-int-min-max/task.md index 4ac7b5fbb..8ce125b79 100644 --- a/1-js/05-data-types/02-number/9-random-int-min-max/task.md +++ b/1-js/05-data-types/02-number/9-random-int-min-max/task.md @@ -2,14 +2,14 @@ importance: 2 --- -# A random integer from min to max +# Náhodné celé číslo od min do max -Create a function `randomInteger(min, max)` that generates a random *integer* number from `min` to `max` including both `min` and `max` as possible values. +Vytvořte funkci `randomInteger(min, max)`, která vygeneruje náhodné *celé* číslo od `min` do `max`, přičemž vygenerovanými hodnotami mohou být i `min` a `max`. -Any number from the interval `min..max` must appear with the same probability. +Každé číslo z intervalu `min..max` se musí objevit se stejnou pravděpodobností. -Examples of its work: +Příklady, jak má fungovat: ```js alert( randomInteger(1, 5) ); // 1 @@ -17,4 +17,4 @@ alert( randomInteger(1, 5) ); // 3 alert( randomInteger(1, 5) ); // 5 ``` -You can use the solution of the [previous task](info:task/random-min-max) as the base. +Jako základ můžete použít řešení z [předchozí úlohy](info:task/random-min-max). diff --git a/1-js/05-data-types/02-number/article.md b/1-js/05-data-types/02-number/article.md index 8e41f673d..3441c5f95 100644 --- a/1-js/05-data-types/02-number/article.md +++ b/1-js/05-data-types/02-number/article.md @@ -1,148 +1,144 @@ -# Numbers +# Čísla -In modern JavaScript, there are two types of numbers: +Moderní JavaScript obsahuje dva druhy čísel: -1. Regular numbers in JavaScript are stored in 64-bit format [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754), also known as "double precision floating point numbers". These are numbers that we're using most of the time, and we'll talk about them in this chapter. +1. Běžná čísla v JavaScriptu jsou uložena v 64-bitovém formátu [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754). Jsou známa také jako „čísla s pohyblivou řádovou čárkou s dvojnásobnou přesností“. To jsou čísla, která používáme ve většině případů a v této kapitole o nich budeme hovořit. -2. BigInt numbers represent integers of arbitrary length. They are sometimes needed because a regular integer number can't safely exceed (253-1) or be less than -(253-1), as we mentioned earlier in the chapter . As bigints are used in a few special areas, we devote them to a special chapter . +2. Čísla typu BigInt představují celá čísla libovolné délky. Jsou někdy zapotřebí, neboť běžné celé číslo nemůže bezpečně překročit (253-1) nebo být menší než -(253-1), jak jsme uvedli již dříve v kapitole . Jelikož biginty se používají jen v některých speciálních oblastech, věnujeme jim zvláštní kapitolu . -So here we'll talk about regular numbers. Let's expand our knowledge of them. +Zde tedy budeme hovořit o běžných číslech. Rozšiřme si své znalosti o nich. -## More ways to write a number +## Další způsoby, jak napsat číslo -Imagine we need to write 1 billion. The obvious way is: +Představme si, že musíme napsat 1 miliardu. Obvyklý způsob je: ```js -let billion = 1000000000; +let miliarda = 1000000000; ``` -We also can use underscore `_` as the separator: +Můžeme jako oddělovač použít podtržítko `_`: ```js -let billion = 1_000_000_000; +let miliarda = 1_000_000_000; ``` -Here the underscore `_` plays the role of the "[syntactic sugar](https://en.wikipedia.org/wiki/Syntactic_sugar)", it makes the number more readable. The JavaScript engine simply ignores `_` between digits, so it's exactly the same one billion as above. +Podtržítko `_` zde hraje roli „[syntaktického cukru](https://cs.wikipedia.org/wiki/Syntaktický_cukr)“, který činí číslo čitelnějším. Motor JavaScriptu podtržítka `_` mezi číslicemi jednoduše ignoruje, takže je to přesně stejná miliarda jako výše uvedená. -In real life though, we try to avoid writing long sequences of zeroes. We're too lazy for that. We'll try to write something like `"1bn"` for a billion or `"7.3bn"` for 7 billion 300 million. The same is true for most large numbers. +V reálném životě se však snažíme vyhnout zápisu dlouhých sekvencí nul. Jsme na to příliš líní. Snažíme se zapsat miliardu nějak jako `"1 mld."` nebo 7 miliard 300 miliónů jako `"7,3 mld."`. To platí pro většinu velkých čísel. -In JavaScript, we can shorten a number by appending the letter `"e"` to it and specifying the zeroes count: +V JavaScriptu můžeme číslo zkrátit tím, že za ně přidáme písmeno `"e"` a uvedeme počet nul: ```js run -let billion = 1e9; // 1 billion, literally: 1 and 9 zeroes +let miliarda = 1e9; // 1 miliarda, doslova: 1 a 9 nul -alert( 7.3e9 ); // 7.3 billions (same as 7300000000 or 7_300_000_000) +alert( 7.3e9 ); // 7.3 miliard (totéž jako 7300000000 nebo 7_300_000_000) ``` -In other words, `e` multiplies the number by `1` with the given zeroes count. +Jinými slovy, `e` toto číslo násobí číslem `1` se zadaným počtem nul. ```js -1e3 === 1 * 1000; // e3 means *1000 -1.23e6 === 1.23 * 1000000; // e6 means *1000000 +1e3 === 1 * 1000 // e3 znamená *1000 +1.23e6 === 1.23 * 1000000 // e6 znamená *1000000 ``` -Now let's write something very small. Say, 1 microsecond (one-millionth of a second): +Nyní zapišme nějaké velmi malé číslo. Třeba 1 mikrosekundu (jednu milióntinu sekundy): ```js -let mсs = 0.000001; +let mcs = 0.000001; ``` -Just like before, using `"e"` can help. If we'd like to avoid writing the zeroes explicitly, we could write the same as: +Stejně jako předtím nám může pomoci použití `"e"`. Jestliže se chceme vyhnout explicitnímu zápisu nul, můžeme zapsat totéž jako: ```js -let mcs = 1e-6; // five zeroes to the left from 1 +let mcs = 1e-6; // pět nul nalevo od 1 ``` -If we count the zeroes in `0.000001`, there are 6 of them. So naturally it's `1e-6`. +Spočítáme-li nuly v čísle `0.000001`, bude jich 6. Je to tedy přirozeně `1e-6`. -In other words, a negative number after `"e"` means a division by 1 with the given number of zeroes: +Jinými slovy, záporné číslo za `"e"` znamená dělení číslem 1 se zadaným počtem nul: ```js -// -3 divides by 1 with 3 zeroes +// -3 znamená dělení číslem 1 se 3 nulami 1e-3 === 1 / 1000; // 0.001 -// -6 divides by 1 with 6 zeroes +// -6 znamená dělení číslem 1 se 6 nulami 1.23e-6 === 1.23 / 1000000; // 0.00000123 -// an example with a bigger number -1234e-2 === 1234 / 100; // 12.34, decimal point moves 2 times +// příklad s větším číslem +1234e-2 === 1234 / 100; // 12.34, desetinná čárka se posune 2krát ``` -### Hex, binary and octal numbers +### Hexadecimální, binární a oktální čísla -[Hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) numbers are widely used in JavaScript to represent colors, encode characters, and for many other things. So naturally, there exists a shorter way to write them: `0x` and then the number. +[Hexadecimální čísla (v šestnáctkové soustavě)](https://cs.wikipedia.org/wiki/Šestnáctková_soustava) se v JavaScriptu široce používají k reprezentaci barev, kódování znaků a mnoha dalším věcem. Pochopitelně tedy existuje kratší způsob, jak je zapsat: `0x` a pak číslo. -For instance: +Například: ```js run alert( 0xff ); // 255 -alert( 0xFF ); // 255 (the same, case doesn't matter) +alert( 0xFF ); // 255 (totéž, malá a velká písmena se nerozlišují) ``` -Binary and octal numeral systems are rarely used, but also supported using the `0b` and `0o` prefixes: +Binární (dvojková) a oktální (osmičková) soustava se používají jen vzácně, ale jsou také podporovány, a to za použití prefixů `0b` a `0o`: ```js run -let a = 0b11111111; // binary form of 255 -let b = 0o377; // octal form of 255 +let a = 0b11111111; // binární podoba 255 +let b = 0o377; // oktální podoba 255 -alert( a == b ); // true, the same number 255 at both sides +alert( a == b ); // true, stejné číslo 255 na obou stranách ``` -There are only 3 numeral systems with such support. For other numeral systems, we should use the function `parseInt` (which we will see later in this chapter). +Takovou podporu mají pouze tři číselné soustavy. Pro jiné číselné soustavy bychom měli použít funkci `parseInt` (kterou uvidíme později v této kapitole). -## toString(base) +## toString(základ) -The method `num.toString(base)` returns a string representation of `num` in the numeral system with the given `base`. +Metoda `číslo.toString(základ)` vrátí řetězcovou reprezentaci čísla `číslo` v číselné soustavě o zadaném základu `základ`. -For example: +Příklad: ```js run -let num = 255; +let číslo = 255; -alert( num.toString(16) ); // ff -alert( num.toString(2) ); // 11111111 +alert( číslo.toString(16) ); // ff +alert( číslo.toString(2) ); // 11111111 ``` -The `base` can vary from `2` to `36`. By default, it's `10`. +Hodnota `základ` může být od `2` do `36`. Standardně je to `10`. -Common use cases for this are: +Běžná použití jsou: -- **base=16** is used for hex colors, character encodings etc, digits can be `0..9` or `A..F`. -- **base=2** is mostly for debugging bitwise operations, digits can be `0` or `1`. -- **base=36** is the maximum, digits can be `0..9` or `A..Z`. The whole Latin alphabet is used to represent a number. A funny, but useful case for `36` is when we need to turn a long numeric identifier into something shorter, for example, to make a short url. Can simply represent it in the numeral system with base `36`: +- **základ=16** se používá pro hexadecimální barvy, kódování znaků atd., číslice mohou být `0..9` nebo `A..F`. +- **základ=2** slouží zejména pro ladění bitových operací, číslice mohou být `0` nebo `1`. +- **základ=36** je maximum, číslice mohou být `0..9` nebo `A..Z`. K reprezentaci čísla se používá celá latinská abeceda. Legrační, ale užitečné využití `36` představuje případ, kdy potřebujeme změnit dlouhý číselný identifikátor na něco kratšího, například abychom vytvořili kratší URL. Můžeme jej snadno reprezentovat v číselné soustavě o základu `36`: ```js run alert( 123456..toString(36) ); // 2n9c ``` -```warn header="Two dots to call a method" -Please note that two dots in `123456..toString(36)` is not a typo. If we want to call a method directly on a number, like `toString` in the example above, then we need to place two dots `..` after it. +```warn header="Volání metody dvěma tečkami" +Prosíme všimněte si, že dvě tečky v `123456..toString(36)` není překlep. Chceme-li volat metodu přímo na čísle, např. `toString` v uvedeném příkladu, pak za číslo musíme umístit dvě tečky `..`. -If we placed a single dot: `123456.toString(36)`, then there would be an error, because JavaScript syntax implies the decimal part after the first dot. And if we place one more dot, then JavaScript knows that the decimal part is empty and now uses the method. +Kdybychom umístili jedinou tečku: `123456.toString(36)`, nastala by chyba, protože syntaxe JavaScriptu očekává za první tečkou desetinnou část. Když však uvedeme další tečku, JavaScript pozná, že desetinná část je prázdná, a nyní použije metodu. -Also could write `(123456).toString(36)`. +## Zaokrouhlování -``` - -## Rounding +Jedna z nejčastěji používaných operací při práci s čísly je zaokrouhlování. -One of the most used operations when working with numbers is rounding. - -There are several built-in functions for rounding: +Pro zaokrouhlování existuje několik vestavěných funkcí: `Math.floor` -: Rounds down: `3.1` becomes `3`, and `-1.1` becomes `-2`. +: Zaokrouhluje dolů: `3.1` se zaokrouhlí na `3`, `-1.1` se zaokrouhlí na `-2`. `Math.ceil` -: Rounds up: `3.1` becomes `4`, and `-1.1` becomes `-1`. +: Zaokrouhluje nahoru: `3.1` se zaokrouhlí na `4`, `-1.1` se zaokrouhlí na `-1`. `Math.round` -: Rounds to the nearest integer: `3.1` becomes `3`, `3.6` becomes `4`. In the middle cases `3.5` rounds up to `4`, and `-3.5` rounds up to `-3`. +: Zaokrouhluje na nejbližší celé číslo: `3.1` se zaokrouhlí na `3`, `3.6` se zaokrouhlí na `4`. V prostředních případech se `3.5` zaokrouhlí nahoru na `4` a `-3.5` se zaokrouhlí nahoru na `-3`. -`Math.trunc` (not supported by Internet Explorer) -: Removes anything after the decimal point without rounding: `3.1` becomes `3`, `-1.1` becomes `-1`. +`Math.trunc` (není podporována v Internet Exploreru) +: Odstraní vše za desetinnou čárkou bez zaokrouhlení: `3.1` se převede na `3`, `-1.1` se převede na `-1`. -Here's the table to summarize the differences between them: +Rozdíly mezi těmito funkcemi shrnuje následující tabulka: | | `Math.floor` | `Math.ceil` | `Math.round` | `Math.trunc` | |---|---------|--------|---------|---------| @@ -154,75 +150,76 @@ Here's the table to summarize the differences between them: |`-1.6`| `-2` | `-1` | `-2` | `-1` | -These functions cover all of the possible ways to deal with the decimal part of a number. But what if we'd like to round the number to `n-th` digit after the decimal? +Tyto funkce pokrývají všechny možné způsoby zacházení s desetinnou částí čísla. Ale co když chceme zaokrouhlit číslo na `n-tou` číslici za desetinnou čárkou? + +Máme například `1.2345` a chceme toto číslo zaokrouhlit na 2 desetinná místa, abychom dostali jen `1.23`. -For instance, we have `1.2345` and want to round it to 2 digits, getting only `1.23`. +Existují dva způsoby, jak to udělat: -There are two ways to do so: +1. Násobit a dělit. -1. Multiply-and-divide. + Abychom například zaokrouhlili číslo na 2. číslici za desetinnou čárkou, můžeme toto číslo vynásobit `100`, zavolat zaokrouhlovací funkci a pak je znovu vydělit. - For example, to round the number to the 2nd digit after the decimal, we can multiply the number by `100`, call the rounding function and then divide it back. ```js run - let num = 1.23456; + let číslo = 1.23456; - alert( Math.round(num * 100) / 100 ); // 1.23456 -> 123.456 -> 123 -> 1.23 + alert( Math.round(číslo * 100) / 100 ); // 1.23456 -> 123.456 -> 123 -> 1.23 ``` -2. The method [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) rounds the number to `n` digits after the point and returns a string representation of the result. +2. Metoda [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) zaokrouhluje číslo na `n` číslic za desetinnou čárkou a vrací řetězcovou reprezentaci výsledku. ```js run - let num = 12.34; - alert( num.toFixed(1) ); // "12.3" + let číslo = 12.34; + alert( číslo.toFixed(1) ); // "12.3" ``` - This rounds up or down to the nearest value, similar to `Math.round`: + Zaokrouhlí číslo nahoru nebo dolů na nejbližší hodnotu, podobně jako `Math.round`: ```js run - let num = 12.36; - alert( num.toFixed(1) ); // "12.4" + let číslo = 12.36; + alert( číslo.toFixed(1) ); // "12.4" ``` - Please note that the result of `toFixed` is a string. If the decimal part is shorter than required, zeroes are appended to the end: + Všimněte si, že výsledkem `toFixed` je řetězec. Je-li desetinná část čísla kratší, než bylo vyžadováno, na konec se přidají nuly: ```js run - let num = 12.34; - alert( num.toFixed(5) ); // "12.34000", added zeroes to make exactly 5 digits + let číslo = 12.34; + alert( číslo.toFixed(5) ); // "12.34000", přidají se nuly, aby číslic bylo přesně 5 ``` - We can convert it to a number using the unary plus or a `Number()` call, e.g. write `+num.toFixed(5)`. + Můžeme jej převést na číslo pomocí unárního plus nebo volání `Number()`, např. napsat `+číslo.toFixed(5)`. -## Imprecise calculations +## Nepřesné výpočty -Internally, a number is represented in 64-bit format [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754), so there are exactly 64 bits to store a number: 52 of them are used to store the digits, 11 of them store the position of the decimal point, and 1 bit is for the sign. +Číslo je vnitřně reprezentováno v 64-bitovém formátu [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754), takže se ukládá přesně do 64 bitů: 52 z nich se používá k uložení číslic, v 11 z nich je uložena pozice desetinné čárky a 1 bit je pro znaménko. -If a number is really huge, it may overflow the 64-bit storage and become a special numeric value `Infinity`: +Je-li číslo opravdu velké, může toto 64-bitové úložiště překročit a stát se speciální číselnou hodnotou `Infinity` (nekonečno): ```js run alert( 1e500 ); // Infinity ``` -What may be a little less obvious, but happens quite often, is the loss of precision. +Co může být trochu méně zřejmé, ale stává se poměrně často, je ztráta přesnosti. -Consider this (falsy!) equality test: +Uvažujme tento (nepravdivý!) test rovnosti: ```js run alert( 0.1 + 0.2 == 0.3 ); // *!*false*/!* ``` -That's right, if we check whether the sum of `0.1` and `0.2` is `0.3`, we get `false`. +Je to tak. Jestliže ověříme, zda součet `0.1` a `0.2` je `0.3`, dostaneme `false`. -Strange! What is it then if not `0.3`? +Zvláštní! Co tedy je, když ne `0.3`? ```js run alert( 0.1 + 0.2 ); // 0.30000000000000004 ``` -Ouch! Imagine you're making an e-shopping site and the visitor puts `$0.10` and `$0.20` goods into their cart. The order total will be `$0.30000000000000004`. That would surprise anyone. +Ouvej! Představme si, že vytváříme elektronický obchod a návštěvník si do košíku uloží zboží za `$0.10` a za `$0.20`. Celková cena pak bude `$0.30000000000000004`. To každého překvapí. -But why does this happen? +Ale proč se to děje? -A number is stored in memory in its binary form, a sequence of bits - ones and zeroes. But fractions like `0.1`, `0.2` that look simple in the decimal numeric system are actually unending fractions in their binary form. +Číslo je v paměti uloženo ve své binární podobě, jako posloupnost bitů -- jedniček a nul. Ale desetinná čísla jako `0.1` nebo `0.2`, která v desítkové soustavě vypadají jednoduše, jsou ve své binární podobě ve skutečnosti nekonečná. ```js run alert(0.1.toString(2)); // 0.0001100110011001100110011001100110011001100110011001101 @@ -230,261 +227,261 @@ alert(0.2.toString(2)); // 0.001100110011001100110011001100110011001100110011001 alert((0.1 + 0.2).toString(2)); // 0.0100110011001100110011001100110011001100110011001101 ``` -What is `0.1`? It is one divided by ten `1/10`, one-tenth. In the decimal numeral system, such numbers are easily representable. Compare it to one-third: `1/3`. It becomes an endless fraction `0.33333(3)`. +Co je vlastně `0.1`? Je to jedna děleno deseti `1/10`, jedna desetina. V desítkové soustavě lze taková čísla snadno reprezentovat. Srovnejme si to s jednou třetinou: `1/3`. Z ní se stane nekonečné desetinné číslo `0.33333(3)`. -So, division by powers `10` is guaranteed to work well in the decimal system, but division by `3` is not. For the same reason, in the binary numeral system, the division by powers of `2` is guaranteed to work, but `1/10` becomes an endless binary fraction. +Je tedy zaručeno, že dělení mocninami `10` bude v desítkové soustavě fungovat dobře, ale dělení třemi ne. Ze stejného důvodu je v binární soustavě zaručeno, že bude fungovat dělení mocninami `2`, ale z `1/10` se stane nekonečné binární číslo. -There's just no way to store *exactly 0.1* or *exactly 0.2* using the binary system, just like there is no way to store one-third as a decimal fraction. +V binární soustavě prostě neexistuje způsob, jak uložit *přesně 0,1* nebo *přesně 0,2*, stejně jako v desítkové soustavě není způsob, jak uložit jako desetinné číslo jednu třetinu. -The numeric format IEEE-754 solves this by rounding to the nearest possible number. These rounding rules normally don't allow us to see that "tiny precision loss", but it exists. +Číselný formát IEEE-754 to řeší zaokrouhlením na nejbližší možné číslo. Tato zaokrouhlovací pravidla nám běžně neumožňují vidět tuto „drobnou ztrátu přesnosti“, ale ta tam je. -We can see this in action: +Můžeme to vidět v akci: ```js run alert( 0.1.toFixed(20) ); // 0.10000000000000000555 ``` -And when we sum two numbers, their "precision losses" add up. +A když sečteme dvě čísla, jejich „ztráty přesnosti“ se sečtou. -That's why `0.1 + 0.2` is not exactly `0.3`. +Proto `0.1 + 0.2` není přesně `0.3`. -```smart header="Not only JavaScript" -The same issue exists in many other programming languages. +```smart header="To není jen JavaScript" +Stejný problém existuje v mnoha jiných programovacích jazycích. -PHP, Java, C, Perl, and Ruby give exactly the same result, because they are based on the same numeric format. +Přesně stejný výsledek vydají i PHP, Java, C, Perl nebo Ruby, protože jsou založeny na stejném číselném formátu. ``` -Can we work around the problem? Sure, the most reliable method is to round the result with the help of a method [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed): +Můžeme se tomuto problému vyhnout? Jistě. Nejspolehlivější metoda je zaokrouhlit výsledek pomocí metody [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed): ```js run -let sum = 0.1 + 0.2; -alert( sum.toFixed(2) ); // "0.30" +let součet = 0.1 + 0.2; +alert( součet.toFixed(2) ); // "0.30" ``` -Please note that `toFixed` always returns a string. It ensures that it has 2 digits after the decimal point. That's actually convenient if we have an e-shopping and need to show `$0.30`. For other cases, we can use the unary plus to coerce it into a number: +Prosíme všimněte si, že `toFixed` vrací vždy řetězec. Zajišťuje, že za desetinnou tečkou má vždy 2 číslice. To se obzvláště hodí, když máme elektronický obchod a potřebujeme zobrazit `$0.30`. V jiných případech můžeme použít unární plus, abychom řetězec převedli na číslo: ```js run -let sum = 0.1 + 0.2; -alert( +sum.toFixed(2) ); // 0.3 +let součet = 0.1 + 0.2; +alert( +součet.toFixed(2) ); // 0.3 ``` -We also can temporarily multiply the numbers by 100 (or a bigger number) to turn them into integers, do the maths, and then divide back. Then, as we're doing maths with integers, the error somewhat decreases, but we still get it on division: +Můžeme také dočasně násobit tato čísla 100 (nebo vyšším číslem), abychom z nich vytvořili celá čísla, provést výpočty a pak je znovu vydělit. Pak, jelikož provádíme výpočty s celými čísly, chyba se trochu sníží, ale při dělení ji stále dostaneme: ```js run alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3 alert( (0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001 ``` -So, the multiply/divide approach reduces the error, but doesn't remove it totally. +Použití násobení a dělení tedy chybu zredukuje, ale úplně ji neodstraní. -Sometimes we could try to evade fractions at all. Like if we're dealing with a shop, then we can store prices in cents instead of dollars. But what if we apply a discount of 30%? In practice, totally evading fractions is rarely possible. Just round them to cut "tails" when needed. +Někdy se snažíme úplně se desetinným číslům vyhnout. Například když vytváříme obchod, můžeme ukládat ceny v centech namísto v dolarech. Ale co když aplikujeme slevu 30%? V praxi je úplné vyhnutí se desetinným číslům možné jen zřídka. Prostě je zaokrouhlujte, abyste odřízli „zbytky“, když je třeba. -````smart header="The funny thing" -Try running this: +````smart header="Legrační věcička" +Zkuste si spustit tohle: ```js run -// Hello! I'm a self-increasing number! -alert( 9999999999999999 ); // shows 10000000000000000 +// Ahoj! Já jsem samozvyšující se číslo! +alert( 9999999999999999 ); // zobrazí 10000000000000000 ``` -This suffers from the same issue: a loss of precision. There are 64 bits for the number, 52 of them can be used to store digits, but that's not enough. So the least significant digits disappear. +To trpí stejným neduhem: ztrátou přesnosti. Pro číslo je 64 bitů, 52 z nich lze použít k uložení číslic, ale to nestačí. Nejméně významné číslice tedy zmizí. -JavaScript doesn't trigger an error in such events. It does its best to fit the number into the desired format, but unfortunately, this format is not big enough. +JavaScript při takových událostech nevyvolá chybu. Udělá, co může, aby se číslo vešlo do požadovaného formátu, ale naneštěstí tento formát není dostatečně velký. ```` -```smart header="Two zeroes" -Another funny consequence of the internal representation of numbers is the existence of two zeroes: `0` and `-0`. +```smart header="Dvě nuly" +Dalším legračním důsledkem této interní reprezentace čísel je existence dvou nul: `0` a `-0`. -That's because a sign is represented by a single bit, so it can be set or not set for any number including a zero. +Je to proto, že znaménko je reprezentováno jediným bitem, který může být nastaven na 1 nebo 0 pro jakékoli číslo včetně nuly. -In most cases, the distinction is unnoticeable, because operators are suited to treat them as the same. +Ve většině případů je tento rozdíl neznatelný, protože operátory jsou vytvořeny tak, aby s oběma nulami zacházely stejně. ``` -## Tests: isFinite and isNaN +## Testy: isFinite a isNaN -Remember these two special numeric values? +Vzpomínáte si na tyto dvě speciální číselné hodnoty? -- `Infinity` (and `-Infinity`) is a special numeric value that is greater (less) than anything. -- `NaN` represents an error. +- `Infinity` (a `-Infinity`) je speciální číselná hodnota, která je větší (menší) než cokoli jiného. +- `NaN` představuje chybu. -They belong to the type `number`, but are not "normal" numbers, so there are special functions to check for them: +Patří k typu `number`, ale nejsou to „normální“ čísla, takže existují speciální funkce, které je prověří: -- `isNaN(value)` converts its argument to a number and then tests it for being `NaN`: +- `isNaN(hodnota)` převede svůj argument na číslo a pak jej otestuje, zda je `NaN`: ```js run alert( isNaN(NaN) ); // true - alert( isNaN("str") ); // true + alert( isNaN("řetězec") ); // true ``` - But do we need this function? Can't we just use the comparison `=== NaN`? Unfortunately not. The value `NaN` is unique in that it does not equal anything, including itself: + Ale potřebujeme vůbec tuto funkci? Nemůžeme jednoduše použít porovnání `=== NaN`? Bohužel ne. Hodnota `NaN` je unikátem, který se nerovná ničemu jinému, dokonce ani sám sobě: ```js run alert( NaN === NaN ); // false ``` -- `isFinite(value)` converts its argument to a number and returns `true` if it's a regular number, not `NaN/Infinity/-Infinity`: +- `isFinite(hodnota)` převede svůj argument na číslo a vrátí `true`, jestliže je to skutečné číslo a ne `NaN/Infinity/-Infinity`: ```js run alert( isFinite("15") ); // true - alert( isFinite("str") ); // false, because a special value: NaN - alert( isFinite(Infinity) ); // false, because a special value: Infinity + alert( isFinite("řetězec") ); // false, protože je to speciální hodnota: NaN + alert( isFinite(Infinity) ); // false, protože je to speciální hodnota: Infinity ``` -Sometimes `isFinite` is used to validate whether a string value is a regular number: +Někdy se `isFinite` používá k ověření, zda řetězcová hodnota je skutečné číslo: ```js run -let num = +prompt("Enter a number", ''); +let číslo = +prompt("Zadejte číslo", ''); -// will be true unless you enter Infinity, -Infinity or not a number -alert( isFinite(num) ); +// bude true, pokud nezadáte Infinity, -Infinity nebo něco jiného než číslo +alert( isFinite(číslo) ); ``` -Please note that an empty or a space-only string is treated as `0` in all numeric functions including `isFinite`. +Prosíme všimněte si, že s prázdným řetězcem nebo s řetězcem složeným pouze z mezer se zachází jako s `0` ve všech číselných funkcích včetně `isFinite`. -````smart header="`Number.isNaN` and `Number.isFinite`" -[Number.isNaN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN) and [Number.isFinite](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isFinite) methods are the more "strict" versions of `isNaN` and `isFinite` functions. They do not autoconvert their argument into a number, but check if it belongs to the `number` type instead. +````smart header="`Number.isNaN` a `Number.isFinite`" +Metody [Number.isNaN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN) a [Number.isFinite](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isFinite) jsou „striktnější“ verze funkcí `isNaN` a `isFinite`. Svůj argument nepřevádějí automaticky na číslo, ale místo toho ověří, zda jejich argument je typu `number`. -- `Number.isNaN(value)` returns `true` if the argument belongs to the `number` type and it is `NaN`. In any other case, it returns `false`. +- `Number.isNaN(hodnota)` vrací `true`, jestliže argument je typu `number` a je `NaN`. V jakémkoli jiném případě vrací `false`. ```js run alert( Number.isNaN(NaN) ); // true - alert( Number.isNaN("str" / 2) ); // true + alert( Number.isNaN("řetězec" / 2) ); // true - // Note the difference: - alert( Number.isNaN("str") ); // false, because "str" belongs to the string type, not the number type - alert( isNaN("str") ); // true, because isNaN converts string "str" into a number and gets NaN as a result of this conversion + // Všimněte si rozdílu: + alert( Number.isNaN("řetězec") ); // false, protože "řetězec" je typu string, ne typu number + alert( isNaN("řetězec") ); // true, protože isNaN převede "řetězec" na číslo a jako výsledek této konverze získá NaN ``` -- `Number.isFinite(value)` returns `true` if the argument belongs to the `number` type and it is not `NaN/Infinity/-Infinity`. In any other case, it returns `false`. +- `Number.isFinite(value)` vrací `true`, jestliže argument je typu `number` a není `NaN/Infinity/-Infinity`. V jakémkoli jiném případě vrací `false`. ```js run alert( Number.isFinite(123) ); // true alert( Number.isFinite(Infinity) ); // false alert( Number.isFinite(2 / 0) ); // false - // Note the difference: - alert( Number.isFinite("123") ); // false, because "123" belongs to the string type, not the number type - alert( isFinite("123") ); // true, because isFinite converts string "123" into a number 123 + // Všimněte si rozdílu: + alert( Number.isFinite("123") ); // false, protože "123" je typu string, ne typu number + alert( isFinite("123") ); // true, protože isFinite převede řetězec "123" na číslo 123 ``` -In a way, `Number.isNaN` and `Number.isFinite` are simpler and more straightforward than `isNaN` and `isFinite` functions. In practice though, `isNaN` and `isFinite` are mostly used, as they're shorter to write. +Svým způsobem jsou `Number.isNaN` a `Number.isFinite` jednodušší a přímější než funkce `isNaN` a `isFinite`. V praxi se však většinou používají `isNaN` a `isFinite`, jelikož jsou kratší na napsání. ```` -```smart header="Comparison with `Object.is`" -There is a special built-in method `Object.is` that compares values like `===`, but is more reliable for two edge cases: +```smart header="Porovnání pomocí `Object.is`" +Existuje speciální vestavěná metoda `Object.is`, která porovnává hodnoty stejně jako `===`, ale ve dvou krajních případech je spolehlivější: -1. It works with `NaN`: `Object.is(NaN, NaN) === true`, that's a good thing. -2. Values `0` and `-0` are different: `Object.is(0, -0) === false`, technically that's correct because internally the number has a sign bit that may be different even if all other bits are zeroes. +1. Funguje pro `NaN`: `Object.is(NaN, NaN) === true`, což je dobrá věc. +2. Hodnoty `0` a `-0` jsou rozdílné: `Object.is(0, -0) === false`, technicky je to správně, protože vnitřně číslo obsahuje znaménkový bit, který se může lišit, i když jsou všechny ostatní bity nulové. -In all other cases, `Object.is(a, b)` is the same as `a === b`. +Ve všech ostatních případech je `Object.is(a, b)` totéž jako `a === b`. -We mention `Object.is` here, because it's often used in JavaScript specification. When an internal algorithm needs to compare two values for being exactly the same, it uses `Object.is` (internally called [SameValue](https://tc39.github.io/ecma262/#sec-samevalue)). +Metodu `Object.is` zde zmiňujeme proto, že se často používá ve specifikaci JavaScriptu. Když interní algoritmus potřebuje porovnat, zda jsou dvě hodnoty přesně stejné, používá `Object.is` (interně nazvanou [SameValue](https://tc39.github.io/ecma262/#sec-samevalue)). ``` -## parseInt and parseFloat +## parseInt a parseFloat -Numeric conversion using a plus `+` or `Number()` is strict. If a value is not exactly a number, it fails: +Číselná konverze prováděná pomocí plus `+` nebo `Number()` je striktní. Není-li hodnota přesně číslo, konverze selže: ```js run alert( +"100px" ); // NaN ``` -The sole exception is spaces at the beginning or at the end of the string, as they are ignored. +Jedinou výjimkou jsou mezery na začátku nebo na konci řetězce, které jsou ignorovány. -But in real life, we often have values in units, like `"100px"` or `"12pt"` in CSS. Also in many countries, the currency symbol goes after the amount, so we have `"19€"` and would like to extract a numeric value out of that. +V reálném životě však často máme hodnoty s jednotkami, např. `"100px"` nebo `"12pt"` v CSS. Navíc v mnoha zemích se symbol měny píše až za částku, takže máme `"19€"` a rádi bychom z toho získali číselnou hodnotu. -That's what `parseInt` and `parseFloat` are for. +K tomu slouží funkce `parseInt` a `parseFloat`. -They "read" a number from a string until they can't. In case of an error, the gathered number is returned. The function `parseInt` returns an integer, whilst `parseFloat` will return a floating-point number: +„Načítají“ číslo z řetězce tak dlouho, dokud to jde. Jakmile nastane chyba, vrátí nahromaděné číslo. Funkce `parseInt` vrátí celé číslo, zatímco `parseFloat` vrátí číslo s pohyblivou řádovou čárkou: ```js run alert( parseInt('100px') ); // 100 alert( parseFloat('12.5em') ); // 12.5 -alert( parseInt('12.3') ); // 12, only the integer part is returned -alert( parseFloat('12.3.4') ); // 12.3, the second point stops the reading +alert( parseInt('12.3') ); // 12, vrátí se jen celá část +alert( parseFloat('12.3.4') ); // 12.3, druhá tečka ukončí načítání ``` -There are situations when `parseInt/parseFloat` will return `NaN`. It happens when no digits could be read: +Existují situace, v nichž `parseInt/parseFloat` vrátí `NaN`. To se stane tehdy, když nelze načíst ani jednu číslici: ```js run -alert( parseInt('a123') ); // NaN, the first symbol stops the process +alert( parseInt('a123') ); // NaN, první znak tento proces zastaví ``` -````smart header="The second argument of `parseInt(str, radix)`" -The `parseInt()` function has an optional second parameter. It specifies the base of the numeral system, so `parseInt` can also parse strings of hex numbers, binary numbers and so on: +````smart header="Druhý argument `parseInt(řetězec, soustava)`" +Funkce `parseInt()` má nepovinný druhý parametr. Ten specifikuje základ číselné soustavy, takže `parseInt` může také načítat řetězce s hexadecimálními čísly, binárními čísly a podobně: ```js run alert( parseInt('0xff', 16) ); // 255 -alert( parseInt('ff', 16) ); // 255, without 0x also works +alert( parseInt('ff', 16) ); // 255, funguje to i bez 0x alert( parseInt('2n9c', 36) ); // 123456 ``` ```` -## Other math functions +## Další matematické funkce -JavaScript has a built-in [Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) object which contains a small library of mathematical functions and constants. +JavaScript má vestavěný objekt [Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math), který obsahuje malou knihovnu matematických funkcí a konstant. -A few examples: +Několik příkladů: `Math.random()` -: Returns a random number from 0 to 1 (not including 1). +: Vrátí náhodné číslo od 0 do 1 (kromě 1). ```js run alert( Math.random() ); // 0.1234567894322 alert( Math.random() ); // 0.5435252343232 - alert( Math.random() ); // ... (any random numbers) + alert( Math.random() ); // ... (jakákoli náhodná čísla) ``` -`Math.max(a, b, c...)` and `Math.min(a, b, c...)` -: Returns the greatest and smallest from the arbitrary number of arguments. +`Math.max(a, b, c...)` a `Math.min(a, b, c...)` +: Vrátí největší a nejmenší z libovolného počtu argumentů. ```js run alert( Math.max(3, 5, -10, 0, 1) ); // 5 alert( Math.min(1, 2) ); // 1 ``` -`Math.pow(n, power)` -: Returns `n` raised to the given power. +`Math.pow(n, exponent)` +: Vrátí `n` umocněné na zadaný exponent. ```js run - alert( Math.pow(2, 10) ); // 2 in power 10 = 1024 + alert( Math.pow(2, 10) ); // 2 na 10 = 1024 ``` -There are more functions and constants in `Math` object, including trigonometry, which you can find in the [docs for the Math object](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math). +V objektu `Math` jsou i další konstanty a funkce včetně goniometrických. Můžete je najít v [dokumentaci k objektu Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math). -## Summary +## Shrnutí -To write numbers with many zeroes: +Abychom napsali číslo s mnoha nulami: -- Append `"e"` with the zeroes count to the number. Like: `123e6` is the same as `123` with 6 zeroes `123000000`. -- A negative number after `"e"` causes the number to be divided by 1 with given zeroes. E.g. `123e-6` means `0.000123` (`123` millionths). +- Připojíme za číslo `"e"` a počet nul. Například `123e6` je totéž jako `123` s 6 nulami: `123000000`. +- Záporné číslo za `"e"` způsobí, že číslo bude děleno číslem 1 se zadaným počtem nul. Například `123e-6` znamená `0.000123` (`123` milióntin). -For different numeral systems: +Pro různé číselné soustavy: -- Can write numbers directly in hex (`0x`), octal (`0o`) and binary (`0b`) systems. -- `parseInt(str, base)` parses the string `str` into an integer in numeral system with given `base`, `2 ≤ base ≤ 36`. -- `num.toString(base)` converts a number to a string in the numeral system with the given `base`. +- Můžeme zapisovat čísla přímo v hexadecimální (`0x`), oktální (`0o`) a binární (`0b`) soustavě. +- `parseInt(řetězec, základ)` převede `řetězec` na celé číslo v číselné soustavě o zadaném základu `základ`, `2 ≤ základ ≤ 36`. +- `číslo.toString(základ)` převede číslo na řetězec v číselné soustavě o zadaném základu `základ`. -For regular number tests: +Pro testování čísel: -- `isNaN(value)` converts its argument to a number and then tests it for being `NaN` -- `Number.isNaN(value)` checks whether its argument belongs to the `number` type, and if so, tests it for being `NaN` -- `isFinite(value)` converts its argument to a number and then tests it for not being `NaN/Infinity/-Infinity` -- `Number.isFinite(value)` checks whether its argument belongs to the `number` type, and if so, tests it for not being `NaN/Infinity/-Infinity` +- `isNaN(hodnota)` převede svůj argument na číslo a pak testuje, zda je `NaN` +- `Number.isNaN(hodnota)` ověří, zda je její argument typu `number`, a pokud ano, testuje, zda je `NaN` +- `isFinite(hodnota)` převede svůj argument na číslo a pak testuje, zda není `NaN/Infinity/-Infinity` +- `Number.isFinite(hodnota)` ověří, zda je její argument typu `number`, a pokud ano, testuje, zda není `NaN/Infinity/-Infinity` -For converting values like `12pt` and `100px` to a number: +Pro převod hodnot jako `12pt` nebo `100px` na číslo: -- Use `parseInt/parseFloat` for the "soft" conversion, which reads a number from a string and then returns the value they could read before the error. +- Pro „měkkou“ konverzi používejte `parseInt/parseFloat`, která načte číslo z řetězce a pak vrátí hodnotu, kterou dokázala přečíst, než nastala chyba. -For fractions: +Pro desetinná čísla: -- Round using `Math.floor`, `Math.ceil`, `Math.trunc`, `Math.round` or `num.toFixed(precision)`. -- Make sure to remember there's a loss of precision when working with fractions. +- Zaokrouhlujte pomocí `Math.floor`, `Math.ceil`, `Math.trunc`, `Math.round` nebo `číslo.toFixed(přesnost)`. +- Při práci s desetinnými čísly se ujistěte, že nezapomínáte na ztrátu přesnosti. -More mathematical functions: +Další matematické funkce: -- See the [Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) object when you need them. The library is very small but can cover basic needs. +- Až je budete potřebovat, podívejte se na objekt [Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math). Je to velmi malá knihovna, ale základní potřeby dokáže pokrýt. diff --git a/1-js/05-data-types/03-string/1-ucfirst/_js.view/solution.js b/1-js/05-data-types/03-string/1-ucfirst/_js.view/solution.js index 20e687a4d..713dc3007 100644 --- a/1-js/05-data-types/03-string/1-ucfirst/_js.view/solution.js +++ b/1-js/05-data-types/03-string/1-ucfirst/_js.view/solution.js @@ -1,5 +1,5 @@ -function ucFirst(str) { - if (!str) return str; +function velkéPrvníPísmeno(řetězec) { + if (!řetězec) return řetězec; - return str[0].toUpperCase() + str.slice(1); + return řetězec[0].toUpperCase() + řetězec.slice(1); } \ No newline at end of file diff --git a/1-js/05-data-types/03-string/1-ucfirst/_js.view/test.js b/1-js/05-data-types/03-string/1-ucfirst/_js.view/test.js index d5c50ff57..097d54458 100644 --- a/1-js/05-data-types/03-string/1-ucfirst/_js.view/test.js +++ b/1-js/05-data-types/03-string/1-ucfirst/_js.view/test.js @@ -1,9 +1,9 @@ -describe("ucFirst", function() { - it('Uppercases the first symbol', function() { - assert.strictEqual(ucFirst("john"), "John"); +describe("velkéPrvníPísmeno", function() { + it('První symbol převede na velké písmeno', function() { + assert.strictEqual(velkéPrvníPísmeno("jan"), "Jan"); }); - it("Doesn't die on an empty string", function() { - assert.strictEqual(ucFirst(""), ""); + it("Nespadne na prázdném řetězci", function() { + assert.strictEqual(velkéPrvníPísmeno(""), ""); }); }); \ No newline at end of file diff --git a/1-js/05-data-types/03-string/1-ucfirst/solution.md b/1-js/05-data-types/03-string/1-ucfirst/solution.md index be5dd2aaf..a706ce327 100644 --- a/1-js/05-data-types/03-string/1-ucfirst/solution.md +++ b/1-js/05-data-types/03-string/1-ucfirst/solution.md @@ -1,21 +1,21 @@ -We can't "replace" the first character, because strings in JavaScript are immutable. +Nemůžeme „nahradit“ první znak, protože řetězce v JavaScriptu jsou neměnné. -But we can make a new string based on the existing one, with the uppercased first character: +Můžeme však vytvořit z existujícího řetězce nový, který bude mít první znak převedený na velké písmeno: ```js -let newStr = str[0].toUpperCase() + str.slice(1); +let novýŘetězec = řetězec[0].toUpperCase() + řetězec.slice(1); ``` -There's a small problem though. If `str` is empty, then `str[0]` is `undefined`, and as `undefined` doesn't have the `toUpperCase()` method, we'll get an error. +Je tady však malý problém. Jestliže `řetězec` je prázdný, pak `řetězec[0]` je `undefined`, a protože `undefined` nemá metodu `toUpperCase()`, dostaneme chybu. -The easiest way out is to add a test for an empty string, like this: +Nejjednodušší způsob, jak to vyřešit, je přidat test na prázdný řetězec, například takto: ```js run demo -function ucFirst(str) { - if (!str) return str; +function velkéPrvníPísmeno(řetězec) { + if (!řetězec) return řetězec; - return str[0].toUpperCase() + str.slice(1); + return řetězec[0].toUpperCase() + řetězec.slice(1); } -alert( ucFirst("john") ); // John +alert( velkéPrvníPísmeno("jan") ); // Jan ``` diff --git a/1-js/05-data-types/03-string/1-ucfirst/task.md b/1-js/05-data-types/03-string/1-ucfirst/task.md index ed8a1e6a7..a2219d395 100644 --- a/1-js/05-data-types/03-string/1-ucfirst/task.md +++ b/1-js/05-data-types/03-string/1-ucfirst/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# Uppercase the first character +# Změňte první znak na velké písmeno -Write a function `ucFirst(str)` that returns the string `str` with the uppercased first character, for instance: +Napište funkci `velkéPrvníPísmeno(řetězec)`, která vrátí `řetězec` upravený tak, že první znak bude převeden na velké písmeno, například: ```js -ucFirst("john") == "John"; +velkéPrvníPísmeno("jan") == "Jan"; ``` diff --git a/1-js/05-data-types/03-string/2-check-spam/_js.view/solution.js b/1-js/05-data-types/03-string/2-check-spam/_js.view/solution.js index 105d70eae..fa3800e01 100644 --- a/1-js/05-data-types/03-string/2-check-spam/_js.view/solution.js +++ b/1-js/05-data-types/03-string/2-check-spam/_js.view/solution.js @@ -1,5 +1,5 @@ -function checkSpam(str) { - let lowerStr = str.toLowerCase(); +function ověřSpam(řetězec) { + let řetězecMalýmiPísmeny = řetězec.toLowerCase(); - return lowerStr.includes('viagra') || lowerStr.includes('xxx'); + return řetězecMalýmiPísmeny.includes('viagra') || řetězecMalýmiPísmeny.includes('xxx'); } \ No newline at end of file diff --git a/1-js/05-data-types/03-string/2-check-spam/_js.view/test.js b/1-js/05-data-types/03-string/2-check-spam/_js.view/test.js index 85eb24fcb..7a9d3252a 100644 --- a/1-js/05-data-types/03-string/2-check-spam/_js.view/test.js +++ b/1-js/05-data-types/03-string/2-check-spam/_js.view/test.js @@ -1,13 +1,13 @@ -describe("checkSpam", function() { - it('finds spam in "buy ViAgRA now"', function() { - assert.isTrue(checkSpam('buy ViAgRA now')); +describe("ověřSpam", function() { + it('najde spam ve "levná ViAgRA zde"', function() { + assert.isTrue(ověřSpam('levná ViAgRA zde')); }); - it('finds spam in "free xxxxx"', function() { - assert.isTrue(checkSpam('free xxxxx')); + it('najde spam ve "zdarma xxxxx"', function() { + assert.isTrue(ověřSpam('zdarma xxxxx')); }); - it('no spam in "innocent rabbit"', function() { - assert.isFalse(checkSpam('innocent rabbit')); + it('není spam v "nevinný králíček"', function() { + assert.isFalse(ověřSpam('nevinný králíček')); }); }); \ No newline at end of file diff --git a/1-js/05-data-types/03-string/2-check-spam/solution.md b/1-js/05-data-types/03-string/2-check-spam/solution.md index de8dde57d..aae59e53c 100644 --- a/1-js/05-data-types/03-string/2-check-spam/solution.md +++ b/1-js/05-data-types/03-string/2-check-spam/solution.md @@ -1,14 +1,14 @@ -To make the search case-insensitive, let's bring the string to lower case and then search: +Aby hledání nerozlišovalo malá a velká písmena, převedeme řetězec na malá písmena a pak budeme hledat: ```js run demo -function checkSpam(str) { - let lowerStr = str.toLowerCase(); +function ověřSpam(řetězec) { + let řetězecMalýmiPísmeny = řetězec.toLowerCase(); - return lowerStr.includes('viagra') || lowerStr.includes('xxx'); + return řetězecMalýmiPísmeny.includes('viagra') || řetězecMalýmiPísmeny.includes('xxx'); } -alert( checkSpam('buy ViAgRA now') ); -alert( checkSpam('free xxxxx') ); -alert( checkSpam("innocent rabbit") ); +alert( ověřSpam('levná ViAgRA zde') ); +alert( ověřSpam('zdarma xxxxx') ); +alert( ověřSpam("nevinný králíček") ); ``` diff --git a/1-js/05-data-types/03-string/2-check-spam/task.md b/1-js/05-data-types/03-string/2-check-spam/task.md index 98b5dd8a0..ef7ec918d 100644 --- a/1-js/05-data-types/03-string/2-check-spam/task.md +++ b/1-js/05-data-types/03-string/2-check-spam/task.md @@ -2,15 +2,15 @@ importance: 5 --- -# Check for spam +# Kontrola spamu -Write a function `checkSpam(str)` that returns `true` if `str` contains 'viagra' or 'XXX', otherwise `false`. +Napište funkci `ověřSpam(řetězec)`, která vrátí `true`, jestliže `řetězec` obsahuje `'viagra'` nebo `'XXX'`, jinak vrátí `false`. -The function must be case-insensitive: +Funkce nesmí rozlišovat malá a velká písmena: ```js -checkSpam('buy ViAgRA now') == true -checkSpam('free xxxxx') == true -checkSpam("innocent rabbit") == false +ověřSpam('levná ViAgRA zde') == true +ověřSpam('zdarma xxxxx') == true +ověřSpam("nevinný králíček") == false ``` diff --git a/1-js/05-data-types/03-string/3-truncate/_js.view/solution.js b/1-js/05-data-types/03-string/3-truncate/_js.view/solution.js index f587df1fa..a3cf6cbc0 100644 --- a/1-js/05-data-types/03-string/3-truncate/_js.view/solution.js +++ b/1-js/05-data-types/03-string/3-truncate/_js.view/solution.js @@ -1,4 +1,4 @@ -function truncate(str, maxlength) { - return (str.length > maxlength) ? - str.slice(0, maxlength - 1) + '…' : str; +function zkrať(řetězec, maxDélka) { + return (řetězec.length > maxDélka) ? + řetězec.slice(0, maxDélka - 1) + '…' : řetězec; } \ No newline at end of file diff --git a/1-js/05-data-types/03-string/3-truncate/_js.view/test.js b/1-js/05-data-types/03-string/3-truncate/_js.view/test.js index 991492331..3cc1a5c0b 100644 --- a/1-js/05-data-types/03-string/3-truncate/_js.view/test.js +++ b/1-js/05-data-types/03-string/3-truncate/_js.view/test.js @@ -1,15 +1,15 @@ -describe("truncate", function() { - it("truncate the long string to the given length (including the ellipsis)", function() { +describe("zkrať", function() { + it("zkrátí dlouhý řetězec na zadanou délku (včetně výpustky)", function() { assert.equal( - truncate("What I'd like to tell on this topic is:", 20), - "What I'd like to te…" + truncate("To, co bych k tomuto tématu rád řekl, je:", 20), + "To, co bych k tomut…" ); }); - it("doesn't change short strings", function() { + it("nezmění krátké řetězce", function() { assert.equal( - truncate("Hi everyone!", 20), - "Hi everyone!" + truncate("Ahoj všichni!", 20), + "Ahoj všichni!" ); }); diff --git a/1-js/05-data-types/03-string/3-truncate/solution.md b/1-js/05-data-types/03-string/3-truncate/solution.md index d51672ae6..c5cd3d96e 100644 --- a/1-js/05-data-types/03-string/3-truncate/solution.md +++ b/1-js/05-data-types/03-string/3-truncate/solution.md @@ -1,10 +1,10 @@ -The maximal length must be `maxlength`, so we need to cut it a little shorter, to give space for the ellipsis. +Maximální délka musí být `maxDélka`, takže musíme odříznout řetězec kratší o jeden znak, abychom získali místo pro výpustku. -Note that there is actually a single Unicode character for an ellipsis. That's not three dots. +Všimněte si, že pro výpustku existuje v Unicode jediný znak. Nejsou to tři tečky za sebou. ```js run demo -function truncate(str, maxlength) { - return (str.length > maxlength) ? - str.slice(0, maxlength - 1) + '…' : str; +function zkrať(řetězec, maxDélka) { + return (řetězec.length > maxDélka) ? + řetězec.slice(0, maxDélka - 1) + '…' : řetězec; } ``` diff --git a/1-js/05-data-types/03-string/3-truncate/task.md b/1-js/05-data-types/03-string/3-truncate/task.md index c99a5f15a..65cc71d13 100644 --- a/1-js/05-data-types/03-string/3-truncate/task.md +++ b/1-js/05-data-types/03-string/3-truncate/task.md @@ -2,16 +2,16 @@ importance: 5 --- -# Truncate the text +# Zkrácení textu -Create a function `truncate(str, maxlength)` that checks the length of the `str` and, if it exceeds `maxlength` -- replaces the end of `str` with the ellipsis character `"…"`, to make its length equal to `maxlength`. +Vytvořte funkci `zkrať(řetězec, maxDélka)`, která zkontroluje délku řetězce `řetězec`, a pokud překročí `maxDélka`, nahradí konec řetězce `řetězec` znakem tří teček (výpustkou) `"…"`, aby jeho délka byla přesně `maxDélka`. -The result of the function should be the truncated (if needed) string. +Výsledkem funkce by měl být zkrácený (je-li to nutné) řetězec. -For instance: +Například: ```js -truncate("What I'd like to tell on this topic is:", 20) == "What I'd like to te…" +zkrať("To, co bych k tomuto tématu rád řekl, je:", 20) == "To, co bych k tomut…" -truncate("Hi everyone!", 20) == "Hi everyone!" +zkrať("Ahoj všichni!", 20) == "Ahoj všichni!" ``` diff --git a/1-js/05-data-types/03-string/4-extract-currency/_js.view/solution.js b/1-js/05-data-types/03-string/4-extract-currency/_js.view/solution.js index 828030dba..75a2c5827 100644 --- a/1-js/05-data-types/03-string/4-extract-currency/_js.view/solution.js +++ b/1-js/05-data-types/03-string/4-extract-currency/_js.view/solution.js @@ -1,3 +1,3 @@ -function extractCurrencyValue(str) { - return +str.slice(1); +function vyjmiČástku(řetězec) { + return +řetězec.slice(1); } \ No newline at end of file diff --git a/1-js/05-data-types/03-string/4-extract-currency/_js.view/test.js b/1-js/05-data-types/03-string/4-extract-currency/_js.view/test.js index 1c3f0bbc1..c5aeed127 100644 --- a/1-js/05-data-types/03-string/4-extract-currency/_js.view/test.js +++ b/1-js/05-data-types/03-string/4-extract-currency/_js.view/test.js @@ -1,7 +1,7 @@ -describe("extractCurrencyValue", function() { +describe("vyjmiČástku", function() { - it("for the string $120 returns the number 120", function() { - assert.strictEqual(extractCurrencyValue('$120'), 120); + it("pro řetězec $120 vrátí číslo 120", function() { + assert.strictEqual(vyjmiČástku('$120'), 120); }); diff --git a/1-js/05-data-types/03-string/4-extract-currency/task.md b/1-js/05-data-types/03-string/4-extract-currency/task.md index feb16e642..bf53601b8 100644 --- a/1-js/05-data-types/03-string/4-extract-currency/task.md +++ b/1-js/05-data-types/03-string/4-extract-currency/task.md @@ -2,15 +2,15 @@ importance: 4 --- -# Extract the money +# Vyjmutí částky -We have a cost in the form `"$120"`. That is: the dollar sign goes first, and then the number. +Máme cenu ve tvaru `"$120"`. Tedy: jako první je znak dolaru, pak číslo. -Create a function `extractCurrencyValue(str)` that would extract the numeric value from such string and return it. +Vytvořte funkci `vyjmiČástku(řetězec)`, která z takového řetězce vytáhne číselnou hodnotu a vrátí ji. -The example: +Příklad: ```js -alert( extractCurrencyValue('$120') === 120 ); // true +alert( vyjmiČástku('$120') === 120 ); // true ``` diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md index 60ce2b6f0..03c65dcf1 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -1,522 +1,522 @@ -# Strings +# Řetězce -In JavaScript, the textual data is stored as strings. There is no separate type for a single character. +Textová data se v JavaScriptu ukládají jako řetězce. Neexistuje zvláštní typ pro jediný znak. -The internal format for strings is always [UTF-16](https://en.wikipedia.org/wiki/UTF-16), it is not tied to the page encoding. +Interní formát řetězce je vždy [UTF-16](https://cs.wikipedia.org/wiki/UTF-16), nezávisle na kódování stránky. -## Quotes +## Uvozovky -Let's recall the kinds of quotes. +Připomeňme si druhy uvozovek. -Strings can be enclosed within either single quotes, double quotes or backticks: +Řetězce mohou být uzavřeny do jednoduchých, dvojitých nebo zpětných uvozovek: ```js -let single = 'single-quoted'; -let double = "double-quoted"; +let jednoduché = 'jednoduché uvozovky'; +let dvojité = "dvojité uvozovky"; -let backticks = `backticks`; +let zpětné = `zpětné uvozovky`; ``` -Single and double quotes are essentially the same. Backticks, however, allow us to embed any expression into the string, by wrapping it in `${…}`: +Jednoduché a dvojité uvozovky fungují v zásadě stejně. Zpětné uvozovky nám však umožňují vložit do řetězce jakýkoli výraz, když jej uzavřeme do `${…}`: ```js run -function sum(a, b) { +function součet(a, b) { return a + b; } -alert(`1 + 2 = ${sum(1, 2)}.`); // 1 + 2 = 3. +alert(`1 + 2 = ${součet(1, 2)}.`); // 1 + 2 = 3. ``` -Another advantage of using backticks is that they allow a string to span multiple lines: +Další výhodou používání zpětných uvozovek je, že umožňují rozdělit řetězec na více řádků: ```js run -let guestList = `Guests: - * John - * Pete - * Mary +let seznamHostů = `Hosté: + * Jan + * Petr + * Marie `; -alert(guestList); // a list of guests, multiple lines +alert(seznamHostů); // seznam hostů, více řádků ``` -Looks natural, right? But single or double quotes do not work this way. +Vypadá to přirozeně, že? Ale jednoduché nebo dvojité uvozovky takto nefungují. -If we use them and try to use multiple lines, there'll be an error: +Jestliže je použijeme a pokusíme se rozdělit text na více řádků, nastane chyba: ```js run -let guestList = "Guests: // Error: Unexpected token ILLEGAL - * John"; +let seznamHostů = "Hosté: // Error: Unexpected token ILLEGAL + * Jan"; ``` -Single and double quotes come from ancient times of language creation, when the need for multiline strings was not taken into account. Backticks appeared much later and thus are more versatile. +Jednoduché a dvojité uvozovky pocházejí ze starých časů vzniku jazyka, kdy nebyla brána v úvahu potřeba víceřádkových řetězců. Zpětné uvozovky se objevily mnohem později, a tak jsou univerzálnější. -Backticks also allow us to specify a "template function" before the first backtick. The syntax is: func`string`. The function `func` is called automatically, receives the string and embedded expressions and can process them. This feature is called "tagged templates", it's rarely seen, but you can read about it in the MDN: [Template literals](mdn:/JavaScript/Reference/Template_literals#Tagged_templates). +Zpětné uvozovky nám také umožňují specifikovat „šablonovou funkci“ před levými uvozovkami. Syntaxe je: funkce`řetězec`. Funkce `funkce` je volána automaticky, obdrží řetězec a vnořené výrazy a může je zpracovat. Tato vlastnost se nazývá „značkované šablony“ (anglicky „tagged templates“). Je k vidění jen zřídka, ale můžete si o ní přečíst v MDN: [Šablonové literály](mdn:/JavaScript/Reference/Template_literals#Tagged_templates). -## Special characters +## Speciální znaky -It is still possible to create multiline strings with single and double quotes by using a so-called "newline character", written as `\n`, which denotes a line break: +Je ovšem možné vytvořit víceřádkové řetězce uzavřené do jednoduchých nebo dvojitých uvozovek pomocí tzv. „znaku nového řádku“, který se zapisuje `\n` a stanovuje konec řádku: ```js run -let guestList = "Guests:\n * John\n * Pete\n * Mary"; +let seznamHostů = "Hosté:\n * Jan\n * Petr\n * Marie"; -alert(guestList); // a multiline list of guests, same as above +alert(seznamHostů); // víceřádkový seznam hostů, stejný jako výše ``` -As a simpler example, these two lines are equal, just written differently: +Jednodušší příklad: tyto dva řádky mají stejný význam, jen jsou různě zapsané: ```js run -let str1 = "Hello\nWorld"; // two lines using a "newline symbol" +let řetězec1 = "Ahoj\nsvěte"; // dva řádky pomocí „symbolu konce řádku“ -// two lines using a normal newline and backticks -let str2 = `Hello -World`; +// dva řádky pomocí obyčejného nového řádku a zpětných uvozovek +let řetězec2 = `Ahoj +světe`; -alert(str1 == str2); // true +alert(řetězec1 == řetězec2); // true ``` -There are other, less common special characters: +Existují i jiné, méně běžné speciální znaky: -| Character | Description | -|-----------|-------------| -|`\n`|New line| -|`\r`|In Windows text files a combination of two characters `\r\n` represents a new break, while on non-Windows OS it's just `\n`. That's for historical reasons, most Windows software also understands `\n`. | -|`\'`, `\"`, \\`|Quotes| -|`\\`|Backslash| -|`\t`|Tab| -|`\b`, `\f`, `\v`| Backspace, Form Feed, Vertical Tab -- mentioned for completeness, coming from old times, not used nowadays (you can forget them right now). | +| Znak | Popis | +|------|-------| +|`\n`|Nový řádek| +|`\r`|V textových souborech ve Windows reprezentuje konec řádku kombinace dvou znaků `\r\n`, zatímco v jiných OS je to pouze `\n`. Je to z historických důvodů, většina softwaru pod Windows rozumí i `\n`.| +|`\'`, `\"`, \\`|Uvozovky| +|`\\`|Zpětné lomítko| +|`\t`|Tabulátor| +|`\b`, `\f`, `\v`| Backspace, Form Feed, vertikální tabulátor -- uvedeny jen pro úplnost, pocházejí z dřívější doby, v současnosti se nepoužívají (můžete na ně rovnou zapomenout). | -As you can see, all special characters start with a backslash character `\`. It is also called an "escape character". +Jak vidíte, všechny speciální znaky začínají zpětným lomítkem `\`, které se také nazývá „únikový znak“. -Because it's so special, if we need to show an actual backslash `\` within the string, we need to double it: +Protože je tak speciální, musíme je zdvojit, jestliže chceme v řetězci zobrazit skutečné zpětné lomítko `\`: ```js run -alert( `The backslash: \\` ); // The backslash: \ +alert( `Zpětné lomítko: \\` ); // Zpětné lomítko: \ ``` -So-called "escaped" quotes `\'`, `\"`, \\` are used to insert a quote into the same-quoted string. + K vložení uvozovek do řetězce, který je ohraničen stejným druhem uvozovek, se používají tzv. „únikované“ uvozovky `\'`, `\"`, \\`. -For instance: +Například: ```js run -alert( 'I*!*\'*/!*m the Walrus!' ); // *!*I'm*/!* the Walrus! +alert( 'To*!*\'*/!*s přehnal!' ); // *!*To's*/!* přehnal! ``` -As you can see, we have to prepend the inner quote by the backslash `\'`, because otherwise it would indicate the string end. +Jak vidíme, museli jsme před vnitřními jednoduchými uvozovkami uvést zpětné lomítko `\'`, jinak by tyto uvozovky znamenaly konec řetězce. -Of course, only the quotes that are the same as the enclosing ones need to be escaped. So, as a more elegant solution, we could switch to double quotes or backticks instead: +Samozřejmě musíme předznamenat únikovým znakem jen stejný druh uvozovek jako ty, které obklopují řetězec. Jako elegantnější řešení bychom tedy mohli použít dvojité nebo zpětné uvozovky: ```js run -alert( "I'm the Walrus!" ); // I'm the Walrus! +alert( `To's přehnal!` ); // To's přehnal! ``` -Besides these special characters, there's also a special notation for Unicode codes `\u…`, it's rarely used and is covered in the optional chapter about [Unicode](info:unicode). +Kromě těchto speciálních znaků existuje i speciální zápis pro kódy Unicode `\u…`. Používá se jen málokdy a je vysvětlen v pokročilejší kapitole o [Unicode](info:unicode). -## String length +## Délka řetězce -The `length` property has the string length: +Délku řetězce obsahuje vlastnost `length`: ```js run -alert( `My\n`.length ); // 3 +alert( `Já\n`.length ); // 3 ``` -Note that `\n` is a single "special" character, so the length is indeed `3`. +Všimněte si, že `\n` je jediný „speciální“ znak, takže délka bude opravdu `3`. -```warn header="`length` is a property" -People with a background in some other languages sometimes mistype by calling `str.length()` instead of just `str.length`. That doesn't work. +```warn header="`length` je vlastnost" +Lidé zvyklí na některé jiné jazyky někdy nesprávně píší volání funkce `řetězec.length()` místo `řetězec.length`. To nefunguje. -Please note that `str.length` is a numeric property, not a function. There is no need to add parenthesis after it. Not `.length()`, but `.length`. +Prosíme všimněte si, že `řetězec.length` je číselná vlastnost, ne funkce. Není důvod za ní uvádět závorky. Nepíše se `.length()`, ale `.length`. ``` -## Accessing characters +## Přístup ke znakům -To get a character at position `pos`, use square brackets `[pos]` or call the method [str.at(pos)](mdn:js/String/at). The first character starts from the zero position: +Abyste získali znak na pozici `poz`, použijte hranaté závorky `[poz]` nebo zavolejte metodu [řetězec.at(poz)](mdn:js/String/at). První znak se nachází na pozici nula: ```js run -let str = `Hello`; +let řetězec = `Ahoj`; -// the first character -alert( str[0] ); // H -alert( str.at(0) ); // H +// první znak +alert( řetězec[0] ); // A +alert( řetězec.at(0) ); // A -// the last character -alert( str[str.length - 1] ); // o -alert( str.at(-1) ); +// poslední znak +alert( řetězec[řetězec.length - 1] ); // j +alert( řetězec.at(-1) ); ``` -As you can see, the `.at(pos)` method has a benefit of allowing negative position. If `pos` is negative, then it's counted from the end of the string. +Jak vidíte, metoda `.at(poz)` má výhodu v tom, že umožňuje zadat zápornou pozici. Je-li `poz` záporná, počítá se od konce řetězce. -So `.at(-1)` means the last character, and `.at(-2)` is the one before it, etc. +Takže `.at(-1)` znamená poslední znak, `.at(-2)` je znak před ním atd. -The square brackets always return `undefined` for negative indexes, for instance: +Hranaté závorky se záporným indexem vrátí vždy `undefined`, například: ```js run -let str = `Hello`; +let řetězec = `Ahoj`; -alert( str[-2] ); // undefined -alert( str.at(-2) ); // l +alert( řetězec[-2] ); // undefined +alert( řetězec.at(-2) ); // o ``` -We can also iterate over characters using `for..of`: +Můžeme také procházet jednotlivé znaky pomocí `for..of`: ```js run -for (let char of "Hello") { - alert(char); // H,e,l,l,o (char becomes "H", then "e", then "l" etc) +for (let znak of "Ahoj") { + alert(znak); // A,h,o,j (znak bude "A", pak "h", pak "o" atd.) } ``` -## Strings are immutable +## Řetězce jsou neměnné -Strings can't be changed in JavaScript. It is impossible to change a character. +Řetězce v JavaScriptu nelze měnit. Není možné v nich změnit některý znak. -Let's try it to show that it doesn't work: +Zkusme to, abychom viděli, že to nefunguje: ```js run -let str = 'Hi'; +let řetězec = 'Ahoj'; -str[0] = 'h'; // error -alert( str[0] ); // doesn't work +řetězec[0] = 'a'; // chyba +alert( řetězec[0] ); // nefunguje to ``` -The usual workaround is to create a whole new string and assign it to `str` instead of the old one. +Obvyklý způsob, jak to obejít, je vytvořit úplně nový řetězec a přiřadit jej do proměnné `řetězec` namísto starého. -For instance: +Například: ```js run -let str = 'Hi'; +let řetězec = 'Pa'; -str = 'h' + str[1]; // replace the string +řetězec = 'p' + řetězec[1]; // nahradí řetězec -alert( str ); // hi +alert( řetězec ); // pa ``` -In the following sections we'll see more examples of this. +V následujících podkapitolách uvidíme další příklady. -## Changing the case +## Změna písmen na malá nebo velká -Methods [toLowerCase()](mdn:js/String/toLowerCase) and [toUpperCase()](mdn:js/String/toUpperCase) change the case: +Metoda [toLowerCase()](mdn:js/string/toLowerCase) mění písmena řetězce na malá a metoda [toUpperCase()](mdn:js/string/toUpperCase) na velká: ```js run -alert( 'Interface'.toUpperCase() ); // INTERFACE -alert( 'Interface'.toLowerCase() ); // interface +alert( 'Rozhraní'.toUpperCase() ); // ROZHRANÍ +alert( 'Rozhraní'.toLowerCase() ); // rozhraní ``` -Or, if we want a single character lowercased: +Nebo pokud chceme jediný znak, změněný na malé písmeno: ```js run -alert( 'Interface'[0].toLowerCase() ); // 'i' +alert( 'Rozhraní'[0].toLowerCase() ); // 'r' ``` -## Searching for a substring +## Hledání podřetězce -There are multiple ways to look for a substring within a string. +Je mnoho způsobů, jak v řetězci najít podřetězec. -### str.indexOf +### řetězec.indexOf -The first method is [str.indexOf(substr, pos)](mdn:js/String/indexOf). +První metoda je [řetězec.indexOf(podřetězec, pozice)](mdn:js/string/indexOf). -It looks for the `substr` in `str`, starting from the given position `pos`, and returns the position where the match was found or `-1` if nothing can be found. +Hledá `podřetězec` v `řetězec`, počínajíc zadanou pozicí `pozice`, a vrátí pozici, na níž byla nalezena shoda. Jestliže podřetězec nebyl nalezen, vrátí `-1`. -For instance: +Například: ```js run -let str = 'Widget with id'; +let řetězec = 'Prorokovo oko'; -alert( str.indexOf('Widget') ); // 0, because 'Widget' is found at the beginning -alert( str.indexOf('widget') ); // -1, not found, the search is case-sensitive +alert( řetězec.indexOf('Prorokovo') ); // 0, protože 'Prorokovo' je nalezen na začátku +alert( řetězec.indexOf('prorokovo') ); // -1, nenalezeno, hledání rozlišuje malá a velká písmena -alert( str.indexOf("id") ); // 1, "id" is found at the position 1 (..idget with id) +alert( řetězec.indexOf("oko") ); // 4, "oko" nalezeno na pozici 4 (..okovo oko) ``` -The optional second parameter allows us to start searching from a given position. +Nepovinný druhý parametr nám umožňuje zahájit hledání na zadané pozici. -For instance, the first occurrence of `"id"` is at position `1`. To look for the next occurrence, let's start the search from position `2`: +Například první výskyt `"oko"` je na pozici `4`. Chceme-li hledat další výskyt, začněme hledání od pozice `5`: ```js run -let str = 'Widget with id'; +let řetězec = 'Prorokovo oko'; -alert( str.indexOf('id', 2) ) // 12 +alert( řetězec.indexOf('oko', 5) ) // 10 ``` -If we're interested in all occurrences, we can run `indexOf` in a loop. Every new call is made with the position after the previous match: +Pokud nás zajímají všechny výskyty, můžeme spustit `indexOf` v cyklu. Každé nové volání bude začínat na pozici za předchozím nálezem: ```js run -let str = 'As sly as a fox, as strong as an ox'; +let řetězec = 'Kdyby byly v řece ryby, nebylo by třeba rybníka'; -let target = 'as'; // let's look for it +let cíl = 'by'; // hledejme -let pos = 0; +let poz = 0; while (true) { - let foundPos = str.indexOf(target, pos); - if (foundPos == -1) break; + let nalezenáPozice = řetězec.indexOf(cíl, poz); + if (nalezenáPozice == -1) break; - alert( `Found at ${foundPos}` ); - pos = foundPos + 1; // continue the search from the next position + alert( `Nalezeno na ${nalezenáPozice}` ); + poz = nalezenáPozice + 1; // pokračujeme v hledání od další pozice } ``` -The same algorithm can be layed out shorter: +Stejný algoritmus lze napsat kratším způsobem: ```js run -let str = "As sly as a fox, as strong as an ox"; -let target = "as"; +let řetězec = "Kdyby byly v řece ryby, nebylo by třeba rybníka"; +let cíl = "by"; *!* -let pos = -1; -while ((pos = str.indexOf(target, pos + 1)) != -1) { - alert( pos ); +let poz = -1; +while ((poz = řetězec.indexOf(cíl, poz + 1)) != -1) { + alert( poz ); } */!* ``` -```smart header="`str.lastIndexOf(substr, position)`" -There is also a similar method [str.lastIndexOf(substr, position)](mdn:js/String/lastIndexOf) that searches from the end of a string to its beginning. +```smart header="`řetězec.lastIndexOf(podřetězec, pozice)`" +Existuje i podobná metoda [řetězec.lastIndexOf(podřetězec, pozice)](mdn:js/string/lastIndexOf), která hledá od konce řetězce směrem k jeho začátku. -It would list the occurrences in the reverse order. +Ta by vypsala výskyty v opačném pořadí. ``` -There is a slight inconvenience with `indexOf` in the `if` test. We can't put it in the `if` like this: +Metoda `indexOf` vnáší do podmínky v `if` drobnou nepříjemnost. Nemůžeme ji umístit do `if` takto: ```js run -let str = "Widget with id"; +let řetězec = "Prorokovo oko"; -if (str.indexOf("Widget")) { - alert("We found it"); // doesn't work! +if (řetězec.indexOf("Prorokovo")) { + alert("Našli jsme"); // to nefunguje! } ``` -The `alert` in the example above doesn't show because `str.indexOf("Widget")` returns `0` (meaning that it found the match at the starting position). Right, but `if` considers `0` to be `false`. +V uvedeném příkladu se `alert` nezobrazí, protože metoda `řetězec.indexOf("Prorokovo")` vrátila `0` (což znamená, že našla shodu na počáteční pozici). To je správně, ale `if` považuje `0` za `false`. -So, we should actually check for `-1`, like this: +Správně bychom tedy měli porovnávat s `-1`, např. takto: ```js run -let str = "Widget with id"; +let řetězec = "Prorokovo oko"; *!* -if (str.indexOf("Widget") != -1) { +if (řetězec.indexOf("Prorokovo") != -1) { */!* - alert("We found it"); // works now! + alert("Našli jsme"); // teď to funguje! } ``` ### includes, startsWith, endsWith -The more modern method [str.includes(substr, pos)](mdn:js/String/includes) returns `true/false` depending on whether `str` contains `substr` within. +Modernější metoda [řetězec.includes(podřetězec, poz)](mdn:js/string/includes) vrátí `true/false` podle toho, zda `řetězec` v sobě obsahuje `podřetězec`. -It's the right choice if we need to test for the match, but don't need its position: +Je to ta pravá možnost, když potřebujeme testovat výskyt, ale nezajímá nás jeho pozice: ```js run -alert( "Widget with id".includes("Widget") ); // true +alert( "Prorokovo oko".includes("Prorok") ); // true -alert( "Hello".includes("Bye") ); // false +alert( "Ahoj".includes("Sbohem") ); // false ``` -The optional second argument of `str.includes` is the position to start searching from: +Nepovinný druhý argument `řetězec.includes` je pozice, od níž se má začít hledat: ```js run -alert( "Widget".includes("id") ); // true -alert( "Widget".includes("id", 3) ); // false, from position 3 there is no "id" +alert( "Prorokovo".includes("oko") ); // true +alert( "Prorokovo".includes("oko", 5) ); // false, od pozice 5 není žádné "oko" ``` -The methods [str.startsWith](mdn:js/String/startsWith) and [str.endsWith](mdn:js/String/endsWith) do exactly what they say: +Metody [řetězec.startsWith](mdn:js/string/startsWith) a [řetězec.endsWith](mdn:js/string/endsWith) dělají přesně to, co je jejich názvem *(zjistí, zda řetězec začíná „startsWith“ nebo končí „endsWith“ zadaným podřetězcem -- pozn. překl.)*: ```js run -alert( "*!*Wid*/!*get".startsWith("Wid") ); // true, "Widget" starts with "Wid" -alert( "Wid*!*get*/!*".endsWith("get") ); // true, "Widget" ends with "get" +alert( "*!*Pro*/!*rok".startsWith("Pro") ); // true, "Prorok" začíná na "Pro" +alert( "Pro*!*rok*/!*".endsWith("rok") ); // true, "Prorok" končí na "rok" ``` -## Getting a substring +## Získání podřetězce -There are 3 methods in JavaScript to get a substring: `substring`, `substr` and `slice`. +V JavaScriptu jsou 3 metody pro získání podřetězce: `substring`, `substr` a `slice`. -`str.slice(start [, end])` -: Returns the part of the string from `start` to (but not including) `end`. +`řetězec.slice(začátek [, konec])` +: Vrátí část řetězce od pozice `začátek` do (ale ne včetně) pozice `konec`. - For instance: + Například: ```js run - let str = "stringify"; - alert( str.slice(0, 5) ); // 'strin', the substring from 0 to 5 (not including 5) - alert( str.slice(0, 1) ); // 's', from 0 to 1, but not including 1, so only character at 0 + let řetězec = "řetězení"; + alert( řetězec.slice(0, 5) ); // 'řetěz', podřetězec od 0 do 5 (mimo 5) + alert( řetězec.slice(0, 1) ); // 'ř', od 0 do 1, ale mimo 1, takže jediný znak na pozici 0 ``` - If there is no second argument, then `slice` goes till the end of the string: + Není-li uveden druhý argument, `slice` vrátí podřetězec až do konce řetězce: ```js run - let str = "st*!*ringify*/!*"; - alert( str.slice(2) ); // 'ringify', from the 2nd position till the end + let řetězec = "ře*!*tězení*/!*"; + alert( řetězec.slice(2) ); // 'tězení', od 2. pozice do konce ``` - Negative values for `start/end` are also possible. They mean the position is counted from the string end: + Je možné, aby `začátek/konec` měly záporné hodnoty. Ty znamenají, že pozice se počítá od konce řetězce: ```js run - let str = "strin*!*gif*/!*y"; + let řetězec = "řetě*!*zen*/!*í"; - // start at the 4th position from the right, end at the 1st from the right - alert( str.slice(-4, -1) ); // 'gif' + // začátek na 4. pozici zprava, konec na 1. pozici zprava + alert( řetězec.slice(-4, -1) ); // 'zen' ``` -`str.substring(start [, end])` -: Returns the part of the string *between* `start` and `end` (not including `end`). +`řetězec.substring(začátek [, konec])` +: Vrátí část řetězce *mezi* pozicemi `začátek` a `konec` (nezahrnuje `konec`). - This is almost the same as `slice`, but it allows `start` to be greater than `end` (in this case it simply swaps `start` and `end` values). + Je to téměř totéž jako `slice`, ale umožňuje, aby `začátek` byl větší než `konec` (v takovém případě se hodnoty `začátek` a `konec` jednoduše prohodí). - For instance: + Například: ```js run - let str = "st*!*ring*/!*ify"; + let řetězec = "ře*!*těze*/!*ní"; - // these are same for substring - alert( str.substring(2, 6) ); // "ring" - alert( str.substring(6, 2) ); // "ring" + // tyto hodnoty jsou totéž pro substring: + alert( řetězec.substring(2, 6) ); // "těze" + alert( řetězec.substring(6, 2) ); // "těze" - // ...but not for slice: - alert( str.slice(2, 6) ); // "ring" (the same) - alert( str.slice(6, 2) ); // "" (an empty string) + // ...ale ne pro slice: + alert( řetězec.slice(2, 6) ); // "těze" (totéž) + alert( řetězec.slice(6, 2) ); // "" (prázdný řetězec) ``` - Negative arguments are (unlike slice) not supported, they are treated as `0`. + Záporné argumenty (na rozdíl od `slice`) nejsou podporovány a zachází se s nimi jako s `0`. -`str.substr(start [, length])` -: Returns the part of the string from `start`, with the given `length`. +`řetězec.substr(začátek [, délka])` +: Vrátí část řetězce od pozice `začátek` se zadanou délkou `délka`. - In contrast with the previous methods, this one allows us to specify the `length` instead of the ending position: + Na rozdíl od předchozích metod nám tato umožňuje specifikovat délku namísto koncové pozice: ```js run - let str = "st*!*ring*/!*ify"; - alert( str.substr(2, 4) ); // 'ring', from the 2nd position get 4 characters + let řetězec = "ře*!*těze*/!*ní"; + alert( řetězec.substr(2, 4) ); // 'těze', od 2. pozice vezme 4 znaky ``` - The first argument may be negative, to count from the end: + První argument může být záporný, pak se bude počítat od konce: ```js run - let str = "strin*!*gi*/!*fy"; - alert( str.substr(-4, 2) ); // 'gi', from the 4th position get 2 characters + let řetězec = "řetě*!*ze*/!*ní"; + alert( řetězec.substr(-4, 2) ); // 'ze', od 4. pozice zprava vezme 2 znaky ``` - This method resides in the [Annex B](https://tc39.es/ecma262/#sec-string.prototype.substr) of the language specification. It means that only browser-hosted Javascript engines should support it, and it's not recommended to use it. In practice, it's supported everywhere. +Tato metoda je obsažena v [Dodatku B](https://tc39.es/ecma262/#sec-string.prototype.substr) specifikace jazyka. Znamená to, že by ji měly podporovat jedině motory JavaScriptu uvnitř prohlížečů a nedoporučuje se ji používat. V praxi je však podporována všude. -Let's recap these methods to avoid any confusion: +Abychom předešli zmatkům, všechny tyto metody si zrekapitulujme: -| method | selects... | negatives | -|--------|-----------|-----------| -| `slice(start, end)` | from `start` to `end` (not including `end`) | allows negatives | -| `substring(start, end)` | between `start` and `end` (not including `end`)| negative values mean `0` | -| `substr(start, length)` | from `start` get `length` characters | allows negative `start` | +| metoda | vybírá... | záporné hodnoty | +|--------|-----------|-----------------| +| `slice(začátek, konec)` | od `začátek` do `konec` (mimo `konec`) | umožňuje záporné hodnoty | +| `substring(začátek, konec)` | mezi `začátek` a `konec` (mimo `konec`) | záporné hodnoty znamenají `0` | +| `substr(začátek, délka)` | od `začátek` vezme `délka` znaků | umožňuje záporný `začátek` | -```smart header="Which one to choose?" -All of them can do the job. Formally, `substr` has a minor drawback: it is described not in the core JavaScript specification, but in Annex B, which covers browser-only features that exist mainly for historical reasons. So, non-browser environments may fail to support it. But in practice it works everywhere. +```smart header="Kterou zvolit?" +Potřebnou práci odvedou všechny. Formálně má `substr` drobnou nevýhodu: není popsána v jádru specifikace JavaScriptu, ale v Dodatku B, který pokrývá vlastnosti fungující jen v prohlížečích a existující zejména z historických důvodů. Prostředí mimo prohlížeče ji tedy nemusejí podporovat. V praxi však funguje všude. -Of the other two variants, `slice` is a little bit more flexible, it allows negative arguments and shorter to write. +Ze zbývajících dvou variant je `slice` trochu flexibilnější, protože umožňuje záporné hodnoty a je kratší na napsání. -So, for practical use it's enough to remember only `slice`. +Pro praktické použití si tedy stačí pamatovat jen `slice`. ``` -## Comparing strings +## Porovnávání řetězců -As we know from the chapter , strings are compared character-by-character in alphabetical order. +Jak víme z kapitoly , řetězce se porovnávají znak po znaku v abecedním pořadí. -Although, there are some oddities. +Existují však některé zvláštnosti. -1. A lowercase letter is always greater than the uppercase: +1. Malé písmeno je vždy větší než velké: ```js run alert( 'a' > 'Z' ); // true ``` -2. Letters with diacritical marks are "out of order": +2. Písmena s diakritickými znaménky jsou „mimo pořadí“: ```js run - alert( 'Österreich' > 'Zealand' ); // true + alert( 'Írán' > 'Zéland' ); // true ``` - This may lead to strange results if we sort these country names. Usually people would expect `Zealand` to come after `Österreich` in the list. + To může vést ke zvláštním výsledkům, budeme-li řadit tyto názvy zemí. Obvykle se očekává, že `Zéland` bude v seznamu až za `Írán`. -To understand what happens, we should be aware that strings in Javascript are encoded using [UTF-16](https://en.wikipedia.org/wiki/UTF-16). That is: each character has a corresponding numeric code. +Abychom pochopili, co se tady děje, měli bychom vědět, že všechny řetězce jsou zakódovány pomocí [UTF-16](https://cs.wikipedia.org/wiki/UTF-16). To znamená, že každý znak má odpovídající číselný kód. -There are special methods that allow to get the character for the code and back: +Existují speciální metody, které umožňují získat znak pro zadaný kód a naopak: -`str.codePointAt(pos)` -: Returns a decimal number representing the code for the character at position `pos`: +`řetězec.codePointAt(poz)` +: Vrátí desítkové číslo představující kód znaku na pozici `poz`: ```js run - // different case letters have different codes + // malá a velká písmena mají různé kódy alert( "Z".codePointAt(0) ); // 90 alert( "z".codePointAt(0) ); // 122 - alert( "z".codePointAt(0).toString(16) ); // 7a (if we need a hexadecimal value) + alert( "z".codePointAt(0).toString(16) ); // 7a (potřebujeme-li hexadecimální hodnotu) ``` -`String.fromCodePoint(code)` -: Creates a character by its numeric `code` +`String.fromCodePoint(kód)` +: Vytvoří znak podle jeho číselného kódu `kód`: ```js run alert( String.fromCodePoint(90) ); // Z - alert( String.fromCodePoint(0x5a) ); // Z (we can also use a hex value as an argument) + alert( String.fromCodePoint(0x5a) ); // Z (jako argument můžeme použít i hexadecimální hodnotu) ``` -Now let's see the characters with codes `65..220` (the latin alphabet and a little bit extra) by making a string of them: +Nyní se podívejme na znaky s kódy `65..220` (latinská abeceda a něco navíc), když z nich vytvoříme řetězec: ```js run -let str = ''; +let řetězec = ''; for (let i = 65; i <= 220; i++) { - str += String.fromCodePoint(i); + řetězec += String.fromCodePoint(i); } -alert( str ); -// Output: +alert( řetězec ); +// Výstup: // ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„ // ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜ ``` -See? Capital characters go first, then a few special ones, then lowercase characters, and `Ö` near the end of the output. +Vidíte? Napřed jsou velká písmena, pak několik speciálních znaků, pak malá písmena a `Í` je poblíž konce výstupu. -Now it becomes obvious why `a > Z`. +Nyní bude zřejmé, proč `a > Z`. -The characters are compared by their numeric code. The greater code means that the character is greater. The code for `a` (97) is greater than the code for `Z` (90). +Znaky se porovnávají podle svého číselného kódu. Vyšší kód znamená, že znak je větší. Kód `a` (97) je vyšší než kód `Z` (90). -- All lowercase letters go after uppercase letters because their codes are greater. -- Some letters like `Ö` stand apart from the main alphabet. Here, its code is greater than anything from `a` to `z`. +- Všechna malá písmena jsou až za velkými písmeny, protože jejich kódy jsou vyšší. +- Některá písmena, např. `Í`, stojí mimo hlavní abecedu. Jejich kód je zde vyšší než kód kteréhokoli písmene od `a` do `z`. -### Correct comparisons [#correct-comparisons] +### Správné porovnání [#correct-comparisons] -The "right" algorithm to do string comparisons is more complex than it may seem, because alphabets are different for different languages. +„Správný“ algoritmus pro porovnání řetězců je složitější, než se může zdát, protože různé jazyky mají různé abecedy. -So, the browser needs to know the language to compare. +Prohlížeč tedy musí znát jazyk, v němž porovnává. -Luckily, modern browsers support the internationalization standard [ECMA-402](https://www.ecma-international.org/publications-and-standards/standards/ecma-402/). +Naštěstí moderní prohlížeče podporují internacionalizační standard [ECMA-402](https://www.ecma-international.org/publications-and-standards/standards/ecma-402/). -It provides a special method to compare strings in different languages, following their rules. +Ten poskytuje speciální metodu, jak porovnávat řetězce v různých jazycích podle jejich pravidel. -The call [str.localeCompare(str2)](mdn:js/String/localeCompare) returns an integer indicating whether `str` is less, equal or greater than `str2` according to the language rules: +Volání [řetězec.localeCompare(řetězec2)](mdn:js/string/localeCompare) vrátí celé číslo, které oznamuje, zda `řetězec` je menší, roven nebo větší než `řetězec2` podle pravidel jazyka: -- Returns a negative number if `str` is less than `str2`. -- Returns a positive number if `str` is greater than `str2`. -- Returns `0` if they are equivalent. +- Je-li `řetězec` menší než `řetězec2`, vrátí záporné číslo. +- Je-li `řetězec` větší než `řetězec2`, vrátí kladné číslo. +- Jsou-li si rovny, vrátí `0`. -For instance: +Například: ```js run -alert( 'Österreich'.localeCompare('Zealand') ); // -1 +alert( 'Česko'.localeCompare('Zéland') ); // -1 ``` -This method actually has two additional arguments specified in [the documentation](mdn:js/String/localeCompare), which allows it to specify the language (by default taken from the environment, letter order depends on the language) and setup additional rules like case sensitivity or should `"a"` and `"á"` be treated as the same etc. +Tato metoda má ve skutečnosti ještě dva další argumenty specifikované v [dokumentaci](mdn:js/string/localeCompare), které umožňují specifikovat jazyk (standardně se vezme z prostředí, na jazyku závisí pořadí písmen) a nastavit další pravidla, např. rozlišování malých a velkých písmen, nebo zda se `"a"` a `"á"` mají považovat za stejné znaky, atd. -## Summary +## Shrnutí -- There are 3 types of quotes. Backticks allow a string to span multiple lines and embed expressions `${…}`. -- We can use special characters, such as a line break `\n`. -- To get a character, use: `[]` or `at` method. -- To get a substring, use: `slice` or `substring`. -- To lowercase/uppercase a string, use: `toLowerCase/toUpperCase`. -- To look for a substring, use: `indexOf`, or `includes/startsWith/endsWith` for simple checks. -- To compare strings according to the language, use: `localeCompare`, otherwise they are compared by character codes. +- Existují 3 druhy uvozovek. Zpětné uvozovky umožňují rozdělit řetězec na více řádků a vnořit výrazy `${…}`. +- Můžeme používat speciální znaky, například konec řádku `\n`. +- Chceme-li získat znak, použijeme `[]` nebo metodu `at`. +- Chceme-li získat podřetězec, použijeme `slice` nebo `substring`. +- Chceme-li převést řetězec na malá/velká písmena, použijeme `toLowerCase/toUpperCase`. +- Chceme-li najít podřetězec, použijeme `indexOf` nebo pro jednoduché kontroly `includes/startsWith/endsWith`. +- Chceme-li porovnat řetězce podle jazykových pravidel, použijeme `localeCompare`, jinak se budou porovnávat podle kódů znaků. -There are several other helpful methods in strings: +Pro řetězce existuje i několik dalších užitečných metod: -- `str.trim()` -- removes ("trims") spaces from the beginning and end of the string. -- `str.repeat(n)` -- repeats the string `n` times. -- ...and more to be found in the [manual](mdn:js/String). +- `řetězec.trim()` -- odstraní mezery ze začátku a konce řetězce. +- `řetězec.repeat(n)` -- zopakuje řetězec `n`-krát. +- ...a další lze najít v [manuálu](mdn:js/string). -Strings also have methods for doing search/replace with regular expressions. But that's big topic, so it's explained in a separate tutorial section . +Řetězce mají také metody pro hledání a nahrazování pomocí regulárních výrazů. To je však rozsáhlé téma, proto je vysvětleno v samostatné části tutoriálu . -Also, as of now it's important to know that strings are based on Unicode encoding, and hence there're issues with comparisons. There's more about Unicode in the chapter . +Nyní je také důležité vědět, že řetězce jsou založeny na kódování Unicode, a proto jsou zde určité problémy s porovnáváním. O Unicode se dozvíte víc v kapitole . diff --git a/1-js/05-data-types/04-array/1-item-value/solution.md b/1-js/05-data-types/04-array/1-item-value/solution.md index e631f1c70..037d070b3 100644 --- a/1-js/05-data-types/04-array/1-item-value/solution.md +++ b/1-js/05-data-types/04-array/1-item-value/solution.md @@ -1,17 +1,17 @@ -The result is `4`: +Výsledek je `4`: ```js run -let fruits = ["Apples", "Pear", "Orange"]; +let ovoce = ["Jablko", "Hruška", "Pomeranč"]; -let shoppingCart = fruits; +let nákupníKošík = ovoce; -shoppingCart.push("Banana"); +nákupníKošík.push("Banán"); *!* -alert( fruits.length ); // 4 +alert( ovoce.length ); // 4 */!* ``` -That's because arrays are objects. So both `shoppingCart` and `fruits` are the references to the same array. +Je to tím, že pole jsou objekty. Proto jsou `nákupníKošík` i `ovoce` odkazy na totéž pole. diff --git a/1-js/05-data-types/04-array/1-item-value/task.md b/1-js/05-data-types/04-array/1-item-value/task.md index 4fcf384fb..f942521f8 100644 --- a/1-js/05-data-types/04-array/1-item-value/task.md +++ b/1-js/05-data-types/04-array/1-item-value/task.md @@ -2,18 +2,18 @@ importance: 3 --- -# Is array copied? +# Zkopíruje se pole? -What is this code going to show? +Co zobrazí tento kód? ```js -let fruits = ["Apples", "Pear", "Orange"]; +let ovoce = ["Jablko", "Hruška", "Pomeranč"]; -// push a new value into the "copy" -let shoppingCart = fruits; -shoppingCart.push("Banana"); +// přidáme do „kopie“ novou hodnotu +let nákupníKošík = ovoce; +nákupníKošík.push("Banán"); -// what's in fruits? -alert( fruits.length ); // ? +// co bude v poli ovoce? +alert( ovoce.length ); // ? ``` diff --git a/1-js/05-data-types/04-array/10-maximal-subarray/_js.view/solution.js b/1-js/05-data-types/04-array/10-maximal-subarray/_js.view/solution.js index 516328379..8424068dc 100644 --- a/1-js/05-data-types/04-array/10-maximal-subarray/_js.view/solution.js +++ b/1-js/05-data-types/04-array/10-maximal-subarray/_js.view/solution.js @@ -1,11 +1,11 @@ -function getMaxSubSum(arr) { - let maxSum = 0; - let partialSum = 0; +function vraťMaxSoučetPodpole(arr) { + let maxSoučet = 0; + let částečnýSoučet = 0; - for (let item of arr) { - partialSum += item; - maxSum = Math.max(maxSum, partialSum); - if (partialSum < 0) partialSum = 0; + for (let prvek of pole) { + částečnýSoučet += prvek; + maxSoučet = Math.max(maxSoučet, částečnýSoučet); + if (částečnýSoučet < 0) částečnýSoučet = 0; } - return maxSum; + return maxSoučet; } \ No newline at end of file diff --git a/1-js/05-data-types/04-array/10-maximal-subarray/_js.view/test.js b/1-js/05-data-types/04-array/10-maximal-subarray/_js.view/test.js index b44e76fe7..24a829435 100644 --- a/1-js/05-data-types/04-array/10-maximal-subarray/_js.view/test.js +++ b/1-js/05-data-types/04-array/10-maximal-subarray/_js.view/test.js @@ -1,37 +1,37 @@ -describe("getMaxSubSum", function() { - it("maximal subsum of [1, 2, 3] equals 6", function() { - assert.equal(getMaxSubSum([1, 2, 3]), 6); +describe("vraťMaxSoučetPodpole", function() { + it("maximální podsoučet [1, 2, 3] se rovná 6", function() { + assert.equal(vraťMaxSoučetPodpole([1, 2, 3]), 6); }); - it("maximal subsum of [-1, 2, 3, -9] equals 5", function() { - assert.equal(getMaxSubSum([-1, 2, 3, -9]), 5); + it("maximální podsoučet [-1, 2, 3, -9] se rovná 5", function() { + assert.equal(vraťMaxSoučetPodpole([-1, 2, 3, -9]), 5); }); - it("maximal subsum of [-1, 2, 3, -9, 11] equals 11", function() { - assert.equal(getMaxSubSum([-1, 2, 3, -9, 11]), 11); + it("maximální podsoučet [-1, 2, 3, -9, 11] se rovná 11", function() { + assert.equal(vraťMaxSoučetPodpole([-1, 2, 3, -9, 11]), 11); }); - it("maximal subsum of [-2, -1, 1, 2] equals 3", function() { - assert.equal(getMaxSubSum([-2, -1, 1, 2]), 3); + it("maximální podsoučet [-2, -1, 1, 2] se rovná 3", function() { + assert.equal(vraťMaxSoučetPodpole([-2, -1, 1, 2]), 3); }); - it("maximal subsum of [100, -9, 2, -3, 5] equals 100", function() { - assert.equal(getMaxSubSum([100, -9, 2, -3, 5]), 100); + it("maximální podsoučet [100, -9, 2, -3, 5] se rovná 100", function() { + assert.equal(vraťMaxSoučetPodpole([100, -9, 2, -3, 5]), 100); }); - it("maximal subsum of [] equals 0", function() { - assert.equal(getMaxSubSum([]), 0); + it("maximální podsoučet [] se rovná 0", function() { + assert.equal(vraťMaxSoučetPodpole([]), 0); }); - it("maximal subsum of [-1] equals 0", function() { - assert.equal(getMaxSubSum([-1]), 0); + it("maximální podsoučet [-1] se rovná 0", function() { + assert.equal(vraťMaxSoučetPodpole([-1]), 0); }); - it("maximal subsum of [-1, -2] equals 0", function() { - assert.equal(getMaxSubSum([-1, -2]), 0); + it("maximální podsoučet [-1, -2] se rovná 0", function() { + assert.equal(vraťMaxSoučetPodpole([-1, -2]), 0); }); - it("maximal subsum of [2, -8, 5, -1, 2, -3, 2] equals 6", function() { - assert.equal(getMaxSubSum([2, -8, 5, -1, 2, -3, 2]), 6); + it("maximální podsoučet [2, -8, 5, -1, 2, -3, 2] se rovná 6", function() { + assert.equal(vraťMaxSoučetPodpole([2, -8, 5, -1, 2, -3, 2]), 6); }); }); diff --git a/1-js/05-data-types/04-array/10-maximal-subarray/solution.md b/1-js/05-data-types/04-array/10-maximal-subarray/solution.md index 7e1ca3bde..279b93ec5 100644 --- a/1-js/05-data-types/04-array/10-maximal-subarray/solution.md +++ b/1-js/05-data-types/04-array/10-maximal-subarray/solution.md @@ -1,94 +1,94 @@ -# Slow solution +# Pomalé řešení -We can calculate all possible subsums. +Můžeme spočítat všechny možné podsoučty. -The simplest way is to take every element and calculate sums of all subarrays starting from it. +Nejjednodušším způsobem je vzít každý prvek a počítat součty všech podpolí, která jím začínají. -For instance, for `[-1, 2, 3, -9, 11]`: +Například pro `[-1, 2, 3, -9, 11]`: ```js no-beautify -// Starting from -1: +// Začínající -1: -1 -1 + 2 -1 + 2 + 3 -1 + 2 + 3 + (-9) -1 + 2 + 3 + (-9) + 11 -// Starting from 2: +// Začínající 2: 2 2 + 3 2 + 3 + (-9) 2 + 3 + (-9) + 11 -// Starting from 3: +// Začínající 3: 3 3 + (-9) 3 + (-9) + 11 -// Starting from -9 +// Začínající -9: -9 -9 + 11 -// Starting from 11 +// Začínající 11: 11 ``` -The code is actually a nested loop: the external loop over array elements, and the internal counts subsums starting with the current element. +Kód je ve skutečnosti vnořený cyklus: vnější cyklus prochází prvky pole, vnitřní počítá podsoučty počínaje aktuálním prvkem. ```js run -function getMaxSubSum(arr) { - let maxSum = 0; // if we take no elements, zero will be returned - - for (let i = 0; i < arr.length; i++) { - let sumFixedStart = 0; - for (let j = i; j < arr.length; j++) { - sumFixedStart += arr[j]; - maxSum = Math.max(maxSum, sumFixedStart); +function vraťMaxSoučetPodpole(pole) { + let maxSoučet = 0; // nevezmeme-li žádné prvky, vrátí se nula + + for (let i = 0; i < pole.length; i++) { + let součetPevnýZačátek = 0; + for (let j = i; j < pole.length; j++) { + součetPevnýZačátek += pole[j]; + maxSoučet = Math.max(maxSoučet, součetPevnýZačátek); } } - return maxSum; + return maxSoučet; } -alert( getMaxSubSum([-1, 2, 3, -9]) ); // 5 -alert( getMaxSubSum([-1, 2, 3, -9, 11]) ); // 11 -alert( getMaxSubSum([-2, -1, 1, 2]) ); // 3 -alert( getMaxSubSum([1, 2, 3]) ); // 6 -alert( getMaxSubSum([100, -9, 2, -3, 5]) ); // 100 +alert( vraťMaxSoučetPodpole([-1, 2, 3, -9]) ); // 5 +alert( vraťMaxSoučetPodpole([-1, 2, 3, -9, 11]) ); // 11 +alert( vraťMaxSoučetPodpole([-2, -1, 1, 2]) ); // 3 +alert( vraťMaxSoučetPodpole([1, 2, 3]) ); // 6 +alert( vraťMaxSoučetPodpole([100, -9, 2, -3, 5]) ); // 100 ``` -The solution has a time complexity of [O(n2)](https://en.wikipedia.org/wiki/Big_O_notation). In other words, if we increase the array size 2 times, the algorithm will work 4 times longer. +Toto řešení má časovou složitost [O(n2)](https://cs.wikipedia.org/wiki/Landauova_notace). Jinými slovy, když zvětšíme pole dvojnásobně, algoritmus bude pracovat čtyřikrát déle. -For big arrays (1000, 10000 or more items) such algorithms can lead to serious sluggishness. +Pro velká pole (1000, 10000 nebo více prvků) mohou takové algoritmy vést k vážnému zpomalení. -# Fast solution +# Rychlé řešení -Let's walk the array and keep the current partial sum of elements in the variable `s`. If `s` becomes negative at some point, then assign `s=0`. The maximum of all such `s` will be the answer. +Budeme procházet prvky pole a pamatovat si aktuální částečný součet prvků v proměnné `s`. Bude-li `s` v některém bodě záporné, přiřadíme `s=0`. Odpovědí bude maximum všech takových `s`. -If the description is too vague, please see the code, it's short enough: +Pokud je popis příliš vágní, prosíme nahlédněte do kódu, je dosti krátký: ```js run demo -function getMaxSubSum(arr) { - let maxSum = 0; - let partialSum = 0; - - for (let item of arr) { // for each item of arr - partialSum += item; // add it to partialSum - maxSum = Math.max(maxSum, partialSum); // remember the maximum - if (partialSum < 0) partialSum = 0; // zero if negative +function vraťMaxSoučetPodpole(pole) { + let maxSoučet = 0; + let částečnýSoučet = 0; + + for (let prvek of pole) { // pro každý prvek pole + částečnýSoučet += prvek; // přičteme jej do částečnýSoučet + maxSoučet = Math.max(maxSoučet, částečnýSoučet); // zapamatujeme si maximum + if (částečnýSoučet < 0) částečnýSoučet = 0; // je-li součet záporný, vynulujeme ho } - return maxSum; + return maxSoučet; } -alert( getMaxSubSum([-1, 2, 3, -9]) ); // 5 -alert( getMaxSubSum([-1, 2, 3, -9, 11]) ); // 11 -alert( getMaxSubSum([-2, -1, 1, 2]) ); // 3 -alert( getMaxSubSum([100, -9, 2, -3, 5]) ); // 100 -alert( getMaxSubSum([1, 2, 3]) ); // 6 -alert( getMaxSubSum([-1, -2, -3]) ); // 0 +alert( vraťMaxSoučetPodpole([-1, 2, 3, -9]) ); // 5 +alert( vraťMaxSoučetPodpole([-1, 2, 3, -9, 11]) ); // 11 +alert( vraťMaxSoučetPodpole([-2, -1, 1, 2]) ); // 3 +alert( vraťMaxSoučetPodpole([100, -9, 2, -3, 5]) ); // 100 +alert( vraťMaxSoučetPodpole([1, 2, 3]) ); // 6 +alert( vraťMaxSoučetPodpole([-1, -2, -3]) ); // 0 ``` -The algorithm requires exactly 1 array pass, so the time complexity is O(n). +Tento algoritmus vyžaduje přesně 1 průchod polem, takže jeho časová složitost je O(n). -You can find more detailed information about the algorithm here: [Maximum subarray problem](http://en.wikipedia.org/wiki/Maximum_subarray_problem). If it's still not obvious why that works, then please trace the algorithm on the examples above, see how it works, that's better than any words. +Podrobnější informace o algoritmu můžete najít zde: [Maximum subarray problem (Problém maximálního podpole)](http://en.wikipedia.org/wiki/Maximum_subarray_problem). Není-li vám stále jasné, proč to funguje, potom si prosíme projděte algoritmus na výše uvedených příkladech a podívejte se, jak funguje. Je to lepší než jakákoli slova. diff --git a/1-js/05-data-types/04-array/10-maximal-subarray/task.md b/1-js/05-data-types/04-array/10-maximal-subarray/task.md index f1a1d9f95..8e6275ff6 100644 --- a/1-js/05-data-types/04-array/10-maximal-subarray/task.md +++ b/1-js/05-data-types/04-array/10-maximal-subarray/task.md @@ -2,29 +2,29 @@ importance: 2 --- -# A maximal subarray +# Maximální podpole -The input is an array of numbers, e.g. `arr = [1, -2, 3, 4, -9, 6]`. +Na vstupu je pole čísel, např. `pole = [1, -2, 3, 4, -9, 6]`. -The task is: find the contiguous subarray of `arr` with the maximal sum of items. +Úkol zní: najděte souvislé podpole tohoto pole s maximálním součtem prvků. -Write the function `getMaxSubSum(arr)` that will return that sum. +Napište funkci `vraťMaxSoučetPodpole(pole)`, která tento součet vrátí. -For instance: +Příklad: ```js -getMaxSubSum([-1, *!*2, 3*/!*, -9]) == 5 (the sum of highlighted items) -getMaxSubSum([*!*2, -1, 2, 3*/!*, -9]) == 6 -getMaxSubSum([-1, 2, 3, -9, *!*11*/!*]) == 11 -getMaxSubSum([-2, -1, *!*1, 2*/!*]) == 3 -getMaxSubSum([*!*100*/!*, -9, 2, -3, 5]) == 100 -getMaxSubSum([*!*1, 2, 3*/!*]) == 6 (take all) +vraťMaxSoučetPodpole([-1, *!*2, 3*/!*, -9]) == 5 (součet zvýrazněných prvků) +vraťMaxSoučetPodpole([*!*2, -1, 2, 3*/!*, -9]) == 6 +vraťMaxSoučetPodpole([-1, 2, 3, -9, *!*11*/!*]) == 11 +vraťMaxSoučetPodpole([-2, -1, *!*1, 2*/!*]) == 3 +vraťMaxSoučetPodpole([*!*100*/!*, -9, 2, -3, 5]) == 100 +vraťMaxSoučetPodpole([*!*1, 2, 3*/!*]) == 6 (vezmi vše) ``` -If all items are negative, it means that we take none (the subarray is empty), so the sum is zero: +Jsou-li všechny prvky záporné, znamená to, že nevezmeme žádný (podpole je prázdné), takže součet je nulový: ```js -getMaxSubSum([-1, -2, -3]) = 0 +vraťMaxSoučetPodpole([-1, -2, -3]) = 0 ``` -Please try to think of a fast solution: [O(n2)](https://en.wikipedia.org/wiki/Big_O_notation) or even O(n) if you can. +Snažte se prosíme vymyslet rychlé řešení: [O(n2)](https://cs.wikipedia.org/wiki/Landauova_notace) nebo dokonce O(n), jestliže to dokážete. \ No newline at end of file diff --git a/1-js/05-data-types/04-array/2-create-array/solution.md b/1-js/05-data-types/04-array/2-create-array/solution.md index f032b55f0..50d9a1f7d 100644 --- a/1-js/05-data-types/04-array/2-create-array/solution.md +++ b/1-js/05-data-types/04-array/2-create-array/solution.md @@ -1,10 +1,10 @@ ```js run -let styles = ["Jazz", "Blues"]; -styles.push("Rock-n-Roll"); -styles[Math.floor((styles.length - 1) / 2)] = "Classics"; -alert( styles.shift() ); -styles.unshift("Rap", "Reggae"); +let styly = ["Jazz", "Blues"]; +styly.push("Rock-n-Roll"); +styly[Math.floor((styly.length - 1) / 2)] = "Klasika"; +alert( styly.shift() ); +styly.unshift("Rap", "Reggae"); ``` diff --git a/1-js/05-data-types/04-array/2-create-array/task.md b/1-js/05-data-types/04-array/2-create-array/task.md index d4551c79c..177d1136a 100644 --- a/1-js/05-data-types/04-array/2-create-array/task.md +++ b/1-js/05-data-types/04-array/2-create-array/task.md @@ -2,23 +2,23 @@ importance: 5 --- -# Array operations. +# Operace s poli -Let's try 5 array operations. +Zkusme provést s polem 5 operací. -1. Create an array `styles` with items "Jazz" and "Blues". -2. Append "Rock-n-Roll" to the end. -3. Replace the value in the middle with "Classics". Your code for finding the middle value should work for any arrays with odd length. -4. Strip off the first value of the array and show it. -5. Prepend `Rap` and `Reggae` to the array. +1. Vytvořte pole `styly` s prvky „Jazz“ a „Blues“. +2. Připojte na konec „Rock-n-Roll“. +3. Nahraďte prostřední hodnotu prvkem „Klasika“. Váš kód pro nalezení prostřední hodnoty by měl fungovat pro všechna pole liché délky. +4. Vyjměte z pole první hodnotu a zobrazte ji. +5. Připojte na začátek pole „Rap“ a „Reggae“. -The array in the process: +Pole během tohoto procesu: ```js no-beautify Jazz, Blues Jazz, Blues, Rock-n-Roll -Jazz, Classics, Rock-n-Roll -Classics, Rock-n-Roll -Rap, Reggae, Classics, Rock-n-Roll +Jazz, Klasika, Rock-n-Roll +Klasika, Rock-n-Roll +Rap, Reggae, Klasika, Rock-n-Roll ``` diff --git a/1-js/05-data-types/04-array/3-call-array-this/solution.md b/1-js/05-data-types/04-array/3-call-array-this/solution.md index 3cb0317cf..1cae6fc0b 100644 --- a/1-js/05-data-types/04-array/3-call-array-this/solution.md +++ b/1-js/05-data-types/04-array/3-call-array-this/solution.md @@ -1,15 +1,15 @@ -The call `arr[2]()` is syntactically the good old `obj[method]()`, in the role of `obj` we have `arr`, and in the role of `method` we have `2`. +Volání `pole[2]()` je syntakticky stará dobrá `obj[metoda]()`, v roli `obj` máme `pole` a v roli `metoda` máme `2`. -So we have a call of the function `arr[2]` as an object method. Naturally, it receives `this` referencing the object `arr` and outputs the array: +Zavolali jsme tedy funkci `pole[2]` jako objektovou metodu. Ta přirozeně obdrží `this` odkazující se na objekt `pole` a vypíše toto pole: ```js run -let arr = ["a", "b"]; +let pole = ["a", "b"]; -arr.push(function() { +pole.push(function() { alert( this ); }) -arr[2](); // a,b,function(){...} +pole[2](); // a,b,function(){...} ``` -The array has 3 values: initially it had two, plus the function. +Toto pole má 3 hodnoty: na začátku mělo dvě, plus funkce. diff --git a/1-js/05-data-types/04-array/3-call-array-this/task.md b/1-js/05-data-types/04-array/3-call-array-this/task.md index f1e13499c..e349db367 100644 --- a/1-js/05-data-types/04-array/3-call-array-this/task.md +++ b/1-js/05-data-types/04-array/3-call-array-this/task.md @@ -2,17 +2,17 @@ importance: 5 --- -# Calling in an array context +# Volání v kontextu pole -What is the result? Why? +Jaký je výsledek? Proč? ```js -let arr = ["a", "b"]; +let pole = ["a", "b"]; -arr.push(function() { +pole.push(function() { alert( this ); }); -arr[2](); // ? +pole[2](); // ? ``` diff --git a/1-js/05-data-types/04-array/5-array-input-sum/solution.md b/1-js/05-data-types/04-array/5-array-input-sum/solution.md index 75bd683b5..112db1925 100644 --- a/1-js/05-data-types/04-array/5-array-input-sum/solution.md +++ b/1-js/05-data-types/04-array/5-array-input-sum/solution.md @@ -1,28 +1,28 @@ -Please note the subtle, but important detail of the solution. We don't convert `value` to number instantly after `prompt`, because after `value = +value` we would not be able to tell an empty string (stop sign) from the zero (valid number). We do it later instead. +Prosíme všimněte si drobného, ale důležitého detailu řešení. Nepřevádíme `hodnota` na číslo okamžitě po `prompt`, jelikož po `hodnota = +hodnota` bychom neměli jak poznat prázdný řetězec (znamení konce) od nuly (platné číslo). Děláme to až později. ```js run demo -function sumInput() { +function sečtiVstup() { - let numbers = []; + let čísla = []; while (true) { - let value = prompt("A number please?", 0); + let hodnota = prompt("Číslo, prosím?", 0); - // should we cancel? - if (value === "" || value === null || !isFinite(value)) break; + // měli bychom skončit? + if (hodnota === "" || hodnota === null || !isFinite(hodnota)) break; - numbers.push(+value); + čísla.push(+hodnota); } - let sum = 0; - for (let number of numbers) { - sum += number; + let součet = 0; + for (let číslo of čísla) { + součet += číslo; } - return sum; + return součet; } -alert( sumInput() ); +alert( sečtiVstup() ); ``` diff --git a/1-js/05-data-types/04-array/5-array-input-sum/task.md b/1-js/05-data-types/04-array/5-array-input-sum/task.md index 4af8e7c95..67180115b 100644 --- a/1-js/05-data-types/04-array/5-array-input-sum/task.md +++ b/1-js/05-data-types/04-array/5-array-input-sum/task.md @@ -2,14 +2,14 @@ importance: 4 --- -# Sum input numbers +# Sečtěte čísla na vstupu -Write the function `sumInput()` that: +Napište funkci `sečtiVstup()`, která: -- Asks the user for values using `prompt` and stores the values in the array. -- Finishes asking when the user enters a non-numeric value, an empty string, or presses "Cancel". -- Calculates and returns the sum of array items. +- Bude se uživatele ptát na hodnoty pomocí `prompt` a ukládat tyto hodnoty do pole. +- Přestane se ptát, když uživatel zadá nečíselnou hodnotu, prázdný řetězec nebo stiskne „Storno“. +- Vypočítá a vrátí součet prvků pole. -P.S. A zero `0` is a valid number, please don't stop the input on zero. +P.S. Nula `0` je platné číslo, proto prosíme neukončujte vstup při nule. [demo] diff --git a/1-js/05-data-types/04-array/array-pop.svg b/1-js/05-data-types/04-array/array-pop.svg index 82b112b4a..54e80c656 100644 --- a/1-js/05-data-types/04-array/array-pop.svg +++ b/1-js/05-data-types/04-array/array-pop.svg @@ -1 +1 @@ -0123"Apple""Orange""Pear""Lemon"length = 4clear012"Apple""Orange""Pear"length = 3 \ No newline at end of file +0123"Apple""Orange""Pear""Lemon"length = 4vymazat012"Apple""Orange""Pear"length = 3 \ No newline at end of file diff --git a/1-js/05-data-types/04-array/array-shift.svg b/1-js/05-data-types/04-array/array-shift.svg index 9485a3c96..f82368324 100644 --- a/1-js/05-data-types/04-array/array-shift.svg +++ b/1-js/05-data-types/04-array/array-shift.svg @@ -1 +1 @@ -123"Orange""Pear""Lemon"length = 423"Orange""Pear""Lemon"length = 3clearmove elements to the left0"Apple"012"Orange""Pear""Lemon"11 \ No newline at end of file +123"Orange""Pear""Lemon"length = 423"Orange""Pear""Lemon"length = 3vymazatposunout prvky doleva0"Apple"012"Orange""Pear""Lemon"11 \ No newline at end of file diff --git a/1-js/05-data-types/04-array/article.md b/1-js/05-data-types/04-array/article.md index e71e86a5b..216112a2f 100644 --- a/1-js/05-data-types/04-array/article.md +++ b/1-js/05-data-types/04-array/article.md @@ -1,449 +1,449 @@ -# Arrays +# Pole -Objects allow you to store keyed collections of values. That's fine. +Objekty nám umožňují ukládat kolekci hodnot roztříděnou podle klíčů. To je pěkné. -But quite often we find that we need an *ordered collection*, where we have a 1st, a 2nd, a 3rd element and so on. For example, we need that to store a list of something: users, goods, HTML elements etc. +Poměrně často však zjišťujeme, že potřebujeme *seřazenou kolekci*, v níž máme první, druhý, třetí prvek a tak dále. Například do ní potřebujeme uložit seznam nějakých věcí: uživatelů, zboží, HTML prvků a podobně. -It is not convenient to use an object here, because it provides no methods to manage the order of elements. We can’t insert a new property “between” the existing ones. Objects are just not meant for such use. +Použít k tomu objekt se nehodí, protože ten neposkytuje žádné metody, jak ovládat pořadí prvků. Nemůžeme vložit novou vlastnost „mezi“ existující. Objekty k takovému použití prostě nejsou stavěny. -There exists a special data structure named `Array`, to store ordered collections. +K uložení seřazených kolekcí však existuje speciální datová struktura nazvaná `Array`, česky „pole“. -## Declaration +## Deklarace -There are two syntaxes for creating an empty array: +K vytvoření prázdného pole existují dvě syntaxe: ```js -let arr = new Array(); -let arr = []; +let pole = new Array(); +let pole = []; ``` -Almost all the time, the second syntax is used. We can supply initial elements in the brackets: +Téměř vždy se používá ta druhá. Do hranatých závorek můžeme uvést počáteční prvky pole: ```js -let fruits = ["Apple", "Orange", "Plum"]; +let ovoce = ["Jablko", "Pomeranč", "Švestka"]; ``` -Array elements are numbered, starting with zero. +Prvky pole jsou očíslovány a začínají nulou. -We can get an element by its number in square brackets: +Získat prvek pole můžeme tak, že uvedeme jeho číslo v hranatých závorkách: ```js run -let fruits = ["Apple", "Orange", "Plum"]; +let ovoce = ["Jablko", "Pomeranč", "Švestka"]; -alert( fruits[0] ); // Apple -alert( fruits[1] ); // Orange -alert( fruits[2] ); // Plum +alert( ovoce[0] ); // Jablko +alert( ovoce[1] ); // Pomeranč +alert( ovoce[2] ); // Švestka ``` -We can replace an element: +Můžeme nahradit prvek jiným: ```js -fruits[2] = 'Pear'; // now ["Apple", "Orange", "Pear"] +ovoce[2] = 'Hruška'; // nyní ["Jablko", "Pomeranč", "Hruška"] ``` -...Or add a new one to the array: +...Nebo přidat do pole nový prvek: ```js -fruits[3] = 'Lemon'; // now ["Apple", "Orange", "Pear", "Lemon"] +ovoce[3] = 'Citrón'; // nyní ["Jablko", "Pomeranč", "Hruška", "Citrón"] ``` -The total count of the elements in the array is its `length`: +Celkový počet prvků pole představuje jeho délku, která je uložena ve vlastnosti `length`: ```js run -let fruits = ["Apple", "Orange", "Plum"]; +let ovoce = ["Jablko", "Pomeranč", "Švestka"]; -alert( fruits.length ); // 3 +alert( ovoce.length ); // 3 ``` -We can also use `alert` to show the whole array. +Můžeme také použít `alert` k zobrazení celého pole. ```js run -let fruits = ["Apple", "Orange", "Plum"]; +let ovoce = ["Jablko", "Pomeranč", "Švestka"]; -alert( fruits ); // Apple,Orange,Plum +alert( ovoce ); // Jablko,Pomeranč,Švestka ``` -An array can store elements of any type. +Do pole lze uložit prvky jakéhokoli typu. -For instance: +Například: ```js run no-beautify -// mix of values -let arr = [ 'Apple', { name: 'John' }, true, function() { alert('hello'); } ]; +// směs hodnot +let pole = [ 'Jablko', { jméno: 'Jan' }, true, function() { alert('ahoj'); } ]; -// get the object at index 1 and then show its name -alert( arr[1].name ); // John +// získáme objekt na indexu 1 a zobrazíme jeho jméno +alert( pole[1].jméno ); // Jan -// get the function at index 3 and run it -arr[3](); // hello +// získáme funkci na indexu 3 a zavoláme ji +pole[3](); // ahoj ``` -````smart header="Trailing comma" -An array, just like an object, may end with a comma: +````smart header="Vlečná čárka" +Pole, stejně jako objekt, může končit čárkou: ```js -let fruits = [ - "Apple", - "Orange", - "Plum"*!*,*/!* +let ovoce = [ + "Jablko", + "Pomeranč", + "Švestka"*!*,*/!* ]; ``` -The "trailing comma" style makes it easier to insert/remove items, because all lines become alike. +Styl „vlečné (trailing) čárky“ zjednodušuje přidávání a odstraňování prvků, protože všechny řádky vypadají podobně. ```` -## Get last elements with "at" +## Získání posledního prvku pomocí „at“ [recent browser="new"] -Let's say we want the last element of the array. +Dejme tomu, že chceme získat poslední prvek pole. -Some programming languages allow the use of negative indexes for the same purpose, like `fruits[-1]`. +Některé programovací jazyky umožňují ke stejnému účelu použít záporné indexy, například `ovoce[-1]`. -Although, in JavaScript it won't work. The result will be `undefined`, because the index in square brackets is treated literally. +V JavaScriptu to však nefunguje. Výsledek bude `undefined`, protože index v hranatých závorkách se zpracovává tak, jak je uveden. -We can explicitly calculate the last element index and then access it: `fruits[fruits.length - 1]`. +Můžeme výslovně vypočítat index posledního prvku a pak jej použít: `ovoce[ovoce.length - 1]`. ```js run -let fruits = ["Apple", "Orange", "Plum"]; +let ovoce = ["Jablko", "Pomeranč", "Švestka"]; -alert( fruits[fruits.length-1] ); // Plum +alert( ovoce[ovoce.length-1] ); // Švestka ``` -A bit cumbersome, isn't it? We need to write the variable name twice. +Trochu těžkopádné, že? Musíme napsat název proměnné dvakrát. -Luckily, there's a shorter syntax: `fruits.at(-1)`: +Naštěstí existuje kratší syntaxe: `ovoce.at(-1)`: ```js run -let fruits = ["Apple", "Orange", "Plum"]; +let ovoce = ["Jablko", "Pomeranč", "Švestka"]; -// same as fruits[fruits.length-1] -alert( fruits.at(-1) ); // Plum +// totéž jako ovoce[ovoce.length-1] +alert( ovoce.at(-1) ); // Švestka ``` -In other words, `arr.at(i)`: -- is exactly the same as `arr[i]`, if `i >= 0`. -- for negative values of `i`, it steps back from the end of the array. +Jinými slovy, `pole.at(i)`: +- je přesně totéž jako `pole[i]`, je-li `i >= 0`. +- pro záporné hodnoty `i` postupuje od konce pole nazpátek. -## Methods pop/push, shift/unshift +## Metody pop/push, shift/unshift -A [queue](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)) is one of the most common uses of an array. In computer science, this means an ordered collection of elements which supports two operations: +Jedním z nejběžnějších využití pole je [fronta](https://cs.wikipedia.org/wiki/Fronta_(datová_struktura)). V informatice znamená seřazenou kolekci prvků, která podporuje dvě operace: -- `push` appends an element to the end. -- `shift` get an element from the beginning, advancing the queue, so that the 2nd element becomes the 1st. +- `push` připojí prvek na konec. +- `shift` vezme prvek ze začátku a posune frontu, takže druhý prvek se stane prvním. ![](queue.svg) -Arrays support both operations. +Pole podporují obě operace. -In practice we need it very often. For example, a queue of messages that need to be shown on-screen. +V praxi ji potřebujeme velmi často. Máme například frontu zpráv, které musíme zobrazit na obrazovce. -There's another use case for arrays -- the data structure named [stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)). +Dalším využitím polí je datová struktura nazvaná [zásobník](https://cs.wikipedia.org/wiki/Zásobník_(datová_struktura)). -It supports two operations: +Podporuje dvě operace: -- `push` adds an element to the end. -- `pop` takes an element from the end. +- `push` přidá prvek na konec. +- `pop` vezme prvek z konce. -So new elements are added or taken always from the "end". +Nové prvky se tedy vždy přidávají a odebírají z „konce“. -A stack is usually illustrated as a pack of cards: new cards are added to the top or taken from the top: +Zásobník se obvykle ilustruje jako balíček karet: nové karty se přidávají na vrch a berou se z vrchu: ![](stack.svg) -For stacks, the latest pushed item is received first, that's also called LIFO (Last-In-First-Out) principle. For queues, we have FIFO (First-In-First-Out). +U zásobníků se naposledy vložený prvek odebírá jako první. Tento princip se také nazývá LIFO (Last-In-First-Out, česky „poslední dovnitř, první ven“). U fronty máme princip FIFO (First-In-First-Out, česky „první dovnitř, první ven“). -Arrays in JavaScript can work both as a queue and as a stack. They allow you to add/remove elements, both to/from the beginning or the end. +Pole v JavaScriptu mohou fungovat jako fronta i jako zásobník. Umožňují nám přidávat/odebírat prvky do/ze začátku i konce. -In computer science, the data structure that allows this, is called [deque](https://en.wikipedia.org/wiki/Double-ended_queue). +Datová struktura, která to umožňuje, se v informatice nazývá [deque](https://en.wikipedia.org/wiki/Double-ended_queue) („double-ended queue“ -- „fronta s dvojitým koncem“). -**Methods that work with the end of the array:** +**Metody, které pracují s koncem pole:** `pop` -: Extracts the last element of the array and returns it: +: Vyjme z pole poslední prvek a vrátí jej: ```js run - let fruits = ["Apple", "Orange", "Pear"]; + let ovoce = ["Jablko", "Pomeranč", "Hruška"]; - alert( fruits.pop() ); // remove "Pear" and alert it + alert( ovoce.pop() ); // odstraní prvek "Hruška" a zobrazí jej - alert( fruits ); // Apple, Orange + alert( ovoce ); // Jablko, Pomeranč ``` - Both `fruits.pop()` and `fruits.at(-1)` return the last element of the array, but `fruits.pop()` also modifies the array by removing it. + Obě metody `ovoce.pop()` i `ovoce.at(-1)` vracejí poslední prvek pole, ale `ovoce.pop()` navíc změní pole tím, že tento prvek odstraní. `push` -: Append the element to the end of the array: +: Připojí prvek na konec pole: ```js run - let fruits = ["Apple", "Orange"]; + let ovoce = ["Jablko", "Pomeranč"]; - fruits.push("Pear"); + ovoce.push("Hruška"); - alert( fruits ); // Apple, Orange, Pear + alert( ovoce ); // Jablko, Pomeranč, Hruška ``` - The call `fruits.push(...)` is equal to `fruits[fruits.length] = ...`. + Volání `ovoce.push(...)` se rovná volání `ovoce[ovoce.length] = ...`. -**Methods that work with the beginning of the array:** +**Metody, které pracují se začátkem pole:** `shift` -: Extracts the first element of the array and returns it: +: Vyjme první prvek z pole a vrátí jej: ```js run - let fruits = ["Apple", "Orange", "Pear"]; + let ovoce = ["Jablko", "Pomeranč", "Hruška"]; - alert( fruits.shift() ); // remove Apple and alert it + alert( ovoce.shift() ); // odstraní prvek Jablko a zobrazí jej - alert( fruits ); // Orange, Pear + alert( ovoce ); // Pomeranč, Hruška ``` `unshift` -: Add the element to the beginning of the array: +: Přidá prvek na začátek pole: ```js run - let fruits = ["Orange", "Pear"]; + let ovoce = ["Pomeranč", "Hruška"]; - fruits.unshift('Apple'); + ovoce.unshift('Jablko'); - alert( fruits ); // Apple, Orange, Pear + alert( ovoce ); // Jablko, Pomeranč, Hruška ``` -Methods `push` and `unshift` can add multiple elements at once: +Metody `push` a `unshift` mohou přidávat více prvků najednou: ```js run -let fruits = ["Apple"]; +let ovoce = ["Jablko"]; -fruits.push("Orange", "Peach"); -fruits.unshift("Pineapple", "Lemon"); +ovoce.push("Pomeranč", "Broskev"); +ovoce.unshift("Ananas", "Citrón"); -// ["Pineapple", "Lemon", "Apple", "Orange", "Peach"] -alert( fruits ); +// ["Ananas", "Citrón", "Jablko", "Pomeranč", "Broskev"] +alert( ovoce ); ``` -## Internals +## Vnitřní reprezentace -An array is a special kind of object. The square brackets used to access a property `arr[0]` actually come from the object syntax. That's essentially the same as `obj[key]`, where `arr` is the object, while numbers are used as keys. +Pole je speciální druh objektu. Hranaté závorky, kterými se přistupuje k vlastnosti `pole[0]`, ve skutečnosti pocházejí ze syntaxe objektu. Je to v zásadě totéž jako `objekt[klíč]`, kde objektem je `pole`, zatímco jako klíče se používají čísla. -They extend objects providing special methods to work with ordered collections of data and also the `length` property. But at the core it's still an object. +Pole rozšiřují objekty pomocí speciálních metod, které pracují se seřazenými kolekcemi dat, a vlastnosti `length`. V jádru jsou to však stále objekty. -Remember, there are only eight basic data types in JavaScript (see the [Data types](info:types) chapter for more info). Array is an object and thus behaves like an object. +Pamatujte, že v JavaScriptu je pouze osm základních datových typů (pro více informací viz kapitolu [Datové typy](info:types)). Pole je objekt, a proto se chová jako objekt. -For instance, it is copied by reference: +Například je kopírováno odkazem: ```js run -let fruits = ["Banana"] +let ovoce = ["Banán"] -let arr = fruits; // copy by reference (two variables reference the same array) +let pole = ovoce; // kopírování odkazem (dvě proměnné se odkazují na stejné pole) -alert( arr === fruits ); // true +alert( pole === ovoce ); // true -arr.push("Pear"); // modify the array by reference +pole.push("Hruška"); // modifikace pole odkazem -alert( fruits ); // Banana, Pear - 2 items now +alert( ovoce ); // Banán, Hruška - nyní 2 prvky ``` -...But what makes arrays really special is their internal representation. The engine tries to store its elements in the contiguous memory area, one after another, just as depicted on the illustrations in this chapter, and there are other optimizations as well, to make arrays work really fast. +...Avšak to, co činí pole opravdu speciálními, je jejich vnitřní reprezentace. Motor se snaží ukládat prvky pole do souvislé oblasti v paměti, jeden za druhým, jak je zobrazeno na obrázcích v této kapitole. Existují i jiné optimalizace, které způsobují, že pole fungují opravdu rychle. -But they all break if we quit working with an array as with an "ordered collection" and start working with it as if it were a regular object. +Ty se však všechny rozbijí, jestliže přestaneme pracovat s polem jako se „seřazenou kolekcí“ a začneme s ním pracovat tak, jako by to byl běžný objekt. -For instance, technically we can do this: +Například technicky můžeme udělat tohle: ```js -let fruits = []; // make an array +let ovoce = []; // vytvoříme pole -fruits[99999] = 5; // assign a property with the index far greater than its length +ovoce[99999] = 5; // přidáme vlastnost s indexem daleko větším, než jeho délka -fruits.age = 25; // create a property with an arbitrary name +ovoce.věk = 25; // vytvoříme vlastnost s libovolným názvem ``` -That's possible, because arrays are objects at their base. We can add any properties to them. +To je možné, protože pole jsou od základu objekty. Můžeme do nich přidávat jakékoli vlastnosti. -But the engine will see that we're working with the array as with a regular object. Array-specific optimizations are not suited for such cases and will be turned off, their benefits disappear. +Avšak motor uvidí, že s polem pracujeme jako s běžným objektem. Optimalizace specifické pro pole nejsou pro takové případy uzpůsobeny, a tak budou vypnuty a jejich výhody zmizí. -The ways to misuse an array: +Způsoby nesprávného používání pole: -- Add a non-numeric property like `arr.test = 5`. -- Make holes, like: add `arr[0]` and then `arr[1000]` (and nothing between them). -- Fill the array in the reverse order, like `arr[1000]`, `arr[999]` and so on. +- Přidání nečíselné vlastnosti, např. `pole.test = 5`. +- Vytváření děr, např. přidáme `pole[0]` a pak `pole[1000]` (a nic mezi nimi). +- Zaplňování pole v obráceném pořadí, např. `pole[1000]`, `pole[999]` a tak dále. -Please think of arrays as special structures to work with the *ordered data*. They provide special methods for that. Arrays are carefully tuned inside JavaScript engines to work with contiguous ordered data, please use them this way. And if you need arbitrary keys, chances are high that you actually require a regular object `{}`. +Prosíme, považujte pole za speciální struktury, které pracují se *seřazenými daty*. Poskytují pro ně speciální metody. V JavaScriptových motorech jsou pole pečlivě vyladěna, aby pracovala se spojitými seřazenými daty, a tak je prosíme používejte tímto způsobem. Budete-li potřebovat libovolné klíče, je velmi pravděpodobné, že ve skutečnosti potřebujete běžný objekt `{}`. -## Performance +## Výkon -Methods `push/pop` run fast, while `shift/unshift` are slow. +Metody `push/pop` běží rychle, zatímco `shift/unshift` jsou pomalé. ![](array-speed.svg) -Why is it faster to work with the end of an array than with its beginning? Let's see what happens during the execution: +Proč je rychlejší pracovat s koncem pole než s jeho začátkem? Podívejme se, co se děje při provádění metod: ```js -fruits.shift(); // take 1 element from the start +ovoce.shift(); // odebere 1 prvek ze začátku ``` -It's not enough to take and remove the element with the index `0`. Other elements need to be renumbered as well. +Nestačí vzít a odstranit prvek s indexem `0`. Je třeba také přečíslovat ostatní prvky. -The `shift` operation must do 3 things: +Operace `shift` musí provést 3 věci: -1. Remove the element with the index `0`. -2. Move all elements to the left, renumber them from the index `1` to `0`, from `2` to `1` and so on. -3. Update the `length` property. +1. Odstranit prvek s indexem `0`. +2. Posunout všechny prvky doleva a přečíslovat je z indexu `1` na `0`, z `2` na `1` a tak dále. +3. Upravit vlastnost `length`. ![](array-shift.svg) -**The more elements in the array, the more time to move them, more in-memory operations.** +**Čím více prvků pole obsahuje, tím více času a paměťových operací zabere jejich přesun.** -The similar thing happens with `unshift`: to add an element to the beginning of the array, we need first to move existing elements to the right, increasing their indexes. +Podobná věc se děje při `unshift`: abychom přidali prvek na začátek pole, musíme napřed posunout existující prvky doprava a zvýšit jejich indexy. -And what's with `push/pop`? They do not need to move anything. To extract an element from the end, the `pop` method cleans the index and shortens `length`. +A jak je to s `push/pop`? Ty nemusejí nic posunovat. Metoda `pop` vyjme prvek z konce tak, že smaže jeho index a zkrátí `length`. -The actions for the `pop` operation: +Akce pro operaci `pop`: ```js -fruits.pop(); // take 1 element from the end +ovoce.pop(); // odebere 1 prvek z konce ``` ![](array-pop.svg) -**The `pop` method does not need to move anything, because other elements keep their indexes. That's why it's blazingly fast.** +**Metoda `pop` nemusí nic posunovat, jelikož indexy ostatních prvků zůstanou zachovány. Proto je bleskově rychlá.** -The similar thing with the `push` method. +Podobně je tomu u metody `push`. -## Loops +## Cykly -One of the oldest ways to cycle array items is the `for` loop over indexes: +Jeden z nejstarších způsobů, jak procházet prvky pole, je cyklus `for` nad jeho indexy: ```js run -let arr = ["Apple", "Orange", "Pear"]; +let pole = ["Jablko", "Pomeranč", "Hruška"]; *!* -for (let i = 0; i < arr.length; i++) { +for (let i = 0; i < pole.length; i++) { */!* - alert( arr[i] ); + alert( pole[i] ); } ``` -But for arrays there is another form of loop, `for..of`: +Pro pole však existuje i jiná forma cyklu, `for..of`: ```js run -let fruits = ["Apple", "Orange", "Plum"]; +let ovoce = ["Jablko", "Pomeranč", "Švestka"]; -// iterates over array elements -for (let fruit of fruits) { - alert( fruit ); +// prochází prvky pole +for (let jednoOvoce of ovoce) { + alert( jednoOvoce ); } ``` -The `for..of` doesn't give access to the number of the current element, just its value, but in most cases that's enough. And it's shorter. +Cyklus `for..of` neposkytuje přístup k indexu aktuálního prvku, jen jeho hodnotu, ale ve většině případů to stačí. A je to kratší. -Technically, because arrays are objects, it is also possible to use `for..in`: +Protože pole jsou objekty, je technicky možné použít i `for..in`: ```js run -let arr = ["Apple", "Orange", "Pear"]; +let pole = ["Jablko", "Pomeranč", "Hruška"]; *!* -for (let key in arr) { +for (let klíč in pole) { */!* - alert( arr[key] ); // Apple, Orange, Pear + alert( pole[klíč] ); // Jablko, Pomeranč, Hruška } ``` -But that's actually a bad idea. There are potential problems with it: +Ve skutečnosti je to však špatný nápad. Mohou s ním nastat problémy: -1. The loop `for..in` iterates over *all properties*, not only the numeric ones. +1. Cyklus `for..in` prochází *všechny vlastnosti*, nejenom číselné. - There are so-called "array-like" objects in the browser and in other environments, that *look like arrays*. That is, they have `length` and indexes properties, but they may also have other non-numeric properties and methods, which we usually don't need. The `for..in` loop will list them though. So if we need to work with array-like objects, then these "extra" properties can become a problem. + V prohlížeči a v jiných prostředích existují tzv. „polím podobné“ objekty, které *vypadají jako pole*. To znamená, že mají vlastnost `length` a indexové vlastnosti, ale mohou mít také jiné nečíselné vlastnosti a metody, které obvykle nepotřebujeme. Avšak cyklus `for..in` je prochází. Když tedy potřebujeme pracovat s objekty podobnými polím, tyto vlastnosti „navíc“ mohou představovat problém. -2. The `for..in` loop is optimized for generic objects, not arrays, and thus is 10-100 times slower. Of course, it's still very fast. The speedup may only matter in bottlenecks. But still we should be aware of the difference. +2. Cyklus `for..in` je optimalizován pro generické objekty, ne pro pole, a tak je 10-100krát pomalejší. Samozřejmě je stále velmi rychlý, zpomalení se může projevit jen na kritických místech. Měli bychom si však být tohoto rozdílu vědomi. -Generally, we shouldn't use `for..in` for arrays. +Obecně bychom neměli `for..in` používat pro pole. -## A word about "length" +## Něco o „length“ -The `length` property automatically updates when we modify the array. To be precise, it is actually not the count of values in the array, but the greatest numeric index plus one. +Když modifikujeme pole, vlastnost `length` se automaticky aktualizuje. Abychom byli přesní, ve skutečnosti to není počet hodnot v poli, ale nejvyšší číselný index plus jedna. -For instance, a single element with a large index gives a big length: +Například jediný prvek s velkým indexem způsobí, že `length` bude vysoká: ```js run -let fruits = []; -fruits[123] = "Apple"; +let ovoce = []; +ovoce[123] = "Jablko"; -alert( fruits.length ); // 124 +alert( ovoce.length ); // 124 ``` -Note that we usually don't use arrays like that. +Všimněte si, že pole obvykle takto nepoužíváme. -Another interesting thing about the `length` property is that it's writable. +Další zajímavostí na vlastnosti `length` je, že do ní lze zapisovat. -If we increase it manually, nothing interesting happens. But if we decrease it, the array is truncated. The process is irreversible, here's the example: +Když ji ručně zvýšíme, nestane se nic zajímavého. Ale když ji snížíme, pole bude zkráceno. Tento proces je nezvratný, viz příklad: ```js run -let arr = [1, 2, 3, 4, 5]; +let pole = [1, 2, 3, 4, 5]; -arr.length = 2; // truncate to 2 elements -alert( arr ); // [1, 2] +pole.length = 2; // zkrácení na 2 prvky +alert( pole ); // [1, 2] -arr.length = 5; // return length back -alert( arr[3] ); // undefined: the values do not return +pole.length = 5; // vrátíme délku zpět +alert( pole[3] ); // undefined: hodnoty se nevrátily ``` -So, the simplest way to clear the array is: `arr.length = 0;`. +Nejjednodušší způsob, jak pole vyčistit, je tedy `pole.length = 0;`. ## new Array() [#new-array] -There is one more syntax to create an array: +Existuje ještě jedna syntaxe, jak vytvořit pole: ```js -let arr = *!*new Array*/!*("Apple", "Pear", "etc"); +let pole = *!*new Array*/!*("Jablko", "Hruška", "atd."); ``` -It's rarely used, because square brackets `[]` are shorter. Also, there's a tricky feature with it. +Používá se jen zřídka, protože hranaté závorky `[]` jsou kratší. Navíc má jednu ošidnou vlastnost. -If `new Array` is called with a single argument which is a number, then it creates an array *without items, but with the given length*. +Pokud `new Array` voláme s jediným argumentem, kterým je číslo, pak vytvoří pole *bez prvků, ale se zadanou délkou*. -Let's see how one can shoot themselves in the foot: +Podívejme se, jak se můžeme snadno postřelit: ```js run -let arr = new Array(2); // will it create an array of [2] ? +let pole = new Array(2); // vznikne pole [2] ? -alert( arr[0] ); // undefined! no elements. +alert( pole[0] ); // undefined! bez prvků. -alert( arr.length ); // length 2 +alert( pole.length ); // délka 2 ``` -To avoid such surprises, we usually use square brackets, unless we really know what we're doing. +Abychom předešli takovým překvapením, používáme zpravidla hranaté závorky, kromě případů, kdy opravdu dobře víme, co děláme. -## Multidimensional arrays +## Vícerozměrná pole -Arrays can have items that are also arrays. We can use it for multidimensional arrays, for example to store matrices: +Prvky obsažené v poli mohou být také pole. To můžeme využít pro vytváření vícerozměrných polí, například pro ukládání matic: ```js run -let matrix = [ +let matice = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]; -alert( matrix[0][1] ); // 2, the second value of the first inner array +alert( matice[0][1] ); // 2, druhá hodnota prvního vnitřního pole ``` ## toString -Arrays have their own implementation of `toString` method that returns a comma-separated list of elements. +Pole mají svou vlastní implementaci metody `toString`, která vrátí seznam prvků oddělených čárkou. -For instance: +Příklad: ```js run -let arr = [1, 2, 3]; +let pole = [1, 2, 3]; -alert( arr ); // 1,2,3 -alert( String(arr) === '1,2,3' ); // true +alert( pole ); // 1,2,3 +alert( String(pole) === '1,2,3' ); // true ``` -Also, let's try this: +Zkuste také tohle: ```js run alert( [] + 1 ); // "1" @@ -451,9 +451,9 @@ alert( [1] + 1 ); // "11" alert( [1,2] + 1 ); // "1,21" ``` -Arrays do not have `Symbol.toPrimitive`, neither a viable `valueOf`, they implement only `toString` conversion, so here `[]` becomes an empty string, `[1]` becomes `"1"` and `[1,2]` becomes `"1,2"`. +Pole nemají `Symbol.toPrimitive` ani životaschopné `valueOf`, implementují jedině konverzi `toString`, takže `[]` se převede na prázdný řetězec, `[1]` se převede na `"1"` a `[1,2]` se převede na `"1,2"`. -When the binary plus `"+"` operator adds something to a string, it converts it to a string as well, so the next step looks like this: +Když operátor binárního plus `"+"` přičítá k řetězci něco jiného, převede to také na řetězec, takže další krok vypadá následovně: ```js run alert( "" + 1 ); // "1" @@ -461,31 +461,31 @@ alert( "1" + 1 ); // "11" alert( "1,2" + 1 ); // "1,21" ``` -## Don't compare arrays with == +## Neporovnávejte pole pomocí == -Arrays in JavaScript, unlike some other programming languages, shouldn't be compared with operator `==`. +Pole v JavaScriptu, na rozdíl od jiných programovacích jazyků, by neměla být porovnávána operátorem `==`. -This operator has no special treatment for arrays, it works with them as with any objects. +Tento operátor neobsahuje žádné zvláštní zacházení s poli a pracuje s nimi jako s kterýmikoli jinými objekty. -Let's recall the rules: +Připomeňme si pravidla: -- Two objects are equal `==` only if they're references to the same object. -- If one of the arguments of `==` is an object, and the other one is a primitive, then the object gets converted to primitive, as explained in the chapter . -- ...With an exception of `null` and `undefined` that equal `==` each other and nothing else. +- Dva objekty jsou si rovny `==`, jedině když to jsou odkazy na tentýž objekt. +- Je-li jeden z argumentů `==` objekt a druhý je primitiv, objekt bude konvertován na primitiv, jak bylo vysvětleno v kapitole . +- ...Výjimkou jsou `null` a `undefined`, které se rovnají `==` sobě navzájem a ničemu jinému. -The strict comparison `===` is even simpler, as it doesn't convert types. +Striktní porovnání `===` je ještě jednodušší, jelikož neprovádí typovou konverzi. -So, if we compare arrays with `==`, they are never the same, unless we compare two variables that reference exactly the same array. +Když tedy porovnáváme pole pomocí `==`, nejsou si nikdy rovna, pokud neporovnáváme dvě proměnné, které odkazují na jedno a totéž pole. -For example: +Příklad: ```js run alert( [] == [] ); // false alert( [0] == [0] ); // false ``` -These arrays are technically different objects. So they aren't equal. The `==` operator doesn't do item-by-item comparison. +Tato pole jsou technicky různé objekty. Proto si nejsou rovna. Operátor `==` neprovádí porovnání prvek po prvku. -Comparison with primitives may give seemingly strange results as well: +Také porovnání s primitivy mohou vydat zdánlivě podivné výsledky: ```js run alert( 0 == [] ); // true @@ -493,59 +493,59 @@ alert( 0 == [] ); // true alert('0' == [] ); // false ``` -Here, in both cases, we compare a primitive with an array object. So the array `[]` gets converted to primitive for the purpose of comparison and becomes an empty string `''`. +V obou případech zde porovnáváme primitiv s objektem pole. Pro účely porovnávání je tedy pole `[]` konvertováno na primitiv a stane se z něj prázdný řetězec `''`. -Then the comparison process goes on with the primitives, as described in the chapter : +Pak proces porovnávání pokračuje na primitivech, jak je popsáno v kapitole : ```js run -// after [] was converted to '' -alert( 0 == '' ); // true, as '' becomes converted to number 0 +// poté, co [] bylo konvertováno na '' +alert( 0 == '' ); // true, jelikož '' bude konvertováno na číslo 0 -alert('0' == '' ); // false, no type conversion, different strings +alert('0' == '' ); // false, žádná typová konverze, různé řetězce ``` -So, how to compare arrays? +Jak tedy porovnávat pole? -That's simple: don't use the `==` operator. Instead, compare them item-by-item in a loop or using iteration methods explained in the next chapter. +Je to jednoduché: nepoužívejte operátor `==`. Místo toho je porovnávejte prvek po prvku v cyklu nebo pomocí iteračních metod, které budou vysvětleny v další kapitole. -## Summary +## Shrnutí -Array is a special kind of object, suited to storing and managing ordered data items. +Pole je speciální druh objektu, uzpůsobený k ukládání a spravování seřazených datových prvků. -The declaration: +Deklarace: ```js -// square brackets (usual) -let arr = [item1, item2...]; +// hranaté závorky (obvyklé) +let pole = [prvek1, prvek2...]; -// new Array (exceptionally rare) -let arr = new Array(item1, item2...); +// new Array (výjimečně vzácné) +let pole = new Array(prvek1, prvek2...); ``` -The call to `new Array(number)` creates an array with the given length, but without elements. +Volání `new Array(číslo)` vytvoří pole o zadané délce, ale bez prvků. -- The `length` property is the array length or, to be precise, its last numeric index plus one. It is auto-adjusted by array methods. -- If we shorten `length` manually, the array is truncated. +- Vlastnost `length` je délka pole neboli, abychom byli přesní, jeho poslední číselný index plus jedna. Metody pole ji automaticky aktualizují. +- Snížíme-li `length` ručně, pole bude zkráceno. -Getting the elements: +Získávání prvků: -- we can get element by its index, like `arr[0]` -- also we can use `at(i)` method that allows negative indexes. For negative values of `i`, it steps back from the end of the array. If `i >= 0`, it works same as `arr[i]`. +- můžeme získat prvek podle jeho indexu, například `pole[0]` +- můžeme také použít metodu `at(i)`, která umožňuje záporné indexy. Pro záporné hodnoty `i` postupuje zpětně od konce pole. Je-li `i >= 0`, funguje stejně jako `pole[i]`. -We can use an array as a deque with the following operations: +Pole můžeme používat jako deque (frontu s dvojitým koncem) s následujícími operacemi: -- `push(...items)` adds `items` to the end. -- `pop()` removes the element from the end and returns it. -- `shift()` removes the element from the beginning and returns it. -- `unshift(...items)` adds `items` to the beginning. +- `push(...prvky)` přidá `prvky` na konec. +- `pop()` odstraní prvek z konce a vrátí jej. +- `shift()` odstraní prvek ze začátku a vrátí jej. +- `unshift(...prvky)` přidá `prvky` na začátek. -To loop over the elements of the array: - - `for (let i=0; i`, `<` and others), as they have no special treatment for arrays. They handle them as any objects, and it's not what we usually want. +Pro porovnávání polí nepoužívejte operátor `==` (stejně jako `>`, `<` a jiné), jelikož tyto operátory neobsahují žádné zvláštní zacházení s poli. Zacházejí s nimi jako s objekty, což není obvykle to, co chceme. -Instead you can use `for..of` loop to compare arrays item-by-item. +Místo toho můžete použít cyklus `for..of` a porovnávat pole prvek po prvku. -We will continue with arrays and study more methods to add, remove, extract elements and sort arrays in the next chapter . +V další kapitole budeme s poli pokračovat a prostudujeme další metody, jak přidávat, odstraňovat a vybírat prvky a jak pole řadit. \ No newline at end of file diff --git a/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js b/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js index 490f570ad..dfaadb742 100644 --- a/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js +++ b/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js @@ -1,10 +1,10 @@ -function camelize(str) { - return str - .split('-') // splits 'my-long-word' into array ['my', 'long', 'word'] +function camelizace(řetězec) { + return řetězec + .split('-') // rozdělí 'mé-dlouhé-slovo' na pole ['mé', 'dlouhé', 'slovo'] .map( - // capitalizes first letters of all array items except the first one - // converts ['my', 'long', 'word'] into ['my', 'Long', 'Word'] - (word, index) => index == 0 ? word : word[0].toUpperCase() + word.slice(1) + // převede první písmena všech prvků pole kromě prvního na velká + // převede ['mé', 'dlouhé', 'slovo'] na ['mé', 'Dlouhé', 'Slovo'] + (slovo, index) => index == 0 ? slovo : slovo[0].toUpperCase() + slovo.slice(1) ) - .join(''); // joins ['my', 'Long', 'Word'] into 'myLongWord' + .join(''); // spojí ['mé', 'Dlouhé', 'Slovo'] do 'méDlouhéSlovo' } diff --git a/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/test.js b/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/test.js index bcf5e9555..35a47c4b4 100644 --- a/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/test.js +++ b/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/test.js @@ -1,19 +1,19 @@ -describe("camelize", function() { +describe("camelizace", function() { - it("leaves an empty line as is", function() { - assert.equal(camelize(""), ""); + it("prázdný řádek nechá tak, jak je", function() { + assert.equal(camelizace(""), ""); }); - it("turns background-color into backgroundColor", function() { - assert.equal(camelize("background-color"), "backgroundColor"); + it("změní background-color na backgroundColor", function() { + assert.equal(camelizace("background-color"), "backgroundColor"); }); - it("turns list-style-image into listStyleImage", function() { - assert.equal(camelize("list-style-image"), "listStyleImage"); + it("změní list-style-image na listStyleImage", function() { + assert.equal(camelizace("list-style-image"), "listStyleImage"); }); - it("turns -webkit-transition into WebkitTransition", function() { - assert.equal(camelize("-webkit-transition"), "WebkitTransition"); + it("změní -webkit-transition na WebkitTransition", function() { + assert.equal(camelizace("-webkit-transition"), "WebkitTransition"); }); }); \ No newline at end of file diff --git a/1-js/05-data-types/05-array-methods/1-camelcase/task.md b/1-js/05-data-types/05-array-methods/1-camelcase/task.md index ef5944636..328a04684 100644 --- a/1-js/05-data-types/05-array-methods/1-camelcase/task.md +++ b/1-js/05-data-types/05-array-methods/1-camelcase/task.md @@ -2,18 +2,18 @@ importance: 5 --- -# Translate border-left-width to borderLeftWidth +# Změňte border-left-width na borderLeftWidth -Write the function `camelize(str)` that changes dash-separated words like "my-short-string" into camel-cased "myShortString". +Napište funkci `camelizace(řetězec)`, která změní slova oddělená pomlčkou, např. „můj-krátký-řetězec“, na velbloudí notaci „můjKrátkýŘetězec“. -That is: removes all dashes, each word after dash becomes uppercased. +To znamená, že odstraní všechny pomlčky a u všech slov za pomlčkami změní první písmeno na velké. -Examples: +Příklad: ```js -camelize("background-color") == 'backgroundColor'; -camelize("list-style-image") == 'listStyleImage'; -camelize("-webkit-transition") == 'WebkitTransition'; +camelizace("background-color") == 'backgroundColor'; +camelizace("list-style-image") == 'listStyleImage'; +camelizace("-webkit-transition") == 'WebkitTransition'; ``` -P.S. Hint: use `split` to split the string into an array, transform it and `join` back. +P.S. Rada: použijte `split` pro rozdělení řetězce na pole, přeměňte je a spojte zpět pomocí `join`. diff --git a/1-js/05-data-types/05-array-methods/10-average-age/solution.md b/1-js/05-data-types/05-array-methods/10-average-age/solution.md index f5d4df931..646c164c1 100644 --- a/1-js/05-data-types/05-array-methods/10-average-age/solution.md +++ b/1-js/05-data-types/05-array-methods/10-average-age/solution.md @@ -1,14 +1,14 @@ ```js run -function getAverageAge(users) { - return users.reduce((prev, user) => prev + user.age, 0) / users.length; +function vraťPrůměrnýVěk(uživatelé) { + return uživatelé.reduce((předchozí, uživatel) => předchozí + uživatel.věk, 0) / uživatelé.length; } -let john = { name: "John", age: 25 }; -let pete = { name: "Pete", age: 30 }; -let mary = { name: "Mary", age: 29 }; +let jan = { jméno: "Jan", věk: 25 }; +let petr = { jméno: "Petr", věk: 30 }; +let marie = { jméno: "Marie", věk: 29 }; -let arr = [ john, pete, mary ]; +let pole = [ jan, petr, marie ]; -alert( getAverageAge(arr) ); // 28 +alert( vraťPrůměrnýVěk(pole) ); // 28 ``` diff --git a/1-js/05-data-types/05-array-methods/10-average-age/task.md b/1-js/05-data-types/05-array-methods/10-average-age/task.md index bf5f85df3..b5a986f13 100644 --- a/1-js/05-data-types/05-array-methods/10-average-age/task.md +++ b/1-js/05-data-types/05-array-methods/10-average-age/task.md @@ -2,20 +2,20 @@ importance: 4 --- -# Get average age +# Zjištění průměrného věku -Write the function `getAverageAge(users)` that gets an array of objects with property `age` and returns the average age. +Napište funkci `vraťPrůměrnýVěk(uživatelé)`, která obdrží pole objektů s vlastností `věk` a vrátí průměrný věk. -The formula for the average is `(age1 + age2 + ... + ageN) / N`. +Vzorec pro výpočet průměru je `(věk1 + věk2 + ... + věkN) / N`. -For instance: +Příklad: ```js no-beautify -let john = { name: "John", age: 25 }; -let pete = { name: "Pete", age: 30 }; -let mary = { name: "Mary", age: 29 }; +let jan = { jméno: "Jan", věk: 25 }; +let petr = { jméno: "Petr", věk: 30 }; +let marie = { jméno: "Marie", věk: 29 }; -let arr = [ john, pete, mary ]; +let pole = [ jan, petr, marie ]; -alert( getAverageAge(arr) ); // (25 + 30 + 29) / 3 = 28 +alert( vraťPrůměrnýVěk(pole) ); // (25 + 30 + 29) / 3 = 28 ``` diff --git a/1-js/05-data-types/05-array-methods/11-array-unique/_js.view/solution.js b/1-js/05-data-types/05-array-methods/11-array-unique/_js.view/solution.js index d15cea2c7..c38edc5a5 100644 --- a/1-js/05-data-types/05-array-methods/11-array-unique/_js.view/solution.js +++ b/1-js/05-data-types/05-array-methods/11-array-unique/_js.view/solution.js @@ -1,11 +1,11 @@ -function unique(arr) { - let result = []; +function unikát(pole) { + let výsledek = []; - for (let str of arr) { - if (!result.includes(str)) { - result.push(str); + for (let řetězec of pole) { + if (!výsledek.includes(řetězec)) { + výsledek.push(řetězec); } } - return result; + return výsledek; } diff --git a/1-js/05-data-types/05-array-methods/11-array-unique/_js.view/test.js b/1-js/05-data-types/05-array-methods/11-array-unique/_js.view/test.js index cfc7b1fc3..f196ad2bb 100644 --- a/1-js/05-data-types/05-array-methods/11-array-unique/_js.view/test.js +++ b/1-js/05-data-types/05-array-methods/11-array-unique/_js.view/test.js @@ -1,15 +1,15 @@ -describe("unique", function() { - it("removes non-unique elements", function() { - let strings = ["Hare", "Krishna", "Hare", "Krishna", - "Krishna", "Krishna", "Hare", "Hare", ":-O" +describe("unikát", function() { + it("odstraní neunikátní prvky", function() { + let řetězce = ["Haré", "Kršna", "Haré", "Kršna", + "Kršna", "Kršna", "Haré", "Haré", ":-O" ]; - assert.deepEqual(unique(strings), ["Hare", "Krishna", ":-O"]); + assert.deepEqual(unikát(řetězce), ["Haré", "Kršna", ":-O"]); }); - it("does not change the source array", function() { - let strings = ["Krishna", "Krishna", "Hare", "Hare"]; - unique(strings); - assert.deepEqual(strings, ["Krishna", "Krishna", "Hare", "Hare"]); + it("nemění zdrojové pole", function() { + let řetězce = ["Kršna", "Kršna", "Haré", "Haré"]; + unikát(řetězce); + assert.deepEqual(řetězce, ["Kršna", "Kršna", "Haré", "Haré"]); }); }); diff --git a/1-js/05-data-types/05-array-methods/11-array-unique/solution.md b/1-js/05-data-types/05-array-methods/11-array-unique/solution.md index b9d627a0a..3faa5f27c 100644 --- a/1-js/05-data-types/05-array-methods/11-array-unique/solution.md +++ b/1-js/05-data-types/05-array-methods/11-array-unique/solution.md @@ -1,39 +1,39 @@ -Let's walk the array items: -- For each item we'll check if the resulting array already has that item. -- If it is so, then ignore, otherwise add to results. +Projděme si prvky pole: +- U každého prvku ověříme, zda výsledné pole již tento prvek obsahuje. +- Pokud je tomu tak, budeme ho ignorovat, jinak ho přidáme do výsledku. ```js run demo -function unique(arr) { - let result = []; +function unikát(pole) { + let výsledek = []; - for (let str of arr) { - if (!result.includes(str)) { - result.push(str); + for (let řetězec of pole) { + if (!výsledek.includes(řetězec)) { + výsledek.push(řetězec); } } - return result; + return výsledek; } -let strings = ["Hare", "Krishna", "Hare", "Krishna", - "Krishna", "Krishna", "Hare", "Hare", ":-O" +let řetězce = ["Haré", "Kršna", "Haré", "Kršna", + "Kršna", "Kršna", "Haré", "Haré", ":-O" ]; -alert( unique(strings) ); // Hare, Krishna, :-O +alert( unikát(řetězce) ); // Haré, Kršna, :-O ``` -The code works, but there's a potential performance problem in it. +Tento kód funguje, ale má potenciální problém s výkonem. -The method `result.includes(str)` internally walks the array `result` and compares each element against `str` to find the match. +Metoda `výsledek.includes(řetězec)` vnitřně prochází pole `výsledek` a porovná každý jeho prvek s `řetězec`, aby našla shodu. -So if there are `100` elements in `result` and no one matches `str`, then it will walk the whole `result` and do exactly `100` comparisons. And if `result` is large, like `10000`, then there would be `10000` comparisons. +Jestliže tedy v poli `výsledek` je `100` prvků a žádný se nerovná `řetězec`, pak projde celé pole `výsledek` a provede právě `100` porovnání. A je-li `výsledek` velký, např. `10000`, pak se vykoná `10000` porovnání. -That's not a problem by itself, because JavaScript engines are very fast, so walk `10000` array is a matter of microseconds. +To samo o sobě není problém, jelikož JavaScriptové motory jsou velmi rychlé, takže projít pole `10000` prvků je otázkou mikrosekund. -But we do such test for each element of `arr`, in the `for` loop. +My však provádíme takový test pro každý prvek `pole` v cyklu `for`. -So if `arr.length` is `10000` we'll have something like `10000*10000` = 100 millions of comparisons. That's a lot. +Jestliže tedy `pole.length` je `10000`, budeme mít něco jako `10000*10000` = 100 miliónů porovnání. To je hodně. -So the solution is only good for small arrays. +Toto řešení je tedy dobré jen pro malá pole. -Further in the chapter we'll see how to optimize it. +Později v kapitole uvidíme, jak je optimalizovat. diff --git a/1-js/05-data-types/05-array-methods/11-array-unique/task.md b/1-js/05-data-types/05-array-methods/11-array-unique/task.md index 5b56d3621..441e96273 100644 --- a/1-js/05-data-types/05-array-methods/11-array-unique/task.md +++ b/1-js/05-data-types/05-array-methods/11-array-unique/task.md @@ -2,22 +2,22 @@ importance: 4 --- -# Filter unique array members +# Filtrace unikátních prvků pole -Let `arr` be an array. +Nechť `pole` je nějaké pole. -Create a function `unique(arr)` that should return an array with unique items of `arr`. +Vytvořte funkci `unikát(pole)`, která vrátí pole obsahující všechny různé prvky `pole`. -For instance: +Příklad: ```js -function unique(arr) { - /* your code */ +function unikát(pole) { + /* váš kód */ } -let strings = ["Hare", "Krishna", "Hare", "Krishna", - "Krishna", "Krishna", "Hare", "Hare", ":-O" +let řetězce = ["Haré", "Kršna", "Haré", "Kršna", + "Kršna", "Kršna", "Haré", "Haré", ":-O" ]; -alert( unique(strings) ); // Hare, Krishna, :-O +alert( unikát(řetězce) ); // Haré, Kršna, :-O ``` diff --git a/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/solution.js b/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/solution.js index 8dea23a06..3f3712ccc 100644 --- a/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/solution.js +++ b/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/solution.js @@ -1,6 +1,6 @@ -function groupById(array) { - return array.reduce((obj, value) => { - obj[value.id] = value; +function seskupPodleId(pole) { + return pole.reduce((obj, hodnota) => { + obj[hodnota.id] = hodnota; return obj; }, {}) } diff --git a/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/test.js b/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/test.js index e48ba138d..e1d58ca1c 100644 --- a/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/test.js +++ b/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/test.js @@ -1,21 +1,21 @@ -describe("groupById", function() { +describe("seskupPodleId", function() { - it("creates an object grouped by id", function() { - let users = [ - {id: 'john', name: "John Smith", age: 20}, - {id: 'ann', name: "Ann Smith", age: 24}, - {id: 'pete', name: "Pete Peterson", age: 31}, + it("vytvoří objekt seskupený podle id", function() { + let uživatelé = [ + {id: 'jan', jméno: "Jan Novák", věk: 20}, + {id: 'anna', jméno: "Anna Nováková", věk: 24}, + {id: 'petr', jméno: "Petr Petřík", věk: 31}, ]; - assert.deepEqual(groupById(users), { - john: {id: 'john', name: "John Smith", age: 20}, - ann: {id: 'ann', name: "Ann Smith", age: 24}, - pete: {id: 'pete', name: "Pete Peterson", age: 31}, + assert.deepEqual(seskupPodleId(uživatelé), { + jan: {id: 'jan', jméno: "Jan Novák", věk: 20}, + anna: {id: 'anna', jméno: "Anna Nováková", věk: 24}, + petr: {id: 'petr', jméno: "Petr Petřík", věk: 31}, }); }); - it("works with an empty array", function() { - users = []; - assert.deepEqual(groupById(users), {}); + it("funguje s prázdným polem", function() { + uživatelé = []; + assert.deepEqual(seskupPodleId(uživatelé), {}); }); }); diff --git a/1-js/05-data-types/05-array-methods/12-reduce-object/task.md b/1-js/05-data-types/05-array-methods/12-reduce-object/task.md index 7f0082357..d5cb0921b 100644 --- a/1-js/05-data-types/05-array-methods/12-reduce-object/task.md +++ b/1-js/05-data-types/05-array-methods/12-reduce-object/task.md @@ -2,36 +2,36 @@ importance: 4 --- -# Create keyed object from array +# Vytvoření klíčovaného objektu z pole -Let's say we received an array of users in the form `{id:..., name:..., age:... }`. +Řekněme, že jsme získali pole uživatelů ve formě `{id:..., jméno:..., věk... }`. -Create a function `groupById(arr)` that creates an object from it, with `id` as the key, and array items as values. +Vytvořte funkci `seskupPodleId(pole)`, která z něj vytvoří objekt, jehož klíči budou hodnoty `id` a hodnotami prvky pole. -For example: +Příklad: ```js -let users = [ - {id: 'john', name: "John Smith", age: 20}, - {id: 'ann', name: "Ann Smith", age: 24}, - {id: 'pete', name: "Pete Peterson", age: 31}, +let uživatelé = [ + {id: 'jan', jméno: "Jan Novák", věk: 20}, + {id: 'anna', jméno: "Anna Nováková", věk: 24}, + {id: 'petr', jméno: "Petr Petřík", věk: 31}, ]; -let usersById = groupById(users); +let uživateléPodleId = seskupPodleId(uživatelé); /* -// after the call we should have: +// po volání bychom měli mít: -usersById = { - john: {id: 'john', name: "John Smith", age: 20}, - ann: {id: 'ann', name: "Ann Smith", age: 24}, - pete: {id: 'pete', name: "Pete Peterson", age: 31}, +uživateléPodleId = { + jan: {id: 'jan', jméno: "Jan Novák", věk: 20}, + anna: {id: 'anna', jméno: "Anna Nováková", věk: 24}, + petr: {id: 'petr', jméno: "Petr Petřík", věk: 31}, } */ ``` -Such function is really handy when working with server data. +Taková funkce se opravdu hodí, když pracujeme se serverovými daty. -In this task we assume that `id` is unique. There may be no two array items with the same `id`. +V této úloze předpokládáme, že `id` je unikátní. V poli nesmějí být dva prvky se stejným `id`. -Please use array `.reduce` method in the solution. +Prosíme použijte v řešení metodu pole `.reduce`. diff --git a/1-js/05-data-types/05-array-methods/2-filter-range/_js.view/solution.js b/1-js/05-data-types/05-array-methods/2-filter-range/_js.view/solution.js index 0bdfbae5a..2b6f090dc 100644 --- a/1-js/05-data-types/05-array-methods/2-filter-range/_js.view/solution.js +++ b/1-js/05-data-types/05-array-methods/2-filter-range/_js.view/solution.js @@ -1,5 +1,5 @@ -function filterRange(arr, a, b) { - // added brackets around the expression for better readability - return arr.filter(item => (a <= item && item <= b)); +function filtrujPodleRozsahu(pole, a, b) { + // závorky kolem výrazu jsou přidány pro lepší čitelnost + return pole.filter(prvek => (a <= prvek && prvek <= b)); } \ No newline at end of file diff --git a/1-js/05-data-types/05-array-methods/2-filter-range/_js.view/test.js b/1-js/05-data-types/05-array-methods/2-filter-range/_js.view/test.js index fb26c8dc0..ab838238a 100644 --- a/1-js/05-data-types/05-array-methods/2-filter-range/_js.view/test.js +++ b/1-js/05-data-types/05-array-methods/2-filter-range/_js.view/test.js @@ -1,21 +1,21 @@ -describe("filterRange", function() { +describe("filtrujPodleRozsahu", function() { - it("returns the filtered values", function() { + it("vrátí filtrované hodnoty", function() { - let arr = [5, 3, 8, 1]; + let pole = [5, 3, 8, 1]; - let filtered = filterRange(arr, 1, 4); + let filtrovanéPole = filtrujPodleRozsahu(pole, 1, 4); - assert.deepEqual(filtered, [3, 1]); + assert.deepEqual(filtrovanéPole, [3, 1]); }); - it("doesn't change the array", function() { + it("nezmění pole", function() { - let arr = [5, 3, 8, 1]; + let pole = [5, 3, 8, 1]; - let filtered = filterRange(arr, 1, 4); + let filtrovanéPole = filtrujPodleRozsahu(pole, 1, 4); - assert.deepEqual(arr, [5,3,8,1]); + assert.deepEqual(pole, [5,3,8,1]); }); }); \ No newline at end of file diff --git a/1-js/05-data-types/05-array-methods/2-filter-range/solution.md b/1-js/05-data-types/05-array-methods/2-filter-range/solution.md index 73993a07a..080c21776 100644 --- a/1-js/05-data-types/05-array-methods/2-filter-range/solution.md +++ b/1-js/05-data-types/05-array-methods/2-filter-range/solution.md @@ -1,14 +1,14 @@ ```js run demo -function filterRange(arr, a, b) { - // added brackets around the expression for better readability - return arr.filter(item => (a <= item && item <= b)); +function filtrujPodleRozsahu(pole, a, b) { + // závorky kolem výrazu jsou přidány pro lepší čitelnost + return pole.filter(prvek => (a <= prvek && prvek <= b)); } -let arr = [5, 3, 8, 1]; +let testovacíPole = [5, 3, 8, 1]; -let filtered = filterRange(arr, 1, 4); +let filtrovanéPole = filtrujPodleRozsahu(testovacíPole, 1, 4); -alert( filtered ); // 3,1 (matching values) +alert( filtrovanéPole ); // 3,1 (odpovídající hodnoty) -alert( arr ); // 5,3,8,1 (not modified) +alert( testovacíPole ); // 5,3,8,1 (nezměněno) ``` diff --git a/1-js/05-data-types/05-array-methods/2-filter-range/task.md b/1-js/05-data-types/05-array-methods/2-filter-range/task.md index 46e47c93d..f80b3b6b3 100644 --- a/1-js/05-data-types/05-array-methods/2-filter-range/task.md +++ b/1-js/05-data-types/05-array-methods/2-filter-range/task.md @@ -2,21 +2,21 @@ importance: 4 --- -# Filter range +# Filtrace podle rozsahu -Write a function `filterRange(arr, a, b)` that gets an array `arr`, looks for elements with values higher or equal to `a` and lower or equal to `b` and return a result as an array. +Napište funkci `filtrujPodleRozsahu(pole, a, b)`, která obdrží pole `pole`, najde prvky, jejichž hodnoty jsou vyšší nebo rovny `a` a nižší nebo rovny `b` a vrátí výsledek jako pole. -The function should not modify the array. It should return the new array. +Funkce by neměla pole modifikovat. Měla by vrátit nové pole. -For instance: +Příklad: ```js -let arr = [5, 3, 8, 1]; +let pole = [5, 3, 8, 1]; -let filtered = filterRange(arr, 1, 4); +let filtrovanéPole = filtrujPodleRozsahu(pole, 1, 4); -alert( filtered ); // 3,1 (matching values) +alert( filtrovanéPole ); // 3,1 (odpovídající hodnoty) -alert( arr ); // 5,3,8,1 (not modified) +alert( pole ); // 5,3,8,1 (nezměněno) ``` diff --git a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/solution.js b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/solution.js index 488db3755..eea54c657 100644 --- a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/solution.js +++ b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/solution.js @@ -1,12 +1,12 @@ -function filterRangeInPlace(arr, a, b) { +function filtrujPodleRozsahuNaMístě(pole, a, b) { - for (let i = 0; i < arr.length; i++) { - let val = arr[i]; + for (let i = 0; i < pole.length; i++) { + let hodnota = pole[i]; - // remove if outside of the interval - if (val < a || val > b) { - arr.splice(i, 1); + // odstraní hodnotu, jestliže je mimo interval + if (hodnota < a || hodnota > b) { + pole.splice(i, 1); i--; } } diff --git a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/test.js b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/test.js index 241b74c6e..8e1e27918 100644 --- a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/test.js +++ b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/test.js @@ -1,16 +1,16 @@ -describe("filterRangeInPlace", function() { +describe("filtrujPodleRozsahuNaMístě", function() { - it("returns the filtered values", function() { + it("vrátí filtrované hodnoty", function() { - let arr = [5, 3, 8, 1]; + let pole = [5, 3, 8, 1]; - filterRangeInPlace(arr, 2, 5); + filtrujPodleRozsahuNaMístě(pole, 2, 5); - assert.deepEqual(arr, [5, 3]); + assert.deepEqual(pole, [3, 1]); }); - it("doesn't return anything", function() { - assert.isUndefined(filterRangeInPlace([1,2,3], 1, 4)); + it("nic nevrací", function() { + assert.isUndefined(filtrujPodleRozsahuNaMístě([1,2,3], 1, 4)); }); }); diff --git a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/solution.md b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/solution.md index 36e3130ff..42f0a8daf 100644 --- a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/solution.md +++ b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/solution.md @@ -1,21 +1,21 @@ ```js run demo -function filterRangeInPlace(arr, a, b) { +function filtrujPodleRozsahuNaMístě(pole, a, b) { - for (let i = 0; i < arr.length; i++) { - let val = arr[i]; + for (let i = 0; i < pole.length; i++) { + let hodnota = pole[i]; - // remove if outside of the interval - if (val < a || val > b) { - arr.splice(i, 1); + // odstraní hodnotu, jestliže je mimo interval + if (hodnota < a || hodnota > b) { + pole.splice(i, 1); i--; } } } -let arr = [5, 3, 8, 1]; +let testovacíPole = [5, 3, 8, 1]; -filterRangeInPlace(arr, 1, 4); // removed the numbers except from 1 to 4 +filtrujPodleRozsahuNaMístě(testovacíPole, 1, 4); // odstraní čísla, která nejsou od 1 do 4 -alert( arr ); // [3, 1] +alert( testovacíPole ); // [3, 1] ``` diff --git a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/task.md b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/task.md index 7066a51ab..856a3fa12 100644 --- a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/task.md +++ b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/task.md @@ -2,17 +2,17 @@ importance: 4 --- -# Filter range "in place" +# Filtrace podle rozsahu „na místě“ -Write a function `filterRangeInPlace(arr, a, b)` that gets an array `arr` and removes from it all values except those that are between `a` and `b`. The test is: `a ≤ arr[i] ≤ b`. +Napište funkci `filtrujPodleRozsahuNaMístě(pole, a, b)`, která obdrží pole `pole` a odstraní z něj všechny hodnoty, které neleží mezi `a` a `b`. Test je: `a ≤ pole[i] ≤ b`. -The function should only modify the array. It should not return anything. +Funkce by měla jen modifikovat pole. Neměla by nic vracet. -For instance: +Příklad: ```js -let arr = [5, 3, 8, 1]; +let pole = [5, 3, 8, 1]; -filterRangeInPlace(arr, 1, 4); // removed the numbers except from 1 to 4 +filtrujPodleRozsahuNaMístě(pole, 1, 4); // odstraní čísla, která nejsou od 1 do 4 -alert( arr ); // [3, 1] +alert( pole ); // [3, 1] ``` diff --git a/1-js/05-data-types/05-array-methods/4-sort-back/solution.md b/1-js/05-data-types/05-array-methods/4-sort-back/solution.md index cdf133511..f12bd15fc 100644 --- a/1-js/05-data-types/05-array-methods/4-sort-back/solution.md +++ b/1-js/05-data-types/05-array-methods/4-sort-back/solution.md @@ -1,10 +1,10 @@ ```js run -let arr = [5, 2, 1, -10, 8]; +let pole = [5, 2, 1, -10, 8]; -arr.sort((a, b) => b - a); +pole.sort((a, b) => b - a); -alert( arr ); +alert( pole ); ``` diff --git a/1-js/05-data-types/05-array-methods/4-sort-back/task.md b/1-js/05-data-types/05-array-methods/4-sort-back/task.md index 0e3eeab76..26f8a05c7 100644 --- a/1-js/05-data-types/05-array-methods/4-sort-back/task.md +++ b/1-js/05-data-types/05-array-methods/4-sort-back/task.md @@ -2,13 +2,13 @@ importance: 4 --- -# Sort in decreasing order +# Seřaďte pole v sestupném pořadí ```js -let arr = [5, 2, 1, -10, 8]; +let pole = [5, 2, 1, -10, 8]; -// ... your code to sort it in decreasing order +// ... váš kód je má seřadit v sestupném pořadí -alert( arr ); // 8, 5, 2, 1, -10 +alert( pole ); // 8, 5, 2, 1, -10 ``` diff --git a/1-js/05-data-types/05-array-methods/5-copy-sort-array/solution.md b/1-js/05-data-types/05-array-methods/5-copy-sort-array/solution.md index 8537b129e..f67e2bc99 100644 --- a/1-js/05-data-types/05-array-methods/5-copy-sort-array/solution.md +++ b/1-js/05-data-types/05-array-methods/5-copy-sort-array/solution.md @@ -1,17 +1,17 @@ -We can use `slice()` to make a copy and run the sort on it: +Můžeme použít metodu `slice()`, aby vytvořila kopii, a spustit řazení na ní: ```js run -function copySorted(arr) { - return arr.slice().sort(); +function zkopírujASeřaď(pole) { + return pole.slice().sort(); } -let arr = ["HTML", "JavaScript", "CSS"]; +let původníPole = ["HTML", "JavaScript", "CSS"]; *!* -let sorted = copySorted(arr); +let seřazenéPole = zkopírujASeřaď(původníPole); */!* -alert( sorted ); -alert( arr ); +alert( seřazenéPole ); +alert( původníPole ); ``` diff --git a/1-js/05-data-types/05-array-methods/5-copy-sort-array/task.md b/1-js/05-data-types/05-array-methods/5-copy-sort-array/task.md index c1395b4ad..8283824aa 100644 --- a/1-js/05-data-types/05-array-methods/5-copy-sort-array/task.md +++ b/1-js/05-data-types/05-array-methods/5-copy-sort-array/task.md @@ -2,17 +2,17 @@ importance: 5 --- -# Copy and sort array +# Zkopírujte a seřaďte pole -We have an array of strings `arr`. We'd like to have a sorted copy of it, but keep `arr` unmodified. +Máme pole řetězců `pole`. Chtěli bychom mít jeho seřazenou kopii, ale `pole` chceme ponechat nezměněné. -Create a function `copySorted(arr)` that returns such a copy. +Napište funkci `zkopírujASeřaď(pole)`, která takovou kopii vrátí. ```js -let arr = ["HTML", "JavaScript", "CSS"]; +let pole = ["HTML", "JavaScript", "CSS"]; -let sorted = copySorted(arr); +let seřazenéPole = zkopírujASeřaď(pole); -alert( sorted ); // CSS, HTML, JavaScript -alert( arr ); // HTML, JavaScript, CSS (no changes) +alert( seřazenéPole ); // CSS, HTML, JavaScript +alert( pole ); // HTML, JavaScript, CSS (beze změn) ``` diff --git a/1-js/05-data-types/05-array-methods/6-array-get-names/solution.md b/1-js/05-data-types/05-array-methods/6-array-get-names/solution.md index f44a2b812..938e0a91e 100644 --- a/1-js/05-data-types/05-array-methods/6-array-get-names/solution.md +++ b/1-js/05-data-types/05-array-methods/6-array-get-names/solution.md @@ -1,13 +1,13 @@ ```js run -let john = { name: "John", age: 25 }; -let pete = { name: "Pete", age: 30 }; -let mary = { name: "Mary", age: 28 }; +let jan = { jméno: "Jan", věk: 25 }; +let petr = { jméno: "Petr", věk: 30 }; +let marie = { jméno: "Marie", věk: 28 }; -let users = [ john, pete, mary ]; +let uživatelé = [ jan, petr, marie ]; -let names = users.map(item => item.name); +let jména = uživatelé.map(prvek => prvek.jméno); -alert( names ); // John, Pete, Mary +alert( jména ); // Jan, Petr, Marie ``` diff --git a/1-js/05-data-types/05-array-methods/6-array-get-names/task.md b/1-js/05-data-types/05-array-methods/6-array-get-names/task.md index 74c8a9d74..0f70081d9 100644 --- a/1-js/05-data-types/05-array-methods/6-array-get-names/task.md +++ b/1-js/05-data-types/05-array-methods/6-array-get-names/task.md @@ -2,21 +2,21 @@ importance: 5 --- -# Map to names +# Mapování na jména -You have an array of `user` objects, each one has `user.name`. Write the code that converts it into an array of names. +Máte pole objektů `uživatel`, každý z nich má vlastnost `uživatel.jméno`. Napište kód, který je převede na pole jmen. -For instance: +Příklad: ```js no-beautify -let john = { name: "John", age: 25 }; -let pete = { name: "Pete", age: 30 }; -let mary = { name: "Mary", age: 28 }; +let jan = { jméno: "Jan", věk: 25 }; +let petr = { jméno: "Petr", věk: 30 }; +let marie = { jméno: "Marie", věk: 28 }; -let users = [ john, pete, mary ]; +let uživatelé = [ jan, petr, marie ]; -let names = /* ... your code */ +let jména = /* ... váš kód */ -alert( names ); // John, Pete, Mary +alert( jména ); // Jan, Petr, Marie ``` diff --git a/1-js/05-data-types/05-array-methods/6-calculator-extendable/_js.view/solution.js b/1-js/05-data-types/05-array-methods/6-calculator-extendable/_js.view/solution.js index f62452a5f..d57f77429 100644 --- a/1-js/05-data-types/05-array-methods/6-calculator-extendable/_js.view/solution.js +++ b/1-js/05-data-types/05-array-methods/6-calculator-extendable/_js.view/solution.js @@ -1,25 +1,25 @@ -function Calculator() { +function Kalkulátor() { - this.methods = { + this.metody = { "-": (a, b) => a - b, "+": (a, b) => a + b }; - this.calculate = function(str) { + this.vypočítej = function(řetězec) { - let split = str.split(' '), + let split = řetězec.split(' '), a = +split[0], op = split[1], b = +split[2]; - if (!this.methods[op] || isNaN(a) || isNaN(b)) { + if (!this.metody[op] || isNaN(a) || isNaN(b)) { return NaN; } - return this.methods[op](a, b); + return this.metody[op](a, b); }; - this.addMethod = function(name, func) { - this.methods[name] = func; + this.přidejMetodu = function(jméno, funkce) { + this.metody[jméno] = funkce; }; } diff --git a/1-js/05-data-types/05-array-methods/6-calculator-extendable/_js.view/test.js b/1-js/05-data-types/05-array-methods/6-calculator-extendable/_js.view/test.js index eac4f54a0..43f05210d 100644 --- a/1-js/05-data-types/05-array-methods/6-calculator-extendable/_js.view/test.js +++ b/1-js/05-data-types/05-array-methods/6-calculator-extendable/_js.view/test.js @@ -1,25 +1,25 @@ -describe("Calculator", function() { - let calculator; +describe("Kalkulátor", function() { + let kalkulátor; before(function() { - calculator = new Calculator; + kalkulátor = new Kalkulátor; }); - it("calculate(12 + 34) = 46", function() { - assert.equal(calculator.calculate("12 + 34"), 46); + it("vypočítej(12 + 34) = 46", function() { + assert.equal(kalkulátor.vypočítej("12 + 34"), 46); }); - it("calculate(34 - 12) = 22", function() { - assert.equal(calculator.calculate("34 - 12"), 22); + it("vypočítej(34 - 12) = 22", function() { + assert.equal(kalkulátor.vypočítej("34 - 12"), 22); }); - it("add multiplication: calculate(2 * 3) = 6", function() { - calculator.addMethod("*", (a, b) => a * b); - assert.equal(calculator.calculate("2 * 3"), 6); + it("přidáme násobení: vypočítej(2 * 3) = 6", function() { + kalkulátor.přidejMetodu("*", (a, b) => a * b); + assert.equal(kalkulátor.vypočítej("2 * 3"), 6); }); - it("add power: calculate(2 ** 3) = 8", function() { - calculator.addMethod("**", (a, b) => a ** b); - assert.equal(calculator.calculate("2 ** 3"), 8); + it("přidáme umocňování: vypočítej(2 ** 3) = 8", function() { + kalkulátor.přidejMetodu("**", (a, b) => a ** b); + assert.equal(kalkulátor.vypočítej("2 ** 3"), 8); }); }); diff --git a/1-js/05-data-types/05-array-methods/6-calculator-extendable/solution.md b/1-js/05-data-types/05-array-methods/6-calculator-extendable/solution.md index ebe0714cf..f1df4abf3 100644 --- a/1-js/05-data-types/05-array-methods/6-calculator-extendable/solution.md +++ b/1-js/05-data-types/05-array-methods/6-calculator-extendable/solution.md @@ -1,3 +1,3 @@ -- Please note how methods are stored. They are simply added to `this.methods` property. -- All tests and numeric conversions are done in the `calculate` method. In future it may be extended to support more complex expressions. +- Prosíme všimněte si, jak jsou metody uloženy. Jednoduše se přidávají do vlastnosti `this.metody`. +- Všechny testy a číselné konverze se provádějí v metodě `vypočítej`. V budoucnu může být rozšířena, aby podporovala složitější výrazy. diff --git a/1-js/05-data-types/05-array-methods/6-calculator-extendable/task.md b/1-js/05-data-types/05-array-methods/6-calculator-extendable/task.md index e0d302f4c..742ed69be 100644 --- a/1-js/05-data-types/05-array-methods/6-calculator-extendable/task.md +++ b/1-js/05-data-types/05-array-methods/6-calculator-extendable/task.md @@ -2,35 +2,36 @@ importance: 5 --- -# Create an extendable calculator +# Vytvořte rozšiřitelný kalkulátor -Create a constructor function `Calculator` that creates "extendable" calculator objects. +Vytvořte konstruktor `Kalkulátor`, který bude vytvářet „rozšiřitelné“ objekty kalkulátoru. -The task consists of two parts. +Úloha se skládá ze dvou částí. -1. First, implement the method `calculate(str)` that takes a string like `"1 + 2"` in the format "NUMBER operator NUMBER" (space-delimited) and returns the result. Should understand plus `+` and minus `-`. - Usage example: +1. Nejprve implementujte metodu `vypočítej(řetězec)`, která obdrží řetězec, např. `"1 + 2"`, ve formátu „ČÍSLO operátor ČÍSLO“ (oddělené mezerou) a vrátí výsledek. Měla by rozumět plusu `+` a minusu `-`. + + Příklad použití: ```js - let calc = new Calculator; + let kalkulátor = new Kalkulátor; - alert( calc.calculate("3 + 7") ); // 10 + alert( kalkulátor.vypočítej("3 + 7") ); // 10 ``` -2. Then add the method `addMethod(name, func)` that teaches the calculator a new operation. It takes the operator `name` and the two-argument function `func(a,b)` that implements it. +2. Pak přidejte metodu `přidejMetodu(název, funkce)`, která naučí kalkulátor nové operaci. Obdrží operátor `název` a funkci o dvou argumentech `funkce(a, b)`, která jej implementuje. - For instance, let's add the multiplication `*`, division `/` and power `**`: + Například přidáme násobení`*`, dělení `/` a umocňování `**`: ```js - let powerCalc = new Calculator; - powerCalc.addMethod("*", (a, b) => a * b); - powerCalc.addMethod("/", (a, b) => a / b); - powerCalc.addMethod("**", (a, b) => a ** b); + let silnýKalkulátor = new Kalkulátor; + silnýKalkulátor.přidejMetodu("*", (a, b) => a * b); + silnýKalkulátor.přidejMetodu("/", (a, b) => a / b); + silnýKalkulátor.přidejMetodu("**", (a, b) => a ** b); - let result = powerCalc.calculate("2 ** 3"); - alert( result ); // 8 + let výsledek = silnýKalkulátor.vypočítej("2 ** 3"); + alert( výsledek ); // 8 ``` -- No parentheses or complex expressions in this task. -- The numbers and the operator are delimited with exactly one space. -- There may be error handling if you'd like to add it. +- V této úloze nejsou závorky ani složité výrazy. +- Čísla a operátor jsou oddělena právě jednou mezerou. +- Pokud chcete přidat ošetřování chyb, můžete. diff --git a/1-js/05-data-types/05-array-methods/7-map-objects/solution.md b/1-js/05-data-types/05-array-methods/7-map-objects/solution.md index 2d8d4fb0e..183afdf9e 100644 --- a/1-js/05-data-types/05-array-methods/7-map-objects/solution.md +++ b/1-js/05-data-types/05-array-methods/7-map-objects/solution.md @@ -1,51 +1,51 @@ ```js run no-beautify -let john = { name: "John", surname: "Smith", id: 1 }; -let pete = { name: "Pete", surname: "Hunt", id: 2 }; -let mary = { name: "Mary", surname: "Key", id: 3 }; +let jan = { jméno: "Jan", příjmení: "Novák", id: 1 }; +let petr = { jméno: "Petr", příjmení: "Horák", id: 2 }; +let marie = { jméno: "Marie", příjmení: "Králová", id: 3 }; -let users = [ john, pete, mary ]; +let uživatelé = [ jan, petr, marie ]; *!* -let usersMapped = users.map(user => ({ - fullName: `${user.name} ${user.surname}`, - id: user.id +let mapovaníUživatelé = uživatelé.map(uživatel => ({ + celéJméno: `${uživatel.jméno} ${uživatel.příjmení}`, + id: uživatel.id })); */!* /* -usersMapped = [ - { fullName: "John Smith", id: 1 }, - { fullName: "Pete Hunt", id: 2 }, - { fullName: "Mary Key", id: 3 } +mapovaníUživatelé = [ + { celéJméno: "Jan Novák", id: 1 }, + { celéJméno: "Petr Horák", id: 2 }, + { celéJméno: "Marie Králová", id: 3 } ] */ -alert( usersMapped[0].id ); // 1 -alert( usersMapped[0].fullName ); // John Smith +alert( mapovaníUživatelé[0].id ); // 1 +alert( mapovaníUživatelé[0].celéJméno ); // Jan Novák ``` -Please note that in the arrow functions we need to use additional brackets. +Prosíme všimněte si, že v šipkové funkci musíme použít závorky navíc. -We can't write like this: +Nemůžeme ji napsat takto: ```js -let usersMapped = users.map(user => *!*{*/!* - fullName: `${user.name} ${user.surname}`, - id: user.id +let mapovaníUživatelé = uživatelé.map(uživatel => *!*{*/!* + celéJméno: `${uživatel.jméno} ${uživatel.příjmení}`, + id: uživatel.id }); ``` -As we remember, there are two arrow functions: without body `value => expr` and with body `value => {...}`. +Jak si pamatujeme, existují dva druhy šipkových funkcí: bez těla `hodnota => výraz` a s tělem `hodnota => {...}`. -Here JavaScript would treat `{` as the start of function body, not the start of the object. The workaround is to wrap them in the "normal" brackets: +Zde JavaScript zachází s `{` jako se začátkem těla funkce, ne jako se začátkem objektu. Řešením je uzavřít objekt do „obyčejných“ závorek: ```js -let usersMapped = users.map(user => *!*({*/!* - fullName: `${user.name} ${user.surname}`, - id: user.id +let mapovaníUživatelé = uživatelé.map(uživatel => *!*({*/!* + celéJméno: `${uživatel.jméno} ${uživatel.příjmení}`, + id: uživatel.id })); ``` -Now fine. +Nyní je to v pořádku. diff --git a/1-js/05-data-types/05-array-methods/7-map-objects/task.md b/1-js/05-data-types/05-array-methods/7-map-objects/task.md index b11d12155..5e097ff27 100644 --- a/1-js/05-data-types/05-array-methods/7-map-objects/task.md +++ b/1-js/05-data-types/05-array-methods/7-map-objects/task.md @@ -2,35 +2,35 @@ importance: 5 --- -# Map to objects +# Mapování na objekty -You have an array of `user` objects, each one has `name`, `surname` and `id`. +Máme pole objektů `uživatel`, každý z nich má vlastnosti `jméno`, `příjmení` a `id`. -Write the code to create another array from it, of objects with `id` and `fullName`, where `fullName` is generated from `name` and `surname`. +Napište kód, který z něj vytvoří jiné pole, které bude obsahovat objekty s vlastnostmi `id` a `celéJméno`, kde `celéJméno` se vygeneruje ze `jméno` a `příjmení`. -For instance: +Příklad: ```js no-beautify -let john = { name: "John", surname: "Smith", id: 1 }; -let pete = { name: "Pete", surname: "Hunt", id: 2 }; -let mary = { name: "Mary", surname: "Key", id: 3 }; +let jan = { jméno: "Jan", příjmení: "Novák", id: 1 }; +let petr = { jméno: "Petr", příjmení: "Horák", id: 2 }; +let marie = { jméno: "Marie", příjmení: "Králová", id: 3 }; -let users = [ john, pete, mary ]; +let uživatelé = [ jan, petr, marie ]; *!* -let usersMapped = /* ... your code ... */ +let mapovaníUživatelé = /* ... váš kód ... */ */!* /* -usersMapped = [ - { fullName: "John Smith", id: 1 }, - { fullName: "Pete Hunt", id: 2 }, - { fullName: "Mary Key", id: 3 } +mapovaníUživatelé = [ + { celéJméno: "Jan Novák", id: 1 }, + { celéJméno: "Petr Horák", id: 2 }, + { celéJméno: "Marie Králová", id: 3 } ] */ -alert( usersMapped[0].id ) // 1 -alert( usersMapped[0].fullName ) // John Smith +alert( mapovaníUživatelé[0].id ) // 1 +alert( mapovaníUživatelé[0].celéJméno ) // Jan Novák ``` -So, actually you need to map one array of objects to another. Try using `=>` here. There's a small catch. \ No newline at end of file +Ve skutečnosti tedy potřebujete mapovat jedno pole objektů na druhé. Zkuste zde použít `=>`. Je tady malý chyták. \ No newline at end of file diff --git a/1-js/05-data-types/05-array-methods/8-sort-objects/solution.md b/1-js/05-data-types/05-array-methods/8-sort-objects/solution.md index cfaf9761a..c06cec18c 100644 --- a/1-js/05-data-types/05-array-methods/8-sort-objects/solution.md +++ b/1-js/05-data-types/05-array-methods/8-sort-objects/solution.md @@ -1,18 +1,18 @@ ```js run no-beautify -function sortByAge(arr) { - arr.sort((a, b) => a.age - b.age); +function seřaďPodleVěku(pole) { + pole.sort((a, b) => a.věk - b.věk); } -let john = { name: "John", age: 25 }; -let pete = { name: "Pete", age: 30 }; -let mary = { name: "Mary", age: 28 }; +let jan = { jméno: "Jan", věk: 25 }; +let petr = { jméno: "Petr", věk: 30 }; +let marie = { jméno: "Marie", věk: 28 }; -let arr = [ pete, john, mary ]; +let pole = [ petr, jan, marie ]; -sortByAge(arr); +seřaďPodleVěku(pole); -// now sorted is: [john, mary, pete] -alert(arr[0].name); // John -alert(arr[1].name); // Mary -alert(arr[2].name); // Pete +// nyní seřazenéPole je: [jan, marie, petr] +alert(pole[0].jméno); // Jan +alert(pole[1].jméno); // Marie +alert(pole[2].jméno); // Petr ``` diff --git a/1-js/05-data-types/05-array-methods/8-sort-objects/task.md b/1-js/05-data-types/05-array-methods/8-sort-objects/task.md index 9a215c9f4..0e9bdd951 100644 --- a/1-js/05-data-types/05-array-methods/8-sort-objects/task.md +++ b/1-js/05-data-types/05-array-methods/8-sort-objects/task.md @@ -2,23 +2,23 @@ importance: 5 --- -# Sort users by age +# Seřazení uživatelů podle věku -Write the function `sortByAge(users)` that gets an array of objects with the `age` property and sorts them by `age`. +Napište funkci `seřaďPodleVěku(uživatelé)`, která obdrží pole objektů s vlastností `věk` a seřadí je podle této vlastnosti. -For instance: +Příklad: ```js no-beautify -let john = { name: "John", age: 25 }; -let pete = { name: "Pete", age: 30 }; -let mary = { name: "Mary", age: 28 }; +let jan = { jméno: "Jan", věk: 25 }; +let petr = { jméno: "Petr", věk: 30 }; +let marie = { jméno: "Marie", věk: 28 }; -let arr = [ pete, john, mary ]; +let pole = [ petr, jan, marie ]; -sortByAge(arr); +seřaďPodleVěku(pole); -// now: [john, mary, pete] -alert(arr[0].name); // John -alert(arr[1].name); // Mary -alert(arr[2].name); // Pete +// nyní: [jan, marie, petr] +alert(pole[0].jméno); // Jan +alert(pole[1].jméno); // Marie +alert(pole[2].jméno); // Petr ``` diff --git a/1-js/05-data-types/05-array-methods/9-shuffle/solution.md b/1-js/05-data-types/05-array-methods/9-shuffle/solution.md index 6674c444f..5300a1493 100644 --- a/1-js/05-data-types/05-array-methods/9-shuffle/solution.md +++ b/1-js/05-data-types/05-array-methods/9-shuffle/solution.md @@ -1,30 +1,30 @@ -The simple solution could be: +Jednoduché řešení by mohlo být: ```js run *!* -function shuffle(array) { - array.sort(() => Math.random() - 0.5); +function zamíchej(pole) { + pole.sort(() => Math.random() - 0.5); } */!* -let arr = [1, 2, 3]; -shuffle(arr); -alert(arr); +let pole = [1, 2, 3]; +zamíchej(pole); +alert(pole); ``` -That somewhat works, because `Math.random() - 0.5` is a random number that may be positive or negative, so the sorting function reorders elements randomly. +To jakžtakž funguje, protože `Math.random() - 0.5` je náhodné číslo, které může být kladné nebo záporné, takže řadicí funkce přehází prvky náhodně. -But because the sorting function is not meant to be used this way, not all permutations have the same probability. +Protože však řadicí funkce není určena k takovému použití, nebudou mít všechny permutace stejnou pravděpodobnost. -For instance, consider the code below. It runs `shuffle` 1000000 times and counts appearances of all possible results: +Například uvažujte níže uvedený kód. Spustí `zamíchej` 1 000 000krát a spočítá výskyty všech možných výsledků: ```js run -function shuffle(array) { - array.sort(() => Math.random() - 0.5); +function zamíchej(pole) { + pole.sort(() => Math.random() - 0.5); } -// counts of appearances for all possible permutations -let count = { +// spočítáme výskyty všech možných permutací +let počty = { '123': 0, '132': 0, '213': 0, @@ -34,18 +34,18 @@ let count = { }; for (let i = 0; i < 1000000; i++) { - let array = [1, 2, 3]; - shuffle(array); - count[array.join('')]++; + let pole = [1, 2, 3]; + zamíchej(pole); + počty[pole.join('')]++; } -// show counts of all possible permutations -for (let key in count) { - alert(`${key}: ${count[key]}`); +// zobrazíme počty všech možných permutací +for (let klíč in počty) { + alert(`${klíč}: ${počty[klíč]}`); } ``` -An example result (depends on JS engine): +Příklad výsledku (závisí na motoru JavaScriptu): ```js 123: 250706 @@ -56,41 +56,41 @@ An example result (depends on JS engine): 321: 125223 ``` -We can see the bias clearly: `123` and `213` appear much more often than others. +Jasně vidíme odchylku: `123` a `213` se objevují mnohem častěji než ostatní. -The result of the code may vary between JavaScript engines, but we can already see that the approach is unreliable. +Výsledek kódu se může u různých JavaScriptových motorů lišit, ale už vidíme, že tento přístup je nespolehlivý. -Why it doesn't work? Generally speaking, `sort` is a "black box": we throw an array and a comparison function into it and expect the array to be sorted. But due to the utter randomness of the comparison the black box goes mad, and how exactly it goes mad depends on the concrete implementation that differs between engines. +Proč to nefunguje? Zhruba řečeno, `sort` je „černá skříňka“: vhodíme do ní pole a porovnávací funkci a očekáváme, že pole bude seřazeno. Kvůli naprosté náhodnosti řazení se však černá skříňka zblázní. To, jak přesně se zblázní, závisí na konkrétní implementaci, která se mezi jednotlivými motory liší. -There are other good ways to do the task. For instance, there's a great algorithm called [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle). The idea is to walk the array in the reverse order and swap each element with a random one before it: +Existují jiné dobré způsoby, jak tuto úlohu vyřešit. Například existuje skvělý algoritmus nazvaný [Fisher-Yatesovo míchání](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle). Myšlenkou je procházet pole v obráceném pořadí a vyměnit každý prvek s jiným prvkem před ním, náhodně vybraným: ```js -function shuffle(array) { - for (let i = array.length - 1; i > 0; i--) { - let j = Math.floor(Math.random() * (i + 1)); // random index from 0 to i - - // swap elements array[i] and array[j] - // we use "destructuring assignment" syntax to achieve that - // you'll find more details about that syntax in later chapters - // same can be written as: - // let t = array[i]; array[i] = array[j]; array[j] = t - [array[i], array[j]] = [array[j], array[i]]; +function zamíchej(pole) { + for (let i = pole.length - 1; i > 0; i--) { + let j = Math.floor(Math.random() * (i + 1)); // náhodný index od 0 do i + + // vyměníme prvky pole[i] a pole[j] + // dosáhneme toho použitím syntaxe „destrukturačního přiřazení“ + // podrobnosti o této syntaxi najdete v dalších kapitolách + // totéž lze zapsat jako: + // let t = pole[i]; pole[i] = pole[j]; pole[j] = t + [pole[i], pole[j]] = [pole[j], pole[i]]; } } ``` -Let's test it the same way: +Otestujme to stejným způsobem: ```js run -function shuffle(array) { - for (let i = array.length - 1; i > 0; i--) { +function zamíchej(pole) { + for (let i = pole.length - 1; i > 0; i--) { let j = Math.floor(Math.random() * (i + 1)); - [array[i], array[j]] = [array[j], array[i]]; + [pole[i], pole[j]] = [pole[j], pole[i]]; } } -// counts of appearances for all possible permutations -let count = { +// spočítáme výskyty všech možných permutací +let počty = { '123': 0, '132': 0, '213': 0, @@ -100,18 +100,18 @@ let count = { }; for (let i = 0; i < 1000000; i++) { - let array = [1, 2, 3]; - shuffle(array); - count[array.join('')]++; + let pole = [1, 2, 3]; + zamíchej(pole); + počty[pole.join('')]++; } -// show counts of all possible permutations -for (let key in count) { - alert(`${key}: ${count[key]}`); +// zobrazíme počty všech možných permutací +for (let klíč in počty) { + alert(`${klíč}: ${počty[klíč]}`); } ``` -The example output: +Příklad výstupu: ```js 123: 166693 @@ -122,6 +122,6 @@ The example output: 321: 166316 ``` -Looks good now: all permutations appear with the same probability. +Nyní to vypadá dobře: všechny permutace se objevují se stejnou pravděpodobností. -Also, performance-wise the Fisher-Yates algorithm is much better, there's no "sorting" overhead. +Navíc je Fisher-Yatesův algoritmus mnohem méně náročný na výkon, jelikož v něm není žádné „řazení“. \ No newline at end of file diff --git a/1-js/05-data-types/05-array-methods/9-shuffle/task.md b/1-js/05-data-types/05-array-methods/9-shuffle/task.md index 970c53417..735f0a1d9 100644 --- a/1-js/05-data-types/05-array-methods/9-shuffle/task.md +++ b/1-js/05-data-types/05-array-methods/9-shuffle/task.md @@ -2,24 +2,24 @@ importance: 3 --- -# Shuffle an array +# Míchání pole -Write the function `shuffle(array)` that shuffles (randomly reorders) elements of the array. +Napište funkci `zamíchej(pole)`, která zamíchá (náhodně seřadí) prvky pole. -Multiple runs of `shuffle` may lead to different orders of elements. For instance: +Vícenásobná volání `zamíchej` mohou vést k různým pořadím prvků. Například: ```js -let arr = [1, 2, 3]; +let pole = [1, 2, 3]; -shuffle(arr); -// arr = [3, 2, 1] +zamíchej(pole); +// pole = [3, 2, 1] -shuffle(arr); -// arr = [2, 1, 3] +zamíchej(pole); +// pole = [2, 1, 3] -shuffle(arr); -// arr = [3, 1, 2] +zamíchej(pole); +// pole = [3, 1, 2] // ... ``` -All element orders should have an equal probability. For instance, `[1,2,3]` can be reordered as `[1,2,3]` or `[1,3,2]` or `[3,1,2]` etc, with equal probability of each case. +Všechna pořadí prvků by měla mít stejnou pravděpodobnost. Například `[1,2,3]` lze seřadit jako `[1,2,3]` nebo `[1,3,2]` nebo `[3,1,2]` atd., přičemž všechny možnosti mají mít stejnou pravděpodobnost. diff --git a/1-js/05-data-types/05-array-methods/article.md b/1-js/05-data-types/05-array-methods/article.md index 853645958..cfcb28ddf 100644 --- a/1-js/05-data-types/05-array-methods/article.md +++ b/1-js/05-data-types/05-array-methods/article.md @@ -1,460 +1,460 @@ -# Array methods +# Metody polí -Arrays provide a lot of methods. To make things easier, in this chapter, they are split into groups. +Pole poskytují mnoho metod. Pro zjednodušení jsme je v této kapitole rozdělili do několika skupin. -## Add/remove items +## Přidávání a odebírání prvků -We already know methods that add and remove items from the beginning or the end: +Známe už metody, které přidávají a odebírají prvky na začátku nebo na konci pole: -- `arr.push(...items)` -- adds items to the end, -- `arr.pop()` -- extracts an item from the end, -- `arr.shift()` -- extracts an item from the beginning, -- `arr.unshift(...items)` -- adds items to the beginning. +- `pole.push(...prvky)` -- přidává prvky na konec, +- `pole.pop()` -- vybírá prvek z konce, +- `pole.shift()` -- vybírá prvek ze začátku, +- `pole.unshift(...prvky)` -- přidává prvky na začátek. -Here are a few others. +Zde uvedeme několik dalších. ### splice -How to delete an element from the array? +Jak smazat prvek z pole? -The arrays are objects, so we can try to use `delete`: +Pole jsou objekty, takže se můžeme pokusit použít `delete`: ```js run -let arr = ["I", "go", "home"]; +let pole = ["Já", "jdu", "domů"]; -delete arr[1]; // remove "go" +delete pole[1]; // odstraníme "jdu" -alert( arr[1] ); // undefined +alert( pole[1] ); // undefined -// now arr = ["I", , "home"]; -alert( arr.length ); // 3 +// nyní pole = ["Já", , "domů"]; +alert( pole.length ); // 3 ``` -The element was removed, but the array still has 3 elements, we can see that `arr.length == 3`. +Prvek byl odstraněn, ale pole má stále 3 prvky. Vidíme, že `pole.length == 3`. -That's natural, because `delete obj.key` removes a value by the `key`. It's all it does. Fine for objects. But for arrays we usually want the rest of the elements to shift and occupy the freed place. We expect to have a shorter array now. +To je přirozené, poněvadž `delete obj.klíč` odstraňuje hodnotu podle `klíč`. To je vše, co udělá. Pro objekty je to dobře. Ale u polí zpravidla chceme, aby se ostatní prvky posunuly a obsadily uvolněné místo. Očekáváme, že nyní budeme mít kratší pole. -So, special methods should be used. +Měli bychom tedy použít speciální metody. -The [arr.splice](mdn:js/Array/splice) method is a Swiss army knife for arrays. It can do everything: insert, remove and replace elements. +Metoda [pole.splice](mdn:js/Array/splice) je jako švýcarský nůž pro pole. Umí všechno: vkládat, odstraňovat i nahrazovat prvky. -The syntax is: +Syntaxe je: ```js -arr.splice(start[, deleteCount, elem1, ..., elemN]) +pole.splice(začátek[, početSmazaných, prvek1, ..., prvekN]) ``` -It modifies `arr` starting from the index `start`: removes `deleteCount` elements and then inserts `elem1, ..., elemN` at their place. Returns the array of removed elements. +Modifikuje `pole` od indexu `začátek`: napřed odstraní `početSmazaných` prvků a pak vloží na jejich místo `prvek1, ..., prvekN`. Vrátí pole odstraněných prvků. -This method is easy to grasp by examples. +Tato metoda je snadno pochopitelná na příkladech. -Let's start with the deletion: +Začněme s mazáním: ```js run -let arr = ["I", "study", "JavaScript"]; +let pole = ["Já", "studuji", "JavaScript"]; *!* -arr.splice(1, 1); // from index 1 remove 1 element +pole.splice(1, 1); // od indexu 1 odstraníme 1 prvek */!* -alert( arr ); // ["I", "JavaScript"] +alert( pole ); // ["Já", "JavaScript"] ``` -Easy, right? Starting from the index `1` it removed `1` element. +Snadné, že? Počínajíc indexem `1` metoda odstranila `1` prvek. -In the next example, we remove 3 elements and replace them with the other two: +V dalším příkladu odstraníme 3 prvky a nahradíme je dvěma jinými: ```js run -let arr = [*!*"I", "study", "JavaScript",*/!* "right", "now"]; +let pole = [*!*"Já", "studuji", "JavaScript",*/!* "právě", "teď"]; -// remove 3 first elements and replace them with another -arr.splice(0, 3, "Let's", "dance"); +// odstraníme první 3 prvky a nahradíme je dvěma jinými +pole.splice(0, 3, "Zatancujme", "si"); -alert( arr ) // now [*!*"Let's", "dance"*/!*, "right", "now"] +alert( pole ) // nyní [*!*"Zatancujme", "si"*/!*, "právě", "teď"] ``` -Here we can see that `splice` returns the array of removed elements: +Zde vidíme, že `splice` vrací pole odstraněných prvků: ```js run -let arr = [*!*"I", "study",*/!* "JavaScript", "right", "now"]; +let pole = [*!*"Já", "studuji",*/!* "JavaScript", "právě", "teď"]; -// remove 2 first elements -let removed = arr.splice(0, 2); +// odstraníme první 2 prvky +let odstraněno = pole.splice(0, 2); -alert( removed ); // "I", "study" <-- array of removed elements +alert( odstraněno ); // "Já", "studuji" <-- pole odstraněných prvků ``` -The `splice` method is also able to insert the elements without any removals. For that, we need to set `deleteCount` to `0`: +Metoda `splice` dokáže také vkládat prvky bez odstraňování. Toho dosáhneme tak, že nastavíme `početSmazaných` na `0`: ```js run -let arr = ["I", "study", "JavaScript"]; +let pole = ["Já", "studuji", "JavaScript"]; -// from index 2 -// delete 0 -// then insert "complex" and "language" -arr.splice(2, 0, "complex", "language"); +// od indexu 2 +// smažeme 0 prvků +// pak vložíme "složitý" a "jazyk" +pole.splice(2, 0, "složitý", "jazyk"); -alert( arr ); // "I", "study", "complex", "language", "JavaScript" +alert( pole ); // "Já", "studuji", "složitý", "jazyk", "JavaScript" ``` -````smart header="Negative indexes allowed" -Here and in other array methods, negative indexes are allowed. They specify the position from the end of the array, like here: +````smart header="Záporné indexy jsou povoleny" +Zde i v jiných metodách polí jsou povoleny záporné indexy. Ty specifikují pozici od konce pole, například: ```js run -let arr = [1, 2, 5]; +let pole = [1, 2, 5]; -// from index -1 (one step from the end) -// delete 0 elements, -// then insert 3 and 4 -arr.splice(-1, 0, 3, 4); +// od indexu -1 (jeden krok před koncem) +// smažeme 0 prvků, +// pak vložíme 3 a 4 +pole.splice(-1, 0, 3, 4); -alert( arr ); // 1,2,3,4,5 +alert( pole ); // 1,2,3,4,5 ``` ```` ### slice -The method [arr.slice](mdn:js/Array/slice) is much simpler than the similar-looking `arr.splice`. +Metoda [pole.slice](mdn:js/Array/slice) je mnohem jednodušší než podobně vypadající `pole.splice`. -The syntax is: +Syntaxe je: ```js -arr.slice([start], [end]) +pole.slice([začátek], [konec]) ``` -It returns a new array copying to it all items from index `start` to `end` (not including `end`). Both `start` and `end` can be negative, in that case position from array end is assumed. +Vrátí nové pole, do něhož zkopíruje všechny prvky od indexu `začátek` do indexu `konec` (`konec` není zahrnut). Jak `začátek`, tak `konec` mohou být záporné. V tom případě se pozice počítá od konce pole. -It's similar to a string method `str.slice`, but instead of substrings, it makes subarrays. +Podobá se řetězcové metodě `str.slice`, ale místo podřetězců vytváří podpole. -For instance: +Například: ```js run -let arr = ["t", "e", "s", "t"]; +let pole = ["t", "e", "s", "t"]; -alert( arr.slice(1, 3) ); // e,s (copy from 1 to 3) +alert( pole.slice(1, 3) ); // e,s (kopíruje od 1 do 3) -alert( arr.slice(-2) ); // s,t (copy from -2 till the end) +alert( pole.slice(-2) ); // s,t (kopíruje od -2 do konce) ``` -We can also call it without arguments: `arr.slice()` creates a copy of `arr`. That's often used to obtain a copy for further transformations that should not affect the original array. +Můžeme ji volat i bez argumentů: `pole.slice()` vytvoří kopii `pole`. To se často používá k vytvoření kopie pole pro další transformace, které nemají ovlivnit původní pole. ### concat -The method [arr.concat](mdn:js/Array/concat) creates a new array that includes values from other arrays and additional items. +Metoda [pole.concat](mdn:js/Array/concat) vytvoří nové pole, které obsahuje hodnoty z jiných polí a další prvky. -The syntax is: +Syntaxe je: ```js -arr.concat(arg1, arg2...) +pole.concat(arg1, arg2...) ``` -It accepts any number of arguments -- either arrays or values. +Přijímá libovolný počet argumentů -- mohou jimi být pole nebo hodnoty. -The result is a new array containing items from `arr`, then `arg1`, `arg2` etc. +Výsledkem je nové pole, které obsahuje prvky z `pole`, pak `arg1`, `arg2` atd. -If an argument `argN` is an array, then all its elements are copied. Otherwise, the argument itself is copied. +Je-li argument `argN` pole, pak se zkopírují všechny jeho prvky. V opačném případě se zkopíruje sám argument. -For instance: +Příklad: ```js run -let arr = [1, 2]; +let pole = [1, 2]; -// create an array from: arr and [3,4] -alert( arr.concat([3, 4]) ); // 1,2,3,4 +// vytvoříme pole z: pole a [3,4] +alert( pole.concat([3, 4]) ); // 1,2,3,4 -// create an array from: arr and [3,4] and [5,6] -alert( arr.concat([3, 4], [5, 6]) ); // 1,2,3,4,5,6 +// vytvoříme pole z: pole a [3,4] a [5,6] +alert( pole.concat([3, 4], [5, 6]) ); // 1,2,3,4,5,6 -// create an array from: arr and [3,4], then add values 5 and 6 -alert( arr.concat([3, 4], 5, 6) ); // 1,2,3,4,5,6 +// vytvoříme pole z: pole a [3,4], pak přidáme hodnoty 5 a 6 +alert( pole.concat([3, 4], 5, 6) ); // 1,2,3,4,5,6 ``` -Normally, it only copies elements from arrays. Other objects, even if they look like arrays, are added as a whole: +Běžně kopíruje prvky jen z polí. Ostatní objekty, i ty, které vypadají jako pole, se přidají jako celek: ```js run -let arr = [1, 2]; +let pole = [1, 2]; -let arrayLike = { - 0: "something", +let jakoPole = { + 0: "něco", length: 1 }; -alert( arr.concat(arrayLike) ); // 1,2,[object Object] +alert( pole.concat(jakoPole) ); // 1,2,[object Object] ``` -...But if an array-like object has a special `Symbol.isConcatSpreadable` property, then it's treated as an array by `concat`: its elements are added instead: +...Jestliže však objekt podobný poli má speciální vlastnost `Symbol.isConcatSpreadable`, pak s ním metoda `concat` zachází jako s polem -- místo objektu se přidají jeho prvky: ```js run -let arr = [1, 2]; +let pole = [1, 2]; -let arrayLike = { - 0: "something", - 1: "else", +let jakoPole = { + 0: "něco", + 1: "jiného", *!* [Symbol.isConcatSpreadable]: true, */!* length: 2 }; -alert( arr.concat(arrayLike) ); // 1,2,something,else +alert( pole.concat(jakoPole) ); // 1,2,něco,jiného ``` -## Iterate: forEach +## Iterace: forEach -The [arr.forEach](mdn:js/Array/forEach) method allows to run a function for every element of the array. +Metoda [pole.forEach](mdn:js/Array/forEach) umožňuje pro každý prvek pole volat zadanou funkci. -The syntax: +Syntaxe: ```js -arr.forEach(function(item, index, array) { - // ... do something with an item +pole.forEach(function(prvek, index, pole) { + // ... provádí něco s prvkem }); ``` -For instance, this shows each element of the array: +Například tohle zobrazí každý prvek pole: ```js run -// for each element call alert -["Bilbo", "Gandalf", "Nazgul"].forEach(alert); +// pro každý prvek volá alert +["Bilbo", "Gandalf", "Nazgúl"].forEach(alert); ``` -And this code is more elaborate about their positions in the target array: +A tento kód podrobně vypíše pozice prvků v cílovém poli: ```js run -["Bilbo", "Gandalf", "Nazgul"].forEach((item, index, array) => { - alert(`${item} is at index ${index} in ${array}`); +["Bilbo", "Gandalf", "Nazgúl"].forEach((prvek, index, pole) => { + alert(`${prvek} je na indexu ${index} v poli ${pole}`); }); ``` -The result of the function (if it returns any) is thrown away and ignored. +Pokud funkce vrátí nějaký výsledek, je zahozen a ignorován. -## Searching in array +## Hledání v poli -Now let's cover methods that search in an array. +Uveďme nyní metody, které prohledávají pole. -### indexOf/lastIndexOf and includes +### indexOf/lastIndexOf a includes -The methods [arr.indexOf](mdn:js/Array/indexOf) and [arr.includes](mdn:js/Array/includes) have the similar syntax and do essentially the same as their string counterparts, but operate on items instead of characters: +Metody [pole.indexOf](mdn:js/Array/indexOf) a [pole.includes](mdn:js/Array/includes) mají podobnou syntaxi a dělají v zásadě totéž, jako jejich řetězcové protějšky, ale místo znaků pracují nad prvky pole: -- `arr.indexOf(item, from)` -- looks for `item` starting from index `from`, and returns the index where it was found, otherwise `-1`. -- `arr.includes(item, from)` -- looks for `item` starting from index `from`, returns `true` if found. +- `pole.indexOf(prvek, odkud)` -- hledá `prvek` počínajíc indexem `odkud` a vrátí index, na němž byl prvek nalezen, anebo `-1`, když nalezen nebyl. +- `pole.includes(prvek, odkud)` -- hledá `prvek` počínajíc indexem `odkud` a vrátí `true`, pokud byl nalezen. -Usually, these methods are used with only one argument: the `item` to search. By default, the search is from the beginning. +Tyto metody se obvykle používají jen s jedním argumentem: tím je `prvek`, který se má hledat. Standardně se hledá od začátku pole. -For instance: +Příklad: ```js run -let arr = [1, 0, false]; +let pole = [1, 0, false]; -alert( arr.indexOf(0) ); // 1 -alert( arr.indexOf(false) ); // 2 -alert( arr.indexOf(null) ); // -1 +alert( pole.indexOf(0) ); // 1 +alert( pole.indexOf(false) ); // 2 +alert( pole.indexOf(null) ); // -1 -alert( arr.includes(1) ); // true +alert( pole.includes(1) ); // true ``` -Please note that `indexOf` uses the strict equality `===` for comparison. So, if we look for `false`, it finds exactly `false` and not the zero. +Prosíme všimněte si, že metoda `indexOf` používá striktní porovnávání `===`. Hledáme-li tedy `false`, najde přesně `false` a ne nulu. -If we want to check if `item` exists in the array and don't need the index, then `arr.includes` is preferred. +Pokud chceme jen ověřit, zda `prvek` je obsažen v poli, a nepotřebujeme jeho index, dává se přednost metodě `pole.includes`. -The method [arr.lastIndexOf](mdn:js/Array/lastIndexOf) is the same as `indexOf`, but looks for from right to left. +Metoda [pole.lastIndexOf](mdn:js/Array/lastIndexOf) je totéž jako `indexOf`, ale hledá zprava doleva. ```js run -let fruits = ['Apple', 'Orange', 'Apple'] +let ovoce = ['Jablko', 'Pomeranč', 'Jablko'] -alert( fruits.indexOf('Apple') ); // 0 (first Apple) -alert( fruits.lastIndexOf('Apple') ); // 2 (last Apple) +alert( ovoce.indexOf('Jablko') ); // 0 (první Jablko) +alert( ovoce.lastIndexOf('Jablko') ); // 2 (poslední Jablko) ``` -````smart header="The `includes` method handles `NaN` correctly" -A minor, but noteworthy feature of `includes` is that it correctly handles `NaN`, unlike `indexOf`: +````smart header="Metoda `includes` zpracovává správně `NaN`" +Drobný, ale pozoruhodný rozdíl metody `includes` je také v tom, že na rozdíl od `indexOf` správně zpracovává `NaN`: ```js run -const arr = [NaN]; -alert( arr.indexOf(NaN) ); // -1 (wrong, should be 0) -alert( arr.includes(NaN) );// true (correct) +const pole = [NaN]; +alert( pole.indexOf(NaN) ); // -1 (mělo by být 0, ale rovnost === pro NaN nefunguje) +alert( pole.includes(NaN) ); // true (správně) ``` -That's because `includes` was added to JavaScript much later and uses the more up-to-date comparison algorithm internally. +Je to proto, že metoda `includes` byla do JavaScriptu přidána mnohem později a vnitřně používá aktuálnější porovnávací algoritmus. ```` -### find and findIndex/findLastIndex +### find a findIndex/findLastIndex -Imagine we have an array of objects. How do we find an object with a specific condition? +Představme si, že máme pole objektů. Jak najdeme objekt, pro který platí specifická podmínka? -Here the [arr.find(fn)](mdn:js/Array/find) method comes in handy. +Tady se nám hodí metoda [pole.find(fn)](mdn:js/Array/find). -The syntax is: +Syntaxe je: ```js -let result = arr.find(function(item, index, array) { - // if true is returned, item is returned and iteration is stopped - // for falsy scenario returns undefined +let výsledek = pole.find(function(prvek, index, pole) { + // jestliže funkce vrátí true, bude vrácen prvek a iterace se zastaví + // pokud funkce vrátí samá false, bude vráceno undefined }); ``` -The function is called for elements of the array, one after another: +Funkce je volána na prvcích pole postupně na jednom za druhým: -- `item` is the element. -- `index` is its index. -- `array` is the array itself. +- `prvek` je prvek. +- `index` je jeho index. +- `pole` je samotné pole. -If it returns `true`, the search is stopped, the `item` is returned. If nothing is found, `undefined` is returned. +Jestliže vrátí `true`, hledání se zastaví a vrátí se `prvek`. Není-li nic nalezeno, vrátí se `undefined`. -For example, we have an array of users, each with the fields `id` and `name`. Let's find the one with `id == 1`: +Například máme pole uživatelů, každý má vlastnosti `id` a `jméno`. Najděme toho, který má `id == 1`: ```js run -let users = [ - {id: 1, name: "John"}, - {id: 2, name: "Pete"}, - {id: 3, name: "Mary"} +let uživatelé = [ + {id: 1, jméno: "Jan"}, + {id: 2, jméno: "Petr"}, + {id: 3, jméno: "Marie"} ]; -let user = users.find(item => item.id == 1); +let uživatel = uživatelé.find(prvek => prvek.id == 1); -alert(user.name); // John +alert(uživatel.jméno); // Jan ``` -In real life, arrays of objects are a common thing, so the `find` method is very useful. +V reálném životě se pole objektů běžně používají, takže metoda `find` je velmi užitečná. -Note that in the example we provide to `find` the function `item => item.id == 1` with one argument. That's typical, other arguments of this function are rarely used. +Všimněte si, že v tomto příkladu poskytujeme metodě `find` funkci `prvek => prvek.id == 1` s jedním argumentem. To je typické, ostatní argumenty této funkce se používají málokdy. -The [arr.findIndex](mdn:js/Array/findIndex) method has the same syntax but returns the index where the element was found instead of the element itself. The value of `-1` is returned if nothing is found. +Metoda [pole.findIndex](mdn:js/Array/findIndex) má stejnou syntaxi, ale namísto samotného prvku vrací index, na němž byl prvek nalezen. Jestliže nebylo nalezeno nic, vrátí hodnotu `-1`. -The [arr.findLastIndex](mdn:js/Array/findLastIndex) method is like `findIndex`, but searches from right to left, similar to `lastIndexOf`. +Metoda [pole.findLastIndex](mdn:js/Array/findLastIndex) je podobná metodě `findIndex`, ale hledá zprava doleva, podobně jako `lastIndexOf`. -Here's an example: +Příklad: ```js run -let users = [ - {id: 1, name: "John"}, - {id: 2, name: "Pete"}, - {id: 3, name: "Mary"}, - {id: 4, name: "John"} +let uživatelé = [ + {id: 1, jméno: "Jan"}, + {id: 2, jméno: "Petr"}, + {id: 3, jméno: "Marie"}, + {id: 4, jméno: "Jan"} ]; -// Find the index of the first John -alert(users.findIndex(user => user.name == 'John')); // 0 +// Najde index prvního Jana +alert(uživatelé.findIndex(uživatel => uživatel.jméno == 'Jan')); // 0 -// Find the index of the last John -alert(users.findLastIndex(user => user.name == 'John')); // 3 +// Najde index posledního Jana +alert(uživatelé.findLastIndex(uživatel => uživatel.jméno == 'Jan')); // 3 ``` ### filter -The `find` method looks for a single (first) element that makes the function return `true`. +Metoda `find` najde jediný (první) prvek, který způsobí, že funkce vrátí `true`. -If there may be many, we can use [arr.filter(fn)](mdn:js/Array/filter). +Jestliže takových prvků může být více, můžeme použít metodu [pole.filter(fn)](mdn:js/Array/filter). -The syntax is similar to `find`, but `filter` returns an array of all matching elements: +Její syntaxe je podobná `find`, ale `filter` vrací pole všech odpovídajících prvků: ```js -let results = arr.filter(function(item, index, array) { - // if true item is pushed to results and the iteration continues - // returns empty array if nothing found +let výsledky = pole.filter(function(prvek, index, pole) { + // vrátí-li true, prvek se vloží metodou push do výsledků a iterace pokračuje + // není-li nic nalezeno, je vráceno prázdné pole }); ``` -For instance: +Příklad: ```js run -let users = [ - {id: 1, name: "John"}, - {id: 2, name: "Pete"}, - {id: 3, name: "Mary"} +let uživatelé = [ + {id: 1, jméno: "Jan"}, + {id: 2, jméno: "Petr"}, + {id: 3, jméno: "Marie"} ]; -// returns array of the first two users -let someUsers = users.filter(item => item.id < 3); +// vrátí pole prvních dvou uživatelů +let nějacíUživatelé = uživatelé.filter(prvek => prvek.id < 3); -alert(someUsers.length); // 2 +alert(nějacíUživatelé.length); // 2 ``` -## Transform an array +## Transformace polí -Let's move on to methods that transform and reorder an array. +Přejděme nyní k metodám, které pole transformují a přeskupují. ### map -The [arr.map](mdn:js/Array/map) method is one of the most useful and often used. +Metoda [pole.map](mdn:js/Array/map) je jedna z nejužitečnějších a nejčastěji používaných. -It calls the function for each element of the array and returns the array of results. +Volá zadanou funkci pro každý prvek pole a vrací pole výsledků. -The syntax is: +Syntaxe je: ```js -let result = arr.map(function(item, index, array) { - // returns the new value instead of item +let výsledek = pole.map(function(prvek, index, pole) { + // vrátí novou hodnotu místo prvku }); ``` -For instance, here we transform each element into its length: +Například zde přetransformujeme každý prvek na jeho délku: ```js run -let lengths = ["Bilbo", "Gandalf", "Nazgul"].map(item => item.length); -alert(lengths); // 5,7,6 +let délky = ["Bilbo", "Gandalf", "Nazgúl"].map(prvek => prvek.length); +alert(délky); // 5,7,6 ``` ### sort(fn) -The call to [arr.sort()](mdn:js/Array/sort) sorts the array *in place*, changing its element order. +Volání metody [pole.sort()](mdn:js/Array/sort) seřadí pole *uvnitř* a změní pořadí jeho prvků. -It also returns the sorted array, but the returned value is usually ignored, as `arr` itself is modified. +Vrací také seřazené pole, ale návratová hodnota se obvykle ignoruje, jelikož je modifikováno samotné `pole`. -For instance: +Příklad: ```js run -let arr = [ 1, 2, 15 ]; +let pole = [ 1, 2, 15 ]; -// the method reorders the content of arr -arr.sort(); +// metoda přehází obsah pole +pole.sort(); -alert( arr ); // *!*1, 15, 2*/!* +alert( pole ); // *!*1, 15, 2*/!* ``` -Did you notice anything strange in the outcome? +Všimli jste si na výstupu něčeho divného? -The order became `1, 15, 2`. Incorrect. But why? +Seřazené pole je `1, 15, 2`. To není správně. Ale proč? -**The items are sorted as strings by default.** +**Prvky jsou standardně řazeny jako řetězce.** -Literally, all elements are converted to strings for comparisons. For strings, lexicographic ordering is applied and indeed `"2" > "15"`. +Všechny prvky bez výjimky se při porovnávání převádějí na řetězce. Pro řetězce se použije lexikografické řazení a skutečně `"2" > "15"`. -To use our own sorting order, we need to supply a function as the argument of `arr.sort()`. +Abychom použili naše vlastní řazení, musíme jako argument `pole.sort()` poskytnout funkci. -The function should compare two arbitrary values and return: +Tato funkce by měla porovnávat dvě libovolné hodnoty a vracet: ```js -function compare(a, b) { - if (a > b) return 1; // if the first value is greater than the second - if (a == b) return 0; // if values are equal - if (a < b) return -1; // if the first value is less than the second +function porovnej(a, b) { + if (a > b) return 1; // je-li první hodnota větší než druhá + if (a == b) return 0; // jsou-li si hodnoty rovny + if (a < b) return -1; // je-li první hodnota menší než druhá } ``` -For instance, to sort as numbers: +Například když řadíme čísla: ```js run -function compareNumeric(a, b) { +function porovnejČísla(a, b) { if (a > b) return 1; if (a == b) return 0; if (a < b) return -1; } -let arr = [ 1, 2, 15 ]; +let pole = [ 1, 2, 15 ]; *!* -arr.sort(compareNumeric); +pole.sort(porovnejČísla); */!* -alert(arr); // *!*1, 2, 15*/!* +alert(pole); // *!*1, 2, 15*/!* ``` -Now it works as intended. +Nyní to funguje tak, jak jsme zamýšleli. -Let's step aside and think about what's happening. The `arr` can be an array of anything, right? It may contain numbers or strings or objects or whatever. We have a set of *some items*. To sort it, we need an *ordering function* that knows how to compare its elements. The default is a string order. +Udělejme nyní krok stranou a zamysleme se nad tím, co se děje. `pole` může obsahovat cokoli, že? Může obsahovat čísla, řetězce, objekty, zkrátka cokoli. Máme sadu *nějakých prvků*. Abychom ji seřadili, potřebujeme *řadicí funkci*, která umí její prvky porovnat. Standardní řazení je řetězcové. -The `arr.sort(fn)` method implements a generic sorting algorithm. We don't need to care how it internally works (an optimized [quicksort](https://en.wikipedia.org/wiki/Quicksort) or [Timsort](https://en.wikipedia.org/wiki/Timsort) most of the time). It will walk the array, compare its elements using the provided function and reorder them, all we need is to provide the `fn` which does the comparison. +Metoda `pole.sort(fn)` implementuje generický algoritmus řazení. Nemusíme se zajímat o to, jak vnitřně funguje (většinou je to optimalizované [rychlé řazení (quicksort)](https://cs.wikipedia.org/wiki/Rychlé_řazení) nebo [Timsort](https://en.wikipedia.org/wiki/Timsort)). Projde pole, porovná jeho prvky poskytnutou funkcí a seřadí je. Vše, co potřebujeme, je poskytnout funkci `fn`, která provede porovnání. -By the way, if we ever want to know which elements are compared -- nothing prevents us from alerting them: +Mimochodem, jestliže chceme vědět, které prvky se porovnávají -- nic nám nebrání je zobrazit: ```js run [1, -2, 15, 2, 0, 8].sort(function(a, b) { @@ -463,221 +463,221 @@ By the way, if we ever want to know which elements are compared -- nothing preve }); ``` -The algorithm may compare an element with multiple others in the process, but it tries to make as few comparisons as possible. +Algoritmus může v tomto procesu porovnat jeden prvek s několika jinými, ale snaží se učinit co nejméně porovnání. -````smart header="A comparison function may return any number" -Actually, a comparison function is only required to return a positive number to say "greater" and a negative number to say "less". +````smart header="Porovnávací funkce může vracet číslo" +Ve skutečnosti se od porovnávací funkce vyžaduje jen to, aby vrátila kladné číslo, když říká „větší“, a záporné, když říká „menší“. -That allows to write shorter functions: +To nám umožňuje psát kratší funkce: ```js run -let arr = [ 1, 2, 15 ]; +let pole = [ 1, 2, 15 ]; -arr.sort(function(a, b) { return a - b; }); +pole.sort(function(a, b) { return a - b; }); -alert(arr); // *!*1, 2, 15*/!* +alert(pole); // *!*1, 2, 15*/!* ``` ```` -````smart header="Arrow functions for the best" -Remember [arrow functions](info:arrow-functions-basics)? We can use them here for neater sorting: +````smart header="Nejlepší jsou šipkové funkce" +Vzpomínáte si na [šipkové funkce](info:arrow-functions-basics)? Můžeme je zde použít, aby kód řazení byl úhlednější: ```js -arr.sort( (a, b) => a - b ); +pole.sort( (a, b) => a - b ); ``` -This works exactly the same as the longer version above. +Funguje to přesně stejně jako výše uvedená delší verze. ```` -````smart header="Use `localeCompare` for strings" -Remember [strings](info:string#correct-comparisons) comparison algorithm? It compares letters by their codes by default. +````smart header="Pro řetězce používejte `localeCompare`" +Vzpomínáte si na porovnávací algoritmus [pro řetězce](info:string#correct-comparisons)? Standardně porovnává písmena podle jejich kódů. -For many alphabets, it's better to use `str.localeCompare` method to correctly sort letters, such as `Ö`. +Pro mnoho abeced je lepší používat metodu `řetězec.localeCompare`, která seřadí správně písmena, např. `Č`. -For example, let's sort a few countries in German: +Například seřaďme několik států v češtině: ```js run -let countries = ['Österreich', 'Andorra', 'Vietnam']; +let státy = ['Česko', 'Andorra', 'Vietnam']; -alert( countries.sort( (a, b) => a > b ? 1 : -1) ); // Andorra, Vietnam, Österreich (wrong) +alert( státy.sort( (a, b) => a > b ? 1 : -1) ); // Andorra, Vietnam, Česko (špatně) -alert( countries.sort( (a, b) => a.localeCompare(b) ) ); // Andorra,Österreich,Vietnam (correct!) +alert( státy.sort( (a, b) => a.localeCompare(b) ) ); // Andorra, Česko, Vietnam (správně!) ``` ```` ### reverse -The method [arr.reverse](mdn:js/Array/reverse) reverses the order of elements in `arr`. +Metoda [pole.reverse](mdn:js/Array/reverse) převrátí pořadí prvků `pole`. -For instance: +Příklad: ```js run -let arr = [1, 2, 3, 4, 5]; -arr.reverse(); +let pole = [1, 2, 3, 4, 5]; +pole.reverse(); -alert( arr ); // 5,4,3,2,1 +alert( pole ); // 5,4,3,2,1 ``` -It also returns the array `arr` after the reversal. +I ona vrací převrácené `pole`. -### split and join +### split a join -Here's the situation from real life. We are writing a messaging app, and the person enters the comma-delimited list of receivers: `John, Pete, Mary`. But for us an array of names would be much more comfortable than a single string. How to get it? +Máme zde situaci z běžného života. Píšeme aplikaci pro posílání zpráv a uživatel zadá seznam příjemců oddělených čárkou: `Jan, Petr, Marie`. Pro nás by však bylo daleko pohodlnější mít pole jmen než jediný řetězec. Jak je získat? -The [str.split(delim)](mdn:js/String/split) method does exactly that. It splits the string into an array by the given delimiter `delim`. +Přesně tohle dělá metoda [řetězec.split(oddělovač)](mdn:js/String/split), která rozdělí řetězec na pole podle zadaného oddělovače `oddělovač`. -In the example below, we split by a comma followed by a space: +V níže uvedeném příkladu oddělujeme čárkou, po níž následuje mezera: ```js run -let names = 'Bilbo, Gandalf, Nazgul'; +let jména = 'Bilbo, Gandalf, Nazgúl'; -let arr = names.split(', '); +let pole = jména.split(', '); -for (let name of arr) { - alert( `A message to ${name}.` ); // A message to Bilbo (and other names) +for (let jméno of pole) { + alert( `Zpráva pro ${jméno}.` ); // Zpráva pro Bilbo (a další jména) } ``` -The `split` method has an optional second numeric argument -- a limit on the array length. If it is provided, then the extra elements are ignored. In practice it is rarely used though: +Metoda `split` má nepovinný druhý číselný argument -- limit délky pole. Pokud je uveden, pak se po dosažení tohoto limitu další prvky ignorují. V praxi se však používá jen zřídka: ```js run -let arr = 'Bilbo, Gandalf, Nazgul, Saruman'.split(', ', 2); +let pole = 'Bilbo, Gandalf, Nazgúl, Saruman'.split(', ', 2); -alert(arr); // Bilbo, Gandalf +alert(pole); // Bilbo, Gandalf ``` -````smart header="Split into letters" -The call to `split(s)` with an empty `s` would split the string into an array of letters: +````smart header="Rozdělení na písmena" +Volání `split(s)` s prázdným `s` rozdělí řetězec na pole písmen: ```js run -let str = "test"; +let řetězec = "test"; -alert( str.split('') ); // t,e,s,t +alert( řetězec.split('') ); // t,e,s,t ``` ```` -The call [arr.join(glue)](mdn:js/Array/join) does the reverse to `split`. It creates a string of `arr` items joined by `glue` between them. +Metoda [pole.join(spojka)](mdn:js/Array/join) provádí opak metody `split`. Vytvoří řetězec z prvků `pole`, které budou mezi sebou spojeny řetězcem `spojka`. -For instance: +Příklad: ```js run -let arr = ['Bilbo', 'Gandalf', 'Nazgul']; +let pole = ['Bilbo', 'Gandalf', 'Nazgúl']; -let str = arr.join(';'); // glue the array into a string using ; +let řetězec = pole.join(';'); // spojíme pole do řetězce pomocí ; -alert( str ); // Bilbo;Gandalf;Nazgul +alert( řetězec ); // Bilbo;Gandalf;Nazgúl ``` ### reduce/reduceRight -When we need to iterate over an array -- we can use `forEach`, `for` or `for..of`. +Když potřebujeme procházet prvky pole -- můžeme použít `forEach`, `for` nebo `for..of`. -When we need to iterate and return the data for each element -- we can use `map`. +Když potřebujeme procházet prvky a pro každý prvek vrátit nějaká data -- můžeme použít `map`. -The methods [arr.reduce](mdn:js/Array/reduce) and [arr.reduceRight](mdn:js/Array/reduceRight) also belong to that breed, but are a little bit more intricate. They are used to calculate a single value based on the array. +Do této skupiny patří i metody [pole.reduce](mdn:js/Array/reduce) a [pole.reduceRight](mdn:js/Array/reduceRight), ale ty jsou trochu záludnější. Používají se k výpočtu jediné hodnoty závisející na poli. -The syntax is: +Syntaxe je: ```js -let value = arr.reduce(function(accumulator, item, index, array) { +let hodnota = pole.reduce(function(akumulátor, prvek, index, pole) { // ... -}, [initial]); +}, [počátečníHodnota]); ``` -The function is applied to all array elements one after another and "carries on" its result to the next call. +Funkce se volá postupně na všech prvcích pole a svůj výsledek „přenáší“ do dalšího volání. -Arguments: +Argumenty: -- `accumulator` -- is the result of the previous function call, equals `initial` the first time (if `initial` is provided). -- `item` -- is the current array item. -- `index` -- is its position. -- `array` -- is the array. +- `akumulátor` -- výsledek předchozího volání funkce, napoprvé se rovná `počátečníHodnota` (je-li `počátečníHodnota` uvedena). +- `prvek` -- je aktuální prvek pole. +- `index` -- je jeho pozice. +- `pole` -- je pole. -As the function is applied, the result of the previous function call is passed to the next one as the first argument. +Poté, co je funkce provedena, se výsledek předchozího volání funkce předá jako první argument v dalším volání. -So, the first argument is essentially the accumulator that stores the combined result of all previous executions. And at the end, it becomes the result of `reduce`. +První argument je tedy v podstatě akumulátor, do něhož se ukládá kombinovaný výsledek ze všech předchozích volání. Nakonec se stane výsledkem funkce `reduce`. -Sounds complicated? +Zní to složitě? -The easiest way to grasp that is by example. +Nejjednodušší způsob, jak to pochopit, je příklad. -Here we get a sum of an array in one line: +Zde získáme součet celého pole na jediném řádku: ```js run -let arr = [1, 2, 3, 4, 5]; +let pole = [1, 2, 3, 4, 5]; -let result = arr.reduce((sum, current) => sum + current, 0); +let výsledek = pole.reduce((součet, aktuální) => součet + aktuální, 0); -alert(result); // 15 +alert(výsledek); // 15 ``` -The function passed to `reduce` uses only 2 arguments, that's typically enough. +Funkce předaná do `reduce` používá jen 2 argumenty, to zpravidla stačí. -Let's see the details of what's going on. +Podívejme se na podrobnosti toho, co se děje. -1. On the first run, `sum` is the `initial` value (the last argument of `reduce`), equals `0`, and `current` is the first array element, equals `1`. So the function result is `1`. -2. On the second run, `sum = 1`, we add the second array element (`2`) to it and return. -3. On the 3rd run, `sum = 3` and we add one more element to it, and so on... +1. Při prvním průběhu je `součet` roven hodnotě `počátečníHodnota` (poslední argument `reduce`), tedy `0`, a `aktuální` je první prvek pole, tedy `1`. Výsledek funkce je tedy `1`. +2. Při druhém průběhu `součet = 1`, přičteme k němu druhý prvek pole (`2`) a vrátíme výsledek. +3. Při třetím průběhu `součet = 3`, přičteme k němu další prvek, a tak dále... -The calculation flow: +Průběh výpočtu: ![](reduce.svg) -Or in the form of a table, where each row represents a function call on the next array element: +Nebo ve formě tabulky, v níž každý řádek představuje volání funkce na dalším prvku pole: -| |`sum`|`current`|result| +| |`součet`|`aktuální`|výsledek| |---|-----|---------|---------| -|the first call|`0`|`1`|`1`| -|the second call|`1`|`2`|`3`| -|the third call|`3`|`3`|`6`| -|the fourth call|`6`|`4`|`10`| -|the fifth call|`10`|`5`|`15`| +|první volání|`0`|`1`|`1`| +|druhé volání|`1`|`2`|`3`| +|třetí volání|`3`|`3`|`6`| +|čtvrté volání|`6`|`4`|`10`| +|páté volání|`10`|`5`|`15`| -Here we can clearly see how the result of the previous call becomes the first argument of the next one. +Tady jasně vidíme, jak se výsledek předchozího volání stává prvním argumentem následujícího. -We also can omit the initial value: +Můžeme také vypustit počáteční hodnotu: ```js run -let arr = [1, 2, 3, 4, 5]; +let pole = [1, 2, 3, 4, 5]; -// removed initial value from reduce (no 0) -let result = arr.reduce((sum, current) => sum + current); +// z reduce je odstraněna počáteční hodnota (žádná 0) +let výsledek = pole.reduce((součet, aktuální) => součet + aktuální); -alert( result ); // 15 +alert( výsledek ); // 15 ``` -The result is the same. That's because if there's no initial, then `reduce` takes the first element of the array as the initial value and starts the iteration from the 2nd element. +Výsledek je stejný. Je to proto, že není-li uvedena počáteční hodnota, `reduce` vezme jako počáteční hodnotu první prvek pole a zahájí iteraci až od druhého. -The calculation table is the same as above, minus the first row. +Výpočetní tabulka je stejná jako výše uvedená, jen bez prvního řádku. -But such use requires an extreme care. If the array is empty, then `reduce` call without initial value gives an error. +Takové použití však vyžaduje extrémní pozornost. Je-li pole prázdné, pak volání `reduce` bez počáteční hodnoty ohlásí chybu. -Here's an example: +Příklad: ```js run -let arr = []; +let pole = []; -// Error: Reduce of empty array with no initial value -// if the initial value existed, reduce would return it for the empty arr. -arr.reduce((sum, current) => sum + current); +// Chyba: Reduce of empty array with no initial value +// kdyby počáteční hodnota existovala, reduce by pro prázdné pole vrátila ji. +pole.reduce((součet, aktuální) => součet + aktuální); ``` -So it's advised to always specify the initial value. +Doporučuje se tedy počáteční hodnotu vždy uvádět. -The method [arr.reduceRight](mdn:js/Array/reduceRight) does the same but goes from right to left. +Metoda [pole.reduceRight](mdn:js/Array/reduceRight) dělá totéž, ale postupuje zprava doleva. ## Array.isArray -Arrays do not form a separate language type. They are based on objects. +Pole netvoří samostatný jazykový typ, ale jsou založena na objektech. -So `typeof` does not help to distinguish a plain object from an array: +Proto `typeof` nedokáže rozlišit planý objekt od pole: ```js run alert(typeof {}); // object -alert(typeof []); // object (same) +alert(typeof []); // object (totéž) ``` -...But arrays are used so often that there's a special method for that: [Array.isArray(value)](mdn:js/Array/isArray). It returns `true` if the `value` is an array, and `false` otherwise. +...Pole se však používají natolik často, že pro ně existuje speciální metoda: [Array.isArray(hodnota)](mdn:js/Array/isArray). Vrátí `true`, jestliže `hodnota` je pole, a `false` jinak. ```js run alert(Array.isArray({})); // false @@ -685,118 +685,118 @@ alert(Array.isArray({})); // false alert(Array.isArray([])); // true ``` -## Most methods support "thisArg" +## Většina metod podporuje „thisArg“ -Almost all array methods that call functions -- like `find`, `filter`, `map`, with a notable exception of `sort`, accept an optional additional parameter `thisArg`. +Téměř všechny metody polí, které volají funkce -- např. `find`, `filter`, `map`, s významnou výjimkou metody `sort`, přijímají nepovinný další parametr `thisArg`. -That parameter is not explained in the sections above, because it's rarely used. But for completeness, we have to cover it. +Tento parametr nebyl vysvětlen ve výše uvedených podkapitolách, protože se používá jen zřídka. Ale pro úplnost jej musíme uvést. -Here's the full syntax of these methods: +Zde je úplná syntaxe těchto metod: ```js -arr.find(func, thisArg); -arr.filter(func, thisArg); -arr.map(func, thisArg); +pole.find(funkce, thisArg); +pole.filter(funkce, thisArg); +pole.map(funkce, thisArg); // ... -// thisArg is the optional last argument +// thisArg je nepovinný poslední argument ``` -The value of `thisArg` parameter becomes `this` for `func`. +Hodnota parametru `thisArg` se ve funkci `funkce` stane `this`. -For example, here we use a method of `army` object as a filter, and `thisArg` passes the context: +Například zde použijeme metodu objektu `armáda` jako filtr a `thisArg` předá kontext: ```js run -let army = { - minAge: 18, - maxAge: 27, - canJoin(user) { - return user.age >= this.minAge && user.age < this.maxAge; +let armáda = { + minVěk: 18, + maxVěk: 27, + můžeVstoupit(uživatel) { + return uživatel.věk >= this.minVěk && uživatel.věk < this.maxVěk; } }; -let users = [ - {age: 16}, - {age: 20}, - {age: 23}, - {age: 30} +let uživatelé = [ + {věk: 16}, + {věk: 20}, + {věk: 23}, + {věk: 30} ]; *!* -// find users, for who army.canJoin returns true -let soldiers = users.filter(army.canJoin, army); +// najdeme uživatele, pro které armáda.můžeVstoupit vrátí true +let vojáci = uživatelé.filter(armáda.můžeVstoupit, armáda); */!* -alert(soldiers.length); // 2 -alert(soldiers[0].age); // 20 -alert(soldiers[1].age); // 23 +alert(vojáci.length); // 2 +alert(vojáci[0].věk); // 20 +alert(vojáci[1].věk); // 23 ``` -If in the example above we used `users.filter(army.canJoin)`, then `army.canJoin` would be called as a standalone function, with `this=undefined`, thus leading to an instant error. +Kdybychom v uvedeném příkladu použili `uživatelé.filter(armáda.můžeVstoupit)`, pak by `armáda.můžeVstoupit` byla volána jako samostatná funkce, v níž by bylo `this=undefined`, což by okamžitě vedlo k chybě. -A call to `users.filter(army.canJoin, army)` can be replaced with `users.filter(user => army.canJoin(user))`, that does the same. The latter is used more often, as it's a bit easier to understand for most people. +Volání `uživatelé.filter(armáda.můžeVstoupit, armáda)` můžeme nahradit za `uživatelé.filter(uživatel => armáda.můžeVstoupit(uživatel))`, které by udělalo totéž. Tato varianta se používá častěji, jelikož pro většinu lidí je trochu srozumitelnější. -## Summary +## Shrnutí -A cheat sheet of array methods: +Přehled metod polí: -- To add/remove elements: - - `push(...items)` -- adds items to the end, - - `pop()` -- extracts an item from the end, - - `shift()` -- extracts an item from the beginning, - - `unshift(...items)` -- adds items to the beginning. - - `splice(pos, deleteCount, ...items)` -- at index `pos` deletes `deleteCount` elements and inserts `items`. - - `slice(start, end)` -- creates a new array, copies elements from index `start` till `end` (not inclusive) into it. - - `concat(...items)` -- returns a new array: copies all members of the current one and adds `items` to it. If any of `items` is an array, then its elements are taken. +- Pro přidávání a odebírání prvků: + - `push(...prvky)` -- přidá prvky na konec. + - `pop()` -- vyjme prvek z konce. + - `shift()` -- vyjme prvek ze začátku. + - `unshift(...prvky)` -- přidá prvky na začátek. + - `splice(pozice, početSmazaných, ...prvky)` -- na indexu `pozice` smaže `početSmazaných` prvků a vloží `prvky`. + - `slice(začátek, konec)` -- vytvoří nové pole, zkopíruje do něj prvky od indexu `začátek` do indexu `konec` (kromě něj). + - `concat(...prvky)` -- vrátí nové pole: zkopíruje všechny prvky z aktuálního pole a přidá do něj `prvky`. Je-li kterýmkoli prvkem z `prvky` pole, pak se místo něj přidají jeho prvky. -- To search among elements: - - `indexOf/lastIndexOf(item, pos)` -- look for `item` starting from position `pos`, and return the index or `-1` if not found. - - `includes(value)` -- returns `true` if the array has `value`, otherwise `false`. - - `find/filter(func)` -- filter elements through the function, return first/all values that make it return `true`. - - `findIndex` is like `find`, but returns the index instead of a value. +- Pro hledání mezi prvky: + - `indexOf/lastIndexOf(prvek, pozice)` -- hledá `prvek` počínajíc pozicí `pozice`, vrátí jeho index nebo `-1`, pokud není nalezen. + - `includes(hodnota)` -- jestliže pole obsahuje hodnotu `hodnota`, vrátí `true`, jinak vrátí `false`. + - `find/filter(funkce)` -- filtruje prvky podle zadané funkce, vrátí první hodnotu/všechny hodnoty, na níž/nichž funkce vrátila `true`. + - `findIndex` je jako `find`, ale namísto hodnoty vrátí index. -- To iterate over elements: - - `forEach(func)` -- calls `func` for every element, does not return anything. +- Pro procházení prvků: + - `forEach(funkce)` -- volá `funkce` pro každý prvek, nic nevrací. -- To transform the array: - - `map(func)` -- creates a new array from results of calling `func` for every element. - - `sort(func)` -- sorts the array in-place, then returns it. - - `reverse()` -- reverses the array in-place, then returns it. - - `split/join` -- convert a string to array and back. - - `reduce/reduceRight(func, initial)` -- calculate a single value over the array by calling `func` for each element and passing an intermediate result between the calls. +- Pro transformaci pole: + - `map(funkce)` -- vytvoří nové pole z výsledků volání `funkce` pro každý prvek. + - `sort(funkce)` -- seřadí prvky uvnitř pole, pak toto pole vrátí. + - `reverse()` -- převrátí pořadí prvků uvnitř pole, pak toto pole vrátí. + - `split/join` -- převádí řetězec na pole a zpět. + - `reduce/reduceRight(funkce, počátečníHodnota)` -- vypočítá z pole jedinou hodnotu tak, že volá `funkce` pro každý prvek a předává mezivýsledek mezi voláními. -- Additionally: - - `Array.isArray(value)` checks `value` for being an array, if so returns `true`, otherwise `false`. +- Ostatní: + - `Array.isArray(hodnota)` ověří, zda `hodnota` je pole. Pokud ano, vrátí `true`, jinak vrátí `false`. -Please note that methods `sort`, `reverse` and `splice` modify the array itself. +Prosíme všimněte si, že metody `sort`, `reverse` a `splice` modifikují samotné pole. -These methods are the most used ones, they cover 99% of use cases. But there are few others: +Tyto metody jsou nejpoužívanější a v 99% případů dostačují. Existuje však i několik dalších: -- [arr.some(fn)](mdn:js/Array/some)/[arr.every(fn)](mdn:js/Array/every) check the array. +- [pole.some(fn)](mdn:js/Array/some)/[pole.every(fn)](mdn:js/Array/every) prověří pole. - The function `fn` is called on each element of the array similar to `map`. If any/all results are `true`, returns `true`, otherwise `false`. + Na každém prvku pole je volána funkce `fn`, podobně jako u funkce `map`. Jestliže některý výsledek je/všechny výsledky jsou `true`, vrátí `true`, jinak vrátí `false`. - These methods behave sort of like `||` and `&&` operators: if `fn` returns a truthy value, `arr.some()` immediately returns `true` and stops iterating over the rest of items; if `fn` returns a falsy value, `arr.every()` immediately returns `false` and stops iterating over the rest of items as well. - - We can use `every` to compare arrays: + Tyto metody se chovají obdobně jako operátory `||` a `&&`: jestliže `fn` vrátí pravdivou hodnotu, `pole.some()` okamžitě vrátí `true` a zastaví procházení zbývajících prvků; jestliže `fn` vrátí nepravdivou hodnotu, `pole.every()` okamžitě vrátí `false` a rovněž zastaví procházení zbývajících prvků. + Pomocí `every` můžeme porovnávat pole: + ```js run - function arraysEqual(arr1, arr2) { - return arr1.length === arr2.length && arr1.every((value, index) => value === arr2[index]); + function poleSeRovnají(pole1, pole2) { + return pole1.length === pole2.length && pole1.every((hodnota, index) => hodnota === pole2[index]); } - alert( arraysEqual([1, 2], [1, 2])); // true + alert( poleSeRovnají([1, 2], [1, 2])); // true ``` -- [arr.fill(value, start, end)](mdn:js/Array/fill) -- fills the array with repeating `value` from index `start` to `end`. +- [pole.fill(hodnota, začátek, konec)](mdn:js/Array/fill) -- vyplní pole opakující se hodnotou `hodnota` od indexu `začátek` do indexu `konec`. -- [arr.copyWithin(target, start, end)](mdn:js/Array/copyWithin) -- copies its elements from position `start` till position `end` into *itself*, at position `target` (overwrites existing). +- [pole.copyWithin(cíl, začátek, konec)](mdn:js/Array/copyWithin) -- zkopíruje prvky pole od pozice `začátek` do pozice `konec` *do téhož pole* na pozici `cíl` (existující prvky přepíše). -- [arr.flat(depth)](mdn:js/Array/flat)/[arr.flatMap(fn)](mdn:js/Array/flatMap) create a new flat array from a multidimensional array. +- [pole.flat(hloubka)](mdn:js/Array/flat)/[pole.flatMap(fn)](mdn:js/Array/flatMap) vytvoří nové jednorozměrné pole z vícerozměrného. -For the full list, see the [manual](mdn:js/Array). +Pro úplný seznam nahlédněte do [manuálu](mdn:js/Array). -At first sight, it may seem that there are so many methods, quite difficult to remember. But actually, that's much easier. +Na první pohled se může zdát, že je tady spousta metod a je těžké si je pamatovat. Ve skutečnosti je to však mnohem snazší. -Look through the cheat sheet just to be aware of them. Then solve the tasks of this chapter to practice, so that you have experience with array methods. +Projděte si přehled metod, abyste o nich věděli. Pak vyřešte úlohy v této kapitole, abyste se pocvičili. Tak získáte s metodami polí zkušenosti. -Afterwards whenever you need to do something with an array, and you don't know how -- come here, look at the cheat sheet and find the right method. Examples will help you to write it correctly. Soon you'll automatically remember the methods, without specific efforts from your side. +Když později budete potřebovat udělat něco s polem a nebudete vědět jak -- přijďte sem, podívejte se do přehledu a najděte správnou metodu. Příklady vám pomohou napsat ji správně. Brzy si budete metody automaticky pamatovat, aniž by vás to stálo nějakou zvláštní námahu. diff --git a/1-js/05-data-types/06-iterable/article.md b/1-js/05-data-types/06-iterable/article.md index e2c0d4f97..aaa7d4b6a 100644 --- a/1-js/05-data-types/06-iterable/article.md +++ b/1-js/05-data-types/06-iterable/article.md @@ -1,60 +1,59 @@ +# Iterovatelné objekty -# Iterables +*Iterovatelné* objekty jsou zobecněním polí. Je to koncept, který nám umožňuje učinit kterýkoli objekt použitelným v cyklu `for..of`. -*Iterable* objects are a generalization of arrays. That's a concept that allows us to make any object useable in a `for..of` loop. +Jistě, pole jsou iterovatelná. Existuje však mnoho dalších vestavěných objektů, které jsou rovněž iterovatelné. Například řetězce jsou také iterovatelné. -Of course, Arrays are iterable. But there are many other built-in objects, that are iterable as well. For instance, strings are also iterable. - -If an object isn't technically an array, but represents a collection (list, set) of something, then `for..of` is a great syntax to loop over it, so let's see how to make it work. +Jestliže objekt není technicky pole, ale představuje kolekci (seznam, množinu) nějakých prvků, pak je `for..of` skvělá syntaxe, jak tyto prvky procházet. Podívejme se tedy, jak ji zprovoznit. ## Symbol.iterator -We can easily grasp the concept of iterables by making one of our own. +Koncept iterovatelných objektů můžeme snadno pochopit tak, že si vytvoříme vlastní. -For instance, we have an object that is not an array, but looks suitable for `for..of`. +Například máme objekt, který sice není pole, ale zdá se být vhodný pro `for..of`. -Like a `range` object that represents an interval of numbers: +Třeba objekt `rozsah`, který představuje interval čísel: ```js -let range = { - from: 1, - to: 5 +let rozsah = { + začátek: 1, + konec: 5 }; -// We want the for..of to work: -// for(let num of range) ... num=1,2,3,4,5 +// Chceme, aby for..of fungovalo: +// for(let číslo of rozsah) ... číslo=1,2,3,4,5 ``` -To make the `range` object iterable (and thus let `for..of` work) we need to add a method to the object named `Symbol.iterator` (a special built-in symbol just for that). +Abychom učinili objekt `rozsah` iterovatelným (a tím zprovoznili `for..of`), musíme do tohoto objektu přidat metodu nazvanou `Symbol.iterator` (speciální vestavěný symbol právě pro tento účel). -1. When `for..of` starts, it calls that method once (or errors if not found). The method must return an *iterator* -- an object with the method `next`. -2. Onward, `for..of` works *only with that returned object*. -3. When `for..of` wants the next value, it calls `next()` on that object. -4. The result of `next()` must have the form `{done: Boolean, value: any}`, where `done=true` means that the loop is finished, otherwise `value` is the next value. +1. Když `for..of` začne, jedenkrát tuto metodu zavolá (nebo ohlásí chybu, není-li nalezena). Metoda musí vracet *iterátor* -- objekt obsahující metodu `next`. +2. Nadále `for..of` pracuje *pouze s tímto vráceným objektem*. +3. Když `for..of` chce další hodnotu, volá na tomto objektu `next()`. +4. Výsledek `next()` musí mít tvar `{done: Boolean, value: cokoli}`, kde `done=true` znamená, že cyklus má skončit, v opačném případě je `value` jeho další hodnotou. -Here's the full implementation for `range` with remarks: +Zde je úplná implementace objektu `rozsah` s komentáři: ```js run -let range = { - from: 1, - to: 5 +let rozsah = { + začátek: 1, + konec: 5 }; -// 1. call to for..of initially calls this -range[Symbol.iterator] = function() { +// 1. volání for..of nejprve zavolá tuto funkci +rozsah[Symbol.iterator] = function() { - // ...it returns the iterator object: - // 2. Onward, for..of works only with the iterator object below, asking it for next values + // ...tato funkce vrátí objekt iterátoru: + // 2. Od této chvíle for..of pracuje jen s níže uvedeným objektem iterátoru a ptá se ho na další hodnoty return { - current: this.from, - last: this.to, + aktuální: this.začátek, + poslední: this.konec, - // 3. next() is called on each iteration by the for..of loop + // 3. next() je volána cyklem for..of při každé iteraci next() { - // 4. it should return the value as an object {done:.., value :...} - if (this.current <= this.last) { - return { done: false, value: this.current++ }; + // 4. měla by vrátit hodnotu jako objekt {done:..., value :...} + if (this.aktuální <= this.poslední) { + return { done: false, value: this.aktuální++ }; } else { return { done: true }; } @@ -62,246 +61,245 @@ range[Symbol.iterator] = function() { }; }; -// now it works! -for (let num of range) { - alert(num); // 1, then 2, 3, 4, 5 +// teď to funguje! +for (let číslo of rozsah) { + alert(číslo); // 1, pak 2, 3, 4, 5 } ``` -Please note the core feature of iterables: separation of concerns. +Prosíme všimněte si důležité vlastnosti iterovatelných objektů: jednotlivé záležitosti jsou odděleny. -- The `range` itself does not have the `next()` method. -- Instead, another object, a so-called "iterator" is created by the call to `range[Symbol.iterator]()`, and its `next()` generates values for the iteration. +- Sám objekt `rozsah` nemá metodu `next()`. +- Místo toho se voláním `rozsah[Symbol.iterator]()` vytvoří jiný objekt, tzv. „iterátor“, a hodnoty pro iteraci generuje jeho metoda `next()`. -So, the iterator object is separate from the object it iterates over. +Objekt iterátoru je tedy oddělen od objektu, nad nímž se iteruje. -Technically, we may merge them and use `range` itself as the iterator to make the code simpler. +Technicky je můžeme spojit a použít jako iterátor samotný `rozsah`, abychom kód zjednodušili. -Like this: +Třeba takto: ```js run -let range = { - from: 1, - to: 5, +let rozsah = { + začátek: 1, + konec: 5, [Symbol.iterator]() { - this.current = this.from; + this.aktuální = this.začátek; return this; }, next() { - if (this.current <= this.to) { - return { done: false, value: this.current++ }; + if (this.aktuální <= this.konec) { + return { done: false, value: this.aktuální++ }; } else { return { done: true }; } } }; -for (let num of range) { - alert(num); // 1, then 2, 3, 4, 5 +for (let číslo of rozsah) { + alert(číslo); // 1, pak 2, 3, 4, 5 } ``` -Now `range[Symbol.iterator]()` returns the `range` object itself: it has the necessary `next()` method and remembers the current iteration progress in `this.current`. Shorter? Yes. And sometimes that's fine too. +Nyní `rozsah[Symbol.iterator]()` vrátí samotný objekt `rozsah`: ten obsahuje potřebnou metodu `next()` a pamatuje si aktuální krok iterace v `this.aktuální`. Je to kratší? Ano. A někdy je to i vhodné. -The downside is that now it's impossible to have two `for..of` loops running over the object simultaneously: they'll share the iteration state, because there's only one iterator -- the object itself. But two parallel for-ofs is a rare thing, even in async scenarios. +Nevýhodou je, že nyní nemůžeme mít dva cykly `for..of`, které budou nad tímto objektem probíhat současně: sdílely by stav iterace, protože iterátor je pouze jeden -- samotný objekt. Ale dva paralelní cykly `for..of` jsou vzácností, dokonce i v asynchronních scénářích. -```smart header="Infinite iterators" -Infinite iterators are also possible. For instance, the `range` becomes infinite for `range.to = Infinity`. Or we can make an iterable object that generates an infinite sequence of pseudorandom numbers. Also can be useful. +```smart header="Nekonečné iterátory" +Je možné vytvářet i nekonečné iterátory. Například `rozsah` se stane nekonečným pro `rozsah.konec = Infinity`. Nebo můžeme vytvořit iterovatelný objekt, který bude generovat nekonečnou posloupnost pseudonáhodných čísel. I ten může být užitečný. -There are no limitations on `next`, it can return more and more values, that's normal. +Na metodu `next` nejsou kladena žádná omezení, může vracet další a další hodnoty, to je normální. -Of course, the `for..of` loop over such an iterable would be endless. But we can always stop it using `break`. +Samozřejmě cyklus `for..of` nad takovým iterovatelným objektem by byl nekonečný. Vždy ho však můžeme zastavit příkazem `break`. ``` -## String is iterable +## Řetězec je iterovatelný -Arrays and strings are most widely used built-in iterables. +Nejčastěji používané iterovatelné objekty jsou pole a řetězce. -For a string, `for..of` loops over its characters: +U řetězce cyklus `for..of` prochází jeho znaky: ```js run -for (let char of "test") { - // triggers 4 times: once for each character - alert( char ); // t, then e, then s, then t +for (let znak of "test") { + // spustí se 4-krát: pro každý znak jednou + alert( znak ); // t, pak e, pak s, pak t } ``` -And it works correctly with surrogate pairs! +Funguje to korektně i se zástupnými páry! ```js run -let str = '𝒳😂'; -for (let char of str) { - alert( char ); // 𝒳, and then 😂 +let řetězec = '𝒳😂'; +for (let znak of řetězec) { + alert( znak ); // 𝒳, a pak 😂 } ``` -## Calling an iterator explicitly +## Explicitní volání iterátoru -For deeper understanding, let's see how to use an iterator explicitly. +Abychom tomu hlouběji porozuměli, podíváme se, jak použít iterátor explicitně. -We'll iterate over a string in exactly the same way as `for..of`, but with direct calls. This code creates a string iterator and gets values from it "manually": +Budeme iterovat nad řetězcem přesně stejným způsobem jako `for..of`, ale přímými voláními. Tento kód vytvoří řetězcový iterátor a získá z něj hodnoty „ručně“: ```js run -let str = "Hello"; +let řetězec = "Ahoj"; -// does the same as -// for (let char of str) alert(char); +// provádí totéž jako +// for (let znak of řetězec) alert(znak); *!* -let iterator = str[Symbol.iterator](); +let iterator = řetězec[Symbol.iterator](); */!* while (true) { - let result = iterator.next(); - if (result.done) break; - alert(result.value); // outputs characters one by one + let výsledek = iterator.next(); + if (výsledek.done) break; + alert(výsledek.value); // vypíše znaky jeden po druhém } ``` -That is rarely needed, but gives us more control over the process than `for..of`. For instance, we can split the iteration process: iterate a bit, then stop, do something else, and then resume later. +Tento přístup potřebujeme jen vzácně, ale dává nám více kontroly nad procesem než `for..of`. Například můžeme proces iterace rozdělit: trochu iterovat, pak to přerušit, udělat něco jiného a pak iteraci obnovit. -## Iterables and array-likes [#array-like] +## Iterovatelné objekty a objekty podobné polím [#array-like] -Two official terms look similar, but are very different. Please make sure you understand them well to avoid the confusion. +Tyto dva oficiální pojmy vypadají podobně, ale jsou zcela odlišné. Prosíme ujistěte se, že jim dobře rozumíte, abyste předešli zmatkům. -- *Iterables* are objects that implement the `Symbol.iterator` method, as described above. -- *Array-likes* are objects that have indexes and `length`, so they look like arrays. +- *Iterovatelné objekty* jsou objekty, které implementují metodu `Symbol.iterator`, jak je popsáno výše. +- *Objekty podobné polím (array-like)* jsou objekty, které mají indexy a vlastnost `length` (délku), takže vypadají jako pole. -When we use JavaScript for practical tasks in a browser or any other environment, we may meet objects that are iterables or array-likes, or both. +Když používáme JavaScript pro praktické úkoly v prohlížeči nebo v kterémkoli jiném prostředí, můžeme se setkat s objekty, které jsou iterovatelné, podobné polím, nebo obojí. -For instance, strings are both iterable (`for..of` works on them) and array-like (they have numeric indexes and `length`). +Například řetězce jsou jak iterovatelné (funguje na nich `for..of`), tak podobné polím (mají číselné indexy a vlastnost `length`). -But an iterable may not be array-like. And vice versa an array-like may not be iterable. +Iterovatelný objekt však nemusí být podobný poli. A naopak, objekt podobný poli nemusí být iterovatelný. -For example, the `range` in the example above is iterable, but not array-like, because it does not have indexed properties and `length`. +Například `rozsah` ve výše uvedeném příkladu je iterovatelný, ale ne podobný poli, jelikož nemá indexované vlastnosti a `length`. -And here's the object that is array-like, but not iterable: +A zde je objekt, který je podobný poli, ale ne iterovatelný: ```js run -let arrayLike = { // has indexes and length => array-like - 0: "Hello", - 1: "World", +let objektPodobnýPoli = { // má indexy a length => je podobný poli + 0: "Ahoj", + 1: "světe", length: 2 }; *!* -// Error (no Symbol.iterator) -for (let item of arrayLike) {} +// Chyba (objekt neobsahuje Symbol.iterator) +for (let prvek of objektPodobnýPoli) {} */!* ``` -Both iterables and array-likes are usually *not arrays*, they don't have `push`, `pop` etc. That's rather inconvenient if we have such an object and want to work with it as with an array. E.g. we would like to work with `range` using array methods. How to achieve that? +Jak iterovatelné objekty, tak objekty podobné polím zpravidla *nejsou pole*, tedy nemají `push`, `pop` atd. To je poněkud nepohodlné, když takový objekt máme a chceme s ním pracovat jako s polem. Například bychom chtěli pracovat s objektem `rozsah` pomocí metod polí. Jak toho docílit? ## Array.from -There's a universal method [Array.from](mdn:js/Array/from) that takes an iterable or array-like value and makes a "real" `Array` from it. Then we can call array methods on it. +Existuje univerzální metoda [Array.from](mdn:js/Array/from), která přijímá iterovatelnou nebo poli podobnou hodnotu a vytvoří z ní „opravdové“ pole `Array`. Na tom pak můžeme volat metody polí. -For instance: +Příklad: ```js run -let arrayLike = { - 0: "Hello", - 1: "World", +let objektPodobnýPoli = { + 0: "Ahoj", + 1: "světe", length: 2 }; *!* -let arr = Array.from(arrayLike); // (*) +let pole = Array.from(objektPodobnýPoli); // (*) */!* -alert(arr.pop()); // World (method works) +alert(pole.pop()); // světe (metoda funguje) ``` -`Array.from` at the line `(*)` takes the object, examines it for being an iterable or array-like, then makes a new array and copies all items to it. +`Array.from` na řádku `(*)` vezme objekt, prozkoumá, zda je iterovatelný nebo podobný poli, a pak vyrobí nové pole a zkopíruje do něj všechny jeho prvky. -The same happens for an iterable: +Pro iterovatelný objekt se děje totéž: ```js run -// assuming that range is taken from the example above -let arr = Array.from(range); -alert(arr); // 1,2,3,4,5 (array toString conversion works) +// předpokládáme, že rozsah vezmeme z výše uvedeného příkladu +let pole = Array.from(rozsah); +alert(pole); // 1,2,3,4,5 (konverze pole pomocí toString funguje) ``` -The full syntax for `Array.from` also allows us to provide an optional "mapping" function: +Úplná syntaxe `Array.from` nám také umožňuje poskytnout nepovinnou „mapovací“ funkci: ```js Array.from(obj[, mapFn, thisArg]) ``` -The optional second argument `mapFn` can be a function that will be applied to each element before adding it to the array, and `thisArg` allows us to set `this` for it. +Nepovinný druhý argument `mapFn` může být funkce, která bude aplikována na každý prvek, než bude přidán do pole, a `thisArg` nám umožňuje nastavit v této funkci `this`. -For instance: +Příklad: ```js run -// assuming that range is taken from the example above +// předpokládáme, že rozsah vezmeme z výše uvedeného příkladu -// square each number -let arr = Array.from(range, num => num * num); +// každé číslo umocníme na druhou +let pole = Array.from(rozsah, číslo => číslo * číslo); -alert(arr); // 1,4,9,16,25 +alert(pole); // 1,4,9,16,25 ``` -Here we use `Array.from` to turn a string into an array of characters: +Zde pomocí `Array.from` přetvoříme řetězec na pole znaků: ```js run -let str = '𝒳😂'; +let řetězec = '𝒳😂'; -// splits str into array of characters -let chars = Array.from(str); +// rozdělí řetězec na pole znaků +let znaky = Array.from(řetězec); -alert(chars[0]); // 𝒳 -alert(chars[1]); // 😂 -alert(chars.length); // 2 +alert(znaky[0]); // 𝒳 +alert(znaky[1]); // 😂 +alert(znaky.length); // 2 ``` -Unlike `str.split`, it relies on the iterable nature of the string and so, just like `for..of`, correctly works with surrogate pairs. +Na rozdíl od `řetězec.split` tato metoda využívá iterovatelnost řetězce, a proto, stejně jako `for..of`, funguje korektně se zástupnými páry. -Technically here it does the same as: +Technicky zde provádí totéž jako: ```js run -let str = '𝒳😂'; +let řetězec = '𝒳😂'; -let chars = []; // Array.from internally does the same loop -for (let char of str) { - chars.push(char); +let znaky = []; // Array.from interně vykonává stejný cyklus +for (let znak of řetězec) { + znaky.push(znak); } -alert(chars); +alert(znaky); ``` -...But it is shorter. +...Ale je to kratší. -We can even build surrogate-aware `slice` on it: +Můžeme na ní dokonce postavit metodu `slice`, která bude rozpoznávat zástupné páry: ```js run -function slice(str, start, end) { - return Array.from(str).slice(start, end).join(''); +function slice(řetězec, začátek, konec) { + return Array.from(řetězec).slice(začátek, konec).join(''); } -let str = '𝒳😂𩷶'; +let řetězec = '𝒳😂𩷶'; -alert( slice(str, 1, 3) ); // 😂𩷶 +alert( slice(řetězec, 1, 3) ); // 😂𩷶 -// the native method does not support surrogate pairs -alert( str.slice(1, 3) ); // garbage (two pieces from different surrogate pairs) +// nativní metoda nepodporuje zástupné páry +alert( řetězec.slice(1, 3) ); // nesmysly (dvě části z různých zástupných párů) ``` -## Summary - -Objects that can be used in `for..of` are called *iterable*. +## Shrnutí -- Technically, iterables must implement the method named `Symbol.iterator`. - - The result of `obj[Symbol.iterator]()` is called an *iterator*. It handles further iteration process. - - An iterator must have the method named `next()` that returns an object `{done: Boolean, value: any}`, here `done:true` denotes the end of the iteration process, otherwise the `value` is the next value. -- The `Symbol.iterator` method is called automatically by `for..of`, but we also can do it directly. -- Built-in iterables like strings or arrays, also implement `Symbol.iterator`. -- String iterator knows about surrogate pairs. +Objekty, které lze použít ve `for..of`, se nazývají *iterovatelné*. +- Technicky musejí iterovatelné objekty implementovat metodu s názvem `Symbol.iterator`. + - Výsledek metody `obj[Symbol.iterator]()` se nazývá *iterátor*. Řídí další iterační proces. + - Iterátor musí obsahovat metodu jménem `next()`, která vrací objekt `{done: Boolean, value: cokoli}`, v němž `done:true` oznamuje konec iteračního procesu, jinak `value` je další hodnota. +- Metoda `Symbol.iterator` je cyklem `for..of` volána automaticky, ale můžeme ji volat i přímo. +- Metodu `Symbol.iterator` implementují i vestavěné iterovatelné objekty, např. řetězce nebo pole. +- Řetězcový iterátor rozpoznává zástupné páry. -Objects that have indexed properties and `length` are called *array-like*. Such objects may also have other properties and methods, but lack the built-in methods of arrays. +Objekty, které mají indexované vlastnosti a vlastnost `length`, se nazývají *podobné polím*. Takové objekty mohou mít i jiné vlastnosti a metody, ale postrádají vestavěné metody polí. -If we look inside the specification -- we'll see that most built-in methods assume that they work with iterables or array-likes instead of "real" arrays, because that's more abstract. +Podíváme-li se do specifikace, uvidíme, že většina vestavěných metod předpokládá, že pracují s iterovatelnými nebo polím podobnými objekty místo „opravdových“ polí, protože je to abstraktnější. -`Array.from(obj[, mapFn, thisArg])` makes a real `Array` from an iterable or array-like `obj`, and we can then use array methods on it. The optional arguments `mapFn` and `thisArg` allow us to apply a function to each item. +`Array.from(obj[, mapFn, thisArg])` vytvoří opravdové pole `Array` z iterovatelného nebo poli podobného objektu `obj`. Na ně pak můžeme používat metody polí. Nepovinné argumenty `mapFn` a `thisArg` nám umožňují na každý prvek aplikovat funkci. \ No newline at end of file diff --git a/1-js/05-data-types/07-map-set/01-array-unique-map/_js.view/solution.js b/1-js/05-data-types/07-map-set/01-array-unique-map/_js.view/solution.js index de504e1ef..263a289e9 100644 --- a/1-js/05-data-types/07-map-set/01-array-unique-map/_js.view/solution.js +++ b/1-js/05-data-types/07-map-set/01-array-unique-map/_js.view/solution.js @@ -1,3 +1,3 @@ -function unique(arr) { - return Array.from(new Set(arr)); +function unikát(pole) { + return Array.from(new Set(pole)); } diff --git a/1-js/05-data-types/07-map-set/01-array-unique-map/_js.view/test.js b/1-js/05-data-types/07-map-set/01-array-unique-map/_js.view/test.js index cfc7b1fc3..f196ad2bb 100644 --- a/1-js/05-data-types/07-map-set/01-array-unique-map/_js.view/test.js +++ b/1-js/05-data-types/07-map-set/01-array-unique-map/_js.view/test.js @@ -1,15 +1,15 @@ -describe("unique", function() { - it("removes non-unique elements", function() { - let strings = ["Hare", "Krishna", "Hare", "Krishna", - "Krishna", "Krishna", "Hare", "Hare", ":-O" +describe("unikát", function() { + it("odstraní neunikátní prvky", function() { + let řetězce = ["Haré", "Kršna", "Haré", "Kršna", + "Kršna", "Kršna", "Haré", "Haré", ":-O" ]; - assert.deepEqual(unique(strings), ["Hare", "Krishna", ":-O"]); + assert.deepEqual(unikát(řetězce), ["Haré", "Kršna", ":-O"]); }); - it("does not change the source array", function() { - let strings = ["Krishna", "Krishna", "Hare", "Hare"]; - unique(strings); - assert.deepEqual(strings, ["Krishna", "Krishna", "Hare", "Hare"]); + it("nemění zdrojové pole", function() { + let řetězce = ["Kršna", "Kršna", "Haré", "Haré"]; + unikát(řetězce); + assert.deepEqual(řetězce, ["Kršna", "Kršna", "Haré", "Haré"]); }); }); diff --git a/1-js/05-data-types/07-map-set/01-array-unique-map/task.md b/1-js/05-data-types/07-map-set/01-array-unique-map/task.md index d68030032..c20c51517 100644 --- a/1-js/05-data-types/07-map-set/01-array-unique-map/task.md +++ b/1-js/05-data-types/07-map-set/01-array-unique-map/task.md @@ -2,26 +2,26 @@ importance: 5 --- -# Filter unique array members +# Filtrace unikátních prvků pole -Let `arr` be an array. +Nechť `pole` je nějaké pole. -Create a function `unique(arr)` that should return an array with unique items of `arr`. +Vytvořte funkci `unikát(pole)`, která vrátí pole obsahující všechny různé prvky `pole`. -For instance: +Příklad: ```js -function unique(arr) { - /* your code */ +function unikát(pole) { + /* váš kód */ } -let values = ["Hare", "Krishna", "Hare", "Krishna", - "Krishna", "Krishna", "Hare", "Hare", ":-O" +let řetězce = ["Haré", "Kršna", "Haré", "Kršna", + "Kršna", "Kršna", "Haré", "Haré", ":-O" ]; -alert( unique(values) ); // Hare, Krishna, :-O +alert( unikát(řetězce) ); // Haré, Kršna, :-O ``` -P.S. Here strings are used, but can be values of any type. +P.S. Zde jsou použity řetězce, ale mohou to být hodnoty libovolného typu. -P.P.S. Use `Set` to store unique values. +P.P.S. K uložení unikátních hodnot použijte `Set`. diff --git a/1-js/05-data-types/07-map-set/02-filter-anagrams/_js.view/solution.js b/1-js/05-data-types/07-map-set/02-filter-anagrams/_js.view/solution.js index b9f5016f8..1cb4cd4e5 100644 --- a/1-js/05-data-types/07-map-set/02-filter-anagrams/_js.view/solution.js +++ b/1-js/05-data-types/07-map-set/02-filter-anagrams/_js.view/solution.js @@ -1,11 +1,11 @@ -function aclean(arr) { - let map = new Map(); +function odstraňAnagramy(pole) { + let mapa = new Map(); - for(let word of arr) { - let sorted = word.toLowerCase().split("").sort().join(""); - map.set(sorted, word); + for(let slovo of pole) { + let seřazené = slovo.toLowerCase().split("").sort().join(""); + mapa.set(seřazené, slovo); } - return Array.from(map.values()); + return Array.from(mapa.values()); } \ No newline at end of file diff --git a/1-js/05-data-types/07-map-set/02-filter-anagrams/_js.view/test.js b/1-js/05-data-types/07-map-set/02-filter-anagrams/_js.view/test.js index 75acb36b7..ec8212b65 100644 --- a/1-js/05-data-types/07-map-set/02-filter-anagrams/_js.view/test.js +++ b/1-js/05-data-types/07-map-set/02-filter-anagrams/_js.view/test.js @@ -1,24 +1,24 @@ -function intersection(arr1, arr2) { - return arr1.filter(item => arr2.includes(item)); +function průnik(arr1, arr2) { + return arr1.filter(prvek => arr2.includes(prvek)); } -describe("aclean", function() { +describe("odstraňAnagramy", function() { - it("returns exactly 1 word from each anagram set", function() { - let arr = ["nap", "teachers", "cheaters", "PAN", "ear", "era", "hectares"]; + it("z každé sady anagramů vrátí právě 1 slovo", function() { + let pole = ["rak", "reklama", "makrela", "KRA", "kostel", "stolek", "karamel"]; - let result = aclean(arr); - assert.equal(result.length, 3); + let výsledek = odstraňAnagramy(pole); + assert.equal(výsledek.length, 3); - assert.equal(intersection(result, ["nap", "PAN"]).length, 1); - assert.equal(intersection(result, ["teachers", "cheaters", "hectares"]).length, 1); - assert.equal(intersection(result, ["ear", "era"]).length, 1); + assert.equal(intersection(výsledek, ["rak", "KRA"]).length, 1); + assert.equal(intersection(výsledek, ["reklama", "makrela", "karamel"]).length, 1); + assert.equal(intersection(výsledek, ["kostel", "stolek"]).length, 1); }); - it("is case-insensitive", function() { - let arr = ["era", "EAR"]; - assert.equal(aclean(arr).length, 1); + it("nerozlišuje malá a velká písmena", function() { + let pole = ["rak", "KRA"]; + assert.equal(odstraňAnagramy(pole).length, 1); }); }); \ No newline at end of file diff --git a/1-js/05-data-types/07-map-set/02-filter-anagrams/solution.md b/1-js/05-data-types/07-map-set/02-filter-anagrams/solution.md index 160675185..fb2f949dd 100644 --- a/1-js/05-data-types/07-map-set/02-filter-anagrams/solution.md +++ b/1-js/05-data-types/07-map-set/02-filter-anagrams/solution.md @@ -1,77 +1,77 @@ -To find all anagrams, let's split every word to letters and sort them. When letter-sorted, all anagrams are same. +Pro nalezení anagramů rozdělíme každé slovo na písmena a ta seřadíme podle abecedy. Po seřazení písmen budou všechny anagramy stejné. -For instance: +Příklad: ``` -nap, pan -> anp -ear, era, are -> aer -cheaters, hectares, teachers -> aceehrst +rak, kra -> akr +kostel, stolek -> eklost +reklama, makrela, karamel -> aaeklmr ... ``` -We'll use the letter-sorted variants as map keys to store only one value per each key: +Varianty slov se seřazenými písmeny použijeme jako klíče mapy, abychom uložili pro každý klíč jen jednu hodnotu: ```js run -function aclean(arr) { - let map = new Map(); +function odstraňAnagramy(pole) { + let mapa = new Map(); - for (let word of arr) { - // split the word by letters, sort them and join back + for (let slovo of pole) { + // rozdělíme slovo na písmena, seřadíme je a znovu spojíme *!* - let sorted = word.toLowerCase().split('').sort().join(''); // (*) + let seřazené = slovo.toLowerCase().split('').sort().join(''); // (*) */!* - map.set(sorted, word); + mapa.set(seřazené, slovo); } - return Array.from(map.values()); + return Array.from(mapa.values()); } -let arr = ["nap", "teachers", "cheaters", "PAN", "ear", "era", "hectares"]; +let pole = ["rak", "reklama", "makrela", "KRA", "kostel", "stolek", "karamel"]; -alert( aclean(arr) ); +alert( odstraňAnagramy(pole) ); ``` -Letter-sorting is done by the chain of calls in the line `(*)`. +Seřazení písmen se děje ve zřetězeném volání na řádku `(*)`. -For convenience let's split it into multiple lines: +Pro přehlednost jej rozdělme na několik řádků: ```js -let sorted = word // PAN - .toLowerCase() // pan - .split('') // ['p','a','n'] - .sort() // ['a','n','p'] - .join(''); // anp +let seřazené = slovo // KRA + .toLowerCase() // kra + .split('') // ['k','r','a'] + .sort() // ['a','k','r'] + .join(''); // akr ``` -Two different words `'PAN'` and `'nap'` receive the same letter-sorted form `'anp'`. +Dvě různá slova `'KRA'` a `'rak'` budou seřazena stejně na `'akr'`. -The next line put the word into the map: +Další řádek vloží slovo do mapy: ```js -map.set(sorted, word); +mapa.set(seřazené, slovo); ``` -If we ever meet a word the same letter-sorted form again, then it would overwrite the previous value with the same key in the map. So we'll always have at maximum one word per letter-form. +Jestliže příště přijde slovo se stejným seřazením písmen, přepíše v mapě předchozí hodnotu se stejným klíčem. Vždy tedy budeme mít pro každou seřazenou skupinu písmen nejvýše jedno slovo. -At the end `Array.from(map.values())` takes an iterable over map values (we don't need keys in the result) and returns an array of them. +Nakonec `Array.from(mapa.values())` vezme iterovatelný objekt nad hodnotami mapy (klíče ve výsledku nepotřebujeme), vytvoří z těchto hodnot pole a vrátí je. -Here we could also use a plain object instead of the `Map`, because keys are strings. +Zde bychom mohli místo `Map` použít i planý objekt, neboť klíče jsou řetězce. -That's how the solution can look: +Řešení by pak mohlo vypadat následovně: ```js run demo -function aclean(arr) { +function odstraňAnagramy(pole) { let obj = {}; - for (let i = 0; i < arr.length; i++) { - let sorted = arr[i].toLowerCase().split("").sort().join(""); - obj[sorted] = arr[i]; + for (let i = 0; i < pole.length; i++) { + let seřazené = pole[i].toLowerCase().split("").sort().join(""); + obj[seřazené] = pole[i]; } return Object.values(obj); } -let arr = ["nap", "teachers", "cheaters", "PAN", "ear", "era", "hectares"]; +let pole = ["rak", "reklama", "makrela", "KRA", "kostel", "stolek", "karamel"]; -alert( aclean(arr) ); +alert( odstraňAnagramy(pole) ); ``` diff --git a/1-js/05-data-types/07-map-set/02-filter-anagrams/task.md b/1-js/05-data-types/07-map-set/02-filter-anagrams/task.md index 731fd2c25..4d1f36a00 100644 --- a/1-js/05-data-types/07-map-set/02-filter-anagrams/task.md +++ b/1-js/05-data-types/07-map-set/02-filter-anagrams/task.md @@ -2,27 +2,26 @@ importance: 4 --- -# Filter anagrams +# Filtrace anagramů -[Anagrams](https://en.wikipedia.org/wiki/Anagram) are words that have the same number of same letters, but in different order. +[Anagramy](https://cs.wikipedia.org/wiki/Anagram) neboli přesmyčky jsou slova, která obsahují stejné počty stejných písmen, ale v jiném pořadí. -For instance: +Příklad: ``` -nap - pan -ear - are - era -cheaters - hectares - teachers +rak - kra +kostel - stolek +reklama - makrela - karamel ``` -Write a function `aclean(arr)` that returns an array cleaned from anagrams. +Napište funkci `odstraňAnagramy(pole)`, která vrátí pole zbavené anagramů. -For instance: +Příklad: ```js -let arr = ["nap", "teachers", "cheaters", "PAN", "ear", "era", "hectares"]; +let pole = ["rak", "reklama", "makrela", "KRA", "kostel", "stolek", "karamel"]; -alert( aclean(arr) ); // "nap,teachers,ear" or "PAN,cheaters,era" +alert( odstraňAnagramy(pole) ); // "rak,karamel,kostel" nebo "KRA,makrela,stolek" ``` -From every anagram group should remain only one word, no matter which one. - +Z každé skupiny přesmyček by mělo zbýt pouze jedno slovo. Nezáleží na tom, které. diff --git a/1-js/05-data-types/07-map-set/03-iterable-keys/solution.md b/1-js/05-data-types/07-map-set/03-iterable-keys/solution.md index 7310d1d36..36469cb06 100644 --- a/1-js/05-data-types/07-map-set/03-iterable-keys/solution.md +++ b/1-js/05-data-types/07-map-set/03-iterable-keys/solution.md @@ -1,19 +1,19 @@ -That's because `map.keys()` returns an iterable, but not an array. +Je to proto, že `mapa.keys()` vrací iterovatelný objekt, ale ne pole. -We can convert it into an array using `Array.from`: +Můžeme jej převést na pole pomocí `Array.from`: ```js run -let map = new Map(); +let mapa = new Map(); -map.set("name", "John"); +mapa.set("jméno", "Jan"); *!* -let keys = Array.from(map.keys()); +let klíče = Array.from(mapa.keys()); */!* -keys.push("more"); +klíče.push("další"); -alert(keys); // name, more +alert(klíče); // jméno,další ``` diff --git a/1-js/05-data-types/07-map-set/03-iterable-keys/task.md b/1-js/05-data-types/07-map-set/03-iterable-keys/task.md index 81507647f..45e809093 100644 --- a/1-js/05-data-types/07-map-set/03-iterable-keys/task.md +++ b/1-js/05-data-types/07-map-set/03-iterable-keys/task.md @@ -2,23 +2,23 @@ importance: 5 --- -# Iterable keys +# Iterovatelné klíče -We'd like to get an array of `map.keys()` in a variable and then apply array-specific methods to it, e.g. `.push`. +Chtěli bychom uložit pole klíčů mapy `mapa.keys()` do proměnné a pak na ní volat metody specifické pro pole, např. `.push`. -But that doesn't work: +Tohle však nefunguje: ```js run -let map = new Map(); +let mapa = new Map(); -map.set("name", "John"); +mapa.set("jméno", "Jan"); -let keys = map.keys(); +let klíče = mapa.keys(); *!* -// Error: keys.push is not a function -keys.push("more"); +// Chyba: klíče.push není funkce +klíče.push("další"); */!* ``` -Why? How can we fix the code to make `keys.push` work? +Proč? Jak můžeme opravit kód, aby `klíče.push` fungovalo? diff --git a/1-js/05-data-types/07-map-set/article.md b/1-js/05-data-types/07-map-set/article.md index 37f5e48c2..280451b38 100644 --- a/1-js/05-data-types/07-map-set/article.md +++ b/1-js/05-data-types/07-map-set/article.md @@ -1,331 +1,330 @@ +# Mapa a množina -# Map and Set +Prozatím jsme se naučili dvěma následujícím složitým datovým strukturám: -Till now, we've learned about the following complex data structures: +- Objekty se používají k ukládání kolekcí hodnot pod klíči. +- Pole se používají k ukládání seřazených kolekcí. -- Objects are used for storing keyed collections. -- Arrays are used for storing ordered collections. +Pro skutečný život to však nestačí. Proto existují také `Map` (mapa) a `Set` (množina). -But that's not enough for real life. That's why `Map` and `Set` also exist. +## Mapa -## Map +[Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) je kolekce datových prvků uložených pod klíči, podobně jako `Object`. Hlavní rozdíl je však v tom, že `Map` umožňuje klíče libovolného typu. -[Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) is a collection of keyed data items, just like an `Object`. But the main difference is that `Map` allows keys of any type. +Její metody a vlastnosti jsou: -Methods and properties are: +- [`new Map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/Map) -- vytvoří mapu. +- [`map.set(klíč, hodnota)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set) -- uloží hodnotu `hodnota` pod klíčem `klíč`. +- [`map.get(klíč)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get) -- vrátí hodnotu uloženou pod klíčem `klíč`, jestliže `klíč` v mapě neexistuje, vrátí `undefined`. +- [`map.has(klíč)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has) -- vrátí `true`, jestliže `klíč` v mapě existuje, jinak `false`. +- [`map.delete(klíč)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete) -- odstraní prvek (dvojici klíč/hodnota) uložený pod klíčem `klíč`. +- [`map.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear) -- odstraní z mapy všechny prvky. +- [`map.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size) -- vrátí aktuální počet prvků. -- [`new Map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/Map) -- creates the map. -- [`map.set(key, value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set) -- stores the value by the key. -- [`map.get(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get) -- returns the value by the key, `undefined` if `key` doesn't exist in map. -- [`map.has(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has) -- returns `true` if the `key` exists, `false` otherwise. -- [`map.delete(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete) -- removes the element (the key/value pair) by the key. -- [`map.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear) -- removes everything from the map. -- [`map.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size) -- returns the current element count. - -For instance: +Příklad: ```js run -let map = new Map(); +let mapa = new Map(); -map.set('1', 'str1'); // a string key -map.set(1, 'num1'); // a numeric key -map.set(true, 'bool1'); // a boolean key +mapa.set('1', 'řetězec1'); // řetězcový klíč +mapa.set(1, 'číslo1'); // číselný klíč +mapa.set(true, 'bool1'); // booleovský klíč -// remember the regular Object? it would convert keys to string -// Map keeps the type, so these two are different: -alert( map.get(1) ); // 'num1' -alert( map.get('1') ); // 'str1' +// pamatujete si na obvyklý Object? ten převádí klíče na řetězce +// Map si pamatuje typ klíče, takže tyto dva klíče jsou rozdílné: +alert( mapa.get(1) ); // 'číslo1' +alert( mapa.get('1') ); // 'řetězec1' -alert( map.size ); // 3 +alert( mapa.size ); // 3 ``` -As we can see, unlike objects, keys are not converted to strings. Any type of key is possible. +Jak vidíme, na rozdíl od objektů zde nejsou klíče převáděny na řetězce. Jsou povoleny klíče jakýchkoli typů. -```smart header="`map[key]` isn't the right way to use a `Map`" -Although `map[key]` also works, e.g. we can set `map[key] = 2`, this is treating `map` as a plain JavaScript object, so it implies all corresponding limitations (only string/symbol keys and so on). +```smart header="`mapa[klíč]` není správný způsob, jak používat mapu" +Ačkoli `mapa[klíč]` funguje také, např. můžeme nastavit `mapa[klíč] = 2`, v tomto případě se s mapou zachází jako s planým JavaScriptovým objektem, takže zde platí všechna příslušná omezení (jen řetězcové/symbolické klíče a podobně). -So we should use `map` methods: `set`, `get` and so on. +Měli bychom tedy používat metody mapy: `set`, `get` a tak dále. ``` -**Map can also use objects as keys.** +**Mapa může používat jako klíče i objekty.** -For instance: +Příklad: ```js run -let john = { name: "John" }; +let jan = { jméno: "Jan" }; -// for every user, let's store their visits count -let visitsCountMap = new Map(); +// pro každého uživatele budeme ukládat počet jeho návštěv +let mapaPočetNávštěv = new Map(); -// john is the key for the map -visitsCountMap.set(john, 123); +// jan je klíč mapy +mapaPočetNávštěv.set(jan, 123); -alert( visitsCountMap.get(john) ); // 123 +alert( mapaPočetNávštěv.get(jan) ); // 123 ``` -Using objects as keys is one of the most notable and important `Map` features. The same does not count for `Object`. String as a key in `Object` is fine, but we can't use another `Object` as a key in `Object`. +Používání objektů jako klíčů je jedna z nejpozoruhodnějších a nejdůležitějších vlastností map. Pro `Object` to neplatí. Řetězec jako klíč objektu je správně, ale jako klíč objektu nemůžeme použít jiný `Object`. -Let's try: +Zkusme to: ```js run -let john = { name: "John" }; -let ben = { name: "Ben" }; +let jan = { jméno: "Jan" }; +let ben = { jméno: "Ben" }; -let visitsCountObj = {}; // try to use an object +let objPočetNávštěv = {}; // zkusíme použít objekt -visitsCountObj[ben] = 234; // try to use ben object as the key -visitsCountObj[john] = 123; // try to use john object as the key, ben object will get replaced +objPočetNávštěv[ben] = 234; // zkusíme použít jako klíč objekt ben +objPočetNávštěv[jan] = 123; // zkusíme použít jako klíč objekt jan, objekt ben bude nahrazen *!* -// That's what got written! -alert( visitsCountObj["[object Object]"] ); // 123 +// Toto bude zapsáno! +alert( objPočetNávštěv["[object Object]"] ); // 123 */!* ``` -As `visitsCountObj` is an object, it converts all `Object` keys, such as `john` and `ben` above, to same string `"[object Object]"`. Definitely not what we want. +Jelikož `objPočetNávštěv` je objekt, převede všechny klíče typu `Object`, např. uvedené `jan` a `ben`, na stejný řetězec `"[object Object]"`. To rozhodně není to, co jsme chtěli. -```smart header="How `Map` compares keys" -To test keys for equivalence, `Map` uses the algorithm [SameValueZero](https://tc39.github.io/ecma262/#sec-samevaluezero). It is roughly the same as strict equality `===`, but the difference is that `NaN` is considered equal to `NaN`. So `NaN` can be used as the key as well. +```smart header="Jak `Map` porovnává klíče" +Pro testování ekvivalence klíčů `Map` používá algoritmus [SameValueZero](https://tc39.github.io/ecma262/#sec-samevaluezero). Je téměř stejný jako striktní rovnost `===`, ale rozdíl spočívá v tom, že `NaN` se považuje za rovné `NaN`. Jako klíč tedy můžeme použít i `NaN`. -This algorithm can't be changed or customized. +Tento algoritmus nemůžeme změnit nebo si ho přizpůsobit. ``` -````smart header="Chaining" -Every `map.set` call returns the map itself, so we can "chain" the calls: +````smart header="Zřetězení" +Každé volání `mapa.set` vrátí samotnou mapu, takže volání můžeme „zřetězit“: ```js -map.set('1', 'str1') - .set(1, 'num1') +mapa.set('1', 'řetězec1') + .set(1, 'číslo1') .set(true, 'bool1'); ``` ```` -## Iteration over Map +## Iterace nad mapou -For looping over a `map`, there are 3 methods: +Pro procházení prvků mapy existují 3 metody: -- [`map.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys) -- returns an iterable for keys, -- [`map.values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/values) -- returns an iterable for values, -- [`map.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries) -- returns an iterable for entries `[key, value]`, it's used by default in `for..of`. +- [`mapa.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys) -- vrátí iterovatelný objekt klíčů, +- [`mapa.values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/values) -- vrátí iterovatelný objekt hodnot, +- [`mapa.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries) -- vrátí iterovatelný objekt dvojic `[klíč, hodnota]`, používá se standardně ve `for..of`. -For instance: +Příklad: ```js run -let recipeMap = new Map([ - ['cucumber', 500], - ['tomatoes', 350], - ['onion', 50] +let mapaRecept = new Map([ + ['okurky', 500], + ['rajčata', 350], + ['cibule', 50] ]); -// iterate over keys (vegetables) -for (let vegetable of recipeMap.keys()) { - alert(vegetable); // cucumber, tomatoes, onion +// iterace nad klíči (zelenina) +for (let zelenina of mapaRecept.keys()) { + alert(zelenina); // okurky, rajčata, cibule } -// iterate over values (amounts) -for (let amount of recipeMap.values()) { - alert(amount); // 500, 350, 50 +// iterace nad hodnotami (množství) +for (let množství of mapaRecept.values()) { + alert(množství); // 500, 350, 50 } -// iterate over [key, value] entries -for (let entry of recipeMap) { // the same as of recipeMap.entries() - alert(entry); // cucumber,500 (and so on) +// iterace nad dvojicemi [klíč, hodnota] +for (let dvojice of mapaRecept) { // totéž jako mapaRecept.entries() + alert(dvojice); // okurky,500 (a tak dále) } ``` -```smart header="The insertion order is used" -The iteration goes in the same order as the values were inserted. `Map` preserves this order, unlike a regular `Object`. +```smart header="Zachovává se pořadí vložení" +Iterace probíhá ve stejném pořadí, v jakém byly hodnoty vloženy. `Map` toto pořadí na rozdíl od `Object` zachovává. ``` -Besides that, `Map` has a built-in `forEach` method, similar to `Array`: +Navíc `Map` obsahuje vestavěnou metodu `forEach`, podobně jako `Array`: ```js -// runs the function for each (key, value) pair -recipeMap.forEach( (value, key, map) => { - alert(`${key}: ${value}`); // cucumber: 500 etc +// spustí tuto funkci pro každou dvojici (klíč, hodnota) +mapaRecepty.forEach( (hodnota, klíč, mapa) => { + alert(`${klíč}: ${hodnota}`); // okurky: 500 atd. }); ``` -## Object.entries: Map from Object +## Object.entries: mapa z objektu -When a `Map` is created, we can pass an array (or another iterable) with key/value pairs for initialization, like this: +Když je vytvořena mapa, můžeme do ní pro inicializaci předat pole (nebo jiný iterovatelný objekt) dvojic klíč/hodnota, například: ```js run -// array of [key, value] pairs -let map = new Map([ - ['1', 'str1'], - [1, 'num1'], +// pole dvojic [klíč, hodnota] +let mapa = new Map([ + ['1', 'řetězec1'], + [1, 'číslo1'], [true, 'bool1'] ]); -alert( map.get('1') ); // str1 +alert( mapa.get('1') ); // řetězec1 ``` -If we have a plain object, and we'd like to create a `Map` from it, then we can use built-in method [Object.entries(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries) that returns an array of key/value pairs for an object exactly in that format. +Máme-li planý objekt a rádi bychom z něj vytvořili mapu, můžeme použít vestavěnou metodu [Object.entries(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries), která vrací pole dvojic klíč/hodnota objektu přesně v tomto formátu. -So we can create a map from an object like this: +Můžeme tedy vytvořit mapu z objektu takto: ```js run let obj = { - name: "John", - age: 30 + jméno: "Jan", + věk: 30 }; *!* -let map = new Map(Object.entries(obj)); +let mapa = new Map(Object.entries(obj)); */!* -alert( map.get('name') ); // John +alert( mapa.get('jméno') ); // Jan ``` -Here, `Object.entries` returns the array of key/value pairs: `[ ["name","John"], ["age", 30] ]`. That's what `Map` needs. +Zde `Object.entries` vrací pole dvojic klíč/hodnota: `[ ["jméno","Jan"], ["věk", 30] ]`. To je přesně to, co potřebuje `Map`. -## Object.fromEntries: Object from Map +## Object.fromEntries: objekt z mapy -We've just seen how to create `Map` from a plain object with `Object.entries(obj)`. +Právě jsme viděli, jak vytvořit `Map` z planého objektu pomocí `Object.entries(obj)`. -There's `Object.fromEntries` method that does the reverse: given an array of `[key, value]` pairs, it creates an object from them: +Existuje i metoda `Object.fromEntries`, která provádí opak -- když jí předáme pole dvojic `[klíč, hodnota]`, vytvoří z něj objekt: ```js run -let prices = Object.fromEntries([ - ['banana', 1], - ['orange', 2], - ['meat', 4] +let ceny = Object.fromEntries([ + ['banán', 1], + ['pomeranč', 2], + ['maso', 4] ]); -// now prices = { banana: 1, orange: 2, meat: 4 } +// nyní ceny = { banán: 1, pomeranč: 2, maso: 4 } -alert(prices.orange); // 2 +alert(ceny.pomeranč); // 2 ``` -We can use `Object.fromEntries` to get a plain object from `Map`. +Použitím `Object.fromEntries` můžeme získat z mapy planý objekt. -E.g. we store the data in a `Map`, but we need to pass it to a 3rd-party code that expects a plain object. +Například uložíme do mapy data, ale potřebujeme je předat kódu třetí strany, který očekává planý objekt. -Here we go: +Postupujeme takto: ```js run -let map = new Map(); -map.set('banana', 1); -map.set('orange', 2); -map.set('meat', 4); +let mapa = new Map(); +mapa.set('banán', 1); +mapa.set('pomeranč', 2); +mapa.set('maso', 4); *!* -let obj = Object.fromEntries(map.entries()); // make a plain object (*) +let obj = Object.fromEntries(mapa.entries()); // vytvoří planý objekt (*) */!* -// done! -// obj = { banana: 1, orange: 2, meat: 4 } +// hotovo! +// obj = { banán: 1, pomeranč: 2, maso: 4 } -alert(obj.orange); // 2 +alert(obj.pomeranč); // 2 ``` -A call to `map.entries()` returns an iterable of key/value pairs, exactly in the right format for `Object.fromEntries`. +Volání `mapa.entries()` vrací iterovatelný objekt dvojic klíč/hodnota, přesně ve správném formátu pro `Object.fromEntries`. -We could also make line `(*)` shorter: +Řádek `(*)` můžeme také zkrátit: ```js -let obj = Object.fromEntries(map); // omit .entries() +let obj = Object.fromEntries(mapa); // vypustíme .entries() ``` -That's the same, because `Object.fromEntries` expects an iterable object as the argument. Not necessarily an array. And the standard iteration for `map` returns same key/value pairs as `map.entries()`. So we get a plain object with same key/values as the `map`. +To je totéž, protože `Object.fromEntries` očekává jako argument iterovatelný objekt, ne nutně pole. A standardní iterace mapy vrací stejné dvojice klíč/hodnota jako `mapa.entries()`. Dostaneme tedy planý objekt se stejnými dvojicemi klíč/hodnota, jaké obsahuje `mapa`. -## Set +## Množina -A [`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) is a special type collection - "set of values" (without keys), where each value may occur only once. +Množina [`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) je speciální typ kolekce -- „množina hodnot“ (bez klíčů), v níž se každá hodnota může vyskytnout pouze jednou. -Its main methods are: +Její hlavní metody jsou: -- [`new Set([iterable])`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/Set) -- creates the set, and if an `iterable` object is provided (usually an array), copies values from it into the set. -- [`set.add(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/add) -- adds a value, returns the set itself. -- [`set.delete(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/delete) -- removes the value, returns `true` if `value` existed at the moment of the call, otherwise `false`. -- [`set.has(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/has) -- returns `true` if the value exists in the set, otherwise `false`. -- [`set.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/clear) -- removes everything from the set. -- [`set.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/size) -- is the elements count. +- [`new Set([iterovatelnýObjekt])`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/Set) -- vytvoří množinu, a je-li poskytnut `iterovatelnýObjekt` (obvykle pole), zkopíruje do ní hodnoty z tohoto objektu. +- [`množina.add(hodnota)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/add) -- přidá hodnotu `hodnota`, vrátí samotnou množinu. +- [`množina.delete(hodnota)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/delete) -- odstraní hodnotu `hodnota`, vrátí `true`, jestliže `hodnota` v okamžiku volání v množině existovala, jinak `false`. +- [`množina.has(hodnota)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/has) -- vrátí `true`, jestliže hodnota `hodnota` v množině existuje, jinak `false`. +- [`množina.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/clear) -- odstraní z množiny všechny hodnoty. +- [`množina.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/size) -- je počet hodnot. -The main feature is that repeated calls of `set.add(value)` with the same value don't do anything. That's the reason why each value appears in a `Set` only once. +Hlavní vlastností množiny je, že opakovaná volání `množina.add(hodnota)` se stejnou hodnotou nic neudělají. To je důvod, proč se každá hodnota v množině objeví pouze jednou. -For example, we have visitors coming, and we'd like to remember everyone. But repeated visits should not lead to duplicates. A visitor must be "counted" only once. +Například máme přicházející návštěvníky a rádi bychom si je všechny pamatovali. Avšak opakované návštěvy by neměly vést ke zdvojení. Každý návštěvník musí být „započítán“ jen jednou. -`Set` is just the right thing for that: +`Set` je pro tento účel to pravé: ```js run -let set = new Set(); +let množina = new Set(); -let john = { name: "John" }; -let pete = { name: "Pete" }; -let mary = { name: "Mary" }; +let jan = { jméno: "Jan" }; +let petr = { jméno: "Petr" }; +let marie = { jméno: "Marie" }; -// visits, some users come multiple times -set.add(john); -set.add(pete); -set.add(mary); -set.add(john); -set.add(mary); +// návštěvy, někteří uživatelé přišli vícekrát +množina.add(jan); +množina.add(petr); +množina.add(marie); +množina.add(jan); +množina.add(marie); -// set keeps only unique values -alert( set.size ); // 3 +// množina si pamatuje jen unikátní hodnoty +alert( množina.size ); // 3 -for (let user of set) { - alert(user.name); // John (then Pete and Mary) +for (let uživatel of množina) { + alert(uživatel.jméno); // Jan (pak Petr a Marie) } ``` -The alternative to `Set` could be an array of users, and the code to check for duplicates on every insertion using [arr.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find). But the performance would be much worse, because this method walks through the whole array checking every element. `Set` is much better optimized internally for uniqueness checks. +Alternativou pro `Set` by mohlo být pole uživatelů a kód, který při každém vložení hledá duplikáty pomocí [pole.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find). Výkon by však byl mnohem horší, protože tato metoda prochází celým polem a ověřuje každý prvek. `Set` je interně pro kontrolu unikátnosti mnohem lépe optimalizována. -## Iteration over Set +## Iterace nad množinou -We can loop over a set either with `for..of` or using `forEach`: +Množinu můžeme procházet buď pomocí `for..of`, nebo pomocí `forEach`: ```js run -let set = new Set(["oranges", "apples", "bananas"]); +let množina = new Set(["pomeranče", "jablka", "banány"]); -for (let value of set) alert(value); +for (let hodnota of množina) alert(hodnota); -// the same with forEach: -set.forEach((value, valueAgain, set) => { - alert(value); +// totéž s forEach: +množina.forEach((hodnota, hodnotaZnovu, množina) => { + alert(hodnota); }); ``` -Note the funny thing. The callback function passed in `forEach` has 3 arguments: a `value`, then *the same value* `valueAgain`, and then the target object. Indeed, the same value appears in the arguments twice. +Všimněte si něčeho veselého. Funkce předávaná do `forEach` má 3 argumenty: `hodnota`, pak *stejnou hodnotu* `hodnotaZnovu` a pak cílový objekt. Opravdu, stejná hodnota se v argumentech objevuje dvakrát. -That's for compatibility with `Map` where the callback passed `forEach` has three arguments. Looks a bit strange, for sure. But this may help to replace `Map` with `Set` in certain cases with ease, and vice versa. +To slouží ke kompatibilitě s `Map`, v níž funkce předávaná do `forEach` má tři argumenty. Jistě, vypadá to trochu zvláštně. Může to však pomoci v některých případech snadno nahradit mapu množinou a naopak. -The same methods `Map` has for iterators are also supported: +Množina také poskytuje stejné metody, jaké má `Map` pro iterátory: -- [`set.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/keys) -- returns an iterable object for values, -- [`set.values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/values) -- same as `set.keys()`, for compatibility with `Map`, -- [`set.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/entries) -- returns an iterable object for entries `[value, value]`, exists for compatibility with `Map`. +- [`množina.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/keys) -- vrátí iterovatelný objekt s hodnotami, +- [`množina.values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/values) -- totéž jako `množina.keys()`, existuje kvůli kompatibilitě s `Map`, +- [`množina.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/entries) -- vrátí iterovatelný objekt s dvojicemi `[hodnota, hodnota]`, existuje kvůli kompatibilitě s `Map`. -## Summary +## Shrnutí -[`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) -- is a collection of keyed values. +[`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) -- je kolekce hodnot s klíči. -Methods and properties: +Metody a vlastnosti: -- [`new Map([iterable])`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/Map) -- creates the map, with optional `iterable` (e.g. array) of `[key,value]` pairs for initialization. -- [`map.set(key, value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set) -- stores the value by the key, returns the map itself. -- [`map.get(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get) -- returns the value by the key, `undefined` if `key` doesn't exist in map. -- [`map.has(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has) -- returns `true` if the `key` exists, `false` otherwise. -- [`map.delete(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete) -- removes the element by the key, returns `true` if `key` existed at the moment of the call, otherwise `false`. -- [`map.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear) -- removes everything from the map. -- [`map.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size) -- returns the current element count. +- [`new Map([iterovatelnýObjekt])`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/Map) -- vytvoří mapu, nepovinný objekt `iterovatelnýObjekt` (např. pole) obsahuje dvojice `[klíč,hodnota]` pro inicializaci. +- [`mapa.set(klíč, hodnota)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set) -- uloží hodnotu `hodnota` pod klíčem `klíč`, vrátí samotnou mapu. +- [`mapa.get(klíč)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get) -- vrátí hodnotu uloženou pod klíčem `klíč`, jestliže `klíč` v mapě neexistuje, vrátí `undefined`. +- [`mapa.has(klíč)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has) -- vrátí `true`, jestliže `klíč` v mapě existuje, jinak `false`. +- [`mapa.delete(klíč)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete) -- odstraní prvek uložený pod klíčem `klíč`, vrátí `true`, jestliže `klíč` v okamžiku volání v mapě existoval, jinak `false`. +- [`mapa.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear) -- odstraní z mapy všechny prvky. +- [`mapa.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size) -- vrátí aktuální počet prvků. -The differences from a regular `Object`: +Rozdíly oproti běžnému objektu: -- Any keys, objects can be keys. -- Additional convenient methods, the `size` property. +- Klíče mohou být libovolného typu včetně objektů. +- Obsahuje další užitečné metody, vlastnost `size`. -[`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) -- is a collection of unique values. +[`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) -- je kolekce unikátních hodnot. -Methods and properties: +Metody a vlastnosti: -- [`new Set([iterable])`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/Set) -- creates the set, with optional `iterable` (e.g. array) of values for initialization. -- [`set.add(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/add) -- adds a value (does nothing if `value` exists), returns the set itself. -- [`set.delete(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/delete) -- removes the value, returns `true` if `value` existed at the moment of the call, otherwise `false`. -- [`set.has(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/has) -- returns `true` if the value exists in the set, otherwise `false`. -- [`set.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/clear) -- removes everything from the set. -- [`set.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/size) -- is the elements count. +- [`new Set(iterovatelnýObjekt)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/Set) -- vytvoří množinu, nepovinný objekt `iterovatelnýObjekt` (např. pole) obsahuje hodnoty pro inicializaci. +- [`množina.add(hodnota)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/add) -- přidá hodnotu `hodnota` (pokud `hodnota` již existuje, neudělá nic), vrátí samotnou množinu. +- [`množina.delete(hodnota)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/delete) -- odstraní hodnotu `hodnota`, vrátí `true`, jestliže `hodnota` v okamžiku volání v množině existovala, jinak `false`. +- [`množina.has(hodnota)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/has) -- vrátí `true`, jestliže hodnota `hodnota` v množině existuje, jinak `false`. +- [`množina.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/clear) -- odstraní z množiny všechny hodnoty. +- [`množina.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/size) -- je počet hodnot. -Iteration over `Map` and `Set` is always in the insertion order, so we can't say that these collections are unordered, but we can't reorder elements or directly get an element by its number. +Iterace nad mapou a množinou probíhá vždy ve stejném pořadí, v jakém byly prvky vloženy. Nemůžeme tedy říci, že tyto kolekce nejsou seřazené, ale nemůžeme prvky seřadit jinak ani přímo získat prvek na určitém pořadí. \ No newline at end of file diff --git a/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/solution.md b/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/solution.md index e2147ccfa..dc68ccb48 100644 --- a/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/solution.md +++ b/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/solution.md @@ -1,43 +1,43 @@ -Let's store read messages in `WeakSet`: +Uložme přečtené zprávy do `WeakSet`: ```js run -let messages = [ - {text: "Hello", from: "John"}, - {text: "How goes?", from: "John"}, - {text: "See you soon", from: "Alice"} +let zprávy = [ + {text: "Ahoj", od: "Jan"}, + {text: "Jak se máš?", od: "Jan"}, + {text: "Brzy nashle", od: "Alice"} ]; -let readMessages = new WeakSet(); +let přečtenéZprávy = new WeakSet(); -// two messages have been read -readMessages.add(messages[0]); -readMessages.add(messages[1]); -// readMessages has 2 elements +// dvě zprávy byly přečteny +přečtenéZprávy.add(zprávy[0]); +přečtenéZprávy.add(zprávy[1]); +// přečtenéZprávy obsahuje 2 prvky -// ...let's read the first message again! -readMessages.add(messages[0]); -// readMessages still has 2 unique elements +// ...znovu přečteme první zprávu! +přečtenéZprávy.add(zprávy[0]); +// přečtenéZprávy stále obsahuje 2 unikátní prvky -// answer: was the message[0] read? -alert("Read message 0: " + readMessages.has(messages[0])); // true +// odpověď: byla zpráva s indexem 0 přečtena? +alert("Zpráva 0 přečtena: " + přečtenéZprávy.has(zprávy[0])); // true -messages.shift(); -// now readMessages has 1 element (technically memory may be cleaned later) +zprávy.shift(); +// nyní přečtenéZprávy obsahuje 1 prvek (technicky může být paměť vyčištěna později) ``` -The `WeakSet` allows to store a set of messages and easily check for the existence of a message in it. +`WeakSet` nám umožňuje uložit množinu zpráv a snadno ověřovat, zda v ní zpráva existuje. -It cleans up itself automatically. The tradeoff is that we can't iterate over it, can't get "all read messages" from it directly. But we can do it by iterating over all messages and filtering those that are in the set. +Automaticky se vyčistí. Nevýhodou je, že nad ní nemůžeme iterovat, nemůžeme získat „všechny přečtené zprávy“ přímo z ní. Můžeme to však udělat iterací nad všemi zprávami a filtrováním těch, které jsou v této množině. -Another, different solution could be to add a property like `message.isRead=true` to a message after it's read. As messages objects are managed by another code, that's generally discouraged, but we can use a symbolic property to avoid conflicts. +Jiným řešením by bylo přidání vlastnosti, např. `zpráva.jePřečtena=true`, do zprávy poté, co bude přečtena. Pokud objekty zpráv spravuje jiný kód, obecně se to nedoporučuje, ale můžeme se vyhnout konfliktům použitím symbolické vlastnosti. -Like this: +Třeba takto: ```js -// the symbolic property is only known to our code -let isRead = Symbol("isRead"); -messages[0][isRead] = true; +// symbolickou vlastnost zná pouze náš kód +let jePřečtena = Symbol("jePřečtena"); +zprávy[0][jePřečtena] = true; ``` -Now third-party code probably won't see our extra property. +Nyní kód třetí strany naši přidanou vlastnost neuvidí. -Although symbols allow to lower the probability of problems, using `WeakSet` is better from the architectural point of view. +Přestože symboly mohou snížit pravděpodobnost problémů, z architektonického hlediska je lepší použít `WeakSet`. \ No newline at end of file diff --git a/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/task.md b/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/task.md index fd31a891b..c4b4dfb1f 100644 --- a/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/task.md +++ b/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/task.md @@ -2,22 +2,22 @@ importance: 5 --- -# Store "unread" flags +# Uložení označení „přečteno“ -There's an array of messages: +Máme pole zpráv: ```js -let messages = [ - {text: "Hello", from: "John"}, - {text: "How goes?", from: "John"}, - {text: "See you soon", from: "Alice"} +let zprávy = [ + {text: "Ahoj", od: "Jan"}, + {text: "Jak se máš?", od: "Jan"}, + {text: "Brzy nashle", od: "Alice"} ]; ``` -Your code can access it, but the messages are managed by someone else's code. New messages are added, old ones are removed regularly by that code, and you don't know the exact moments when it happens. +Váš kód k němu může přistupovat, ale zprávy spravuje kód někoho jiného. Tento kód pravidelně přidává nové zprávy a odebírá staré. Vy neznáte přesný okamžik, kdy se to stane. -Now, which data structure could you use to store information about whether the message "has been read"? The structure must be well-suited to give the answer "was it read?" for the given message object. +Kterou datovou strukturu nyní můžete použít k uložení informace, že zpráva „byla přečtena“? Struktura musí být vybavena tak, aby pro zadaný objekt zprávy vydala odpověď na otázku „byla zpráva přečtena?“. -P.S. When a message is removed from `messages`, it should disappear from your structure as well. +P.S. Když je zpráva odstraněna z pole `zprávy`, měla by zmizet i z vaší struktury. -P.P.S. We shouldn't modify message objects, add our properties to them. As they are managed by someone else's code, that may lead to bad consequences. +P.P.S. Objekty zpráv bychom neměli modifikovat a přidávat do nich naše vlastnosti. Protože je spravuje kód někoho jiného, mohlo by to vést k nežádoucím důsledkům. diff --git a/1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/solution.md b/1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/solution.md index 2af0547c1..6e2116c66 100644 --- a/1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/solution.md +++ b/1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/solution.md @@ -1,15 +1,15 @@ -To store a date, we can use `WeakMap`: +K uložení data můžeme použít `WeakMap`: ```js -let messages = [ - {text: "Hello", from: "John"}, - {text: "How goes?", from: "John"}, - {text: "See you soon", from: "Alice"} +let zprávy = [ + {text: "Ahoj", od: "Jan"}, + {text: "Jak se máš?", od: "Jan"}, + {text: "Brzy se uvidíme", od: "Alice"} ]; -let readMap = new WeakMap(); +let mapaPřečtení = new WeakMap(); -readMap.set(messages[0], new Date(2017, 1, 1)); -// Date object we'll study later +mapaPřečtení.set(zprávy[0], new Date(2017, 1, 1)); +// objekty Date prostudujeme později ``` diff --git a/1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/task.md b/1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/task.md index 8e341c184..86fe2cd79 100644 --- a/1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/task.md +++ b/1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/task.md @@ -2,20 +2,20 @@ importance: 5 --- -# Store read dates +# Uložení data přečtení -There's an array of messages as in the [previous task](info:task/recipients-read). The situation is similar. +Máme stejné pole zpráv, jako [v předchozí úloze](info:task/recipients-read). Situace je obdobná. ```js -let messages = [ - {text: "Hello", from: "John"}, - {text: "How goes?", from: "John"}, - {text: "See you soon", from: "Alice"} +let zprávy = [ + {text: "Ahoj", od: "Jan"}, + {text: "Jak se máš?", od: "Jan"}, + {text: "Brzy se uvidíme", od: "Alice"} ]; ``` -The question now is: which data structure you'd suggest to store the information: "when the message was read?". +Otázka teď zní: kterou datovou strukturu byste doporučili k uložení informace „kdy byla zpráva přečtena“? -In the previous task we only needed to store the "yes/no" fact. Now we need to store the date, and it should only remain in memory until the message is garbage collected. +V předchozí úloze jsme potřebovali ukládat jen skutečnost „ano/ne“. Nyní musíme ukládat datum, které by mělo zůstat v paměti jen do doby, než bude zpráva odklizena sběračem odpadků. -P.S. Dates can be stored as objects of built-in `Date` class, that we'll cover later. +P.S. Data lze ukládat jako objekty vestavěné třídy `Date`, kterou probereme později. diff --git a/1-js/05-data-types/08-weakmap-weakset/article.md b/1-js/05-data-types/08-weakmap-weakset/article.md index 9795017d4..fd520e213 100644 --- a/1-js/05-data-types/08-weakmap-weakset/article.md +++ b/1-js/05-data-types/08-weakmap-weakset/article.md @@ -1,295 +1,295 @@ -# WeakMap and WeakSet +# Slabá mapa a slabá množina -As we know from the chapter , JavaScript engine keeps a value in memory while it is "reachable" and can potentially be used. +Jak víme z kapitoly , motor JavaScriptu si udržuje hodnotu v paměti, dokud je „dosažitelná“ a může být použita. -For instance: +Příklad: ```js -let john = { name: "John" }; +let jan = { jméno: "Jan" }; -// the object can be accessed, john is the reference to it +// k objektu může být přistupováno, jan je odkaz na něj -// overwrite the reference -john = null; +// přepíšeme odkaz +jan = null; *!* -// the object will be removed from memory +// objekt bude odstraněn z paměti */!* ``` -Usually, properties of an object or elements of an array or another data structure are considered reachable and kept in memory while that data structure is in memory. +Obvykle jsou vlastnosti objektu nebo prvky pole či jiné datové struktury považovány za dosažitelné a udržovány v paměti, dokud je v paměti tato datová struktura. -For instance, if we put an object into an array, then while the array is alive, the object will be alive as well, even if there are no other references to it. +Například uložíme-li objekt do pole, pak dokud je toto pole živé, bude živý i tento objekt, i když na něj nebudou existovat žádné jiné odkazy. -Like this: +Třeba takto: ```js -let john = { name: "John" }; +let jan = { jméno: "Jan" }; -let array = [ john ]; +let pole = [ jan ]; -john = null; // overwrite the reference +jan = null; // přepíšeme odkaz *!* -// the object previously referenced by john is stored inside the array -// therefore it won't be garbage-collected -// we can get it as array[0] +// objekt, na který se dříve odkazoval jan, je uložen uvnitř pole +// proto nebude odklizen sběračem odpadků +// můžeme k němu přistoupit pomocí pole[0] */!* ``` -Similar to that, if we use an object as the key in a regular `Map`, then while the `Map` exists, that object exists as well. It occupies memory and may not be garbage collected. +Podobně když použijeme objekt jako klíč v běžné mapě `Map`, pak dokud tato mapa bude existovat, bude existovat i tento objekt. Bude zabírat místo v paměti a nebude moci být odstraněn sběračem odpadků. -For instance: +Příklad: ```js -let john = { name: "John" }; +let jan = { jméno: "Jan" }; -let map = new Map(); -map.set(john, "..."); +let mapa = new Map(); +mapa.set(jan, "..."); -john = null; // overwrite the reference +jan = null; // přepíšeme odkaz *!* -// john is stored inside the map, -// we can get it by using map.keys() +// jan je uložen uvnitř mapy, +// můžeme k němu přistoupit pomocí mapa.keys() */!* ``` -[`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) is fundamentally different in this aspect. It doesn't prevent garbage-collection of key objects. +[`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) („slabá mapa“) se v tomto ohledu zásadně liší. Nebrání odstraňování svých klíčových objektů sběračem odpadků. -Let's see what it means on examples. +Na příkladech se podívejme, co to znamená. ## WeakMap -The first difference between [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) and [`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) is that keys must be objects, not primitive values: +Prvním rozdílem mezi [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) a [`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) je, že klíče musejí být objekty, ne primitivní hodnoty: ```js run -let weakMap = new WeakMap(); +let slabáMapa = new WeakMap(); let obj = {}; -weakMap.set(obj, "ok"); // works fine (object key) +slabáMapa.set(obj, "ok"); // funguje správně (klíč je objekt) *!* -// can't use a string as the key -weakMap.set("test", "Whoops"); // Error, because "test" is not an object +// jako klíč nemůžeme použít řetězec +slabáMapa.set("test", "Hop!"); // Chyba, protože "test" není objekt */!* ``` -Now, if we use an object as the key in it, and there are no other references to that object -- it will be removed from memory (and from the map) automatically. +Jestliže nyní použijeme objekt jako klíč a nebudou na něj existovat žádné jiné odkazy -- bude automaticky odstraněn z paměti (a z mapy). ```js -let john = { name: "John" }; +let jan = { jméno: "Jan" }; -let weakMap = new WeakMap(); -weakMap.set(john, "..."); +let slabáMapa = new WeakMap(); +slabáMapa.set(jan, "..."); -john = null; // overwrite the reference +jan = null; // přepíšeme odkaz -// john is removed from memory! +// jan se odstraní z paměti! ``` -Compare it with the regular `Map` example above. Now if `john` only exists as the key of `WeakMap` -- it will be automatically deleted from the map (and memory). +Srovnejte si to s výše uvedeným příkladem běžné mapy `Map`. Když nyní `jan` existuje jen jako klíč `WeakMap` -- bude automaticky smazán z mapy (a z paměti). -`WeakMap` does not support iteration and methods `keys()`, `values()`, `entries()`, so there's no way to get all keys or values from it. +`WeakMap` nepodporuje iteraci a metody `keys()`, `values()`, `entries()`, neexistuje tedy žádný způsob, jak z ní získat všechny klíče nebo hodnoty. -`WeakMap` has only the following methods: +`WeakMap` má pouze následující metody: -- [`weakMap.set(key, value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/set) -- [`weakMap.get(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/get) -- [`weakMap.delete(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/delete) -- [`weakMap.has(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/has) +- [`slabáMapa.set(klíč, hodnota)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/set) +- [`slabáMapa.get(klíč)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/get) +- [`slabáMapa.delete(klíč)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/delete) +- [`slabáMapa.has(klíč)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/has) -Why such a limitation? That's for technical reasons. If an object has lost all other references (like `john` in the code above), then it is to be garbage-collected automatically. But technically it's not exactly specified *when the cleanup happens*. +Proč takové omezení? Je tomu tak z technických důvodů. Pokud objekt ztratil všechny ostatní odkazy (např. `jan` v uvedeném kódu), má být automaticky odstraněn sběračem odpadků. Technicky však není přesně specifikováno, *kdy k odstranění dojde*. -The JavaScript engine decides that. It may choose to perform the memory cleanup immediately or to wait and do the cleaning later when more deletions happen. So, technically, the current element count of a `WeakMap` is not known. The engine may have cleaned it up or not, or did it partially. For that reason, methods that access all keys/values are not supported. +O tom rozhoduje motor JavaScriptu. Ten se může rozhodnout provést úklid paměti okamžitě anebo s ním počkat a provést jej až později, když se uskuteční více mazání. Technicky tedy není znám aktuální počet prvků `WeakMap`. Motor je už mohl pročistit nebo ještě ne, nebo to mohl udělat zatím jen částečně. Z tohoto důvodu nejsou podporovány metody, které přistupují ke všem klíčům a hodnotám. -Now, where do we need such a data structure? +K čemu nyní takovou datovou strukturu potřebujeme? -## Use case: additional data +## Případ použití: dodatečná data -The main area of application for `WeakMap` is an *additional data storage*. +Hlavní oblastí použití `WeakMap` je *úložiště dodatečných dat*. -If we're working with an object that "belongs" to another code, maybe even a third-party library, and would like to store some data associated with it, that should only exist while the object is alive - then `WeakMap` is exactly what's needed. +Jestliže pracujeme s objektem, který „patří“ do jiného kódu, třeba i do knihovny třetí strany, a chtěli bychom si uložit nějaká data s ním spojená, která by měla existovat, jen dokud je tento objekt živý -- pak `WeakMap` je přesně to, co potřebujeme. -We put the data to a `WeakMap`, using the object as the key, and when the object is garbage collected, that data will automatically disappear as well. +Uložíme data do `WeakMap` a onen objekt použijeme jako klíč. Když bude objekt odklizen sběračem odpadků, data automaticky zmizí s ním. ```js -weakMap.set(john, "secret documents"); -// if john dies, secret documents will be destroyed automatically +slabáMapa.set(jan, "tajné dokumenty"); +// jestliže jan zemře, tajné dokumenty budou automaticky zničeny ``` -Let's look at an example. +Podívejme se na příklad. -For instance, we have code that keeps a visit count for users. The information is stored in a map: a user object is the key and the visit count is the value. When a user leaves (its object gets garbage collected), we don't want to store their visit count anymore. +Máme například kód, který si udržuje počet návštěv jednotlivých uživatelů. Tato informace je uložena v mapě: objekt uživatele je klíč a počet návštěv je hodnota. Když uživatel odejde (jeho objekt bude odklizen sběračem odpadků), nechceme již nadále mít počet jeho návštěv uložen. -Here's an example of a counting function with `Map`: +Zde je příklad počítací funkce s `Map`: ```js -// 📁 visitsCount.js -let visitsCountMap = new Map(); // map: user => visits count +// 📁 početNávštěv.js +let mapaPočetNávštěv = new Map(); // mapa: uživatel => počet návštěv -// increase the visits count -function countUser(user) { - let count = visitsCountMap.get(user) || 0; - visitsCountMap.set(user, count + 1); +// zvýší počet návštěv +function započítejUživatele(uživatel) { + let počet = mapaPočetNávštěv.get(uživatel) || 0; + mapaPočetNávštěv.set(uživatel, počet + 1); } ``` -And here's another part of the code, maybe another file using it: +A zde je další část kódu, třeba další soubor, který tuto funkci používá: ```js -// 📁 main.js -let john = { name: "John" }; +// 📁 hlavní.js +let jan = { jméno: "Jan" }; -countUser(john); // count his visits +započítejUživatele(jan); // počet jeho návštěv -// later john leaves us -john = null; +// později nás jan opustí +jan = null; ``` -Now, `john` object should be garbage collected, but remains in memory, as it's a key in `visitsCountMap`. +Nyní by objekt `jan` měl být odklizen, ale zůstává v paměti, neboť je to klíč v mapě `mapaPočetNávštěv`. -We need to clean `visitsCountMap` when we remove users, otherwise it will grow in memory indefinitely. Such cleaning can become a tedious task in complex architectures. +Když tedy odstraňujeme uživatele, musíme mapu `mapaPočetNávštěv` pročistit, jinak bude neustále narůstat v paměti. Ve složitých architekturách se takové pročišťování může stát nepříjemným úkolem. -We can avoid it by switching to `WeakMap` instead: +Můžeme se tomu vyhnout, když použijeme `WeakMap`: ```js -// 📁 visitsCount.js -let visitsCountMap = new WeakMap(); // weakmap: user => visits count +// 📁 početNávštěv.js +let mapaPočetNávštěv = new WeakMap(); // slabá mapa: uživatel => počet návštěv -// increase the visits count -function countUser(user) { - let count = visitsCountMap.get(user) || 0; - visitsCountMap.set(user, count + 1); +// zvýší počet návštěv +function započítejUživatele(uživatel) { + let počet = mapaPočetNávštěv.get(uživatel) || 0; + mapaPočetNávštěv.set(uživatel, počet + 1); } ``` -Now we don't have to clean `visitsCountMap`. After `john` object becomes unreachable, by all means except as a key of `WeakMap`, it gets removed from memory, along with the information by that key from `WeakMap`. +Nyní mapu `mapaPočetNávštěv` čistit nemusíme. Jakmile se objekt `jan` stane nedosažitelným všemi jinými způsoby než jako klíč `WeakMap`, bude odstraněn z paměti spolu s informací uloženou pod tímto klíčem ve `WeakMap`. -## Use case: caching +## Případ použití: mezipaměť -Another common example is caching. We can store ("cache") results from a function, so that future calls on the same object can reuse it. +Dalším běžným příkladem je mezipaměť. Můžeme si ukládat do paměti (tato paměť se nazývá „cache“ nebo „mezipaměť“) výsledky funkce, abychom je mohli znovu použít při dalších voláních stejné funkce na témže objektu. -To achieve that, we can use `Map` (not optimal scenario): +Abychom toho dosáhli, můžeme použít `Map` (neoptimální scénář): ```js run -// 📁 cache.js -let cache = new Map(); +// 📁 mezipaměť.js +let mezipaměť = new Map(); -// calculate and remember the result -function process(obj) { - if (!cache.has(obj)) { - let result = /* calculations of the result for */ obj; +// vypočítá a zapamatuje si výsledek +function proces(obj) { + if (!mezipaměť.has(obj)) { + let výsledek = /* výpočet výsledku pro */ obj; - cache.set(obj, result); - return result; + mezipaměť.set(obj, výsledek); + return výsledek; } - return cache.get(obj); + return mezipaměť.get(obj); } *!* -// Now we use process() in another file: +// Nyní použijeme proces() v jiném souboru: */!* -// 📁 main.js -let obj = {/* let's say we have an object */}; +// 📁 hlavní.js +let obj = {/* řekněme, že máme nějaký objekt */}; -let result1 = process(obj); // calculated +let výsledek1 = proces(obj); // vypočteno -// ...later, from another place of the code... -let result2 = process(obj); // remembered result taken from cache +// ...později z jiného místa kódu... +let výsledek2 = proces(obj); // vezmeme z mezipaměti výsledek, který si pamatujeme -// ...later, when the object is not needed any more: +// ...později, když už tento objekt nebudeme potřebovat: obj = null; -alert(cache.size); // 1 (Ouch! The object is still in cache, taking memory!) +alert(mezipaměť.size); // 1 (Ouha! Objekt je stále v mezipaměti a zabírá paměť!) ``` -For multiple calls of `process(obj)` with the same object, it only calculates the result the first time, and then just takes it from `cache`. The downside is that we need to clean `cache` when the object is not needed any more. +Při více voláních `proces(obj)` nad stejným objektem funkce vypočítá výsledek jen poprvé a pak ho bude jednoduše brát z `mezipaměť`. Nevýhodou je, že když už objekt nebudeme potřebovat, musíme `mezipaměť` vyčistit. -If we replace `Map` with `WeakMap`, then this problem disappears. The cached result will be removed from memory automatically after the object gets garbage collected. +Když místo `Map` použijeme `WeakMap`, tento problém zmizí. Výsledek v mezipaměti bude z paměti odstraněn automaticky poté, co bude objekt odklizen sběračem odpadků. ```js run -// 📁 cache.js +// 📁 mezipaměť.js *!* -let cache = new WeakMap(); +let mezipaměť = new WeakMap(); */!* -// calculate and remember the result -function process(obj) { - if (!cache.has(obj)) { - let result = /* calculate the result for */ obj; +// vypočítá a zapamatuje si výsledek +function proces(obj) { + if (!mezipaměť.has(obj)) { + let výsledek = /* výpočet výsledku pro */ obj; - cache.set(obj, result); - return result; + mezipaměť.set(obj, výsledek); + return výsledek; } - return cache.get(obj); + return mezipaměť.get(obj); } -// 📁 main.js -let obj = {/* some object */}; +// 📁 hlavní.js +let obj = {/* nějaký objekt */}; -let result1 = process(obj); -let result2 = process(obj); +let výsledek1 = proces(obj); +let výsledek2 = proces(obj); -// ...later, when the object is not needed any more: +// ...později, když už tento objekt nebudeme potřebovat: obj = null; -// Can't get cache.size, as it's a WeakMap, -// but it's 0 or soon be 0 -// When obj gets garbage collected, cached data will be removed as well +// Nemůžeme získat mezipaměť.size, protože to je WeakMap, +// ale je nebo zanedlouho bude 0 +// Když bude obj odklizen, budou odstraněna i data z mezipaměti ``` ## WeakSet -[`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) behaves similarly: +[`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) („slabá množina“) se chová obdobně: -- It is analogous to `Set`, but we may only add objects to `WeakSet` (not primitives). -- An object exists in the set while it is reachable from somewhere else. -- Like `Set`, it supports [`add`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Weakset/add), [`has`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Weakset/has) and [`delete`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Weakset/delete), but not `size`, `keys()` and no iterations. +- Je analogická k `Set`, ale do `WeakSet` můžeme přidávat jedině objekty (ne primitivy). +- Objekt v této množině existuje, dokud je dosažitelný odjinud. +- Stejně jako `Set` podporuje [`add`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Weakset/add), [`has`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Weakset/has) a [`delete`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Weakset/delete), ale ne `size`, `keys()` ani žádné iterace. -Being "weak", it also serves as additional storage. But not for arbitrary data, rather for "yes/no" facts. A membership in `WeakSet` may mean something about the object. +Protože je „slabá“, může sloužit i jako úložiště dodatečných dat. Ne však pro libovolná data, ale jen pro skutečnost „ano/ne“. Členství ve `WeakSet` může o objektu něco znamenat. -For instance, we can add users to `WeakSet` to keep track of those who visited our site: +Například můžeme do `WeakSet` přidávat uživatele, abychom si pamatovali ty, kteří navštívili naše stránky: ```js run -let visitedSet = new WeakSet(); +let množinaNávštěvníků = new WeakSet(); -let john = { name: "John" }; -let pete = { name: "Pete" }; -let mary = { name: "Mary" }; +let jan = { jméno: "Jan" }; +let petr = { jméno: "Petr" }; +let marie = { jméno: "Marie" }; -visitedSet.add(john); // John visited us -visitedSet.add(pete); // Then Pete -visitedSet.add(john); // John again +množinaNávštěvníků.add(jan); // navštívil nás Jan +množinaNávštěvníků.add(petr); // pak Petr +množinaNávštěvníků.add(jan); // znovu Jan -// visitedSet has 2 users now +// množinaNávštěvníků má nyní 2 uživatele -// check if John visited? -alert(visitedSet.has(john)); // true +// ověříme, zda nás navštívil Jan +alert(množinaNávštěvníků.has(jan)); // true -// check if Mary visited? -alert(visitedSet.has(mary)); // false +// ověříme, zda nás navštívila Marie +alert(množinaNávštěvníků.has(marie)); // false -john = null; +jan = null; -// visitedSet will be cleaned automatically +// množinaNávštěvníků bude automaticky pročištěna ``` -The most notable limitation of `WeakMap` and `WeakSet` is the absence of iterations, and the inability to get all current content. That may appear inconvenient, but does not prevent `WeakMap/WeakSet` from doing their main job -- be an "additional" storage of data for objects which are stored/managed at another place. +Nejvýznamnějším omezením `WeakMap` a `WeakSet` je absence iterací a nemožnost získat celý jejich skutečný obsah. To se může zdát nešikovné, ale nebrání to `WeakMap/WeakSet` v tom, aby odváděly svou hlavní práci -- být úložištěm „dodatečných“ dat pro objekty, které jsou uloženy nebo spravovány na jiném místě. -## Summary +## Shrnutí -[`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) is `Map`-like collection that allows only objects as keys and removes them together with associated value once they become inaccessible by other means. +[`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) je kolekce podobná `Map`, která dovoluje používat jako klíče jen objekty a odstraňuje je i s připojenou hodnotou, jakmile se stanou nedosažitelnými jiným způsobem. -[`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) is `Set`-like collection that stores only objects and removes them once they become inaccessible by other means. +[`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) je kolekce podobná `Set`, která ukládá jen objekty a odstraňuje je, jakmile se stanou nedosažitelnými jiným způsobem. -Their main advantages are that they have weak reference to objects, so they can easily be removed by garbage collector. +Jejich hlavní výhodou je, že obsahují slabé odkazy na objekty, takže ty mohou být snadno odklizeny sběračem odpadků. -That comes at the cost of not having support for `clear`, `size`, `keys`, `values`... +Cenou za to je, že nejsou podporovány `clear`, `size`, `keys`, `values`... -`WeakMap` and `WeakSet` are used as "secondary" data structures in addition to the "primary" object storage. Once the object is removed from the primary storage, if it is only found as the key of `WeakMap` or in a `WeakSet`, it will be cleaned up automatically. +`WeakMap` a `WeakSet` se používají jako „sekundární“ datové struktury navíc k „primárním“ úložištím objektů. Když je objekt odstraněn z primárního úložiště, pak pokud se dá najít jen jako klíč `WeakMap` nebo prvek `WeakSet`, bude automaticky odklizen. diff --git a/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/_js.view/solution.js b/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/_js.view/solution.js index 509b35893..e397dd81a 100644 --- a/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/_js.view/solution.js +++ b/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/_js.view/solution.js @@ -1,10 +1,10 @@ -function sumSalaries(salaries) { +function sečtiProdeje(prodeje) { - let sum = 0; - for (let salary of Object.values(salaries)) { - sum += salary; + let součet = 0; + for (let prodej of Object.values(prodeje)) { + součet += prodej; } - return sum; + return součet; } diff --git a/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/_js.view/test.js b/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/_js.view/test.js index 684b0894a..1c0ea2de3 100644 --- a/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/_js.view/test.js +++ b/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/_js.view/test.js @@ -1,15 +1,15 @@ -describe("sumSalaries", function() { - it("returns sum of salaries", function() { - let salaries = { - "John": 100, - "Pete": 300, - "Mary": 250 +describe("sečtiProdeje", function() { + it("vrátí součet prodejů", function() { + let prodeje = { + "Jan": 100, + "Petr": 300, + "Marie": 250 }; - assert.equal( sumSalaries(salaries), 650 ); + assert.equal( sečtiProdeje(prodeje), 650 ); }); - it("returns 0 for the empty object", function() { - assert.strictEqual( sumSalaries({}), 0); + it("pro prázdný objekt vrátí 0", function() { + assert.strictEqual( sečtiProdeje({}), 0); }); }); \ No newline at end of file diff --git a/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/solution.md b/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/solution.md index 27a7b418a..d95ba5ed6 100644 --- a/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/solution.md +++ b/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/solution.md @@ -1,29 +1,29 @@ ```js run demo -function sumSalaries(salaries) { +function sečtiProdeje(prodeje) { - let sum = 0; - for (let salary of Object.values(salaries)) { - sum += salary; + let součet = 0; + for (let prodej of Object.values(prodeje)) { + součet += prodej; } - return sum; // 650 + return součet; // 650 } -let salaries = { - "John": 100, - "Pete": 300, - "Mary": 250 +let prodeje = { + "Jan": 100, + "Petr": 300, + "Marie": 250 }; -alert( sumSalaries(salaries) ); // 650 +alert( sečtiProdeje(prodeje) ); // 650 ``` -Or, optionally, we could also get the sum using `Object.values` and `reduce`: +Nebo volitelně můžeme také získat součet použitím `Object.values` a `reduce`: ```js -// reduce loops over array of salaries, -// adding them up -// and returns the result -function sumSalaries(salaries) { - return Object.values(salaries).reduce((a, b) => a + b, 0) // 650 +// reduce cykluje nad polem prodejů, +// sečte je +// a vrátí výsledek +function sečtiProdeje(prodeje) { + return Object.values(prodeje).reduce((a, b) => a + b, 0) // 650 } ``` diff --git a/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/task.md b/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/task.md index 211357d03..2f75ae5e2 100644 --- a/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/task.md +++ b/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/task.md @@ -2,23 +2,23 @@ importance: 5 --- -# Sum the properties +# Součet vlastností -There is a `salaries` object with arbitrary number of salaries. +Máme objekt `prodeje` obsahující libovolný počet prodejů. -Write the function `sumSalaries(salaries)` that returns the sum of all salaries using `Object.values` and the `for..of` loop. +Napište funkci `sečtiProdeje(prodeje)`, která vrátí součet všech prodejů, přičemž bude využívat `Object.values` a cyklus `for..of`. -If `salaries` is empty, then the result must be `0`. +Je-li objekt `prodeje` prázdný, výsledek musí být `0`. -For instance: +Příklad: ```js -let salaries = { - "John": 100, - "Pete": 300, - "Mary": 250 +let prodeje = { + "Jan": 100, + "Petr": 300, + "Marie": 250 }; -alert( sumSalaries(salaries) ); // 650 +alert( sečtiProdeje(prodeje) ); // 650 ``` diff --git a/1-js/05-data-types/09-keys-values-entries/02-count-properties/_js.view/solution.js b/1-js/05-data-types/09-keys-values-entries/02-count-properties/_js.view/solution.js index 1853d20e6..f73a37fab 100644 --- a/1-js/05-data-types/09-keys-values-entries/02-count-properties/_js.view/solution.js +++ b/1-js/05-data-types/09-keys-values-entries/02-count-properties/_js.view/solution.js @@ -1,4 +1,4 @@ -function count(obj) { +function spočítej(obj) { return Object.keys(obj).length; } diff --git a/1-js/05-data-types/09-keys-values-entries/02-count-properties/_js.view/test.js b/1-js/05-data-types/09-keys-values-entries/02-count-properties/_js.view/test.js index e568c3205..22ed8d476 100644 --- a/1-js/05-data-types/09-keys-values-entries/02-count-properties/_js.view/test.js +++ b/1-js/05-data-types/09-keys-values-entries/02-count-properties/_js.view/test.js @@ -1,13 +1,13 @@ -describe("count", function() { - it("counts the number of properties", function() { - assert.equal( count({a: 1, b: 2}), 2 ); +describe("spočítej", function() { + it("spočítá počet vlastností", function() { + assert.equal( spočítej({a: 1, b: 2}), 2 ); }); - it("returns 0 for an empty object", function() { - assert.equal( count({}), 0 ); + it("pro prázdný objekt vrátí 0", function() { + assert.equal( spočítej({}), 0 ); }); - it("ignores symbolic properties", function() { - assert.equal( count({ [Symbol('id')]: 1 }), 0 ); + it("ignoruje symbolické vlastnosti", function() { + assert.equal( spočítej({ [Symbol('id')]: 1 }), 0 ); }); }); \ No newline at end of file diff --git a/1-js/05-data-types/09-keys-values-entries/02-count-properties/task.md b/1-js/05-data-types/09-keys-values-entries/02-count-properties/task.md index d7aebb1fa..7ab9b3601 100644 --- a/1-js/05-data-types/09-keys-values-entries/02-count-properties/task.md +++ b/1-js/05-data-types/09-keys-values-entries/02-count-properties/task.md @@ -2,20 +2,20 @@ importance: 5 --- -# Count properties +# Počet vlastností -Write a function `count(obj)` that returns the number of properties in the object: +Napište funkci `spočítej(obj)`, která vrátí počet vlastností v objektu: ```js -let user = { - name: 'John', - age: 30 +let uživatel = { + jméno: 'Jan', + věk: 30 }; -alert( count(user) ); // 2 +alert( spočítej(uživatel) ); // 2 ``` -Try to make the code as short as possible. +Snažte se napsat kód co nejkratší. -P.S. Ignore symbolic properties, count only "regular" ones. +P.S. Ignorujte symbolické vlastnosti, počítejte jen „obyčejné“. diff --git a/1-js/05-data-types/09-keys-values-entries/article.md b/1-js/05-data-types/09-keys-values-entries/article.md index bef678f53..c685e854a 100644 --- a/1-js/05-data-types/09-keys-values-entries/article.md +++ b/1-js/05-data-types/09-keys-values-entries/article.md @@ -1,103 +1,103 @@ -# Object.keys, values, entries +# Metody Object.keys, values, entries -Let's step away from the individual data structures and talk about the iterations over them. +Odhlédněme nyní od individuálních datových struktur a promluvme si o iteracích nad nimi. -In the previous chapter we saw methods `map.keys()`, `map.values()`, `map.entries()`. +V předchozí kapitole jsme viděli metody `mapa.keys()`, `mapa.values()`, `mapa.entries()`. -These methods are generic, there is a common agreement to use them for data structures. If we ever create a data structure of our own, we should implement them too. +Tyto metody jsou generické, existuje společná dohoda ohledně jejich používání pro datové struktury. Jestliže si sami vytvoříme vlastní datovou strukturu, měli bychom je implementovat také. -They are supported for: +Jsou podporovány v: -- `Map` -- `Set` -- `Array` +- mapách (`Map`) +- množinách (`Set`) +- polích (`Array`) -Plain objects also support similar methods, but the syntax is a bit different. +Podobné metody jsou podporovány i v planých objektech, ale jejich syntaxe je trochu jiná. ## Object.keys, values, entries -For plain objects, the following methods are available: +Pro plané objekty jsou k dispozici následující metody: -- [Object.keys(obj)](mdn:js/Object/keys) -- returns an array of keys. -- [Object.values(obj)](mdn:js/Object/values) -- returns an array of values. -- [Object.entries(obj)](mdn:js/Object/entries) -- returns an array of `[key, value]` pairs. +- [Object.keys(obj)](mdn:js/Object/keys) -- vrací pole klíčů. +- [Object.values(obj)](mdn:js/Object/values) -- vrací pole hodnot. +- [Object.entries(obj)](mdn:js/Object/entries) -- vrací pole dvojic `[klíč, hodnota]`. -Please note the distinctions (compared to map for example): +Prosíme, všimněte si rozdílů (například ve srovnání s mapou): -| | Map | Object | -|-------------|------------------|--------------| -| Call syntax | `map.keys()` | `Object.keys(obj)`, but not `obj.keys()` | -| Returns | iterable | "real" Array | +| | Mapa | Objekt | +|----------------|---------------------|-----------------------------------------| +| Syntaxe volání | `mapa.keys()` | `Object.keys(obj)`, ale ne `obj.keys()` | +| Vrací | iterovatelný objekt | „opravdové“ pole | -The first difference is that we have to call `Object.keys(obj)`, and not `obj.keys()`. +Prvním rozdílem je, že musíme volat `Object.keys(obj)`, ne `obj.keys()`. -Why so? The main reason is flexibility. Remember, objects are a base of all complex structures in JavaScript. So we may have an object of our own like `data` that implements its own `data.values()` method. And we still can call `Object.values(data)` on it. +Proč tomu tak je? Hlavním důvodem je flexibilita. Pamatujte, že objekty jsou základem všech složitých struktur v JavaScriptu. Můžeme tedy mít svůj vlastní objekt, např. `data`, který implementuje svou vlastní metodu `data.values()`. A přesto na něm můžeme volat `Object.values(data)`. -The second difference is that `Object.*` methods return "real" array objects, not just an iterable. That's mainly for historical reasons. +Druhým rozdílem je, že metody `Object.*` vracejí „opravdová“ pole, ne jen iterovatelné objekty. Tak tomu je zejména z historických důvodů. -For instance: +Příklad: ```js -let user = { - name: "John", - age: 30 +let uživatel = { + jméno: "Jan", + věk: 30 }; ``` -- `Object.keys(user) = ["name", "age"]` -- `Object.values(user) = ["John", 30]` -- `Object.entries(user) = [ ["name","John"], ["age",30] ]` +- `Object.keys(uživatel) = ["jméno", "věk"]` +- `Object.values(uživatel) = ["Jan", 30]` +- `Object.entries(uživatel) = [ ["jméno","Jan"], ["věk",30] ]` -Here's an example of using `Object.values` to loop over property values: +Zde je příklad použití `Object.values` k vytvoření cyklu nad hodnotami vlastností: ```js run -let user = { - name: "John", - age: 30 +let uživatel = { + jméno: "Jan", + věk: 30 }; -// loop over values -for (let value of Object.values(user)) { - alert(value); // John, then 30 +// cyklus nad hodnotami +for (let hodnota of Object.values(uživatel)) { + alert(hodnota); // Jan, poté 30 } ``` -```warn header="Object.keys/values/entries ignore symbolic properties" -Just like a `for..in` loop, these methods ignore properties that use `Symbol(...)` as keys. +```warn header="Object.keys/values/entries ignorují symbolické vlastnosti" +Stejně jako cyklus `for..in`, i tyto metody ignorují vlastnosti, jejichž klíčem je `Symbol(...)`. -Usually that's convenient. But if we want symbolic keys too, then there's a separate method [Object.getOwnPropertySymbols](mdn:js/Object/getOwnPropertySymbols) that returns an array of only symbolic keys. Also, there exist a method [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) that returns *all* keys. +Zpravidla nám to vyhovuje. Jestliže však chceme i symbolické klíče, existuje samostatná metoda [Object.getOwnPropertySymbols](mdn:js/Object/getOwnPropertySymbols), která vrací pole výhradně symbolických klíčů. Existuje i metoda [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys), která vrací *všechny* klíče. ``` -## Transforming objects +## Transformace objektů -Objects lack many methods that exist for arrays, e.g. `map`, `filter` and others. +Objekty postrádají mnohé metody, které existují pro pole, např. `map`, `filter` a jiné. -If we'd like to apply them, then we can use `Object.entries` followed by `Object.fromEntries`: +Pokud je chceme použít, můžeme použít `Object.entries`, po níž bude následovat `Object.fromEntries`: -1. Use `Object.entries(obj)` to get an array of key/value pairs from `obj`. -2. Use array methods on that array, e.g. `map`, to transform these key/value pairs. -3. Use `Object.fromEntries(array)` on the resulting array to turn it back into an object. +1. Použijte `Object.entries(obj)` k získání pole dvojic klíč/hodnota z `obj`. +2. Na tomto poli použijte metody polí, např. `map`, která tyto dvojice klíč/hodnota transformuje. +3. Na výsledné pole volejte `Object.fromEntries(pole)`, která z něj opět udělá objekt. -For example, we have an object with prices, and would like to double them: +Například máme objekt s cenami a rádi bychom je zdvojnásobili: ```js run -let prices = { - banana: 1, - orange: 2, - meat: 4, +let ceny = { + banán: 1, + pomeranč: 2, + maso: 4, }; *!* -let doublePrices = Object.fromEntries( - // convert prices to array, map each key/value pair into another pair - // and then fromEntries gives back the object - Object.entries(prices).map(entry => [entry[0], entry[1] * 2]) +let dvojnásobnéCeny = Object.fromEntries( + // převedeme na pole, zmapujeme každou dvojici klíč/hodnota na jinou dvojici + // a pak nám funkce fromEntries znovu vytvoří objekt + Object.entries(ceny).map(prvek => [prvek[0], prvek[1] * 2]) ); */!* -alert(doublePrices.meat); // 8 -``` +alert(dvojnásobnéCeny.maso); // 8 +``` -It may look difficult at first sight, but becomes easy to understand after you use it once or twice. We can make powerful chains of transforms this way. +Na první pohled to může vypadat obtížně, ale jakmile to jednou nebo dvakrát použijete, bude snadné tomu porozumět. Tímto způsobem můžeme vytvořit silné řetězce transformací. diff --git a/1-js/05-data-types/10-destructuring-assignment/1-destruct-user/solution.md b/1-js/05-data-types/10-destructuring-assignment/1-destruct-user/solution.md index cc226e7c5..abf884c7c 100644 --- a/1-js/05-data-types/10-destructuring-assignment/1-destruct-user/solution.md +++ b/1-js/05-data-types/10-destructuring-assignment/1-destruct-user/solution.md @@ -1,13 +1,13 @@ ```js run -let user = { - name: "John", - years: 30 +let uživatel = { + jméno: "Jan", + roky: 30 }; -let {name, years: age, isAdmin = false} = user; +let {jméno, roky: věk, jeAdmin = false} = uživatel; -alert( name ); // John -alert( age ); // 30 -alert( isAdmin ); // false +alert( jméno ); // Jan +alert( věk ); // 30 +alert( jeAdmin ); // false ``` \ No newline at end of file diff --git a/1-js/05-data-types/10-destructuring-assignment/1-destruct-user/task.md b/1-js/05-data-types/10-destructuring-assignment/1-destruct-user/task.md index b68db5c59..748f31eda 100644 --- a/1-js/05-data-types/10-destructuring-assignment/1-destruct-user/task.md +++ b/1-js/05-data-types/10-destructuring-assignment/1-destruct-user/task.md @@ -2,32 +2,32 @@ importance: 5 --- -# Destructuring assignment +# Destrukturační přiřazení -We have an object: +Máme objekt: ```js -let user = { - name: "John", - years: 30 +let uživatel = { + jméno: "Jan", + roky: 30 }; ``` -Write the destructuring assignment that reads: +Napište destrukturační přiřazení, které načte: -- `name` property into the variable `name`. -- `years` property into the variable `age`. -- `isAdmin` property into the variable `isAdmin` (false, if no such property) +- vlastnost `jméno` do proměnné `jméno`. +- vlastnost `roky` do proměnné `věk`. +- vlastnost `jeAdmin` do proměnné `jeAdmin` (false, pokud taková vlastnost není). -Here's an example of the values after your assignment: +Zde je příklad hodnot po vašem přiřazení: ```js -let user = { name: "John", years: 30 }; +let uživatel = { jméno: "Jan", roky: 30 }; -// your code to the left side: -// ... = user +// váš kód na levé straně: +// ... = uživatel -alert( name ); // John -alert( age ); // 30 -alert( isAdmin ); // false +alert( jméno ); // Jan +alert( věk ); // 30 +alert( jeAdmin ); // false ``` diff --git a/1-js/05-data-types/10-destructuring-assignment/6-max-salary/_js.view/solution.js b/1-js/05-data-types/10-destructuring-assignment/6-max-salary/_js.view/solution.js index 6538af42b..0009ac02c 100644 --- a/1-js/05-data-types/10-destructuring-assignment/6-max-salary/_js.view/solution.js +++ b/1-js/05-data-types/10-destructuring-assignment/6-max-salary/_js.view/solution.js @@ -1,14 +1,14 @@ -function topSalary(salaries) { +function nejvyššíPlat(platy) { - let maxSalary = 0; - let maxName = null; + let maxPlat = 0; + let maxJméno = null; - for(const [name, salary] of Object.entries(salaries)) { - if (maxSalary < salary) { - maxSalary = salary; - maxName = name; + for(const [jméno, plat] of Object.entries(platy)) { + if (maxPlat < plat) { + maxPlat = plat; + maxJméno = jméno; } } - return maxName; + return maxJméno; } \ No newline at end of file diff --git a/1-js/05-data-types/10-destructuring-assignment/6-max-salary/_js.view/test.js b/1-js/05-data-types/10-destructuring-assignment/6-max-salary/_js.view/test.js index e1da754ba..16663b25f 100644 --- a/1-js/05-data-types/10-destructuring-assignment/6-max-salary/_js.view/test.js +++ b/1-js/05-data-types/10-destructuring-assignment/6-max-salary/_js.view/test.js @@ -1,15 +1,15 @@ -describe("topSalary", function() { - it("returns top-paid person", function() { - let salaries = { - "John": 100, - "Pete": 300, - "Mary": 250 +describe("nejvyššíPlat", function() { + it("vrátí nejlépe placenou osobu", function() { + let platy = { + "Jan": 100, + "Petr": 300, + "Marie": 250 }; - assert.equal( topSalary(salaries), "Pete" ); + assert.equal( nejvyššíPlat(platy), "Petr" ); }); - it("returns null for the empty object", function() { - assert.isNull( topSalary({}) ); + it("pro prázdný objekt vrátí null", function() { + assert.isNull( nejvyššíPlat({}) ); }); }); \ No newline at end of file diff --git a/1-js/05-data-types/10-destructuring-assignment/6-max-salary/task.md b/1-js/05-data-types/10-destructuring-assignment/6-max-salary/task.md index 9f33de089..17564a2c0 100644 --- a/1-js/05-data-types/10-destructuring-assignment/6-max-salary/task.md +++ b/1-js/05-data-types/10-destructuring-assignment/6-max-salary/task.md @@ -2,21 +2,21 @@ importance: 5 --- -# The maximal salary +# Nejvyšší plat -There is a `salaries` object: +Máme objekt `platy`: ```js -let salaries = { - "John": 100, - "Pete": 300, - "Mary": 250 +let platy = { + "Jan": 100, + "Petr": 300, + "Marie": 250 }; ``` -Create the function `topSalary(salaries)` that returns the name of the top-paid person. +Vytvořte funkci `nejvyššíPlat(platy)`, která vrátí jméno nejlépe placené osoby. -- If `salaries` is empty, it should return `null`. -- If there are multiple top-paid persons, return any of them. +- Je-li objekt `platy` prázdný, měla by vrátit `null`. +- Jestliže je nejlépe placených osob více, může vrátit libovolnou z nich. -P.S. Use `Object.entries` and destructuring to iterate over key/value pairs. +P.S. K iteraci nad dvojicemi klíč/hodnota použijte `Object.entries` a destrukturaci. diff --git a/1-js/05-data-types/10-destructuring-assignment/article.md b/1-js/05-data-types/10-destructuring-assignment/article.md index 0c52741d1..28440bb3c 100644 --- a/1-js/05-data-types/10-destructuring-assignment/article.md +++ b/1-js/05-data-types/10-destructuring-assignment/article.md @@ -1,579 +1,579 @@ -# Destructuring assignment +# Destrukturační přiřazení -The two most used data structures in JavaScript are `Object` and `Array`. +Dvě nejpoužívanější datové struktury v JavaScriptu jsou objekty a pole. -- Objects allow us to create a single entity that stores data items by key. -- Arrays allow us to gather data items into an ordered list. +- 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. -However, when we pass these to a function, we may not need all of it. The function might only require certain elements or properties. +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. -*Destructuring assignment* is a special syntax that allows us to "unpack" arrays or objects into a bunch of variables, as sometimes that's more convenient. +*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ší. -Destructuring also works well with complex functions that have a lot of parameters, default values, and so on. Soon we'll see that. +Destrukturace také skvěle funguje se složitými funkcemi, které mají spoustu parametrů, standardní hodnoty a tak dále. Brzy to uvidíme. -## Array destructuring +## Destrukturace polí -Here's an example of how an array is destructured into variables: +Zde je příklad, jak je pole destrukturováno do proměnných: ```js -// we have an array with a name and surname -let arr = ["John", "Smith"] +// máme pole obsahující jméno a příjmení +let pole = ["Jan", "Novák"] *!* -// destructuring assignment -// sets firstName = arr[0] -// and surname = arr[1] -let [firstName, surname] = arr; +// 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(firstName); // John -alert(surname); // Smith +alert(křestníJméno); // Jan +alert(příjmení); // Novák ``` -Now we can work with variables instead of array members. +Nyní můžeme místo s prvky pole pracovat s proměnnými. -It looks great when combined with `split` or other array-returning methods: +Vypadá to výborně, když to zkombinujeme se `split` nebo jinými metodami vracejícími pole: ```js run -let [firstName, surname] = "John Smith".split(' '); -alert(firstName); // John -alert(surname); // Smith +let [křestníJméno, příjmení] = "Jan Novák".split(' '); +alert(křestníJméno); // Jan +alert(příjmení); // Novák ``` -As you can see, the syntax is simple. There are several peculiar details though. Let's see more examples to understand it better. +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. -````smart header="\"Destructuring\" does not mean \"destructive\"." -It's called "destructuring assignment," because it "destructurizes" by copying items into variables. However, the array itself is not modified. +````smart header="„Destrukturace“ neznamená „destrukce“" +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í. -It's just a shorter way to write: +Je to jen kratší způsob, jak napsat: ```js -// let [firstName, surname] = arr; -let firstName = arr[0]; -let surname = arr[1]; +// let [křestníJméno, příjmení] = pole; +let křestníJméno = pole[0]; +let příjmení = pole[1]; ``` ```` -````smart header="Ignore elements using commas" -Unwanted elements of the array can also be thrown away via an extra comma: +````smart header="Ignorování prvků pomocí čárek" +Nechtěné prvky pole můžeme zahodit přidáním čárky: ```js run *!* -// second element is not needed -let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"]; +// druhý prvek nepotřebujeme +let [křestníJméno, , titul] = ["Julius", "Caesar", "Konzul", "Římské republiky"]; */!* -alert( title ); // Consul +alert( titul ); // Konzul ``` -In the code above, the second element of the array is skipped, the third one is assigned to `title`, and the rest of the array items are also skipped (as there are no variables for them). +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é). ```` -````smart header="Works with any iterable on the right-side" +````smart header="Funguje s libovolným iterovatelným objektem na pravé straně" -...Actually, we can use it with any iterable, not only arrays: +...Ve skutečnosti můžeme destrukturační přiřazení použít na libovolný iterovatelný objekt, nejenom na pole: ```js let [a, b, c] = "abc"; // ["a", "b", "c"] -let [one, two, three] = new Set([1, 2, 3]); +let [jedna, dvě, tři] = new Set([1, 2, 3]); ``` -That works, because internally a destructuring assignment works by iterating over the right value. It's a kind of syntax sugar for calling `for..of` over the value to the right of `=` and assigning the values. +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. ```` -````smart header="Assign to anything at the left-side" -We can use any "assignables" on the left side. +````smart header="Na levé straně můžeme přiřazovat do čehokoli" +Na levé straně můžeme používat cokoli, do čeho lze přiřazovat. -For instance, an object property: +Například vlastnost objektu: ```js run -let user = {}; -[user.name, user.surname] = "John Smith".split(' '); +let uživatel = {}; +[uživatel.křestníJméno, uživatel.příjmení] = "Jan Novák".split(' '); -alert(user.name); // John -alert(user.surname); // Smith +alert(uživatel.křestníJméno); // Jan +alert(uživatel.příjmení); // Novák ``` ```` -````smart header="Looping with .entries()" -In the previous chapter, we saw the [Object.entries(obj)](mdn:js/Object/entries) method. +````smart header="Cyklus pomocí .entries()" +V předchozí kapitole jsme viděli metodu [Object.entries(obj)](mdn:js/Object/entries). -We can use it with destructuring to loop over the keys-and-values of an object: +Můžeme ji používat společně s destrukturací k procházení dvojic klíčů a hodnot objektu: ```js run -let user = { - name: "John", - age: 30 +let uživatel = { + jméno: "Jan", + věk: 30 }; -// loop over the keys-and-values +// cyklus nad dvojicemi klíč-hodnota *!* -for (let [key, value] of Object.entries(user)) { +for (let [klíč, hodnota] of Object.entries(uživatel)) { */!* - alert(`${key}:${value}`); // name:John, then age:30 + alert(`${klíč}:${hodnota}`); // jméno:Jan, poté věk:30 } ``` -The similar code for a `Map` is simpler, as it's iterable: +Podobný kód pro `Map` je jednodušší, protože mapa je iterovatelná: ```js run -let user = new Map(); -user.set("name", "John"); -user.set("age", "30"); +let uživatel = new Map(); +uživatel.set("jméno", "Jan"); +uživatel.set("věk", "30"); *!* -// Map iterates as [key, value] pairs, very convenient for destructuring -for (let [key, value] of user) { +// Map iteruje nad dvojicemi [klíč, hodnota], což je velmi vhodné pro destrukturaci +for (let [klíč, hodnota] of uživatel) { */!* - alert(`${key}:${value}`); // name:John, then age:30 + alert(`${klíč}:${hodnota}`); // jméno:Jan, poté věk:30 } ``` ```` -````smart header="Swap variables trick" -There's a well-known trick for swapping values of two variables using a destructuring assignment: +````smart header="Trik pro výměnu proměnných" +Existuje dobře známý trik pro výměnu hodnot dvou proměnných použitím destrukturačního přiřazení: ```js run -let guest = "Jane"; -let admin = "Pete"; +let host = "Jana"; +let admin = "Petr"; -// Let's swap the values: make guest=Pete, admin=Jane +// Vyměníme hodnoty: učiníme host=Petr, admin=Jana *!* -[guest, admin] = [admin, guest]; +[host, admin] = [admin, host]; */!* -alert(`${guest} ${admin}`); // Pete Jane (successfully swapped!) +alert(`${host} ${admin}`); // Petr Jana (úspěšně vyměněno!) ``` -Here we create a temporary array of two variables and immediately destructure it in swapped order. +Zde jsme vytvořili dočasné pole dvou proměnných a okamžitě je destrukturovali v obráceném pořadí. -We can swap more than two variables this way. +Tímto způsobem můžeme vyměnit i více než dvě proměnné. ```` -### The rest '...' +### Zbytek „...“ -Usually, if the array is longer than the list at the left, the "extra" items are omitted. +Jestliže je pole delší než seznam nalevo, „přebývající“ prvky jsou obvykle vypuštěny. -For example, here only two items are taken, and the rest is just ignored: +Například zde se vezmou jen první dva prvky a ostatní se jednoduše ignorují: ```js run -let [name1, name2] = ["Julius", "Caesar", "Consul", "of the Roman Republic"]; +let [jméno1, jméno2] = ["Julius", "Caesar", "Konzul", "Římské republiky"]; -alert(name1); // Julius -alert(name2); // Caesar -// Further items aren't assigned anywhere +alert(jméno1); // Julius +alert(jméno2); // Caesar +// Další prvky již nejsou nikam přiřazeny ``` -If we'd like also to gather all that follows -- we can add one more parameter that gets "the rest" using three dots `"..."`: +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 `"..."`: ```js run -let [name1, name2, *!*...rest*/!*] = ["Julius", "Caesar", *!*"Consul", "of the Roman Republic"*/!*]; +let [jméno1, jméno2, *!*...zbytek*/!*] = ["Julius", "Caesar", *!*"Konzul", "Římské republiky"*/!*]; *!* -// rest is an array of items, starting from the 3rd one -alert(rest[0]); // Consul -alert(rest[1]); // of the Roman Republic -alert(rest.length); // 2 +// zbytek je pole prvků počínaje třetím +alert(zbytek[0]); // Konzul +alert(zbytek[1]); // Římské republiky +alert(zbytek.length); // 2 */!* ``` -The value of `rest` is the array of the remaining array elements. +Hodnota proměnné `zbytek` je pole zbývajících prvků pole. -We can use any other variable name in place of `rest`, just make sure it has three dots before it and goes last in the destructuring assignment. +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í. ```js run -let [name1, name2, *!*...titles*/!*] = ["Julius", "Caesar", "Consul", "of the Roman Republic"]; -// now titles = ["Consul", "of the Roman Republic"] +let [jméno1, jméno2, *!*...tituly*/!*] = ["Julius", "Caesar", "Konzul", "Římské republiky"]; +// nyní tituly = ["Konzul", "Římské republiky"] ``` -### Default values +### Standardní hodnoty -If the array is shorter than the list of variables on the left, there will be no errors. Absent values are considered undefined: +Pokud je pole kratší než seznam proměnných nalevo, nedojde k chybě. Neuvedené hodnoty se považují za nedefinované: ```js run *!* -let [firstName, surname] = []; +let [křestníJméno, příjmení] = []; */!* -alert(firstName); // undefined -alert(surname); // undefined +alert(křestníJméno); // undefined +alert(příjmení); // undefined ``` -If we want a "default" value to replace the missing one, we can provide it using `=`: +Chceme-li, aby chybějící hodnoty nahradila nějaká „standardní“ hodnota, můžeme ji uvést pomocí `=`: ```js run *!* -// default values -let [name = "Guest", surname = "Anonymous"] = ["Julius"]; +// standardní hodnoty +let [jméno = "Host", příjmení = "Anonym"] = ["Julius"]; */!* -alert(name); // Julius (from array) -alert(surname); // Anonymous (default used) +alert(jméno); // Julius (z pole) +alert(příjmení); // Anonym (použita standardní hodnota) ``` -Default values can be more complex expressions or even function calls. They are evaluated only if the value is not provided. +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. -For instance, here we use the `prompt` function for two defaults: +Například zde použijeme pro dvě standardní hodnoty funkci `prompt`: ```js run -// runs only prompt for surname -let [name = prompt('name?'), surname = prompt('surname?')] = ["Julius"]; +// spustí prompt jen pro příjmení +let [jméno = prompt('jméno?'), příjmení = prompt('příjmení?')] = ["Julius"]; -alert(name); // Julius (from array) -alert(surname); // whatever prompt gets +alert(jméno); // Julius (z pole) +alert(příjmení); // to, co vrátil prompt ``` -Please note: the `prompt` will run only for the missing value (`surname`). +Prosíme všimněte si: `prompt` se spustí jen pro chybějící hodnotu (`příjmení`). -## Object destructuring +## Destrukturace objektů -The destructuring assignment also works with objects. +Destrukturační přiřazení funguje i pro objekty. -The basic syntax is: +Základní syntaxe je: ```js -let {var1, var2} = {var1:…, var2:…} +let {proměnná1, proměnná2} = {proměnná1:…, proměnná2:…} ``` -We should have an existing object on the right side, that we want to split into variables. The left side contains an object-like "pattern" for corresponding properties. In the simplest case, that's a list of variable names in `{...}`. +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 `{...}`. -For instance: +Příklad: ```js run -let options = { - title: "Menu", - width: 100, - height: 200 +let možnosti = { + titulek: "Menu", + šířka: 100, + výška: 200 }; *!* -let {title, width, height} = options; +let {titulek, šířka, výška} = možnosti; */!* -alert(title); // Menu -alert(width); // 100 -alert(height); // 200 +alert(titulek); // Menu +alert(šířka); // 100 +alert(výška); // 200 ``` -Properties `options.title`, `options.width` and `options.height` are assigned to the corresponding variables. +Vlastnosti `možnosti.titulek`, `možnosti.šířka` a `možnosti.výška` jsou přiřazeny do příslušných proměnných. -The order does not matter. This works too: +Na pořadí nezáleží. Tohle bude fungovat také: ```js -// changed the order in let {...} -let {height, width, title} = { title: "Menu", height: 200, width: 100 } +// změníme pořadí v let {...} +let {výška, šířka, titulek} = { titulek: "Menu", výška: 200, šířka: 100 } ``` -The pattern on the left side may be more complex and specify the mapping between properties and variables. +Vzor na levé straně může být složitější a může specifikovat mapování mezi vlastnostmi a proměnnými. -If we want to assign a property to a variable with another name, for instance, make `options.width` go into the variable named `w`, then we can set the variable name using a colon: +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: ```js run -let options = { - title: "Menu", - width: 100, - height: 200 +let možnosti = { + titulek: "Menu", + šířka: 100, + výška: 200 }; *!* -// { sourceProperty: targetVariable } -let {width: w, height: h, title} = options; +// { zdrojováVlastnost: cílováProměnná } +let {šířka: š, výška: v, titulek} = možnosti; */!* -// width -> w -// height -> h -// title -> title +// šířka -> š +// výška -> v +// titulek -> titulek -alert(title); // Menu -alert(w); // 100 -alert(h); // 200 +alert(titulek); // Menu +alert(š); // 100 +alert(v); // 200 ``` -The colon shows "what : goes where". In the example above the property `width` goes to `w`, property `height` goes to `h`, and `title` is assigned to the same name. +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. -For potentially missing properties we can set default values using `"="`, like this: +Pro vlastnosti, které mohou chybět, můžeme nastavit standardní hodnoty pomocí `"="` takto: ```js run -let options = { - title: "Menu" +let možnosti = { + titulek: "Menu" }; *!* -let {width = 100, height = 200, title} = options; +let {šířka = 100, výška = 200, titulek} = možnosti; */!* -alert(title); // Menu -alert(width); // 100 -alert(height); // 200 +alert(titulek); // Menu +alert(šířka); // 100 +alert(výška); // 200 ``` -Just like with arrays or function parameters, default values can be any expressions or even function calls. They will be evaluated if the value is not provided. +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. -In the code below `prompt` asks for `width`, but not for `title`: +V následujícím kódu se `prompt` zeptá na proměnnou `šířka`, ale ne na `titulek`: ```js run -let options = { - title: "Menu" +let možnosti = { + titulek: "Menu" }; *!* -let {width = prompt("width?"), title = prompt("title?")} = options; +let {šířka = prompt("šířka?"), titulek = prompt("titulek?")} = možnosti; */!* -alert(title); // Menu -alert(width); // (whatever the result of prompt is) +alert(titulek); // Menu +alert(šířka); // (to, co vrátil prompt) ``` -We also can combine both the colon and equality: +Můžeme také zkombinovat dvojtečku a rovnítko: ```js run -let options = { - title: "Menu" +let možnosti = { + titulek: "Menu" }; *!* -let {width: w = 100, height: h = 200, title} = options; +let {šířka: š = 100, výška: v = 200, titulek} = možnosti; */!* -alert(title); // Menu -alert(w); // 100 -alert(h); // 200 +alert(titulek); // Menu +alert(š); // 100 +alert(v); // 200 ``` -If we have a complex object with many properties, we can extract only what we need: +Máme-li složitý objekt s mnoha vlastnostmi, můžeme vytáhnout jen ty, které potřebujeme: ```js run -let options = { - title: "Menu", - width: 100, - height: 200 +let možnosti = { + titulek: "Menu", + šířka: 100, + výška: 200 }; -// only extract title as a variable -let { title } = options; +// do proměnné vyjmeme jen titulek +let { titulek } = možnosti; -alert(title); // Menu +alert(titulek); // Menu ``` -### The rest pattern "..." +### Zbytkový vzor „...“ -What if the object has more properties than we have variables? Can we take some and then assign the "rest" somewhere? +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? -We can use the rest pattern, just like we did with arrays. It's not supported by some older browsers (IE, use Babel to polyfill it), but works in modern ones. +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. -It looks like this: +Vypadá to takto: ```js run -let options = { - title: "Menu", - height: 200, - width: 100 +let možnosti = { + titulek: "Menu", + výška: 200, + šířka: 100 }; *!* -// title = property named title -// rest = object with the rest of properties -let {title, ...rest} = options; +// titulek = vlastnost nazvaná titulek +// zbytek = objekt s ostatními vlastnostmi +let {titulek, ...zbytek} = možnosti; */!* -// now title="Menu", rest={height: 200, width: 100} -alert(rest.height); // 200 -alert(rest.width); // 100 +// nyní titulek="Menu", zbytek={výška: 200, šířka: 100} +alert(zbytek.výška); // 200 +alert(zbytek.šířka); // 100 ``` -````smart header="Gotcha if there's no `let`" -In the examples above variables were declared right in the assignment: `let {…} = {…}`. Of course, we could use existing variables too, without `let`. But there's a catch. +````smart header="Chyták při neuvedení `let`" +Ve 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. -This won't work: +Tohle nebude fungovat: ```js run -let title, width, height; +let titulek, šířka, výška; -// error in this line -{title, width, height} = {title: "Menu", width: 200, height: 100}; +// na tomto řádku je chyba +{titulek, šířka, výška} = {titulek: "Menu", šířka: 200, výška: 100}; ``` -The problem is that JavaScript treats `{...}` in the main code flow (not inside another expression) as a code block. Such code blocks can be used to group statements, like this: +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: ```js run { - // a code block - let message = "Hello"; + // kódový blok + let zpráva = "Ahoj"; // ... - alert( message ); + alert( zpráva ); } ``` -So here JavaScript assumes that we have a code block, that's why there's an error. We want destructuring instead. +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. -To show JavaScript that it's not a code block, we can wrap the expression in parentheses `(...)`: +Abychom sdělili JavaScriptu, že tohle není kódový blok, můžeme uzavřít výraz do závorek `(...)`: ```js run -let title, width, height; +let titulek, šířka, výška; -// okay now -*!*(*/!*{title, width, height} = {title: "Menu", width: 200, height: 100}*!*)*/!*; +// nyní je to v pořádku +*!*(*/!*{titulek, šířka, výška} = {titulek: "Menu", šířka: 200, výška: 100}*!*)*/!*; -alert( title ); // Menu +alert( titulek ); // Menu ``` ```` -## Nested destructuring +## Vnořená destrukturace -If an object or an array contains other nested objects and arrays, we can use more complex left-side patterns to extract deeper portions. +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ě. -In the code below `options` has another object in the property `size` and an array in the property `items`. The pattern on the left side of the assignment has the same structure to extract values from them: +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: ```js run -let options = { - size: { - width: 100, - height: 200 +let možnosti = { + velikost: { + šířka: 100, + výška: 200 }, - items: ["Cake", "Donut"], - extra: true + prvky: ["Koláč", "Vdolek"], + extra: true }; -// destructuring assignment split in multiple lines for clarity +// destrukturační přiřazení, pro čitelnost rozdělené do více řádků let { - size: { // put size here - width, - height + velikost: { // zde uvedeme velikost + šířka, + výška }, - items: [item1, item2], // assign items here - title = "Menu" // not present in the object (default value is used) -} = options; + prvky: [prvek1, prvek2], // zde přiřadíme prvky + titulek = "Menu" // v objektu není přítomen (použije se standardní hodnota) +} = možnosti; -alert(title); // Menu -alert(width); // 100 -alert(height); // 200 -alert(item1); // Cake -alert(item2); // Donut +alert(titulek); // Menu +alert(šířka); // 100 +alert(výška); // 200 +alert(prvek1); // Koláč +alert(prvek2); // Vdolek ``` -All properties of `options` object except `extra` which is absent in the left part, are assigned to corresponding variables: +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í: ![](destructuring-complex.svg) -Finally, we have `width`, `height`, `item1`, `item2` and `title` from the default value. +Nakonec tedy máme `šířka`, `výška`, `prvek1`, `prvek2` a `titulek` ze standardní hodnoty. -Note that there are no variables for `size` and `items`, as we take their content instead. +Všimněte si, že zde nejsou žádné proměnné pro `velikost` a `prvky`, jelikož jsme místo nich vzali jejich obsah. -## Smart function parameters +## Chytré funkční parametry -There are times when a function has many parameters, most of which are optional. That's especially true for user interfaces. Imagine a function that creates a menu. It may have a width, a height, a title, an item list and so on. +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ě. -Here's a bad way to write such a function: +Zde je špatný způsob, jak takovou funkci napsat: ```js -function showMenu(title = "Untitled", width = 200, height = 100, items = []) { +function zobrazMenu(titulek = "Bez názvu", šířka = 200, výška = 100, prvky = []) { // ... } ``` -In real-life, the problem is how to remember the order of arguments. Usually, IDEs try to help us, especially if the code is well-documented, but still... Another problem is how to call a function when most parameters are ok by default. +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. -Like this? +Takhle? ```js -// undefined where default values are fine -showMenu("My Menu", undefined, undefined, ["Item1", "Item2"]) +// undefined tam, kde se má použít standardní hodnota +zobrazMenu("Moje menu", undefined, undefined, ["Prvek1", "Prvek2"]) ``` -That's ugly. And becomes unreadable when we deal with more parameters. +To je ošklivé. A když budeme pracovat s více parametry, bude to nečitelné. -Destructuring comes to the rescue! +Destrukturace nás přichází zachránit! -We can pass parameters as an object, and the function immediately destructurizes them into variables: +Můžeme předávat parametry jako objekt a funkce je okamžitě destrukturuje do proměnných: ```js run -// we pass object to function -let options = { - title: "My menu", - items: ["Item1", "Item2"] +// předáme objekt do funkce +let možnosti = { + titulek: "Moje menu", + prvky: ["Prvek1", "Prvek2"] }; -// ...and it immediately expands it to variables -function showMenu(*!*{title = "Untitled", width = 200, height = 100, items = []}*/!*) { - // title, items – taken from options, - // width, height – defaults used - alert( `${title} ${width} ${height}` ); // My Menu 200 100 - alert( items ); // Item1, Item2 +// ...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 } -showMenu(options); +zobrazMenu(možnosti); ``` -We can also use more complex destructuring with nested objects and colon mappings: +S vnořenými objekty a dvojtečkovým mapováním můžeme použít i složitější destrukturaci: ```js run -let options = { - title: "My menu", - items: ["Item1", "Item2"] +let možnosti = { + titulek: "Moje menu", + prvky: ["Prvek1", "Prvek2"] }; *!* -function showMenu({ - title = "Untitled", - width: w = 100, // width goes to w - height: h = 200, // height goes to h - items: [item1, item2] // items first element goes to item1, second to item2 +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( `${title} ${w} ${h}` ); // My Menu 100 200 - alert( item1 ); // Item1 - alert( item2 ); // Item2 + alert( `${titulek} ${š} ${v}` ); // Moje menu 100 200 + alert( prvek1 ); // Prvek1 + alert( prvek2 ); // Prvek2 } -showMenu(options); +zobrazMenu(možnosti); ``` -The full syntax is the same as for a destructuring assignment: +Úplná syntaxe je stejná jako u destrukturačního přiřazení: ```js function({ - incomingProperty: varName = defaultValue + vstupujícíVlastnost: názevProměnné = standardníHodnota ... }) ``` -Then, for an object of parameters, there will be a variable `varName` for the property `incomingProperty`, with `defaultValue` by default. +Pro objekt parametrů pak budeme mít pro vlastnost `vstupujícíVlastnost` proměnnou `názevProměnné` , jejíž standardní hodnotou bude `standardníHodnota`. -Please note that such destructuring assumes that `showMenu()` does have an argument. If we want all values by default, then we should specify an empty object: +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: ```js -showMenu({}); // ok, all values are default +zobrazMenu({}); // ok, všechny hodnoty jsou standardní -showMenu(); // this would give an error +zobrazMenu(); // tohle ohlásí chybu ``` -We can fix this by making `{}` the default value for the whole object of parameters: +To můžeme opravit tak, že učiníme `{}` standardní hodnotou celého objektu parametrů: ```js run -function showMenu({ title = "Menu", width = 100, height = 200 }*!* = {}*/!*) { - alert( `${title} ${width} ${height}` ); +function zobrazMenu({ titulek = "Menu", šířka = 100, výška = 200 }*!* = {}*/!*) { + alert( `${titulek} ${šířka} ${výška}` ); } -showMenu(); // Menu 100 200 +zobrazMenu(); // Menu 100 200 ``` -In the code above, the whole arguments object is `{}` by default, so there's always something to destructurize. +V uvedeném kódu je celý argumentový objekt standardně `{}`, takže vždy bude co destrukturovat. -## Summary +## Shrnutí -- Destructuring assignment allows for instantly mapping an object or array onto many variables. -- The full object syntax: +- Destrukturační přiřazení umožňuje rychlé mapování objektu nebo pole do mnoha proměnných. +- Úplná syntaxe pro objekt: ```js - let {prop : varName = defaultValue, ...rest} = object + let {vlastnost : názevProměnné = standardníHodnota, ...zbytek} = objekt ``` - This means that property `prop` should go into the variable `varName` and, if no such property exists, then the `default` value should be used. + To znamená, že vlastnost `vlastnost` má přijít do proměnné `názevProměnné`, a pokud taková vlastnost neexistuje, měla by se použít hodnota `standardníHodnota`. - Object properties that have no mapping are copied to the `rest` object. + Objektové vlastnosti, pro které není uvedeno mapování, se zkopírují do objektu `zbytek`. -- The full array syntax: +- Úplná syntaxe pro pole: ```js - let [item1 = defaultValue, item2, ...rest] = array + let [prvek1 = standardníHodnota, prvek2, ...zbytek] = pole ``` - The first item goes to `item1`; the second goes into `item2`, and all the rest makes the array `rest`. + První prvek se uloží do proměnné `prvek1`, druhý do `prvek2`, ze všech ostatních prvků se vytvoří pole `zbytek`. -- It's possible to extract data from nested arrays/objects, for that the left side must have the same structure as the right one. +- 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á. diff --git a/1-js/05-data-types/11-date/1-new-date/solution.md b/1-js/05-data-types/11-date/1-new-date/solution.md index 18286c336..22aeea6e3 100644 --- a/1-js/05-data-types/11-date/1-new-date/solution.md +++ b/1-js/05-data-types/11-date/1-new-date/solution.md @@ -1,18 +1,18 @@ -The `new Date` constructor uses the local time zone. So the only important thing to remember is that months start from zero. +Konstruktor `new Date` používá místní časové pásmo, takže jediná důležitá věc, kterou si musíme pamatovat, je, že měsíce se počítají od nuly. -So February has number 1. +Únor má tedy číslo 1. -Here's an example with numbers as date components: +Zde je příklad s čísly jako složkami data: ```js run -//new Date(year, month, date, hour, minute, second, millisecond) +//new Date(rok, měsíc, den, hodiny, minuty, sekundy, milisekundy) let d1 = new Date(2012, 1, 20, 3, 12); alert( d1 ); ``` -We could also create a date from a string, like this: +Můžeme vytvořit datum i z řetězce, např. takto: ```js run -//new Date(datastring) +//new Date(řetězecSDatem) let d2 = new Date("2012-02-20T03:12"); alert( d2 ); ``` diff --git a/1-js/05-data-types/11-date/1-new-date/task.md b/1-js/05-data-types/11-date/1-new-date/task.md index 1b40d5ac0..10765e94b 100644 --- a/1-js/05-data-types/11-date/1-new-date/task.md +++ b/1-js/05-data-types/11-date/1-new-date/task.md @@ -2,8 +2,8 @@ importance: 5 --- -# Create a date +# Vytvoření data -Create a `Date` object for the date: Feb 20, 2012, 3:12am. The time zone is local. +Vytvořte objekt `Date` pro datum: 20. února 2012, 3.12 hodin. Časové pásmo je místní. -Show it using `alert`. +Zobrazte jej pomocí `alert`. diff --git a/1-js/05-data-types/11-date/2-get-week-day/_js.view/solution.js b/1-js/05-data-types/11-date/2-get-week-day/_js.view/solution.js index 642c376a9..869ee61de 100644 --- a/1-js/05-data-types/11-date/2-get-week-day/_js.view/solution.js +++ b/1-js/05-data-types/11-date/2-get-week-day/_js.view/solution.js @@ -1,5 +1,5 @@ -function getWeekDay(date) { - let days = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA']; +function vraťDenVTýdnu(datum) { + let dny = ['NE', 'PO', 'ÚT', 'ST', 'ČT', 'PÁ', 'SO']; - return days[date.getDay()]; + return dny[datum.getDay()]; } diff --git a/1-js/05-data-types/11-date/2-get-week-day/_js.view/test.js b/1-js/05-data-types/11-date/2-get-week-day/_js.view/test.js index 3cdc91830..dc1c2ed6d 100644 --- a/1-js/05-data-types/11-date/2-get-week-day/_js.view/test.js +++ b/1-js/05-data-types/11-date/2-get-week-day/_js.view/test.js @@ -1,29 +1,29 @@ -describe("getWeekDay", function() { - it("3 January 2014 - friday", function() { - assert.equal(getWeekDay(new Date(2014, 0, 3)), 'FR'); +describe("vraťDenVTýdnu", function() { + it("3. leden 2014 - pátek", function() { + assert.equal(vraťDenVTýdnu(new Date(2014, 0, 3)), 'PÁ'); }); - it("4 January 2014 - saturday", function() { - assert.equal(getWeekDay(new Date(2014, 0, 4)), 'SA'); + it("4. leden 2014 - sobota", function() { + assert.equal(vraťDenVTýdnu(new Date(2014, 0, 4)), 'SO'); }); - it("5 January 2014 - sunday", function() { - assert.equal(getWeekDay(new Date(2014, 0, 5)), 'SU'); + it("5. leden 2014 - neděle", function() { + assert.equal(vraťDenVTýdnu(new Date(2014, 0, 5)), 'NE'); }); - it("6 January 2014 - monday", function() { - assert.equal(getWeekDay(new Date(2014, 0, 6)), 'MO'); + it("6. leden 2014 - pondělí", function() { + assert.equal(vraťDenVTýdnu(new Date(2014, 0, 6)), 'PO'); }); - it("7 January 2014 - tuesday", function() { - assert.equal(getWeekDay(new Date(2014, 0, 7)), 'TU'); + it("7. leden 2014 - úterý", function() { + assert.equal(vraťDenVTýdnu(new Date(2014, 0, 7)), 'ÚT'); }); - it("8 January 2014 - wednesday", function() { - assert.equal(getWeekDay(new Date(2014, 0, 8)), 'WE'); + it("8. leden 2014 - středa", function() { + assert.equal(vraťDenVTýdnu(new Date(2014, 0, 8)), 'ST'); }); - it("9 January 2014 - thursday", function() { - assert.equal(getWeekDay(new Date(2014, 0, 9)), 'TH'); + it("9. leden 2014 - čtvrtek", function() { + assert.equal(vraťDenVTýdnu(new Date(2014, 0, 9)), 'ČT'); }); }); diff --git a/1-js/05-data-types/11-date/2-get-week-day/solution.md b/1-js/05-data-types/11-date/2-get-week-day/solution.md index 58d75c1c3..2a24cffe5 100644 --- a/1-js/05-data-types/11-date/2-get-week-day/solution.md +++ b/1-js/05-data-types/11-date/2-get-week-day/solution.md @@ -1,14 +1,14 @@ -The method `date.getDay()` returns the number of the weekday, starting from sunday. +Metoda `datum.getDay()` vrací číslo dne v týdnu počínajíc nedělí. -Let's make an array of weekdays, so that we can get the proper day name by its number: +Vytvoříme pole dnů v týdnu, abychom mohli získat název příslušného dne podle jeho čísla: ```js run demo -function getWeekDay(date) { - let days = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA']; +function vraťDenVTýdnu(datum) { + let dny = ['NE', 'PO', 'ÚT', 'ST', 'ČT', 'PÁ', 'SO']; - return days[date.getDay()]; + return dny[datum.getDay()]; } -let date = new Date(2014, 0, 3); // 3 Jan 2014 -alert( getWeekDay(date) ); // FR +let datum = new Date(2014, 0, 3); // 3. leden 2014 +alert( vraťDenVTýdnu(datum) ); // PÁ ``` diff --git a/1-js/05-data-types/11-date/2-get-week-day/task.md b/1-js/05-data-types/11-date/2-get-week-day/task.md index 5cf31565d..4d7adc86f 100644 --- a/1-js/05-data-types/11-date/2-get-week-day/task.md +++ b/1-js/05-data-types/11-date/2-get-week-day/task.md @@ -2,13 +2,13 @@ importance: 5 --- -# Show a weekday +# Zobrazení dne v týdnu -Write a function `getWeekDay(date)` to show the weekday in short format: 'MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU'. +Napište funkci `vraťDenVTýdnu(datum)`, která zobrazí den v týdnu ve zkráceném tvaru: „PO“, „ÚT“, „ST“, „ČT“, „PÁ“, „SO“, „NE“. -For instance: +Příklad: ```js no-beautify -let date = new Date(2012, 0, 3); // 3 Jan 2012 -alert( getWeekDay(date) ); // should output "TU" +let datum = new Date(2012, 0, 3); // 3. leden 2012 +alert( vraťDenVTýdnu(datum) ); // měla by vypsat „ÚT“ ``` diff --git a/1-js/05-data-types/11-date/3-weekday/_js.view/solution.js b/1-js/05-data-types/11-date/3-weekday/_js.view/solution.js index fb9e3d2a4..1572b06a4 100644 --- a/1-js/05-data-types/11-date/3-weekday/_js.view/solution.js +++ b/1-js/05-data-types/11-date/3-weekday/_js.view/solution.js @@ -1,10 +1,10 @@ -function getLocalDay(date) { +function vraťMístníDenVTýdnu(datum) { - let day = date.getDay(); + let den = datum.getDay(); - if (day == 0) { // weekday 0 (sunday) is 7 in european - day = 7; + if (den == 0) { // 0. den v týdnu (neděle) je v Evropě 7. + den = 7; } - return day; + return den; } diff --git a/1-js/05-data-types/11-date/3-weekday/_js.view/test.js b/1-js/05-data-types/11-date/3-weekday/_js.view/test.js index 57032154f..e00f2519b 100644 --- a/1-js/05-data-types/11-date/3-weekday/_js.view/test.js +++ b/1-js/05-data-types/11-date/3-weekday/_js.view/test.js @@ -1,29 +1,29 @@ -describe("getLocalDay returns the \"european\" weekday", function() { - it("3 January 2014 - friday", function() { - assert.equal(getLocalDay(new Date(2014, 0, 3)), 5); +describe("vraťMístníDenVTýdnu vrací \"evropský\" den v týdnu", function() { + it("3. leden 2014 - pátek", function() { + assert.equal(vraťMístníDenVTýdnu(new Date(2014, 0, 3)), 5); }); - it("4 January 2014 - saturday", function() { - assert.equal(getLocalDay(new Date(2014, 0, 4)), 6); + it("4. leden 2014 - sobota", function() { + assert.equal(vraťMístníDenVTýdnu(new Date(2014, 0, 4)), 6); }); - it("5 January 2014 - sunday", function() { - assert.equal(getLocalDay(new Date(2014, 0, 5)), 7); + it("5. leden 2014 - neděle", function() { + assert.equal(vraťMístníDenVTýdnu(new Date(2014, 0, 5)), 7); }); - it("6 January 2014 - monday", function() { - assert.equal(getLocalDay(new Date(2014, 0, 6)), 1); + it("6. leden 2014 - pondělí", function() { + assert.equal(vraťMístníDenVTýdnu(new Date(2014, 0, 6)), 1); }); - it("7 January 2014 - tuesday", function() { - assert.equal(getLocalDay(new Date(2014, 0, 7)), 2); + it("7. leden 2014 - úterý", function() { + assert.equal(vraťMístníDenVTýdnu(new Date(2014, 0, 7)), 2); }); - it("8 January 2014 - wednesday", function() { - assert.equal(getLocalDay(new Date(2014, 0, 8)), 3); + it("8. leden 2014 - středa", function() { + assert.equal(vraťMístníDenVTýdnu(new Date(2014, 0, 8)), 3); }); - it("9 January 2014 - thursday", function() { - assert.equal(getLocalDay(new Date(2014, 0, 9)), 4); + it("9. leden 2014 - čtvrtek", function() { + assert.equal(vraťMístníDenVTýdnu(new Date(2014, 0, 9)), 4); }); }); diff --git a/1-js/05-data-types/11-date/3-weekday/task.md b/1-js/05-data-types/11-date/3-weekday/task.md index ba62790cf..c06a4bf21 100644 --- a/1-js/05-data-types/11-date/3-weekday/task.md +++ b/1-js/05-data-types/11-date/3-weekday/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# European weekday +# Evropský den v týdnu -European countries have days of week starting with Monday (number 1), then Tuesday (number 2) and till Sunday (number 7). Write a function `getLocalDay(date)` that returns the "European" day of week for `date`. +V evropských zemích začíná týden pondělím (číslo 1), pak je úterý (číslo 2) a tak dále, až nakonec je neděle (číslo 7). Napište funkci `vraťMístníDenVTýdnu(datum)`, která vrátí „evropský“ den v týdnu pro `datum`. ```js no-beautify -let date = new Date(2012, 0, 3); // 3 Jan 2012 -alert( getLocalDay(date) ); // tuesday, should show 2 +let datum = new Date(2012, 0, 3); // 3. leden 2012 +alert( vraťMístníDenVTýdnu(datum) ); // úterý, měla by zobrazit 2 ``` diff --git a/1-js/05-data-types/11-date/4-get-date-ago/_js.view/solution.js b/1-js/05-data-types/11-date/4-get-date-ago/_js.view/solution.js index 9cce0fb90..163cd8eec 100644 --- a/1-js/05-data-types/11-date/4-get-date-ago/_js.view/solution.js +++ b/1-js/05-data-types/11-date/4-get-date-ago/_js.view/solution.js @@ -1,6 +1,6 @@ -function getDateAgo(date, days) { - let dateCopy = new Date(date); +function vraťDenPřed(datum, dny) { + let kopieData = new Date(datum); - dateCopy.setDate(date.getDate() - days); - return dateCopy.getDate(); + kopieData.setDate(datum.getDate() - dny); + return kopieData.getDate(); } diff --git a/1-js/05-data-types/11-date/4-get-date-ago/_js.view/test.js b/1-js/05-data-types/11-date/4-get-date-ago/_js.view/test.js index 255acffe0..a1ef2eced 100644 --- a/1-js/05-data-types/11-date/4-get-date-ago/_js.view/test.js +++ b/1-js/05-data-types/11-date/4-get-date-ago/_js.view/test.js @@ -1,27 +1,27 @@ -describe("getDateAgo", function() { +describe("vraťDenPřed", function() { - it("1 day before 02.01.2015 -> day 1", function() { - assert.equal(getDateAgo(new Date(2015, 0, 2), 1), 1); + it("1 den před 02.01.2015 -> den 1", function() { + assert.equal(vraťDenPřed(new Date(2015, 0, 2), 1), 1); }); - it("2 days before 02.01.2015 -> day 31", function() { - assert.equal(getDateAgo(new Date(2015, 0, 2), 2), 31); + it("2 dny před 02.01.2015 -> den 31", function() { + assert.equal(vraťDenPřed(new Date(2015, 0, 2), 2), 31); }); - it("100 days before 02.01.2015 -> day 24", function() { - assert.equal(getDateAgo(new Date(2015, 0, 2), 100), 24); + it("100 dní před 02.01.2015 -> den 24", function() { + assert.equal(vraťDenPřed(new Date(2015, 0, 2), 100), 24); }); - it("365 days before 02.01.2015 -> day 2", function() { - assert.equal(getDateAgo(new Date(2015, 0, 2), 365), 2); + it("365 dní před 02.01.2015 -> den 2", function() { + assert.equal(vraťDenPřed(new Date(2015, 0, 2), 365), 2); }); - it("does not modify the given date", function() { - let date = new Date(2015, 0, 2); - let dateCopy = new Date(date); - getDateAgo(dateCopy, 100); - assert.equal(date.getTime(), dateCopy.getTime()); + it("nemění zadané datum", function() { + let datum = new Date(2015, 0, 2); + let kopieData = new Date(datum); + vraťDenPřed(kopieData, 100); + assert.equal(datum.getTime(), kopieData.getTime()); }); }); diff --git a/1-js/05-data-types/11-date/4-get-date-ago/solution.md b/1-js/05-data-types/11-date/4-get-date-ago/solution.md index 5c394c100..8a027e075 100644 --- a/1-js/05-data-types/11-date/4-get-date-ago/solution.md +++ b/1-js/05-data-types/11-date/4-get-date-ago/solution.md @@ -1,27 +1,27 @@ -The idea is simple: to substract given number of days from `date`: +Myšlenka je jednoduchá: odečíst zadaný počet dní od `datum`: ```js -function getDateAgo(date, days) { - date.setDate(date.getDate() - days); - return date.getDate(); +function vraťDenPřed(datum, dny) { + datum.setDate(datum.getDate() - dny); + return datum.getDate(); } ``` -...But the function should not change `date`. That's an important thing, because the outer code which gives us the date does not expect it to change. +...Funkce by však neměla měnit `datum`. To je důležité, jelikož vnější kód, který nám datum předává, neočekává, že bude změněno. -To implement it let's clone the date, like this: +Abychom to implementovali, naklonujeme datum, např. takto: ```js run demo -function getDateAgo(date, days) { - let dateCopy = new Date(date); +function vraťDenPřed(datum, dny) { + let kopieData = new Date(datum); - dateCopy.setDate(date.getDate() - days); - return dateCopy.getDate(); + kopieData.setDate(datum.getDate() - dny); + return kopieData.getDate(); } -let date = new Date(2015, 0, 2); +let datum = new Date(2015, 0, 2); -alert( getDateAgo(date, 1) ); // 1, (1 Jan 2015) -alert( getDateAgo(date, 2) ); // 31, (31 Dec 2014) -alert( getDateAgo(date, 365) ); // 2, (2 Jan 2014) +alert( vraťDenPřed(datum, 1) ); // 1, (1. leden 2015) +alert( vraťDenPřed(datum, 2) ); // 31, (31. prosinec 2014) +alert( vraťDenPřed(datum, 365) ); // 2, (2. leden 2014) ``` diff --git a/1-js/05-data-types/11-date/4-get-date-ago/task.md b/1-js/05-data-types/11-date/4-get-date-ago/task.md index 058d39c7e..c01396b67 100644 --- a/1-js/05-data-types/11-date/4-get-date-ago/task.md +++ b/1-js/05-data-types/11-date/4-get-date-ago/task.md @@ -2,20 +2,20 @@ importance: 4 --- -# Which day of month was many days ago? +# Který den v měsíci byl před mnoha dny? -Create a function `getDateAgo(date, days)` to return the day of month `days` ago from the `date`. +Vytvořte funkci `vraťDenPřed(datum, dny)`, která vrátí den v měsíci, který byl `dny` dnů přede dnem `datum`. -For instance, if today is 20th, then `getDateAgo(new Date(), 1)` should be 19th and `getDateAgo(new Date(), 2)` should be 18th. +Například jestliže dnes je 20., pak `vraťDenPřed(new Date(), 1)` by měla vrátit 19 a `vraťDenPřed(new Date(), 2)` by měla vrátit 18. -Should work reliably for `days=365` or more: +Měla by spolehlivě fungovat i pro `dny=365` nebo více: ```js -let date = new Date(2015, 0, 2); +let datum = new Date(2015, 0, 2); -alert( getDateAgo(date, 1) ); // 1, (1 Jan 2015) -alert( getDateAgo(date, 2) ); // 31, (31 Dec 2014) -alert( getDateAgo(date, 365) ); // 2, (2 Jan 2014) +alert( vraťDenPřed(datum, 1) ); // 1, (1. leden 2015) +alert( vraťDenPřed(datum, 2) ); // 31, (31. prosinec 2014) +alert( vraťDenPřed(datum, 365) ); // 2, (2. leden 2014) ``` -P.S. The function should not modify the given `date`. +P.S. Funkce by neměla modifikovat zadané `datum`. \ No newline at end of file diff --git a/1-js/05-data-types/11-date/5-last-day-of-month/_js.view/solution.js b/1-js/05-data-types/11-date/5-last-day-of-month/_js.view/solution.js index d0d7d37ff..0e44fdda2 100644 --- a/1-js/05-data-types/11-date/5-last-day-of-month/_js.view/solution.js +++ b/1-js/05-data-types/11-date/5-last-day-of-month/_js.view/solution.js @@ -1,4 +1,4 @@ -function getLastDayOfMonth(year, month) { - let date = new Date(year, month + 1, 0); - return date.getDate(); +function vraťPosledníDenVMěsíci(rok, měsíc) { + let datum = new Date(rok, měsíc + 1, 0); + return datum.getDate(); } diff --git a/1-js/05-data-types/11-date/5-last-day-of-month/_js.view/test.js b/1-js/05-data-types/11-date/5-last-day-of-month/_js.view/test.js index 4ff3e116a..b84826fee 100644 --- a/1-js/05-data-types/11-date/5-last-day-of-month/_js.view/test.js +++ b/1-js/05-data-types/11-date/5-last-day-of-month/_js.view/test.js @@ -1,13 +1,13 @@ -describe("getLastDayOfMonth", function() { - it("last day of 01.01.2012 - 31", function() { - assert.equal(getLastDayOfMonth(2012, 0), 31); +describe("vraťPosledníDenVMěsíci", function() { + it("poslední den 01.01.2012 - 31", function() { + assert.equal(vraťPosledníDenVMěsíci(2012, 0), 31); }); - it("last day of 01.02.2012 - 29 (leap year)", function() { - assert.equal(getLastDayOfMonth(2012, 1), 29); + it("poslední den 01.02.2012 - 29 (přestupný rok)", function() { + assert.equal(vraťPosledníDenVMěsíci(2012, 1), 29); }); - it("last day of 01.02.2013 - 28", function() { - assert.equal(getLastDayOfMonth(2013, 1), 28); + it("poslední den 01.02.2013 - 28", function() { + assert.equal(vraťPosledníDenVMěsíci(2013, 1), 28); }); }); diff --git a/1-js/05-data-types/11-date/5-last-day-of-month/solution.md b/1-js/05-data-types/11-date/5-last-day-of-month/solution.md index 4f642536e..da3538503 100644 --- a/1-js/05-data-types/11-date/5-last-day-of-month/solution.md +++ b/1-js/05-data-types/11-date/5-last-day-of-month/solution.md @@ -1,13 +1,13 @@ -Let's create a date using the next month, but pass zero as the day: +Vytvořme datum z následujícího měsíce, ale jako den předáme nulu: ```js run demo -function getLastDayOfMonth(year, month) { - let date = new Date(year, month + 1, 0); - return date.getDate(); +function vraťPosledníDenVMěsíci(rok, měsíc) { + let datum = new Date(rok, měsíc + 1, 0); + return datum.getDate(); } -alert( getLastDayOfMonth(2012, 0) ); // 31 -alert( getLastDayOfMonth(2012, 1) ); // 29 -alert( getLastDayOfMonth(2013, 1) ); // 28 +alert( vraťPosledníDenVMěsíci(2012, 0) ); // 31 +alert( vraťPosledníDenVMěsíci(2012, 1) ); // 29 +alert( vraťPosledníDenVMěsíci(2013, 1) ); // 28 ``` -Normally, dates start from 1, but technically we can pass any number, the date will autoadjust itself. So when we pass 0, then it means "one day before 1st day of the month", in other words: "the last day of the previous month". +Normálně dny začínají od 1, ale technicky můžeme předat jakékoli číslo a datum se samo přizpůsobí. Když tedy předáme 0, bude to znamenat „jeden den před 1. dnem v měsíci“, jinými slovy: „poslední den předcházejícího měsíce“. diff --git a/1-js/05-data-types/11-date/5-last-day-of-month/task.md b/1-js/05-data-types/11-date/5-last-day-of-month/task.md index 10dfb7a7a..ba9af12cd 100644 --- a/1-js/05-data-types/11-date/5-last-day-of-month/task.md +++ b/1-js/05-data-types/11-date/5-last-day-of-month/task.md @@ -2,13 +2,13 @@ importance: 5 --- -# Last day of month? +# Poslední den v měsíci? -Write a function `getLastDayOfMonth(year, month)` that returns the last day of month. Sometimes it is 30th, 31st or even 28/29th for Feb. +Napište funkci `vraťPosledníDenVMěsíci(rok, měsíc)`, která vrátí číslo posledního dne v měsíci. Někdy je to 30., někdy 31., v únoru dokonce 28. nebo 29. -Parameters: +Parametry: -- `year` -- four-digits year, for instance 2012. -- `month` -- month, from 0 to 11. +- `rok` -- čtyřčíslicový rok, např. 2012. +- `měsíc` -- měsíc, od 0 do 11. -For instance, `getLastDayOfMonth(2012, 1) = 29` (leap year, Feb). +Například `vraťPosledníDenVMěsíci(2012, 1) = 29` (přestupný rok, únor). diff --git a/1-js/05-data-types/11-date/6-get-seconds-today/solution.md b/1-js/05-data-types/11-date/6-get-seconds-today/solution.md index 8f8e52b68..54004eea9 100644 --- a/1-js/05-data-types/11-date/6-get-seconds-today/solution.md +++ b/1-js/05-data-types/11-date/6-get-seconds-today/solution.md @@ -1,28 +1,28 @@ -To get the number of seconds, we can generate a date using the current day and time 00:00:00, then substract it from "now". +Abychom získali počet sekund, můžeme vygenerovat datum z dnešního dne a času 00:00:00 a pak je odečíst od „nynějška“. -The difference is the number of milliseconds from the beginning of the day, that we should divide by 1000 to get seconds: +Rozdílem bude počet milisekund od začátku dne, který bychom měli vydělit 1000, abychom získali sekundy: ```js run -function getSecondsToday() { - let now = new Date(); +function vraťDnešníSekundy() { + let nyní = new Date(); - // create an object using the current day/month/year - let today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); + // vytvoříme objekt z dnešního dne/měsíce/roku + let dnešek = new Date(nyní.getFullYear(), nyní.getMonth(), nyní.getDate()); - let diff = now - today; // ms difference - return Math.round(diff / 1000); // make seconds + let rozdíl = nyní - dnešek; // rozdíl v milisekundách + return Math.round(rozdíl / 1000); // vytvoříme sekundy } -alert( getSecondsToday() ); +alert( vraťDnešníSekundy() ); ``` -An alternative solution would be to get hours/minutes/seconds and convert them to seconds: +Alternativním řešením by bylo získat hodiny, minuty a sekundy a převést je na sekundy: ```js run -function getSecondsToday() { +function vraťDnešníSekundy() { let d = new Date(); return d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds(); } -alert( getSecondsToday() ); +alert( vraťDnešníSekundy() ); ``` diff --git a/1-js/05-data-types/11-date/6-get-seconds-today/task.md b/1-js/05-data-types/11-date/6-get-seconds-today/task.md index 456790928..fcdcfb573 100644 --- a/1-js/05-data-types/11-date/6-get-seconds-today/task.md +++ b/1-js/05-data-types/11-date/6-get-seconds-today/task.md @@ -2,14 +2,14 @@ importance: 5 --- -# How many seconds have passed today? +# Kolik sekund už dnes uplynulo? -Write a function `getSecondsToday()` that returns the number of seconds from the beginning of today. +Napište funkci `vraťDnešníSekundy()`, která vrátí počet sekund, které uplynuly od začátku dnešního dne. -For instance, if now were `10:00 am`, and there was no daylight savings shift, then: +Například jestliže je právě `22:00` a dnes se neměnil letní čas na zimní nebo naopak, pak: ```js -getSecondsToday() == 36000 // (3600 * 10) +vraťDnešníSekundy() == 36000 // (3600 * 10) ``` -The function should work in any day. That is, it should not have a hard-coded value of "today". +Funkce by měla fungovat v kterýkoli den. To znamená, že by neměla mít napevno zakódovanou hodnotu „dneška“. diff --git a/1-js/05-data-types/11-date/7-get-seconds-to-tomorrow/solution.md b/1-js/05-data-types/11-date/7-get-seconds-to-tomorrow/solution.md index c337d1199..b61749308 100644 --- a/1-js/05-data-types/11-date/7-get-seconds-to-tomorrow/solution.md +++ b/1-js/05-data-types/11-date/7-get-seconds-to-tomorrow/solution.md @@ -1,32 +1,36 @@ -To get the number of milliseconds till tomorrow, we can from "tomorrow 00:00:00" substract the current date. +Abychom získali počet milisekund zbývajících do zítřka, můžeme odečíst aktuální datum od „zítřka 00:00:00“. -First, we generate that "tomorrow", and then do it: +Nejprve tento „zítřek“ vygenerujeme a pak to provedeme: ```js run -function getSecondsToTomorrow() { - let now = new Date(); +function vraťSekundyDoZítřka() { + let nyní = new Date(); - // tomorrow date - let tomorrow = new Date(now.getFullYear(), now.getMonth(), *!*now.getDate()+1*/!*); + // zítřejší datum + let zítřek = new Date(nyní.getFullYear(), nyní.getMonth(), *!*nyní.getDate()+1*/!*); - let diff = tomorrow - now; // difference in ms - return Math.round(diff / 1000); // convert to seconds + let rozdíl = zítřek - nyní; // rozdíl v ms + return Math.round(rozdíl / 1000); // převod na sekundy } + +alert(vraťSekundyDoZítřka()); ``` -Alternative solution: +Alternativní řešení: ```js run -function getSecondsToTomorrow() { - let now = new Date(); - let hour = now.getHours(); - let minutes = now.getMinutes(); - let seconds = now.getSeconds(); - let totalSecondsToday = (hour * 60 + minutes) * 60 + seconds; - let totalSecondsInADay = 86400; - - return totalSecondsInADay - totalSecondsToday; +function vraťSekundyDoZítřka() { + let nyní = new Date(); + let hodiny = nyní.getHours(); + let minuty = nyní.getMinutes(); + let sekundy = nyní.getSeconds(); + let celkemSekundDnes = (hodiny * 60 + minuty) * 60 + sekundy; + let celkemSekundZaDen = 86400; + + return celkemSekundZaDen - celkemSekundDnes; } + +alert(vraťSekundyDoZítřka()); ``` -Please note that many countries have Daylight Savings Time (DST), so there may be days with 23 or 25 hours. We may want to treat such days separately. +Prosíme všimněte si, že mnoho zemí používá letní čas, takže mohou existovat dny, které mají 23 nebo 25 hodin. S takovými dny můžeme chtít zacházet odlišně. diff --git a/1-js/05-data-types/11-date/7-get-seconds-to-tomorrow/task.md b/1-js/05-data-types/11-date/7-get-seconds-to-tomorrow/task.md index e05903026..9e3977ca8 100644 --- a/1-js/05-data-types/11-date/7-get-seconds-to-tomorrow/task.md +++ b/1-js/05-data-types/11-date/7-get-seconds-to-tomorrow/task.md @@ -2,14 +2,14 @@ importance: 5 --- -# How many seconds till tomorrow? +# Kolik sekund zbývá do zítřka? -Create a function `getSecondsToTomorrow()` that returns the number of seconds till tomorrow. +Vytvořte funkci `vraťSekundyDoZítřka()`, která vrátí počet sekund, které zbývají do zítřka. -For instance, if now is `23:00`, then: +Například jestliže právě je `23:00`, pak: ```js -getSecondsToTomorrow() == 3600 +vraťSekundyDoZítřka() == 3600 ``` -P.S. The function should work at any day, the "today" is not hardcoded. +P.S. Funkce by měla fungovat v kterémkoli dni, „dnešek“ v ní nemá být napevno zakódován. diff --git a/1-js/05-data-types/11-date/8-format-date-relative/_js.view/solution.js b/1-js/05-data-types/11-date/8-format-date-relative/_js.view/solution.js index 4695354a5..aed28507b 100644 --- a/1-js/05-data-types/11-date/8-format-date-relative/_js.view/solution.js +++ b/1-js/05-data-types/11-date/8-format-date-relative/_js.view/solution.js @@ -1,33 +1,34 @@ -function formatDate(date) { - let diff = new Date() - date; // the difference in milliseconds +function formátujDatum(datum) { + let rozdíl = new Date() - datum; // rozdíl v milisekundách - if (diff < 1000) { // less than 1 second - return 'right now'; + if (rozdíl < 1000) { // méně než 1 sekunda + return 'právě teď'; } - let sec = Math.floor(diff / 1000); // convert diff to seconds + let sec = Math.floor(rozdíl / 1000); // převedeme rozdíl na sekundy if (sec < 60) { - return sec + ' sec. ago'; + return 'před ' + sec + ' s'; } - let min = Math.floor(diff / 60000); // convert diff to minutes + let min = Math.floor(rozdíl / 60000); // převedeme rozdíl na minuty if (min < 60) { - return min + ' min. ago'; + return 'před ' + min + ' min.'; } - // format the date - // add leading zeroes to single-digit day/month/hours/minutes - let d = date; + // naformátujeme datum + // před jednociferný den/měsíc/hodiny/minuty přidáme nulu + let d = datum; d = [ '0' + d.getDate(), '0' + (d.getMonth() + 1), '' + d.getFullYear(), '0' + d.getHours(), '0' + d.getMinutes() - ].map(component => component.slice(-2)); // take last 2 digits of every component + ].map(složka => složka.slice(-2)); // z každé složky vezmeme poslední 2 číslice - // join the components into date + // spojíme složky do data return d.slice(0, 3).join('.') + ' ' + d.slice(3).join(':'); } + diff --git a/1-js/05-data-types/11-date/8-format-date-relative/_js.view/test.js b/1-js/05-data-types/11-date/8-format-date-relative/_js.view/test.js index 9b4cb2f58..3f49dfb8d 100644 --- a/1-js/05-data-types/11-date/8-format-date-relative/_js.view/test.js +++ b/1-js/05-data-types/11-date/8-format-date-relative/_js.view/test.js @@ -1,18 +1,18 @@ -describe("formatDate", function() { - it("shows 1ms ago as \"right now\"", function() { - assert.equal(formatDate(new Date(new Date - 1)), 'right now'); +describe("formátujDatum", function() { + it("zobrazí čas před 1ms jako \"právě teď\"", function() { + assert.equal(formátujDatum(new Date(new Date - 1)), 'právě teď'); }); - it('"30 seconds ago"', function() { - assert.equal(formatDate(new Date(new Date - 30 * 1000)), "30 sec. ago"); + it('"před 30 sekundami"', function() { + assert.equal(formátujDatum(new Date(new Date - 30 * 1000)), "před 30 s"); }); - it('"5 minutes ago"', function() { - assert.equal(formatDate(new Date(new Date - 5 * 60 * 1000)), "5 min. ago"); + it('"před 5 minutami"', function() { + assert.equal(formátujDatum(new Date(new Date - 5 * 60 * 1000)), "před 5 min."); }); - it("older dates as DD.MM.YY HH:mm", function() { - assert.equal(formatDate(new Date(2014, 2, 1, 11, 22, 33)), "01.03.14 11:22"); + it("starší data jako DD.MM.YY HH:mm", function() { + assert.equal(formátujDatum(new Date(2014, 2, 1, 11, 22, 33)), "01.03.14 11:22"); }); }); diff --git a/1-js/05-data-types/11-date/8-format-date-relative/solution.md b/1-js/05-data-types/11-date/8-format-date-relative/solution.md index 372485685..46fa36471 100644 --- a/1-js/05-data-types/11-date/8-format-date-relative/solution.md +++ b/1-js/05-data-types/11-date/8-format-date-relative/solution.md @@ -1,78 +1,87 @@ -To get the time from `date` till now -- let's substract the dates. +Abychom získali čas, který uplynul od data `datum` do nynějška, odečteme data. ```js run demo -function formatDate(date) { - let diff = new Date() - date; // the difference in milliseconds +function formátujDatum(datum) { + let rozdíl = new Date() - datum; // rozdíl v milisekundách - if (diff < 1000) { // less than 1 second - return 'right now'; + if (rozdíl < 1000) { // méně než 1 sekunda + return 'právě teď'; } - let sec = Math.floor(diff / 1000); // convert diff to seconds + let sec = Math.floor(rozdíl / 1000); // převedeme rozdíl na sekundy if (sec < 60) { - return sec + ' sec. ago'; + return 'před ' + sec + ' s'; } - let min = Math.floor(diff / 60000); // convert diff to minutes + let min = Math.floor(rozdíl / 60000); // převedeme rozdíl na minuty if (min < 60) { - return min + ' min. ago'; + return 'před ' + min + ' min.'; } - // format the date - // add leading zeroes to single-digit day/month/hours/minutes - let d = date; + // naformátujeme datum + // před jednociferný den/měsíc/hodiny/minuty přidáme nulu + let d = datum; d = [ '0' + d.getDate(), '0' + (d.getMonth() + 1), '' + d.getFullYear(), '0' + d.getHours(), '0' + d.getMinutes() - ].map(component => component.slice(-2)); // take last 2 digits of every component + ].map(složka => složka.slice(-2)); // z každé složky vezmeme poslední 2 číslice - // join the components into date + // spojíme složky do data return d.slice(0, 3).join('.') + ' ' + d.slice(3).join(':'); } -alert( formatDate(new Date(new Date - 1)) ); // "right now" +alert( formátujDatum(new Date(new Date - 1)) ); // "právě teď" -alert( formatDate(new Date(new Date - 30 * 1000)) ); // "30 sec. ago" +alert( formátujDatum(new Date(new Date - 30 * 1000)) ); // "před 30 s" -alert( formatDate(new Date(new Date - 5 * 60 * 1000)) ); // "5 min. ago" +alert( formátujDatum(new Date(new Date - 5 * 60 * 1000)) ); // "před 5 min." -// yesterday's date like 31.12.2016 20:00 -alert( formatDate(new Date(new Date - 86400 * 1000)) ); +// včerejší datum ve formátu 31.12.2016 20:00 +alert( formátujDatum(new Date(new Date - 86400 * 1000)) ); ``` -Alternative solution: +Alternativní řešení: ```js run -function formatDate(date) { - let dayOfMonth = date.getDate(); - let month = date.getMonth() + 1; - let year = date.getFullYear(); - let hour = date.getHours(); - let minutes = date.getMinutes(); - let diffMs = new Date() - date; - let diffSec = Math.round(diffMs / 1000); - let diffMin = diffSec / 60; - let diffHour = diffMin / 60; - - // formatting - year = year.toString().slice(-2); - month = month < 10 ? '0' + month : month; - dayOfMonth = dayOfMonth < 10 ? '0' + dayOfMonth : dayOfMonth; - hour = hour < 10 ? '0' + hour : hour; - minutes = minutes < 10 ? '0' + minutes : minutes; - - if (diffSec < 1) { - return 'right now'; - } else if (diffMin < 1) { - return `${diffSec} sec. ago` - } else if (diffHour < 1) { - return `${diffMin} min. ago` +function formátujDatum(datum) { + let denVMěsíci = datum.getDate(); + let měsíc = datum.getMonth() + 1; + let rok = datum.getFullYear(); + let hodina = datum.getHours(); + let minuta = datum.getMinutes(); + let rozdílMs = new Date() - datum; + let rozdílSec = Math.round(rozdílMs / 1000); + let rozdílMin = rozdílSec / 60; + let rozdílHod = rozdílMin / 60; + + // formátování + rok = rok.toString().slice(-2); + měsíc = měsíc < 10 ? '0' + měsíc : měsíc; + denVMěsíci = denVMěsíci < 10 ? '0' + denVMěsíci : denVMěsíci; + hodina = hodina < 10 ? '0' + hodina : hodina; + minuta = minuta < 10 ? '0' + minuta : minuta; + + if (rozdílSec < 1) { + return 'právě teď'; + } else if (rozdílMin < 1) { + return `před ${rozdílSec} s` + } else if (rozdílHod < 1) { + return `před ${rozdílMin} min.` } else { - return `${dayOfMonth}.${month}.${year} ${hour}:${minutes}` + return `${denVMěsíci}.${měsíc}.${rok} ${hodina}:${minuta}` } } + +alert( formátujDatum(new Date(new Date - 1)) ); // "právě teď" + +alert( formátujDatum(new Date(new Date - 30 * 1000)) ); // "před 30 s" + +alert( formátujDatum(new Date(new Date - 5 * 60 * 1000)) ); // "před 5 min." + +// včerejší datum, např. 31.12.2016 20:00 +alert( formátujDatum(new Date(new Date - 86400 * 1000)) ); ``` diff --git a/1-js/05-data-types/11-date/8-format-date-relative/task.md b/1-js/05-data-types/11-date/8-format-date-relative/task.md index 9651b305f..2f733db53 100644 --- a/1-js/05-data-types/11-date/8-format-date-relative/task.md +++ b/1-js/05-data-types/11-date/8-format-date-relative/task.md @@ -2,24 +2,24 @@ importance: 4 --- -# Format the relative date +# Relativní formátování data -Write a function `formatDate(date)` that should format `date` as follows: +Napište funkci `formátujDatum(datum)`, která by měla formátovat `datum` následovně: -- If since `date` passed less than 1 second, then `"right now"`. -- Otherwise, if since `date` passed less than 1 minute, then `"n sec. ago"`. -- Otherwise, if less than an hour, then `"m min. ago"`. -- Otherwise, the full date in the format `"DD.MM.YY HH:mm"`. That is: `"day.month.year hours:minutes"`, all in 2-digit format, e.g. `31.12.16 10:00`. +- Jestliže od okamžiku `datum` uplynula méně než 1 sekunda, pak `"právě teď"`. +- Jinak jestliže od `datum` uplynula méně než 1 minuta, pak `"před n s"`. +- Jinak jestliže uplynula méně než hodina, pak `"před m min."`. +- Jinak úplné datum ve formátu `"DD.MM.RR HH:mm"`, tedy: `"den.měsíc.rok hodiny:minuty"`, vše v 2-číslicovém formátu, např. `31.12.16 10:00`. -For instance: +Příklad: ```js -alert( formatDate(new Date(new Date - 1)) ); // "right now" +alert( formátujDatum(new Date(new Date - 1)) ); // "právě teď" -alert( formatDate(new Date(new Date - 30 * 1000)) ); // "30 sec. ago" +alert( formátujDatum(new Date(new Date - 30 * 1000)) ); // "před 30 s" -alert( formatDate(new Date(new Date - 5 * 60 * 1000)) ); // "5 min. ago" +alert( formátujDatum(new Date(new Date - 5 * 60 * 1000)) ); // "před 5 min." -// yesterday's date like 31.12.16 20:00 -alert( formatDate(new Date(new Date - 86400 * 1000)) ); +// včerejší datum ve formátu 31.12.16 20:00 +alert( formátujDatum(new Date(new Date - 86400 * 1000)) ); ``` diff --git a/1-js/05-data-types/11-date/article.md b/1-js/05-data-types/11-date/article.md index 6958a3a97..66cabf211 100644 --- a/1-js/05-data-types/11-date/article.md +++ b/1-js/05-data-types/11-date/article.md @@ -1,433 +1,436 @@ -# Date and time +# Datum a čas -Let's meet a new built-in object: [Date](mdn:js/Date). It stores the date, time and provides methods for date/time management. +Seznámíme se s novým vestavěným objektem: [Date](mdn:js/Date). Tento objekt v sobě ukládá datum a čas a poskytuje metody pro práci s nimi. -For instance, we can use it to store creation/modification times, to measure time, or just to print out the current date. +Můžeme jej například použít k uložení času vytvoření nebo modifikace něčeho, k měření času nebo jen k vypsání dnešního data. -## Creation +## Vytvoření -To create a new `Date` object call `new Date()` with one of the following arguments: +Abychom vytvořili objekt `Date`, zavoláme `new Date()` s jedním z následujících argumentů: `new Date()` -: Without arguments -- create a `Date` object for the current date and time: +: Bez argumentů -- vytvoří se objekt `Date` pro aktuální datum a čas: ```js run - let now = new Date(); - alert( now ); // shows current date/time + let nyní = new Date(); + alert( nyní ); // zobrazí aktuální datum a čas ``` -`new Date(milliseconds)` -: Create a `Date` object with the time equal to number of milliseconds (1/1000 of a second) passed after the Jan 1st of 1970 UTC+0. +`new Date(milisekundy)` +: Vytvoří objekt `Date` s časem, který odpovídá počtu milisekund (1/1000 sekundy), které uplynuly od 1. ledna 1970 UTC+0. ```js run - // 0 means 01.01.1970 UTC+0 - let Jan01_1970 = new Date(0); - alert( Jan01_1970 ); + // 0 znamená 01.01.1970 UTC+0 + let leden01_1970 = new Date(0); + alert( leden01_1970 ); - // now add 24 hours, get 02.01.1970 UTC+0 - let Jan02_1970 = new Date(24 * 3600 * 1000); - alert( Jan02_1970 ); + // nyní přidáme 24 hodin a získáme 02.01.1970 UTC+0 + let leden02_1970 = new Date(24 * 3600 * 1000); + alert( leden02_1970 ); ``` - An integer number representing the number of milliseconds that has passed since the beginning of 1970 is called a *timestamp*. + Celé číslo, které představuje počet milisekund, které uplynuly od začátku roku 1970, se nazývá *časové razítko* nebo *časová značka* (anglicky *timestamp*). - It's a lightweight numeric representation of a date. We can always create a date from a timestamp using `new Date(timestamp)` and convert the existing `Date` object to a timestamp using the `date.getTime()` method (see below). + Je to číselná reprezentace data. Z časového razítka můžeme vždy vytvořit datum pomocí `new Date(časovéRazítko)` a existující objekt `Date` můžeme převést na časové razítko pomocí metody `datum.getTime()` (viz níže). - Dates before 01.01.1970 have negative timestamps, e.g.: + Data před 1. lednem 1970 mají záporná časová razítka, např.: ```js run - // 31 Dec 1969 - let Dec31_1969 = new Date(-24 * 3600 * 1000); - alert( Dec31_1969 ); + // 31. prosinec 1969 + let pros31_1969 = new Date(-24 * 3600 * 1000); + alert( pros31_1969 ); ``` -`new Date(datestring)` -: If there is a single argument, and it's a string, then it is parsed automatically. The algorithm is the same as `Date.parse` uses, we'll cover it later. +`new Date(datovýŘetězec)` +: Jestliže je uveden jediný argument a je to řetězec, bude z něj automaticky vytvořeno datum. Algoritmus je stejný, jaký používá `Date.parse`. Probereme ho později. ```js run - let date = new Date("2017-01-26"); - alert(date); - // The time is not set, so it's assumed to be midnight GMT and - // is adjusted according to the timezone the code is run in - // So the result could be + let datum= new Date("2017-01-26"); + alert(datum); + // Čas není nastaven, takže se předpokládá půlnoc GMT a + // přizpůsobí se časovému pásmu, ve kterém je kód spuštěn. + // Výsledek tedy může být: // Thu Jan 26 2017 11:00:00 GMT+1100 (Australian Eastern Daylight Time) - // or + // nebo: // Wed Jan 25 2017 16:00:00 GMT-0800 (Pacific Standard Time) + // V Česku zřejmě bude: + // Thu Jan 26 2017 01:00:00 GMT+1100 (Středoevropský standardní čas) - pozn. překl. ``` -`new Date(year, month, date, hours, minutes, seconds, ms)` -: Create the date with the given components in the local time zone. Only the first two arguments are obligatory. +`new Date(rok, měsíc, den, hodiny, minuty, sekundy, ms)` +: Vytvoří datum ze zadaných složek v místním časovém pásmu. Povinné jsou jen první dva argumenty. - - The `year` should have 4 digits. For compatibility, 2 digits are also accepted and considered `19xx`, e.g. `98` is the same as `1998` here, but always using 4 digits is strongly encouraged. - - The `month` count starts with `0` (Jan), up to `11` (Dec). - - The `date` parameter is actually the day of month, if absent then `1` is assumed. - - If `hours/minutes/seconds/ms` is absent, they are assumed to be equal `0`. + - Parametr `rok` by měl mít 4 číslice. Z důvodu kompatibility se přijímají i 2 číslice a považují se za `19xx`, např. `98` je zde totéž jako `1998`, ale důrazně se doporučuje používat vždy 4 číslice. + - Parametr `měsíc` může být od `0` (leden) do `11` (prosinec). + - Parametr `den` znamená den v měsíci. Není-li uveden, předpokládá se `1`. + - Nejsou-li uvedeny parametry `hodiny/minuty/sekundy/ms`, předpokládá se, že jsou `0`. - For instance: + Příklad: ```js - new Date(2011, 0, 1, 0, 0, 0, 0); // 1 Jan 2011, 00:00:00 - new Date(2011, 0, 1); // the same, hours etc are 0 by default + new Date(2011, 0, 1, 0, 0, 0, 0); // 1. leden 2011, 00:00:00 + new Date(2011, 0, 1); // totéž, hodiny atd. jsou standardně 0 ``` - The maximal precision is 1 ms (1/1000 sec): + Maximální přesnost je 1 ms (1/1000 s): ```js run - let date = new Date(2011, 0, 1, 2, 3, 4, 567); - alert( date ); // 1.01.2011, 02:03:04.567 + let datum = new Date(2011, 0, 1, 2, 3, 4, 567); + alert( datum ); // 1.01.2011, 02:03:04.567 ``` -## Access date components +## Přístup ke složkám data -There are methods to access the year, month and so on from the `Date` object: +Existují metody, kterými můžeme přistupovat k roku, měsíci a dalším složkám objektu `Date`: [getFullYear()](mdn:js/Date/getFullYear) -: Get the year (4 digits) +: Vrací rok (4-číslicový). [getMonth()](mdn:js/Date/getMonth) -: Get the month, **from 0 to 11**. +: Vrací měsíc **od 0 do 11**. [getDate()](mdn:js/Date/getDate) -: Get the day of month, from 1 to 31, the name of the method does look a little bit strange. +: Vrací den v měsíci od 1 do 31. Název metody skutečně vypadá trochu podivně. [getHours()](mdn:js/Date/getHours), [getMinutes()](mdn:js/Date/getMinutes), [getSeconds()](mdn:js/Date/getSeconds), [getMilliseconds()](mdn:js/Date/getMilliseconds) -: Get the corresponding time components. +: Vracejí odpovídající časové složky (`getHours()` vrací hodiny, `getMinutes()` minuty, `getSeconds()` sekundy a `getMilliseconds()` milisekundy -- pozn. překl.). -```warn header="Not `getYear()`, but `getFullYear()`" -Many JavaScript engines implement a non-standard method `getYear()`. This method is deprecated. It returns 2-digit year sometimes. Please never use it. There is `getFullYear()` for the year. +```warn header="Ne `getYear()`, ale `getFullYear()`" +Mnoho JavaScriptových motorů implementuje nestandardní metodu `getYear()`. Tato metoda je zastaralá. Někdy vrací 2-číslicový letopočet. Prosíme nepoužívejte ji. Ke zjištění roku je určena metoda `getFullYear()`. ``` -Additionally, we can get a day of week: +Navíc můžeme získat i den v týdnu: [getDay()](mdn:js/Date/getDay) -: Get the day of week, from `0` (Sunday) to `6` (Saturday). The first day is always Sunday, in some countries that's not so, but can't be changed. +: Vrací den v týdnu od `0` (neděle) do `6` (sobota). První den je vždy neděle. V některých zemích to tak není, ale nedá se to změnit. -**All the methods above return the components relative to the local time zone.** +**Všechny výše uvedené metody vracejí složky relativní k místnímu časovému pásmu.** -There are also their UTC-counterparts, that return day, month, year and so on for the time zone UTC+0: [getUTCFullYear()](mdn:js/Date/getUTCFullYear), [getUTCMonth()](mdn:js/Date/getUTCMonth), [getUTCDay()](mdn:js/Date/getUTCDay). Just insert the `"UTC"` right after `"get"`. +Existují také jejich UTC-protějšky, které vracejí den, měsíc atd. pro časové pásmo UTC+0: [getUTCFullYear()](mdn:js/Date/getUTCFullYear), [getUTCMonth()](mdn:js/Date/getUTCMonth), [getUTCDay()](mdn:js/Date/getUTCDay). Stačí vložit `"UTC"` rovnou za `"get"`. -If your local time zone is shifted relative to UTC, then the code below shows different hours: +Jestliže je vaše místní časové pásmo vzhledem k UTC posunuto, pak následující kód zobrazí různé hodiny: ```js run -// current date -let date = new Date(); +// nynější datum +let datum = new Date(); -// the hour in your current time zone -alert( date.getHours() ); +// hodina ve vašem nynějším časovém pásmu +alert( datum.getHours() ); -// the hour in UTC+0 time zone (London time without daylight savings) -alert( date.getUTCHours() ); +// hodina v časovém pásmu UTC+0 (londýnský zimní čas) +alert( datum.getUTCHours() ); ``` -Besides the given methods, there are two special ones that do not have a UTC-variant: +Kromě uvedených metod existují i dvě speciální, které nemají UTC-variantu: [getTime()](mdn:js/Date/getTime) -: Returns the timestamp for the date -- a number of milliseconds passed from the January 1st of 1970 UTC+0. +: Vrací časové razítko data -- počet milisekund, které uplynuly od 1. ledna 1970 UTC+0. [getTimezoneOffset()](mdn:js/Date/getTimezoneOffset) -: Returns the difference between UTC and the local time zone, in minutes: +: Vrací rozdíl mezi UTC a místním časovým pásmem v minutách: ```js run - // if you are in timezone UTC-1, outputs 60 - // if you are in timezone UTC+3, outputs -180 + // jestliže jste v časovém pásmu UTC-1, vypíše 60 + // jestliže jste v časovém pásmu UTC+3, vypíše -180 + // (v Česku vypíše v letním čase -120, v zimním -60 - pozn. překl.) alert( new Date().getTimezoneOffset() ); ``` -## Setting date components +## Nastavení složek data -The following methods allow to set date/time components: +Následující metody umožňují nastavit složky data a času: -- [`setFullYear(year, [month], [date])`](mdn:js/Date/setFullYear) -- [`setMonth(month, [date])`](mdn:js/Date/setMonth) -- [`setDate(date)`](mdn:js/Date/setDate) -- [`setHours(hour, [min], [sec], [ms])`](mdn:js/Date/setHours) -- [`setMinutes(min, [sec], [ms])`](mdn:js/Date/setMinutes) -- [`setSeconds(sec, [ms])`](mdn:js/Date/setSeconds) +- [`setFullYear(rok, [měsíc], [den])`](mdn:js/Date/setFullYear) +- [`setMonth(měsíc, [den])`](mdn:js/Date/setMonth) +- [`setDate(den)`](mdn:js/Date/setDate) +- [`setHours(hodina, [minuty], [sekundy], [ms])`](mdn:js/Date/setHours) +- [`setMinutes(minuty, [sekundy], [ms])`](mdn:js/Date/setMinutes) +- [`setSeconds(sekundy, [ms])`](mdn:js/Date/setSeconds) - [`setMilliseconds(ms)`](mdn:js/Date/setMilliseconds) -- [`setTime(milliseconds)`](mdn:js/Date/setTime) (sets the whole date by milliseconds since 01.01.1970 UTC) +- [`setTime(milisekundy)`](mdn:js/Date/setTime) (nastaví celé datum z milisekund uplynulých od 1. 1. 1970 UTC) -Every one of them except `setTime()` has a UTC-variant, for instance: `setUTCHours()`. +Každá z nich kromě `setTime()` má UTC-variantu, např. `setUTCHours()`. -As we can see, some methods can set multiple components at once, for example `setHours`. The components that are not mentioned are not modified. +Jak vidíme, některé metody umožňují nastavit více složek najednou, např. `setHours`. Složky, které nejsou uvedeny, nebudou změněny. -For instance: +Příklad: ```js run -let today = new Date(); +let dnes = new Date(); -today.setHours(0); -alert(today); // still today, but the hour is changed to 0 +dnes.setHours(0); +alert(dnes); // stále dnes, ale hodina se změní na 0 -today.setHours(0, 0, 0, 0); -alert(today); // still today, now 00:00:00 sharp. +dnes.setHours(0, 0, 0, 0); +alert(dnes); // stále dnes, nyní 00:00:00 ``` -## Autocorrection +## Automatická oprava -The *autocorrection* is a very handy feature of `Date` objects. We can set out-of-range values, and it will auto-adjust itself. +*Automatická oprava* je velmi šikovná vlastnost objektů `Date`. Můžeme nastavit hodnoty mimo rozsah a ty se automaticky přizpůsobí. -For instance: +Příklad: ```js run -let date = new Date(2013, 0, *!*32*/!*); // 32 Jan 2013 ?!? -alert(date); // ...is 1st Feb 2013! +let datum = new Date(2013, 0, *!*32*/!*); // 32. leden 2013 ?!? +alert(datum); // ...je 1. únor 2013! ``` -Out-of-range date components are distributed automatically. +Datové složky mimo povolený rozsah se automaticky přepočítají. -Let's say we need to increase the date "28 Feb 2016" by 2 days. It may be "2 Mar" or "1 Mar" in case of a leap-year. We don't need to think about it. Just add 2 days. The `Date` object will do the rest: +Řekněme, že potřebujeme zvýšit datum „28. únor 2016“ o 2 dny. Může to být „2. březen“ nebo v případě přestupného roku „1. březen“. Na to nemusíme myslet. Stačí přičíst 2 dny. O zbytek se postará objekt `Date`: ```js run -let date = new Date(2016, 1, 28); +let datum = new Date(2016, 1, 28); *!* -date.setDate(date.getDate() + 2); +datum.setDate(datum.getDate() + 2); */!* -alert( date ); // 1 Mar 2016 +alert( datum ); // 1. březen 2016 ``` -That feature is often used to get the date after the given period of time. For instance, let's get the date for "70 seconds after now": +Tato vlastnost se často používá k získání data, které nastane po uplynutí zadaného času. Například získejme datum, které bude za „70 sekund od nynějška“: ```js run -let date = new Date(); -date.setSeconds(date.getSeconds() + 70); +let datum = new Date(); +datum.setSeconds(datum.getSeconds() + 70); -alert( date ); // shows the correct date +alert( datum ); // zobrazí správné datum ``` -We can also set zero or even negative values. For example: +Můžeme nastavit i nulové nebo záporné hodnoty. Například: ```js run -let date = new Date(2016, 0, 2); // 2 Jan 2016 +let datum = new Date(2016, 0, 2); // 2. leden 2016 -date.setDate(1); // set day 1 of month -alert( date ); +datum.setDate(1); // nastavíme 1. den v měsíci +alert( datum ); -date.setDate(0); // min day is 1, so the last day of the previous month is assumed -alert( date ); // 31 Dec 2015 +datum.setDate(0); // minimální den je 1, takže se předpokládá poslední den předchozího měsíce +alert( datum ); // 31. prosinec 2015 ``` -## Date to number, date diff +## Konverze data na číslo, rozdíl dat -When a `Date` object is converted to number, it becomes the timestamp same as `date.getTime()`: +Když je objekt `Date` konvertován na číslo, převede se na časové razítko, stejné, jaké vrací metoda `datum.getTime()`: ```js run -let date = new Date(); -alert(+date); // the number of milliseconds, same as date.getTime() +let datum = new Date(); +alert(+datum); // počet milisekund, totéž jako datum.getTime() ``` -The important side effect: dates can be subtracted, the result is their difference in ms. +Důležitý vedlejší efekt: data lze od sebe odečítat, výsledkem je jejich rozdíl v milisekundách. -That can be used for time measurements: +To můžeme využít k měření času: ```js run -let start = new Date(); // start measuring time +let začátek = new Date(); // spustíme měření času -// do the job +// uděláme práci for (let i = 0; i < 100000; i++) { - let doSomething = i * i * i; + let dělejNěco = i * i * i; } -let end = new Date(); // end measuring time +let konec = new Date(); // zastavíme měření času -alert( `The loop took ${end - start} ms` ); +alert( `Cyklus trval ${konec - začátek} ms` ); ``` ## Date.now() -If we only want to measure time, we don't need the `Date` object. +Jestliže chceme jenom měřit čas, nepotřebujeme objekt `Date`. -There's a special method `Date.now()` that returns the current timestamp. +Existuje speciální metoda `Date.now()`, která vrací aktuální časové razítko. -It is semantically equivalent to `new Date().getTime()`, but it doesn't create an intermediate `Date` object. So it's faster and doesn't put pressure on garbage collection. +Je sémanticky ekvivalentní `new Date().getTime()`, ale nevytváří dočasný objekt `Date`. Je tedy rychlejší a nezatěžuje sběrač odpadků. -It is used mostly for convenience or when performance matters, like in games in JavaScript or other specialized applications. +Používá se většinou proto, že je pohodlnější, nebo tehdy, když záleží na výkonu, například v JavaScriptových hrách nebo jiných specializovaných aplikacích. -So this is probably better: +Tohle je tedy pravděpodobně lepší: ```js run *!* -let start = Date.now(); // milliseconds count from 1 Jan 1970 +let začátek = Date.now(); // počet milisekund od 1. ledna 1970 */!* -// do the job +// uděláme práci for (let i = 0; i < 100000; i++) { - let doSomething = i * i * i; + let dělejNěco = i * i * i; } *!* -let end = Date.now(); // done +let konec = Date.now(); // hotovo */!* -alert( `The loop took ${end - start} ms` ); // subtract numbers, not dates +alert( `Cyklus trval ${konec - začátek} ms` ); // odečítáme čísla, ne data ``` -## Benchmarking +## Benchmarky -If we want a reliable benchmark of CPU-hungry function, we should be careful. +Jestliže chceme spolehlivý benchmark funkce náročné na CPU, měli bychom být opatrní. -For instance, let's measure two functions that calculate the difference between two dates: which one is faster? +Například změřme dvě funkce, které počítají rozdíl mezi dvěma daty: která z nich je rychlejší? -Such performance measurements are often called "benchmarks". +Taková měření výkonu se často nazývají „benchmarky“. ```js -// we have date1 and date2, which function faster returns their difference in ms? -function diffSubtract(date1, date2) { - return date2 - date1; +// máme datum1 a datum2, která funkce vrátí rychleji jejich rozdíl v ms? +function rozdílOdečtením(datum1, datum2) { + return datum2 - datum1; } -// or -function diffGetTime(date1, date2) { - return date2.getTime() - date1.getTime(); +// nebo +function rozdílPomocíGetTime(datum1, datum2) { + return datum2.getTime() - datum1.getTime(); } ``` -These two do exactly the same thing, but one of them uses an explicit `date.getTime()` to get the date in ms, and the other one relies on a date-to-number transform. Their result is always the same. +Tyto dvě funkce dělají přesně totéž, ale jedna z nich používá explicitní `datum.getTime()`, aby získala datum v milisekundách, zatímco druhá se spoléhá na transformaci data na číslo. Jejich výsledek je vždy stejný. -So, which one is faster? +Která je tedy rychlejší? -The first idea may be to run them many times in a row and measure the time difference. For our case, functions are very simple, so we have to do it at least 100000 times. +Jako první můžeme dostat nápad, že je spustíme mnohokrát za sebou a změříme rozdíl časů. V našem případě jsou tyto funkce velmi jednoduché, takže to musíme udělat alespoň 100 000krát. -Let's measure: +Změřme to: ```js run -function diffSubtract(date1, date2) { - return date2 - date1; +function rozdílOdečtením(datum1, datum2) { + return datum2 - datum1; } -function diffGetTime(date1, date2) { - return date2.getTime() - date1.getTime(); +function rozdílPomocíGetTime(datum1, datum2) { + return datum2.getTime() - datum1.getTime(); } function bench(f) { - let date1 = new Date(0); - let date2 = new Date(); + let datum1 = new Date(0); + let datum2 = new Date(); - let start = Date.now(); - for (let i = 0; i < 100000; i++) f(date1, date2); - return Date.now() - start; + let začátek = Date.now(); + for (let i = 0; i < 100000; i++) f(datum1, datum2); + return Date.now() - začátek; } -alert( 'Time of diffSubtract: ' + bench(diffSubtract) + 'ms' ); -alert( 'Time of diffGetTime: ' + bench(diffGetTime) + 'ms' ); +alert( 'Čas funkce rozdílOdečtením: ' + bench(rozdílOdečtením) + ' ms' ); +alert( 'Čas funkce rozdílPomocíGetTime: ' + bench(rozdílPomocíGetTime) + ' ms' ); ``` -Wow! Using `getTime()` is so much faster! That's because there's no type conversion, it is much easier for engines to optimize. +Páni! Použití `getTime()` je mnohem rychlejší! Je to proto, že tam není žádná typová konverze, a proto je pro motory mnohem snadnější funkci optimalizovat. -Okay, we have something. But that's not a good benchmark yet. +Dobrá, něco tedy máme. To však ještě není dobrý benchmark. -Imagine that at the time of running `bench(diffSubtract)` CPU was doing something in parallel, and it was taking resources. And by the time of running `bench(diffGetTime)` that work has finished. +Představme si, že v době spuštění `bench(rozdílOdečtením)` CPU prováděl paralelně něco jiného a to mu ubíralo zdroje. A v době spuštění `bench(rozdílPomocíGetTime)` tahle práce skončila. -A pretty real scenario for a modern multi-process OS. +V moderních multiprocesních operačních systémech je to dosti reálný scénář. -As a result, the first benchmark will have less CPU resources than the second. That may lead to wrong results. +Výsledkem je, že první benchmark měl méně zdrojů CPU než druhý. To mohlo vést ke špatným výsledkům. -**For more reliable benchmarking, the whole pack of benchmarks should be rerun multiple times.** +**Pro spolehlivější benchmarkové testování bychom měli celý balíček benchmarků spustit několikrát za sebou.** -For example, like this: +Například takto: ```js run -function diffSubtract(date1, date2) { - return date2 - date1; +function rozdílOdečtením(datum1, datum2) { + return datum2 - datum1; } -function diffGetTime(date1, date2) { - return date2.getTime() - date1.getTime(); +function rozdílPomocíGetTime(datum1, datum2) { + return datum2.getTime() - datum1.getTime(); } function bench(f) { - let date1 = new Date(0); - let date2 = new Date(); + let datum1 = new Date(0); + let datum2 = new Date(); - let start = Date.now(); - for (let i = 0; i < 100000; i++) f(date1, date2); - return Date.now() - start; + let začátek = Date.now(); + for (let i = 0; i < 100000; i++) f(datum1, datum2); + return Date.now() - začátek; } -let time1 = 0; -let time2 = 0; +let čas1 = 0; +let čas2 = 0; *!* -// run bench(diffSubtract) and bench(diffGetTime) each 10 times alternating +// spustíme bench(rozdílOdečtením) a bench(rozdílPomocíGetTime) střídavě, každou 10krát for (let i = 0; i < 10; i++) { - time1 += bench(diffSubtract); - time2 += bench(diffGetTime); + čas1 += bench(rozdílOdečtením); + čas2 += bench(rozdílPomocíGetTime); } */!* -alert( 'Total time for diffSubtract: ' + time1 ); -alert( 'Total time for diffGetTime: ' + time2 ); +alert( 'Celkový čas funkce rozdílOdečtením: ' + čas1 ); +alert( 'Celkový čas funkce rozdílPomocíGetTime: ' + čas2 ); ``` -Modern JavaScript engines start applying advanced optimizations only to "hot code" that executes many times (no need to optimize rarely executed things). So, in the example above, first executions are not well-optimized. We may want to add a heat-up run: +Moderní JavaScriptové motory začínají aplikovat pokročilé optimalizace jen na „horký kód“, který se provádí mnohokrát (není třeba optimalizovat to, co se provádí jen vzácně). Ve výše uvedeném příkladu tedy první spuštění nejsou dobře optimalizovaná. Můžeme chtít přidat zahřívací kolo: ```js -// added for "heating up" prior to the main loop -bench(diffSubtract); -bench(diffGetTime); +// přidáno pro „zahřátí“ před hlavní smyčkou +bench(rozdílOdečtením); +bench(rozdílPomocíGetTime); -// now benchmark +// nyní benchmark for (let i = 0; i < 10; i++) { - time1 += bench(diffSubtract); - time2 += bench(diffGetTime); + čas1 += bench(rozdílOdečtením); + čas2 += bench(rozdílPomocíGetTime); } ``` -```warn header="Be careful doing microbenchmarking" -Modern JavaScript engines perform many optimizations. They may tweak results of "artificial tests" compared to "normal usage", especially when we benchmark something very small, such as how an operator works, or a built-in function. So if you seriously want to understand performance, then please study how the JavaScript engine works. And then you probably won't need microbenchmarks at all. +```warn header="Při mikrobenchmarkových testech buďte opatrní" +Moderní JavaScriptové motory provádějí množství optimalizací, které mohou vylepšit výsledky „umělých testů“ ve srovnání s „běžným použitím“, zvláště když provádíme benchmark něčeho velmi malého, např. práce operátoru nebo vestavěné funkce. Pokud tedy chcete skutečně porozumět výkonu, pak si prosíme prostudujte, jak funguje JavaScriptový motor. A pak už pravděpodobně nebudete mikrobenchmarky vůbec potřebovat. -The great pack of articles about V8 can be found at . +Výborný balík článků o V8 naleznete na . ``` -## Date.parse from a string +## Načítání data z řetězce -The method [Date.parse(str)](mdn:js/Date/parse) can read a date from a string. +Metoda [Date.parse(řetězec)](mdn:js/Date/parse) dokáže načíst datum z řetězce. -The string format should be: `YYYY-MM-DDTHH:mm:ss.sssZ`, where: +Řetězec by měl mít formát `RRRR-MM-DDTHH:mm:ss.sssZ`, kde: -- `YYYY-MM-DD` -- is the date: year-month-day. -- The character `"T"` is used as the delimiter. -- `HH:mm:ss.sss` -- is the time: hours, minutes, seconds and milliseconds. -- The optional `'Z'` part denotes the time zone in the format `+-hh:mm`. A single letter `Z` would mean UTC+0. +- `RRRR-MM-DD` -- je datum: rok-měsíc-den. +- Znak `"T"` se používá jako oddělovač. +- `HH:mm:ss.sss` -- je čas: hodiny, minuty, sekundy a milisekundy. +- Nepovinná část `'Z'` označuje časové pásmo ve formátu `+-hh:mm`. Samotné písmeno `Z` znamená UTC+0. -Shorter variants are also possible, like `YYYY-MM-DD` or `YYYY-MM` or even `YYYY`. +Jsou možné i kratší varianty, např. `RRRR-MM-DD` nebo `RRRR-MM` nebo jen `RRRR`. -The call to `Date.parse(str)` parses the string in the given format and returns the timestamp (number of milliseconds from 1 Jan 1970 UTC+0). If the format is invalid, returns `NaN`. +Volání `Date.parse(řetězec)` rozebere řetězec v uvedeném formátu a vrátí časové razítko (počet milisekund od 1. ledna 1970 UTC+0). Není-li formát správný, vrátí `NaN`. -For instance: +Příklad: ```js run let ms = Date.parse('2012-01-26T13:51:50.417-07:00'); -alert(ms); // 1327611110417 (timestamp) +alert(ms); // 1327611110417 (časové razítko) ``` -We can instantly create a `new Date` object from the timestamp: +Z tohoto časového razítka můžeme ihned vytvořit objekt pomocí `new Date`: ```js run -let date = new Date( Date.parse('2012-01-26T13:51:50.417-07:00') ); +let datum = new Date( Date.parse('2012-01-26T13:51:50.417-07:00') ); -alert(date); +alert(datum); ``` -## Summary +## Shrnutí -- Date and time in JavaScript are represented with the [Date](mdn:js/Date) object. We can't create "only date" or "only time": `Date` objects always carry both. -- Months are counted from zero (yes, January is a zero month). -- Days of week in `getDay()` are also counted from zero (that's Sunday). -- `Date` auto-corrects itself when out-of-range components are set. Good for adding/subtracting days/months/hours. -- Dates can be subtracted, giving their difference in milliseconds. That's because a `Date` becomes the timestamp when converted to a number. -- Use `Date.now()` to get the current timestamp fast. +- Datum a čas v JavaScriptu představuje objekt [Date](mdn:js/Date). Nemůžeme vytvořit „jenom datum“ nebo „jenom čas“: objekty `Date` obsahují vždy obojí. +- Měsíce se počítají od nuly (ano, leden je nultý měsíc). +- Dny v týdnu ve funkci `getDay()` se také počítají od nuly (to je neděle). +- `Date` se automaticky opravuje, když jsou nastaveny složky mimo správný rozsah. To je dobré pro přičítání/odečítání dnů/měsíců/hodin. +- Data lze od sebe odečítat, výsledkem je jejich rozdíl v milisekundách. To je proto, že `Date` se při konverzi na číslo převede na časové razítko. +- Časové razítko času, který je právě teď, rychle získáme pomocí `Date.now()`. -Note that unlike many other systems, timestamps in JavaScript are in milliseconds, not in seconds. +Všimněte si, že na rozdíl od mnoha jiných systémů se časová razítka v JavaScriptu počítají v milisekundách, ne v sekundách. -Sometimes we need more precise time measurements. JavaScript itself does not have a way to measure time in microseconds (1 millionth of a second), but most environments provide it. For instance, browser has [performance.now()](mdn:api/Performance/now) that gives the number of milliseconds from the start of page loading with microsecond precision (3 digits after the point): +Někdy potřebujeme přesnější měření času. Samotný JavaScript neobsahuje způsob, jak měřit čas v mikrosekundách (1 milióntina sekundy), ale většina prostředí jej poskytuje. Například prohlížeče mají metodu [performance.now()](mdn:api/Performance/now), která vrací počet milisekund od začátku načítání stránky s přesností na mikrosekundy (3 číslice za desetinnou čárkou): ```js run -alert(`Loading started ${performance.now()}ms ago`); -// Something like: "Loading started 34731.26000000001ms ago" -// .26 is microseconds (260 microseconds) -// more than 3 digits after the decimal point are precision errors, only the first 3 are correct +alert(`Načítání začalo před ${performance.now()}ms`); +// Něco jako: "Načítání začalo před 34731.26000000001ms" +// .26 jsou mikrosekundy (260 mikrosekund) +// více než 3 číslice za desetinnou čárkou jsou chyba přesnosti, jedině první 3 jsou správné ``` -Node.js has `microtime` module and other ways. Technically, almost any device and environment allows to get more precision, it's just not in `Date`. +Node.js má modul `microtime` a jiné způsoby. Technicky téměř každé zařízení a každé prostředí umožňuje získat lepší přesnost, jenom ne pomocí `Date`. \ No newline at end of file diff --git a/1-js/05-data-types/12-json/1-serialize-object/solution.md b/1-js/05-data-types/12-json/1-serialize-object/solution.md index db1bcaa81..98bf30eb4 100644 --- a/1-js/05-data-types/12-json/1-serialize-object/solution.md +++ b/1-js/05-data-types/12-json/1-serialize-object/solution.md @@ -1,13 +1,13 @@ ```js -let user = { - name: "John Smith", - age: 35 +let uživatel = { + jméno: "Jan Novák", + věk: 35 }; *!* -let user2 = JSON.parse(JSON.stringify(user)); +let uživatel2 = JSON.parse(JSON.stringify(uživatel)); */!* ``` diff --git a/1-js/05-data-types/12-json/1-serialize-object/task.md b/1-js/05-data-types/12-json/1-serialize-object/task.md index 53343e4c3..9109e84da 100644 --- a/1-js/05-data-types/12-json/1-serialize-object/task.md +++ b/1-js/05-data-types/12-json/1-serialize-object/task.md @@ -2,13 +2,13 @@ importance: 5 --- -# Turn the object into JSON and back +# Převeďte objekt do JSONu a zpět -Turn the `user` into JSON and then read it back into another variable. +Převeďte objekt `uživatel` do JSONu a pak jej načtěte zpět do jiné proměnné. ```js -let user = { - name: "John Smith", - age: 35 +let uživatel = { + jméno: "Jan Novák", + věk: 35 }; ``` diff --git a/1-js/05-data-types/12-json/2-serialize-event-circular/solution.md b/1-js/05-data-types/12-json/2-serialize-event-circular/solution.md index 7a3a533b0..2509e8d57 100644 --- a/1-js/05-data-types/12-json/2-serialize-event-circular/solution.md +++ b/1-js/05-data-types/12-json/2-serialize-event-circular/solution.md @@ -1,30 +1,30 @@ ```js run -let room = { - number: 23 +let místnost = { + číslo: 23 }; -let meetup = { - title: "Conference", - occupiedBy: [{name: "John"}, {name: "Alice"}], - place: room +let mítink = { + titul: "Konference", + obsazenoČím: [{jméno: "Jan"}, {jméno: "Alice"}], + místo: místnost }; -room.occupiedBy = meetup; -meetup.self = meetup; +místnost.obsazenoČím = mítink; +mítink.onSám = mítink; -alert( JSON.stringify(meetup, function replacer(key, value) { - return (key != "" && value == meetup) ? undefined : value; +alert( JSON.stringify(mítink, function nahrazení(klíč, hodnota) { + return (klíč != "" && hodnota == mítink) ? undefined : hodnota; })); /* { - "title":"Conference", - "occupiedBy":[{"name":"John"},{"name":"Alice"}], - "place":{"number":23} + "titul":"Konference", + "obsazenoČím":[{"jméno":"Jan"},{"jméno":"Alice"}], + "místo":{"číslo":23} } */ ``` -Here we also need to test `key==""` to exclude the first call where it is normal that `value` is `meetup`. +Zde musíme testovat i to, zda `klíč==""`, abychom vyloučili první volání, kde je v pořádku, že `hodnota` je `mítink`. diff --git a/1-js/05-data-types/12-json/2-serialize-event-circular/task.md b/1-js/05-data-types/12-json/2-serialize-event-circular/task.md index 3755a24aa..e49467d54 100644 --- a/1-js/05-data-types/12-json/2-serialize-event-circular/task.md +++ b/1-js/05-data-types/12-json/2-serialize-event-circular/task.md @@ -2,40 +2,40 @@ importance: 5 --- -# Exclude backreferences +# Vyřaďte zpětné odkazy -In simple cases of circular references, we can exclude an offending property from serialization by its name. +V jednoduchých případech kruhových odkazů můžeme závadnou vlastnost vyřadit ze serializace podle jejího názvu. -But sometimes we can't just use the name, as it may be used both in circular references and normal properties. So we can check the property by its value. +Někdy však nemůžeme použít jen název, protože stejný název může být použit jak v kruhových odkazech, tak v normálních vlastnostech. Můžeme tedy zkontrolovat vlastnost podle její hodnoty. -Write `replacer` function to stringify everything, but remove properties that reference `meetup`: +Napište funkci `nahrazení`, která zřetězí všechno, ale odstraní vlastnosti, které se odkazují na `mítink`: ```js run -let room = { - number: 23 +let místnost = { + číslo: 23 }; -let meetup = { - title: "Conference", - occupiedBy: [{name: "John"}, {name: "Alice"}], - place: room +let mítink = { + titul: "Konference", + obsazenoČím: [{jméno: "Jan"}, {jméno: "Alice"}], + místo: místnost }; *!* -// circular references -room.occupiedBy = meetup; -meetup.self = meetup; +// kruhové odkazy +místnost.obsazenoČím = mítink; +mítink.onSám = mítink; */!* -alert( JSON.stringify(meetup, function replacer(key, value) { - /* your code */ +alert( JSON.stringify(mítink, function nahrazení(klíč, hodnota) { + /* váš kód */ })); -/* result should be: +/* výsledek by měl být: { - "title":"Conference", - "occupiedBy":[{"name":"John"},{"name":"Alice"}], - "place":{"number":23} + "titul":"Konference", + "obsazenoČím":[{"jméno":"Jan"},{"jméno":"Alice"}], + "místo":{"číslo":23} } */ ``` diff --git a/1-js/05-data-types/12-json/article.md b/1-js/05-data-types/12-json/article.md index 133ffb353..891fcb050 100644 --- a/1-js/05-data-types/12-json/article.md +++ b/1-js/05-data-types/12-json/article.md @@ -1,98 +1,97 @@ -# JSON methods, toJSON +# Metody pro JSON, toJSON -Let's say we have a complex object, and we'd like to convert it into a string, to send it over a network, or just to output it for logging purposes. +Dejme tomu, že máme složitý objekt a rádi bychom jej konvertovali na řetězec, abychom jej poslali po síti nebo ho jen vypsali pro účely logování. -Naturally, such a string should include all important properties. +Samozřejmě by takový řetězec měl obsahovat všechny důležité vlastnosti. -We could implement the conversion like this: +Můžeme implementovat konverzi například takto: ```js run -let user = { - name: "John", - age: 30, +let uživatel = { + jméno: "Jan", + věk: 30, *!* toString() { - return `{name: "${this.name}", age: ${this.age}}`; + return `{jméno: "${this.jméno}", věk: ${this.věk}}`; } */!* }; -alert(user); // {name: "John", age: 30} +alert(uživatel); // {jméno: "Jan", věk: 30} ``` -...But in the process of development, new properties are added, old properties are renamed and removed. Updating such `toString` every time can become a pain. We could try to loop over properties in it, but what if the object is complex and has nested objects in properties? We'd need to implement their conversion as well. +...Během procesu vývoje se však přidávají nové vlastnosti, staré se přejmenovávají a odstraňují. Pokaždé měnit takový `toString` by mohlo být nepříjemné. Mohli bychom se pokusit vytvořit cyklus nad vlastnostmi, ale co když je objekt složitý a obsahuje ve vlastnostech vnořené objekty? Museli bychom implementovat i jejich konverzi. -Luckily, there's no need to write the code to handle all this. The task has been solved already. +Naštěstí kód, který by tohle všechno zvládl, není třeba psát. Tento úkol byl již vyřešen. ## JSON.stringify -The [JSON](https://en.wikipedia.org/wiki/JSON) (JavaScript Object Notation) is a general format to represent values and objects. It is described as in [RFC 4627](https://tools.ietf.org/html/rfc4627) standard. Initially it was made for JavaScript, but many other languages have libraries to handle it as well. So it's easy to use JSON for data exchange when the client uses JavaScript and the server is written on Ruby/PHP/Java/Whatever. +[JSON](https://cs.wikipedia.org/wiki/JSON) (JavaScript Object Notation -- JavaScriptová objektová notace) je obecný formát sloužící k reprezentaci hodnot a objektů. Je popsán ve standardu [RFC 4627](https://tools.ietf.org/html/rfc4627). Původně byl vytvořen pro JavaScript, ale knihovny pro práci s ním poskytuje i mnoho jiných jazyků. Je tedy snadné používat JSON pro výměnu dat, když klient používá JavaScript a server je napsán v Ruby, PHP, Javě nebo čemkoli jiném. -JavaScript provides methods: +JavaScript poskytuje metody: -- `JSON.stringify` to convert objects into JSON. -- `JSON.parse` to convert JSON back into an object. +- `JSON.stringify` pro konverzi objektů na JSON. +- `JSON.parse` pro konverzi JSONu zpět na objekty. -For instance, here we `JSON.stringify` a student: +Například zde zavoláme `JSON.stringify` na studenta: ```js run let student = { - name: 'John', - age: 30, - isAdmin: false, - courses: ['html', 'css', 'js'], - spouse: null + jméno: 'Jan', + věk: 30, + jeAdmin: false, + kurzy: ['html', 'css', 'js'], + choť: null }; *!* let json = JSON.stringify(student); */!* -alert(typeof json); // we've got a string! +alert(typeof json); // získali jsme řetězec! alert(json); *!* -/* JSON-encoded object: +/* objekt zakódovaný do JSON: { - "name": "John", - "age": 30, - "isAdmin": false, - "courses": ["html", "css", "js"], - "spouse": null + "jméno": "Jan", + "věk": 30, + "jeAdmin": false, + "kurzy": ["html", "css", "js"], + "choť": null } */ */!* ``` -The method `JSON.stringify(student)` takes the object and converts it into a string. +Metoda `JSON.stringify(student)` vezme objekt a konvertuje ho na řetězec. -The resulting `json` string is called a *JSON-encoded* or *serialized* or *stringified* or *marshalled* object. We are ready to send it over the wire or put into a plain data store. +Výsledný řetězec `json` se nazývá *JSONem zakódovaný*, *serializovaný*, *zřetězený* nebo *marshallovaný* objekt. Jsme připraveni poslat ho po drátě nebo umístit ho do úložiště planých dat. +Prosíme všimněte si, že objekt zakódovaný JSONem má několik důležitých rozdílů oproti objektovému literálu: -Please note that a JSON-encoded object has several important differences from the object literal: +- Řetězce jsou uzavřeny v dvojitých uvozovkách. JSON nezná jednoduché ani zpětné uvozovky. Z `'Jan'` se tedy stane `"Jan"`. +- Názvy vlastností objektů jsou rovněž v dvojitých uvozovkách. To je povinné. Z `věk:30` se tedy stane `"věk":30`. -- Strings use double quotes. No single quotes or backticks in JSON. So `'John'` becomes `"John"`. -- Object property names are double-quoted also. That's obligatory. So `age:30` becomes `"age":30`. +`JSON.stringify` lze aplikovat i na primitivy. -`JSON.stringify` can be applied to primitives as well. +JSON podporuje následující datové typy: -JSON supports following data types: - -- Objects `{ ... }` -- Arrays `[ ... ]` -- Primitives: - - strings, - - numbers, - - boolean values `true/false`, +- Objekty `{ ... }` +- Pole `[ ... ]` +- Primitivy: + - řetězce, + - čísla, + - booleovské hodnoty `true/false`, - `null`. -For instance: +Příklad: ```js run -// a number in JSON is just a number +// číslo v JSON je prostě číslo alert( JSON.stringify(1) ) // 1 -// a string in JSON is still a string, but double-quoted +// řetězec v JSON je stále řetězec, ale v uvozovkách alert( JSON.stringify('test') ) // "test" alert( JSON.stringify(true) ); // true @@ -100,431 +99,431 @@ alert( JSON.stringify(true) ); // true alert( JSON.stringify([1, 2, 3]) ); // [1,2,3] ``` -JSON is data-only language-independent specification, so some JavaScript-specific object properties are skipped by `JSON.stringify`. +JSON je jazykově nezávislá specifikace určená jen pro data, takže některé objektové vlastnosti specifické pro JavaScript `JSON.stringify` vynechává. -Namely: +Konkrétně: -- Function properties (methods). -- Symbolic keys and values. -- Properties that store `undefined`. +- Funkční vlastnosti (metody). +- Symbolické klíče a hodnoty. +- Vlastnosti, v nichž je uloženo `undefined`. ```js run -let user = { - sayHi() { // ignored - alert("Hello"); +let uživatel = { + řekniAhoj() { // ignoruje se + alert("Ahoj"); }, - [Symbol("id")]: 123, // ignored - something: undefined // ignored + [Symbol("id")]: 123, // ignoruje se + něco: undefined // ignoruje se }; -alert( JSON.stringify(user) ); // {} (empty object) +alert( JSON.stringify(uživatel) ); // {} (prázdný objekt) ``` -Usually that's fine. If that's not what we want, then soon we'll see how to customize the process. +Obvykle je to dobře. Pokud to chceme nějak jinak, brzy uvidíme, jak si tento proces můžeme přizpůsobit. -The great thing is that nested objects are supported and converted automatically. +Skvělé je, že vnořené objekty jsou podporovány a automaticky se konvertují. -For instance: +Příklad: ```js run -let meetup = { - title: "Conference", +let mítink = { + titul: "Konference", *!* - room: { - number: 23, - participants: ["john", "ann"] + místnost: { + číslo: 23, + účastníci: ["jan", "anna"] } */!* }; -alert( JSON.stringify(meetup) ); -/* The whole structure is stringified: +alert( JSON.stringify(mítink) ); +/* Celá struktura je zřetězena: { - "title":"Conference", - "room":{"number":23,"participants":["john","ann"]}, + "titul":"Konference", + "místnost":{"číslo":23,"účastníci":["jan","anna"]}, } */ ``` -The important limitation: there must be no circular references. +Důležité omezení: v objektu nesmějí být kruhové odkazy. -For instance: +Příklad: ```js run -let room = { - number: 23 +let místnost = { + číslo: 23 }; -let meetup = { - title: "Conference", - participants: ["john", "ann"] +let mítink = { + titul: "Konference", + účastníci: ["jan", "anna"] }; -meetup.place = room; // meetup references room -room.occupiedBy = meetup; // room references meetup +mítink.místo = místnost; // mítink se odkazuje na místnost +místnost.obsazenoČím = mítink; // místnost se odkazuje na mítink *!* -JSON.stringify(meetup); // Error: Converting circular structure to JSON +JSON.stringify(mítink); // Error: Converting circular structure to JSON */!* ``` -Here, the conversion fails, because of circular reference: `room.occupiedBy` references `meetup`, and `meetup.place` references `room`: +Zde konverze selže kvůli kruhovému odkazu: `místnost.obsazenoČím` se odkazuje na `mítink` a `mítink.místo` se odkazuje na `místnost`: ![](json-meetup.svg) -## Excluding and transforming: replacer +## Vyloučení a transformace: funkce nahrazení -The full syntax of `JSON.stringify` is: +Úplná syntaxe `JSON.stringify` je: ```js -let json = JSON.stringify(value[, replacer, space]) +let json = JSON.stringify(hodnota[, nahrazení, mezery]) ``` -value -: A value to encode. +hodnota +: Hodnota k zakódování. -replacer -: Array of properties to encode or a mapping function `function(key, value)`. +nahrazení +: Pole vlastností, které se mají zakódovat, nebo mapovací funkce `function(klíč, hodnota)`. -space -: Amount of space to use for formatting +mezery +: Počet mezer, které se použijí při formátování. -Most of the time, `JSON.stringify` is used with the first argument only. But if we need to fine-tune the replacement process, like to filter out circular references, we can use the second argument of `JSON.stringify`. +Většinou se `JSON.stringify` používá jen s prvním argumentem. Jestliže však potřebujeme proces nahrazení vyladit, například odfiltrovat kruhové odkazy, můžeme použít druhý argument funkce `JSON.stringify`. -If we pass an array of properties to it, only these properties will be encoded. +Předáme-li do něj pole vlastností, budou zakódovány pouze vlastnosti uvedené v tomto poli. -For instance: +Příklad: ```js run -let room = { - number: 23 +let místnost = { + číslo: 23 }; -let meetup = { - title: "Conference", - participants: [{name: "John"}, {name: "Alice"}], - place: room // meetup references room +let mítink = { + titul: "Konference", + účastníci: [{jméno: "Jan"}, {jméno: "Alice"}], + místo: místnost // mítink se odkazuje na místnost }; -room.occupiedBy = meetup; // room references meetup +místnost.obsazenoČím = mítink; // místnost se odkazuje na mítink -alert( JSON.stringify(meetup, *!*['title', 'participants']*/!*) ); -// {"title":"Conference","participants":[{},{}]} +alert( JSON.stringify(mítink, *!*['titul', 'účastníci']*/!*) ); +// {"titul":"Konference","účastníci":[{},{}]} ``` -Here we are probably too strict. The property list is applied to the whole object structure. So the objects in `participants` are empty, because `name` is not in the list. +Tady jsme asi příliš přísní. Seznam vlastností se použije na celou strukturu. Objekty v poli `účastníci` jsou tedy prázdné, protože `jméno` není na seznamu. -Let's include in the list every property except `room.occupiedBy` that would cause the circular reference: +Zahrňme na seznam všechny vlastnosti kromě `místnost.obsazenoČím`, která by způsobila kruhový odkaz: ```js run -let room = { - number: 23 +let místnost = { + číslo: 23 }; -let meetup = { - title: "Conference", - participants: [{name: "John"}, {name: "Alice"}], - place: room // meetup references room +let mítink = { + titul: "Konference", + účastníci: [{jméno: "Jan"}, {jméno: "Alice"}], + místo: místnost // mítink se odkazuje na místnost }; -room.occupiedBy = meetup; // room references meetup +místnost.obsazenoČím = mítink; // místnost se odkazuje na mítink -alert( JSON.stringify(meetup, *!*['title', 'participants', 'place', 'name', 'number']*/!*) ); +alert( JSON.stringify(mítink, *!*['titul', 'účastníci', 'místo', 'jméno', 'číslo']*/!*) ); /* { - "title":"Conference", - "participants":[{"name":"John"},{"name":"Alice"}], - "place":{"number":23} + "titul":"Konference", + "účastníci":[{"jméno":"Jan"},{"jméno":"Alice"}], + "místo":{"číslo":23} } */ ``` -Now everything except `occupiedBy` is serialized. But the list of properties is quite long. +Nyní je serializováno všechno kromě `obsazenoČím`. Seznam vlastností je však poměrně dlouhý. -Fortunately, we can use a function instead of an array as the `replacer`. +Naštěstí můžeme jako `nahrazení` místo pole použít funkci. -The function will be called for every `(key, value)` pair and should return the "replaced" value, which will be used instead of the original one. Or `undefined` if the value is to be skipped. +Tato funkce bude volána pro každou dvojici `(klíč, hodnota)` a měla by vracet „nahrazenou“ hodnotu, která bude použita místo původní, nebo `undefined`, jestliže hodnota má být přeskočena. -In our case, we can return `value` "as is" for everything except `occupiedBy`. To ignore `occupiedBy`, the code below returns `undefined`: +V našem případě můžeme vracet hodnotu `hodnota` tak, „jak je“, pro všechno kromě `obsazenoČím`. Abychom `obsazenoČím` ignorovali, následující kód vrátí `undefined`: ```js run -let room = { - number: 23 +let místnost = { + číslo: 23 }; -let meetup = { - title: "Conference", - participants: [{name: "John"}, {name: "Alice"}], - place: room // meetup references room +let mítink = { + titul: "Konference", + účastníci: [{jméno: "Jan"}, {jméno: "Alice"}], + místo: místnost // mítink se odkazuje na místnost }; -room.occupiedBy = meetup; // room references meetup +místnost.obsazenoČím = mítink; // místnost se odkazuje na mítink -alert( JSON.stringify(meetup, function replacer(key, value) { - alert(`${key}: ${value}`); - return (key == 'occupiedBy') ? undefined : value; +alert( JSON.stringify(mítink, function nahrazení(klíč, hodnota) { + alert(`${klíč}: ${hodnota}`); + return (klíč == 'obsazenoČím') ? undefined : hodnota; })); -/* key:value pairs that come to replacer: +/* dvojice klíč:hodnota, které vstoupily do nahrazení: : [object Object] -title: Conference -participants: [object Object],[object Object] +titul: Konference +účastníci: [object Object],[object Object] 0: [object Object] -name: John +jméno: Jan 1: [object Object] -name: Alice -place: [object Object] -number: 23 -occupiedBy: [object Object] +jméno: Alice +místo: [object Object] +číslo: 23 +obsazenoČím: [object Object] */ ``` -Please note that `replacer` function gets every key/value pair including nested objects and array items. It is applied recursively. The value of `this` inside `replacer` is the object that contains the current property. +Prosíme všimněte si, že funkce `nahrazení` obdrží každou dvojici klíč/hodnota včetně vnořených objektů a prvků pole. Aplikuje se rekurzívně. Hodnota `this` uvnitř funkce `nahrazení` je objekt, který obsahuje aktuální vlastnost. -The first call is special. It is made using a special "wrapper object": `{"": meetup}`. In other words, the first `(key, value)` pair has an empty key, and the value is the target object as a whole. That's why the first line is `":[object Object]"` in the example above. +První volání je speciální. Učiní se pomocí speciálního „obalového objektu“: `{"": mítink}`. Jinými slovy, první dvojice `(klíč, hodnota)` má prázdný klíč a hodnotou je celý cílový objekt. Z tohoto důvodu je první řádek ve výše uvedeném příkladu `":[object Object]"`. -The idea is to provide as much power for `replacer` as possible: it has a chance to analyze and replace/skip even the whole object if necessary. +Stojí za tím úmysl poskytnout funkci `nahrazení` co největší moc: má možnost analyzovat a nahradit či přeskočit i celý objekt, je-li to nutné. -## Formatting: space +## Formátování: mezery -The third argument of `JSON.stringify(value, replacer, space)` is the number of spaces to use for pretty formatting. +Třetí argument `JSON.stringify(hodnota, nahrazení, mezery)` je počet mezer, které se použijí pro pěkné formátování. -Previously, all stringified objects had no indents and extra spaces. That's fine if we want to send an object over a network. The `space` argument is used exclusively for a nice output. +Žádné objekty převedené na řetězce, které jsme doposud uvedli, neměly odsazení a mezery navíc. To je dobře, jestliže chceme poslat objekt po síti. Argument `mezery` se používá výhradně pro zkrášlení výstupu. -Here `space = 2` tells JavaScript to show nested objects on multiple lines, with indentation of 2 spaces inside an object: +Zde `mezery = 2` říká JavaScriptu, aby zobrazil vnořené objekty na více řádcích s odsazením 2 mezery uvnitř objektu: ```js run -let user = { - name: "John", - age: 25, - roles: { - isAdmin: false, - isEditor: true +let uživatel = { + jméno: "Jan", + věk: 25, + role: { + jeAdmin: false, + jeEditor: true } }; -alert(JSON.stringify(user, null, 2)); -/* two-space indents: +alert(JSON.stringify(uživatel, null, 2)); +/* dvoumezerová odsazení: { - "name": "John", - "age": 25, - "roles": { - "isAdmin": false, - "isEditor": true + "jméno": "Jan", + "věk": 25, + "role": { + "jeAdmin": false, + "jeEditor": true } } */ -/* for JSON.stringify(user, null, 4) the result would be more indented: +/* pro JSON.stringify(uživatel, null, 4) by výsledek byl více odsazený: { - "name": "John", - "age": 25, - "roles": { - "isAdmin": false, - "isEditor": true + "jméno": "Jan", + "věk": 25, + "role": { + "jeAdmin": false, + "jeEditor": true } } */ ``` -The third argument can also be a string. In this case, the string is used for indentation instead of a number of spaces. +Třetí argument může být i řetězec. V tom případě se pro odsazení místo stanoveného počtu mezer použije tento řetězec. -The `space` parameter is used solely for logging and nice-output purposes. +Parametr `mezery` se používá výhradně pro účely logování a pěkného výstupu. -## Custom "toJSON" +## Vlastní „toJSON“ -Like `toString` for string conversion, an object may provide method `toJSON` for to-JSON conversion. `JSON.stringify` automatically calls it if available. +Stejně jako `toString` pro konverzi na řetězec může objekt poskytovat i metodu `toJSON` pro konverzi na JSON. Pokud je k dispozici, `JSON.stringify` ji automaticky zavolá. -For instance: +Příklad: ```js run -let room = { - number: 23 +let místnost = { + číslo: 23 }; -let meetup = { - title: "Conference", - date: new Date(Date.UTC(2017, 0, 1)), - room +let mítink = { + titul: "Konference", + datum: new Date(Date.UTC(2017, 0, 1)), + místnost }; -alert( JSON.stringify(meetup) ); +alert( JSON.stringify(mítink) ); /* { - "title":"Conference", + "titul":"Konference", *!* - "date":"2017-01-01T00:00:00.000Z", // (1) + "datum":"2017-01-01T00:00:00.000Z", // (1) */!* - "room": {"number":23} // (2) + "místnost": {"číslo":23} // (2) } */ ``` -Here we can see that `date` `(1)` became a string. That's because all dates have a built-in `toJSON` method which returns such kind of string. +Zde vidíme, že `datum` `(1)` se stalo řetězcem. Je to tím, že všechna data mají vestavěnou metodu `toJSON`, která vrátí řetězec tohoto druhu. -Now let's add a custom `toJSON` for our object `room` `(2)`: +Nyní přidáme vlastní metodu `toJSON` do našeho objektu `místnost` `(2)`: ```js run -let room = { - number: 23, +let místnost = { + číslo: 23, *!* toJSON() { - return this.number; + return this.číslo; } */!* }; -let meetup = { - title: "Conference", - room +let mítink = { + titul: "Konference", + místnost }; *!* -alert( JSON.stringify(room) ); // 23 +alert( JSON.stringify(místnost) ); // 23 */!* -alert( JSON.stringify(meetup) ); +alert( JSON.stringify(mítink) ); /* { - "title":"Conference", + "titul":"Konference", *!* - "room": 23 + "místnost": 23 */!* } */ ``` -As we can see, `toJSON` is used both for the direct call `JSON.stringify(room)` and when `room` is nested in another encoded object. +Jak vidíme, `toJSON` se používá jak při přímém volání `JSON.stringify(místnost)`, tak tehdy, když je `místnost` vnořená v jiném kódovaném objektu. ## JSON.parse -To decode a JSON-string, we need another method named [JSON.parse](mdn:js/JSON/parse). +K dekódování řetězce v JSONu potřebujeme další metodu, která se nazývá [JSON.parse](mdn:js/JSON/parse). -The syntax: +Syntaxe: ```js -let value = JSON.parse(str[, reviver]); +let hodnota = JSON.parse(řetězec[, oživení]); ``` -str -: JSON-string to parse. +řetězec +: Řetězec v JSONu, který se má dekódovat. -reviver -: Optional function(key,value) that will be called for each `(key, value)` pair and can transform the value. +oživení +: Nepovinná funkce `function(klíč, hodnota)`, která bude volána pro každou dvojici `(klíč, hodnota)` a může hodnotu transformovat. -For instance: +Příklad: ```js run -// stringified array -let numbers = "[0, 1, 2, 3]"; +// zřetězené pole +let čísla = "[0, 1, 2, 3]"; -numbers = JSON.parse(numbers); +čísla = JSON.parse(čísla); -alert( numbers[1] ); // 1 +alert( čísla[1] ); // 1 ``` -Or for nested objects: +Nebo pro vnořené objekty: ```js run -let userData = '{ "name": "John", "age": 35, "isAdmin": false, "friends": [0,1,2,3] }'; +let dataUživatele = '{ "jméno": "Jan", "věk": 35, "jeAdmin": false, "přátelé": [0,1,2,3] }'; -let user = JSON.parse(userData); +let uživatel = JSON.parse(dataUživatele); -alert( user.friends[1] ); // 1 +alert( uživatel.přátelé[1] ); // 1 ``` -The JSON may be as complex as necessary, objects and arrays can include other objects and arrays. But they must obey the same JSON format. +JSON může být tak složitý, jak potřebujeme, objekty a pole mohou obsahovat jiné objekty a pole. Všechny však musejí dodržovat stejný formát JSON. -Here are typical mistakes in hand-written JSON (sometimes we have to write it for debugging purposes): +Toto jsou typické chyby v ručně psaném JSONu (někdy jej musíme napsat ručně pro účely ladění): ```js let json = `{ - *!*name*/!*: "John", // mistake: property name without quotes - "surname": *!*'Smith'*/!*, // mistake: single quotes in value (must be double) - *!*'isAdmin'*/!*: false // mistake: single quotes in key (must be double) - "birthday": *!*new Date(2000, 2, 3)*/!*, // mistake: no "new" is allowed, only bare values - "friends": [0,1,2,3] // here all fine + *!*jméno*/!*: "Jan", // chyba: název vlastnosti bez uvozovek + "příjmení": *!*'Novák'*/!*, // chyba: hodnota v jednoduchých uvozovkách (musí být ve dvojitých) + *!*'jeAdmin'*/!*: false // chyba: klíč v jednoduchých uvozovkách (musí být ve dvojitých) + "datumNarození": *!*new Date(2000, 2, 3)*/!*, // chyba: není povoleno "new", jen čisté hodnoty + "přátelé": [0,1,2,3] // zde je vše v pořádku }`; ``` -Besides, JSON does not support comments. Adding a comment to JSON makes it invalid. +Kromě toho JSON nepodporuje komentáře. Přidání komentáře do JSONu jej učiní neplatným. -There's another format named [JSON5](https://json5.org/), which allows unquoted keys, comments etc. But this is a standalone library, not in the specification of the language. +Existuje i jiný formát jménem [JSON5](https://json5.org/), který umožňuje klíče bez uvozovek, komentáře a podobně. To je však samostatná knihovna, která není obsažena ve specifikaci jazyka. -The regular JSON is that strict not because its developers are lazy, but to allow easy, reliable and very fast implementations of the parsing algorithm. +Standardní JSON je tak přísný ne proto, že by jeho vývojáři byli líní, ale proto, aby umožnil snadnou, spolehlivou a velmi rychlou implementaci načítacího algoritmu. -## Using reviver +## Použití oživení -Imagine, we got a stringified `meetup` object from the server. +Představme si, že jsme ze serveru získali zřetězený objekt `mítink`. -It looks like this: +Vypadá takto: ```js -// title: (meetup title), date: (meetup date) -let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}'; +// titul: (titul mítinku), datum: (datum mítinku) +let řetězec = '{"titul":"Konference","datum":"2017-11-30T12:00:00.000Z"}'; ``` -...And now we need to *deserialize* it, to turn back into JavaScript object. +...A nyní jej musíme *deserializovat*, aby se z něj znovu stal JavaScriptový objekt. -Let's do it by calling `JSON.parse`: +Učiníme to voláním `JSON.parse`: ```js run -let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}'; +let řetězec = '{"titul":"Konference","datum":"2017-11-30T12:00:00.000Z"}'; -let meetup = JSON.parse(str); +let mítink = JSON.parse(řetězec); *!* -alert( meetup.date.getDate() ); // Error! +alert( mítink.datum.getDate() ); // Chyba! */!* ``` -Whoops! An error! +Ouha! Chyba! -The value of `meetup.date` is a string, not a `Date` object. How could `JSON.parse` know that it should transform that string into a `Date`? +Hodnota `mítink.datum` je řetězec, ne objekt `Date`. Jak mohl `JSON.parse` vědět, že má tento řetězec transformovat do objektu `Date`? -Let's pass to `JSON.parse` the reviving function as the second argument, that returns all values "as is", but `date` will become a `Date`: +Jako druhý argument předáme do `JSON.parse` funkci oživení, která vrátí všechny hodnoty tak, „jak jsou“, ale `datum` změní na `Date`: ```js run -let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}'; +let řetězec = '{"titul":"Konference","datum":"2017-11-30T12:00:00.000Z"}'; *!* -let meetup = JSON.parse(str, function(key, value) { - if (key == 'date') return new Date(value); - return value; +let mítink = JSON.parse(řetězec, function(klíč, hodnota) { + if (klíč == 'datum') return new Date(hodnota); + return hodnota; }); */!* -alert( meetup.date.getDate() ); // now works! +alert( mítink.datum.getDate() ); // teď to funguje! ``` -By the way, that works for nested objects as well: +Mimochodem, funguje to stejně i pro vnořené objekty: ```js run -let schedule = `{ - "meetups": [ - {"title":"Conference","date":"2017-11-30T12:00:00.000Z"}, - {"title":"Birthday","date":"2017-04-18T12:00:00.000Z"} +let rozvrh = `{ + "seznamMítinků": [ + {"titul":"Konference","datum":"2017-11-30T12:00:00.000Z"}, + {"titul":"Narozeniny","datum":"2017-04-18T12:00:00.000Z"} ] }`; -schedule = JSON.parse(schedule, function(key, value) { - if (key == 'date') return new Date(value); - return value; +rozvrh = JSON.parse(rozvrh, function(klíč, hodnota) { + if (klíč == 'datum') return new Date(hodnota); + return hodnota; }); *!* -alert( schedule.meetups[1].date.getDate() ); // works! +alert( rozvrh.seznamMítinků[1].datum.getDate() ); // funguje to! */!* ``` -## Summary +## Shrnutí -- JSON is a data format that has its own independent standard and libraries for most programming languages. -- JSON supports plain objects, arrays, strings, numbers, booleans, and `null`. -- JavaScript provides methods [JSON.stringify](mdn:js/JSON/stringify) to serialize into JSON and [JSON.parse](mdn:js/JSON/parse) to read from JSON. -- Both methods support transformer functions for smart reading/writing. -- If an object has `toJSON`, then it is called by `JSON.stringify`. +- JSON je datový formát, který má svůj nezávislý standard a knihovny pro většinu programovacích jazyků. +- JSON podporuje plané objekty, pole, řetězce, čísla, booleany a `null`. +- JavaScript poskytuje metody [JSON.stringify](mdn:js/JSON/stringify) pro serializaci do JSONu a [JSON.parse](mdn:js/JSON/parse) pro načítání z JSONu. +- Obě metody podporují transformační funkce pro vylepšené načítání a zápis. +- Má-li objekt metodu `toJSON`, pak ji funkce `JSON.stringify` zavolá. \ No newline at end of file diff --git a/1-js/05-data-types/index.md b/1-js/05-data-types/index.md index 246e2bc91..43fef53d7 100644 --- a/1-js/05-data-types/index.md +++ b/1-js/05-data-types/index.md @@ -1,3 +1,3 @@ -# Data types +# Datové typy -More data structures and more in-depth study of the types. +Další datové struktury a další hloubkové studium typů. diff --git a/1-js/06-advanced-functions/01-recursion/01-sum-to/solution.md b/1-js/06-advanced-functions/01-recursion/01-sum-to/solution.md index 11667f940..04a91c9cf 100644 --- a/1-js/06-advanced-functions/01-recursion/01-sum-to/solution.md +++ b/1-js/06-advanced-functions/01-recursion/01-sum-to/solution.md @@ -1,40 +1,40 @@ -The solution using a loop: +Řešení pomocí cyklu: ```js run -function sumTo(n) { - let sum = 0; +function sečtiDo(n) { + let součet = 0; for (let i = 1; i <= n; i++) { - sum += i; + součet += i; } - return sum; + return součet; } -alert( sumTo(100) ); +alert( sečtiDo(100) ); ``` -The solution using recursion: +Řešení pomocí rekurze: ```js run -function sumTo(n) { +function sečtiDo(n) { if (n == 1) return 1; - return n + sumTo(n - 1); + return n + sečtiDo(n - 1); } -alert( sumTo(100) ); +alert( sečtiDo(100) ); ``` -The solution using the formula: `sumTo(n) = n*(n+1)/2`: +Řešení pomocí vzorce: `sečtiDo(n) = n*(n+1)/2`: ```js run -function sumTo(n) { +function sečtiDo(n) { return n * (n + 1) / 2; } -alert( sumTo(100) ); +alert( sečtiDo(100) ); ``` -P.S. Naturally, the formula is the fastest solution. It uses only 3 operations for any number `n`. The math helps! +P.S. Nejrychlejší řešení je pochopitelně pomocí vzorce. Pro jakékoli číslo `n` vykonává pouze 3 operace. Matematika pomáhá! -The loop variant is the second in terms of speed. In both the recursive and the loop variant we sum the same numbers. But the recursion involves nested calls and execution stack management. That also takes resources, so it's slower. +Druhá nejlepší co do rychlosti je varianta s cyklem. V rekurzívní i v cyklové variantě sčítáme stejná čísla, ale rekurze vyžaduje vnořená volání a správu prováděcího zásobníku. To vyžaduje další zdroje, takže je pomalejší. -P.P.S. Some engines support the "tail call" optimization: if a recursive call is the very last one in the function, with no other calculations performed, then the outer function will not need to resume the execution, so the engine doesn't need to remember its execution context. That removes the burden on memory. But if the JavaScript engine does not support tail call optimization (most of them don't), there will be an error: maximum stack size exceeded, because there's usually a limitation on the total stack size. +P.P.S. Některé motory podporují optimalizaci „koncového volání“: je-li rekurzívní volání ve funkci úplně poslední a žádné další výpočty se neprovádějí, pak se nemusí obnovovat provádění vnější funkce, takže si motor nemusí pamatovat její prováděcí kontext. Tím se sníží paměťová zátěž. Pokud však motor JavaScriptu nepodporuje optimalizaci koncového volání (a většina motorů ji nepodporuje), nastane chyba: bude překročena maximální velikost zásobníku, protože celková velikost zásobníku je obvykle omezena. diff --git a/1-js/06-advanced-functions/01-recursion/01-sum-to/task.md b/1-js/06-advanced-functions/01-recursion/01-sum-to/task.md index cabc13290..c39ba5588 100644 --- a/1-js/06-advanced-functions/01-recursion/01-sum-to/task.md +++ b/1-js/06-advanced-functions/01-recursion/01-sum-to/task.md @@ -2,35 +2,35 @@ importance: 5 --- -# Sum all numbers till the given one +# Sečtěte všechna čísla až do zadaného -Write a function `sumTo(n)` that calculates the sum of numbers `1 + 2 + ... + n`. +Napište funkci `sečtiDo(n)`, která vypočítá součet čísel `1 + 2 + ... + n`. -For instance: +Například: ```js no-beautify -sumTo(1) = 1 -sumTo(2) = 2 + 1 = 3 -sumTo(3) = 3 + 2 + 1 = 6 -sumTo(4) = 4 + 3 + 2 + 1 = 10 +sečtiDo(1) = 1 +sečtiDo(2) = 2 + 1 = 3 +sečtiDo(3) = 3 + 2 + 1 = 6 +sečtiDo(4) = 4 + 3 + 2 + 1 = 10 ... -sumTo(100) = 100 + 99 + ... + 2 + 1 = 5050 +sečtiDo(100) = 100 + 99 + ... + 2 + 1 = 5050 ``` -Make 3 solution variants: +Vytvořte 3 varianty řešení: -1. Using a for loop. -2. Using a recursion, cause `sumTo(n) = n + sumTo(n-1)` for `n > 1`. -3. Using the [arithmetic progression](https://en.wikipedia.org/wiki/Arithmetic_progression) formula. +1. Pomocí cyklu for. +2. Pomocí rekurze `sečtiDo(n) = n + sečtiDo(n-1)` pro `n > 1`. +3. Pomocí vzorce pro [aritmetickou posloupnost](https://cs.wikipedia.org/wiki/Aritmetická_posloupnost). -An example of the result: +Příklad výsledku: ```js -function sumTo(n) { /*... your code ... */ } +function sečtiDo(n) { /*... váš kód ... */ } -alert( sumTo(100) ); // 5050 +alert( sečtiDo(100) ); // 5050 ``` -P.S. Which solution variant is the fastest? The slowest? Why? +P.S. Která varianta řešení je nejrychlejší? A nejpomalejší? Proč? -P.P.S. Can we use recursion to count `sumTo(100000)`? +P.P.S. Můžeme použít rekurzi k výpočtu `sečtiDo(100000)`? diff --git a/1-js/06-advanced-functions/01-recursion/02-factorial/solution.md b/1-js/06-advanced-functions/01-recursion/02-factorial/solution.md index 09e511db5..e1e3e40e3 100644 --- a/1-js/06-advanced-functions/01-recursion/02-factorial/solution.md +++ b/1-js/06-advanced-functions/01-recursion/02-factorial/solution.md @@ -1,21 +1,21 @@ -By definition, a factorial `n!` can be written as `n * (n-1)!`. +Podle definice můžeme faktoriál `n!` zapsat jako `n * (n-1)!`. -In other words, the result of `factorial(n)` can be calculated as `n` multiplied by the result of `factorial(n-1)`. And the call for `n-1` can recursively descend lower, and lower, till `1`. +Jinými slovy, výsledek funkce `faktoriál(n)` můžeme vypočítat jako `n` vynásobené výsledkem volání `faktoriál(n-1)`. A volání pro `n-1` může rekurzívně klesat níž a níž až k `1`. ```js run -function factorial(n) { - return (n != 1) ? n * factorial(n - 1) : 1; +function faktoriál(n) { + return (n != 1) ? n * faktoriál(n - 1) : 1; } -alert( factorial(5) ); // 120 +alert( faktoriál(5) ); // 120 ``` -The basis of recursion is the value `1`. We can also make `0` the basis here, doesn't matter much, but gives one more recursive step: +Základem rekurze je hodnota `1`. Zde můžeme jako základ vzít také `0`, na tom příliš nezáleží, ale to nám dá jeden rekurzívní krok navíc: ```js run -function factorial(n) { - return n ? n * factorial(n - 1) : 1; +function faktoriál(n) { + return n ? n * faktoriál(n - 1) : 1; } -alert( factorial(5) ); // 120 +alert( faktoriál(5) ); // 120 ``` diff --git a/1-js/06-advanced-functions/01-recursion/02-factorial/task.md b/1-js/06-advanced-functions/01-recursion/02-factorial/task.md index d2aef2d90..47cf97520 100644 --- a/1-js/06-advanced-functions/01-recursion/02-factorial/task.md +++ b/1-js/06-advanced-functions/01-recursion/02-factorial/task.md @@ -2,17 +2,17 @@ importance: 4 --- -# Calculate factorial +# Výpočet faktoriálu -The [factorial](https://en.wikipedia.org/wiki/Factorial) of a natural number is a number multiplied by `"number minus one"`, then by `"number minus two"`, and so on till `1`. The factorial of `n` is denoted as `n!` +[Faktoriál](https://cs.wikipedia.org/wiki/Faktoriál) přirozeného čísla je toto číslo násobené `„sebou samým minus 1“`, pak `„sebou samým minus 2“` a tak dále, až do `1`. Faktoriál `n` se značí `n!`. -We can write a definition of factorial like this: +Můžeme napsat definici faktoriálu takto: ```js n! = n * (n - 1) * (n - 2) * ...*1 ``` -Values of factorials for different `n`: +Hodnoty faktoriálů pro různá `n`: ```js 1! = 1 @@ -22,10 +22,10 @@ Values of factorials for different `n`: 5! = 5 * 4 * 3 * 2 * 1 = 120 ``` -The task is to write a function `factorial(n)` that calculates `n!` using recursive calls. +Úkolem je napsat funkci `faktoriál(n)`, která vypočítá `n!` pomocí rekurzívních volání. ```js -alert( factorial(5) ); // 120 +alert( faktoriál(5) ); // 120 ``` -P.S. Hint: `n!` can be written as `n * (n-1)!` For instance: `3! = 3*2! = 3*2*1! = 6` +P.S. Rada: `n!` lze zapsat jako `n * (n-1)!`. Například: `3! = 3*2! = 3*2*1! = 6`. diff --git a/1-js/06-advanced-functions/01-recursion/03-fibonacci-numbers/solution.md b/1-js/06-advanced-functions/01-recursion/03-fibonacci-numbers/solution.md index 36524a45a..52e169c1d 100644 --- a/1-js/06-advanced-functions/01-recursion/03-fibonacci-numbers/solution.md +++ b/1-js/06-advanced-functions/01-recursion/03-fibonacci-numbers/solution.md @@ -1,6 +1,6 @@ -The first solution we could try here is the recursive one. +První řešení, o které se pokusíme, bude rekurzívní. -Fibonacci numbers are recursive by definition: +Fibonacciho čísla jsou podle definice rekurzívní: ```js run function fib(n) { @@ -9,14 +9,14 @@ function fib(n) { alert( fib(3) ); // 2 alert( fib(7) ); // 13 -// fib(77); // will be extremely slow! +// fib(77); // bude extrémně pomalé! ``` -...But for big values of `n` it's very slow. For instance, `fib(77)` may hang up the engine for some time eating all CPU resources. +...Ale pro velké hodnoty `n` to bude velmi pomalé. Například `fib(77)` může na nějaký čas zablokovat motor, protože spotřebuje všechny zdroje CPU. -That's because the function makes too many subcalls. The same values are re-evaluated again and again. +Je to proto, že funkce učiní příliš mnoho vnořených volání. Stejné hodnoty se budou počítat znovu a znovu. -For instance, let's see a piece of calculations for `fib(5)`: +Podívejme se například na část výpočtu `fib(5)`: ```js no-beautify ... @@ -25,68 +25,68 @@ fib(4) = fib(3) + fib(2) ... ``` -Here we can see that the value of `fib(3)` is needed for both `fib(5)` and `fib(4)`. So `fib(3)` will be called and evaluated two times completely independently. +Zde vidíme, že hodnota `fib(3)` je zapotřebí pro `fib(5)` i pro `fib(4)`. Takže `fib(3)` bude volána a vyhodnocena dvakrát zcela nezávisle na sobě. -Here's the full recursion tree: +Zde je úplný rekurzívní strom: -![fibonacci recursion tree](fibonacci-recursion-tree.svg) +![rekurzívní strom Fibonacciho čísel](fibonacci-recursion-tree.svg) -We can clearly notice that `fib(3)` is evaluated two times and `fib(2)` is evaluated three times. The total amount of computations grows much faster than `n`, making it enormous even for `n=77`. +Můžeme jasně vidět, že `fib(3)` se vypočítá dvakrát a `fib(2)` třikrát. Celkový počet výpočtů roste mnohem rychleji než `n`, takže už pro `n=77` bude obrovský. -We can optimize that by remembering already-evaluated values: if a value of say `fib(3)` is calculated once, then we can just reuse it in future computations. +Můžeme to optimalizovat tak, že si budeme pamatovat již vypočtené hodnoty: jestliže se např. hodnota `fib(3)` vypočítá jednou, budeme ji pak moci využít k dalším výpočtům. -Another variant would be to give up recursion and use a totally different loop-based algorithm. +Další variantou by bylo vzdát se rekurze a použít úplně jiný algoritmus založený na cyklu. -Instead of going from `n` down to lower values, we can make a loop that starts from `1` and `2`, then gets `fib(3)` as their sum, then `fib(4)` as the sum of two previous values, then `fib(5)` and goes up and up, till it gets to the needed value. On each step we only need to remember two previous values. +Místo abychom šli od `n` dolů k nižším hodnotám, můžeme vytvořit cyklus, který začne od `1` a `2`, pak vypočítá `fib(3)` jako jejich součet, pak `fib(4)` jako součet předchozích dvou hodnot, pak `fib(5)` a tak to jde výš a výš, až se dostaneme k požadované hodnotě. V každém kroku si musíme pamatovat jen dvě předchozí hodnoty. -Here are the steps of the new algorithm in details. +Zde jsou kroky nového algoritmu podrobně. -The start: +Začátek: ```js -// a = fib(1), b = fib(2), these values are by definition 1 +// a = fib(1), b = fib(2), tyto hodnoty jsou podle definice 1 let a = 1, b = 1; -// get c = fib(3) as their sum +// získáme c = fib(3) jako jejich součet let c = a + b; -/* we now have fib(1), fib(2), fib(3) +/* nyní máme fib(1), fib(2), fib(3) a b c 1, 1, 2 */ ``` -Now we want to get `fib(4) = fib(2) + fib(3)`. +Nyní chceme získat `fib(4) = fib(2) + fib(3)`. -Let's shift the variables: `a,b` will get `fib(2),fib(3)`, and `c` will get their sum: +Posuneme proměnné: `a,b` budou představovat `fib(2),fib(3)` a `c` bude jejich součet: ```js no-beautify -a = b; // now a = fib(2) -b = c; // now b = fib(3) +a = b; // nyní a = fib(2) +b = c; // nyní b = fib(3) c = a + b; // c = fib(4) -/* now we have the sequence: +/* nyní máme posloupnost: a b c 1, 1, 2, 3 */ ``` -The next step gives another sequence number: +Další krok nám dává další číslo v posloupnosti: ```js no-beautify -a = b; // now a = fib(3) -b = c; // now b = fib(4) +a = b; // nyní a = fib(3) +b = c; // nyní b = fib(4) c = a + b; // c = fib(5) -/* now the sequence is (one more number): +/* posloupnost nyní je (jedno další číslo): a b c 1, 1, 2, 3, 5 */ ``` -...And so on until we get the needed value. That's much faster than recursion and involves no duplicate computations. +...A tak dále, dokud nezískáme požadovanou hodnotu. Je to mnohem rychlejší než rekurze a neobsahuje žádné duplicitní výpočty. -The full code: +Úplný kód: ```js run function fib(n) { @@ -105,6 +105,6 @@ alert( fib(7) ); // 13 alert( fib(77) ); // 5527939700884757 ``` -The loop starts with `i=3`, because the first and the second sequence values are hard-coded into variables `a=1`, `b=1`. +Cyklus začíná od `i=3`, protože první a druhá hodnota posloupnosti jsou napevno zakódovány do proměnných `a=1`, `b=1`. -The approach is called [dynamic programming bottom-up](https://en.wikipedia.org/wiki/Dynamic_programming). +Tento přístup se nazývá [dynamické programování](https://cs.wikipedia.org/wiki/Dynamické_programování). diff --git a/1-js/06-advanced-functions/01-recursion/03-fibonacci-numbers/task.md b/1-js/06-advanced-functions/01-recursion/03-fibonacci-numbers/task.md index 3cdadd219..ffa3df1bb 100644 --- a/1-js/06-advanced-functions/01-recursion/03-fibonacci-numbers/task.md +++ b/1-js/06-advanced-functions/01-recursion/03-fibonacci-numbers/task.md @@ -2,24 +2,25 @@ importance: 5 --- -# Fibonacci numbers +# Fibonacciho čísla -The sequence of [Fibonacci numbers](https://en.wikipedia.org/wiki/Fibonacci_number) has the formula Fn = Fn-1 + Fn-2. In other words, the next number is a sum of the two preceding ones. +Posloupnost [Fibonacciho čísel](https://cs.wikipedia.org/wiki/Fibonacciho_posloupnost) je dána vzorcem Fn = Fn-1 + Fn-2. Jinými slovy, každé další číslo je součtem dvou předcházejících. -First two numbers are `1`, then `2(1+1)`, then `3(1+2)`, `5(2+3)` and so on: `1, 1, 2, 3, 5, 8, 13, 21...`. +První dvě čísla jsou `1`, pak `2(1+1)`, pak `3(1+2)`, `5(2+3)` a tak dále: `1, 1, 2, 3, 5, 8, 13, 21...`. -Fibonacci numbers are related to the [Golden ratio](https://en.wikipedia.org/wiki/Golden_ratio) and many natural phenomena around us. +Fibonacciho čísla mají vztah ke [zlatému řezu](https://cs.wikipedia.org/wiki/Zlatý_řez) a mnoha přírodním jevům okolo nás. -Write a function `fib(n)` that returns the `n-th` Fibonacci number. +Napište funkci `fib(n)`, která vrátí `n-té` Fibonacciho číslo. -An example of work: +Příklad funkčnosti: ```js -function fib(n) { /* your code */ } +function fib(n) { /* váš kód */ } alert(fib(3)); // 2 alert(fib(7)); // 13 alert(fib(77)); // 5527939700884757 ``` -P.S. The function should be fast. The call to `fib(77)` should take no more than a fraction of a second. +P.S. Tato funkce by měla být rychlá. Volání `fib(77)` by nemělo trvat déle než zlomek sekundy. + diff --git a/1-js/06-advanced-functions/01-recursion/04-output-single-linked-list/solution.md b/1-js/06-advanced-functions/01-recursion/04-output-single-linked-list/solution.md index cfcbffea5..1a022ea7a 100644 --- a/1-js/06-advanced-functions/01-recursion/04-output-single-linked-list/solution.md +++ b/1-js/06-advanced-functions/01-recursion/04-output-single-linked-list/solution.md @@ -1,88 +1,88 @@ -# Loop-based solution +# Řešení pomocí cyklu -The loop-based variant of the solution: +Varianta řešení pomocí cyklu: ```js run -let list = { - value: 1, - next: { - value: 2, - next: { - value: 3, - next: { - value: 4, - next: null +let seznam = { + hodnota: 1, + další: { + hodnota: 2, + další: { + hodnota: 3, + další: { + hodnota: 4, + další: null } } } }; -function printList(list) { - let tmp = list; +function vypišSeznam(seznam) { + let dočasná = seznam; - while (tmp) { - alert(tmp.value); - tmp = tmp.next; + while (dočasná) { + alert(dočasná.hodnota); + dočasná = dočasná.další; } } -printList(list); +vypišSeznam(seznam); ``` -Please note that we use a temporary variable `tmp` to walk over the list. Technically, we could use a function parameter `list` instead: +Prosíme všimněte si, že k procházení seznamem používáme dočasnou proměnnou `dočasná`. Technicky bychom místo ní mohli použít parametr funkce `seznam`: ```js -function printList(list) { +function vypišSeznam(seznam) { - while(*!*list*/!*) { - alert(list.value); - list = list.next; + while(*!*seznam*/!*) { + alert(seznam.hodnota); + seznam = seznam.další; } } ``` -...But that would be unwise. In the future we may need to extend a function, do something else with the list. If we change `list`, then we lose such ability. +...To by však nebylo moudré. V budoucnosti možná budeme potřebovat funkci rozšířit a provádět se seznamem i něco jiného. Pokud změníme `seznam`, o tuto možnost přijdeme. -Talking about good variable names, `list` here is the list itself. The first element of it. And it should remain like that. That's clear and reliable. +Když mluvíme o dobrých názvech proměnných, `seznam` zde je samotný seznam. Jeho první prvek. A tak by to mělo zůstat. Je to čisté a zodpovědné. -From the other side, the role of `tmp` is exclusively a list traversal, like `i` in the `for` loop. +Naproti tomu role proměnné `dočasná` je výhradně procházení seznamu, podobně jako u proměnné `i` v cyklu `for`. -# Recursive solution +# Rekurzívní řešení -The recursive variant of `printList(list)` follows a simple logic: to output a list we should output the current element `list`, then do the same for `list.next`: +Rekurzívní varianta `vypišSeznam(seznam)` sleduje jednoduchou logiku: pro vypsání seznamu bychom měli vypsat aktuální prvek `seznam`, pak učinit totéž pro `seznam.další`: ```js run -let list = { - value: 1, - next: { - value: 2, - next: { - value: 3, - next: { - value: 4, - next: null +let seznam = { + hodnota: 1, + další: { + hodnota: 2, + další: { + hodnota: 3, + další: { + hodnota: 4, + další: null } } } }; -function printList(list) { +function vypišSeznam(seznam) { - alert(list.value); // output the current item + alert(seznam.hodnota); // vypíše aktuální řádek - if (list.next) { - printList(list.next); // do the same for the rest of the list + if (seznam.další) { + vypišSeznam(seznam.další); // učiní totéž pro zbytek seznamu } } -printList(list); +vypišSeznam(seznam); ``` -Now what's better? +Které řešení je nyní lepší? -Technically, the loop is more effective. These two variants do the same, but the loop does not spend resources for nested function calls. +Technicky je cyklus efektivnější. Obě varianty dělají totéž, ale cyklus nespotřebovává zdroje pro vnořená volání funkce. -From the other side, the recursive variant is shorter and sometimes easier to understand. +Naproti tomu rekurzívní varianta je kratší a někdy je snadnější jí porozumět. diff --git a/1-js/06-advanced-functions/01-recursion/04-output-single-linked-list/task.md b/1-js/06-advanced-functions/01-recursion/04-output-single-linked-list/task.md index 1076b952a..49da26905 100644 --- a/1-js/06-advanced-functions/01-recursion/04-output-single-linked-list/task.md +++ b/1-js/06-advanced-functions/01-recursion/04-output-single-linked-list/task.md @@ -2,28 +2,28 @@ importance: 5 --- -# Output a single-linked list +# Vypište lineární spojový seznam -Let's say we have a single-linked list (as described in the chapter ): +Dejme tomu, že máme lineární spojový seznam (popsaný v kapitole ): ```js -let list = { - value: 1, - next: { - value: 2, - next: { - value: 3, - next: { - value: 4, - next: null +let seznam = { + hodnota: 1, + další: { + hodnota: 2, + další: { + hodnota: 3, + další: { + hodnota: 4, + další: null } } } }; ``` -Write a function `printList(list)` that outputs list items one-by-one. +Napište funkci `vypišSeznam(seznam)`, která vypíše prvky seznamu jeden po druhém. -Make two variants of the solution: using a loop and using recursion. +Vytvořte dvě varianty řešení: pomocí cyklu a pomocí rekurze. -What's better: with recursion or without it? +Která je lepší: s rekurzí nebo bez ní? diff --git a/1-js/06-advanced-functions/01-recursion/05-output-single-linked-list-reverse/solution.md b/1-js/06-advanced-functions/01-recursion/05-output-single-linked-list-reverse/solution.md index 0eb76ea1c..c8f42ebe6 100644 --- a/1-js/06-advanced-functions/01-recursion/05-output-single-linked-list-reverse/solution.md +++ b/1-js/06-advanced-functions/01-recursion/05-output-single-linked-list-reverse/solution.md @@ -1,74 +1,74 @@ -# Using a recursion +# Pomocí rekurze -The recursive logic is a little bit tricky here. +Logika rekurze je tady trochu ošidná. -We need to first output the rest of the list and *then* output the current one: +Nejprve potřebujeme vypsat zbytek seznamu a až *potom* vypíšeme aktuální prvek: ```js run -let list = { - value: 1, - next: { - value: 2, - next: { - value: 3, - next: { - value: 4, - next: null +let seznam = { + hodnota: 1, + další: { + hodnota: 2, + další: { + hodnota: 3, + další: { + hodnota: 4, + další: null } } } }; -function printReverseList(list) { +function vypišSeznamObráceně(seznam) { - if (list.next) { - printReverseList(list.next); + if (seznam.další) { + vypišSeznamObráceně(seznam.další); } - alert(list.value); + alert(seznam.hodnota); } -printReverseList(list); +vypišSeznamObráceně(seznam); ``` -# Using a loop +# Pomocí cyklu -The loop variant is also a little bit more complicated than the direct output. +Také cyklová varianta je trochu složitější než přímý výpis. -There is no way to get the last value in our `list`. We also can't "go back". +Není žádný způsob, jak získat poslední hodnotu našeho `seznamu`. Nemůžeme se ani „vracet“. -So what we can do is to first go through the items in the direct order and remember them in an array, and then output what we remembered in the reverse order: +To, co můžeme udělat jako první, je tedy projít všechny prvky v přímém pořadí, zapamatovat si je v poli a pak vypsat to, co jsme si zapamatovali, v obráceném pořadí: ```js run -let list = { - value: 1, - next: { - value: 2, - next: { - value: 3, - next: { - value: 4, - next: null +let seznam = { + hodnota: 1, + další: { + hodnota: 2, + další: { + hodnota: 3, + další: { + hodnota: 4, + další: null } } } }; -function printReverseList(list) { - let arr = []; - let tmp = list; +function vypišSeznamObráceně(seznam) { + let pole = []; + let dočasná = seznam; - while (tmp) { - arr.push(tmp.value); - tmp = tmp.next; + while (dočasná) { + pole.push(dočasná.hodnota); + dočasná = dočasná.další; } - for (let i = arr.length - 1; i >= 0; i--) { - alert( arr[i] ); + for (let i = pole.length - 1; i >= 0; i--) { + alert( pole[i] ); } } -printReverseList(list); +vypišSeznamObráceně(seznam); ``` -Please note that the recursive solution actually does exactly the same: it follows the list, remembers the items in the chain of nested calls (in the execution context stack), and then outputs them. +Prosíme všimněte si, že rekurzívní řešení dělá ve skutečnosti přesně totéž: prochází seznam, pamatuje si jeho prvky v řetězci vnořených volání (v zásobníku prováděcích kontextů) a pak je vypisuje. diff --git a/1-js/06-advanced-functions/01-recursion/05-output-single-linked-list-reverse/task.md b/1-js/06-advanced-functions/01-recursion/05-output-single-linked-list-reverse/task.md index 81b1f3e33..973d42bda 100644 --- a/1-js/06-advanced-functions/01-recursion/05-output-single-linked-list-reverse/task.md +++ b/1-js/06-advanced-functions/01-recursion/05-output-single-linked-list-reverse/task.md @@ -2,8 +2,8 @@ importance: 5 --- -# Output a single-linked list in the reverse order +# Vypište lineární spojový seznam v opačném pořadí -Output a single-linked list from the previous task in the reverse order. +Vypište lineární spojový seznam z předcházející úlohy v obráceném pořadí. -Make two solutions: using a loop and using a recursion. +Vytvořte dvě řešení: pomocí cyklu a pomocí rekurze. diff --git a/1-js/06-advanced-functions/01-recursion/article.md b/1-js/06-advanced-functions/01-recursion/article.md index 5ae894474..436d4078b 100644 --- a/1-js/06-advanced-functions/01-recursion/article.md +++ b/1-js/06-advanced-functions/01-recursion/article.md @@ -1,542 +1,542 @@ -# Recursion and stack +# Rekurze a zásobník -Let's return to functions and study them more in-depth. +Vraťme se k funkcím a prostudujme je hlouběji. -Our first topic will be *recursion*. +Naším prvním tématem bude *rekurze*. -If you are not new to programming, then it is probably familiar and you could skip this chapter. +Jestliže nejste programátorský nováček, pak to již pravděpodobně znáte a můžete tuto kapitolu přeskočit. -Recursion is a programming pattern that is useful in situations when a task can be naturally split into several tasks of the same kind, but simpler. Or when a task can be simplified into an easy action plus a simpler variant of the same task. Or, as we'll see soon, to deal with certain data structures. +Rekurze je programovací schéma, které je užitečné v situacích, kdy nějakou úlohu můžeme přirozeně rozdělit na několik úloh stejného druhu, ale jednodušších. Nebo když můžeme úlohu zjednodušit na nějakou lehkou akci plus jednodušší variantu téže úlohy. Nebo, jak brzy uvidíme, pro práci s určitými datovými strukturami. -When a function solves a task, in the process it can call many other functions. A partial case of this is when a function calls *itself*. That's called *recursion*. +Když funkce řeší úlohu, může při tomto procesu volat mnoho jiných funkcí. Zvláštním případem je, když funkce volá *sebe sama*. To se nazývá *rekurze*. -## Two ways of thinking +## Dva způsoby myšlení -For something simple to start with -- let's write a function `pow(x, n)` that raises `x` to a natural power of `n`. In other words, multiplies `x` by itself `n` times. +Začneme něčím jednoduchým -- napišme funkci `mocnina(x, n)`, která umocní `x` na přirozené číslo `n`. Jinými slovy, vynásobí `x` sebou samým `n`-krát. ```js -pow(2, 2) = 4 -pow(2, 3) = 8 -pow(2, 4) = 16 +mocnina(2, 2) = 4 +mocnina(2, 3) = 8 +mocnina(2, 4) = 16 ``` -There are two ways to implement it. +Existují dva způsoby, jak ji implementovat. -1. Iterative thinking: the `for` loop: +1. Iterativní myšlení: cyklus `for`: ```js run - function pow(x, n) { - let result = 1; + function mocnina(x, n) { + let výsledek = 1; - // multiply result by x n times in the loop + // vynásobíme výsledek číslem x v cyklu n-krát for (let i = 0; i < n; i++) { - result *= x; + výsledek *= x; } - return result; + return výsledek; } - alert( pow(2, 3) ); // 8 + alert( mocnina(2, 3) ); // 8 ``` -2. Recursive thinking: simplify the task and call self: +2. Rekurzívní myšlení: zjednodušit úlohu a volat sebe sama: ```js run - function pow(x, n) { + function mocnina(x, n) { if (n == 1) { return x; } else { - return x * pow(x, n - 1); + return x * mocnina(x, n - 1); } } - alert( pow(2, 3) ); // 8 + alert( mocnina(2, 3) ); // 8 ``` -Please note how the recursive variant is fundamentally different. +Prosíme všimněte si, jak je rekurzívní varianta diametrálně odlišná. -When `pow(x, n)` is called, the execution splits into two branches: +Když je volána `mocnina(x, n)`, její výkon se rozdělí do dvou větví: ```js if n==1 = x / -pow(x, n) = - \ - else = x * pow(x, n - 1) +mocnina(x, n) = + \ + else = x * mocnina(x, n - 1) ``` -1. If `n == 1`, then everything is trivial. It is called *the base* of recursion, because it immediately produces the obvious result: `pow(x, 1)` equals `x`. -2. Otherwise, we can represent `pow(x, n)` as `x * pow(x, n - 1)`. In maths, one would write xn = x * xn-1. This is called *a recursive step*: we transform the task into a simpler action (multiplication by `x`) and a simpler call of the same task (`pow` with lower `n`). Next steps simplify it further and further until `n` reaches `1`. +1. Je-li `n == 1`, pak je vše triviální. Tento případ se nazývá *základ* rekurze, jelikož okamžitě vydá zřejmý výsledek: `mocnina(x, 1)` se rovná `x`. +2. V opačném případě můžeme reprezentovat `mocnina(x, n)` jako `x * mocnina(x, n - 1)`. V matematice můžeme zapsat xn = x * xn-1. +Tento případ se nazývá *rekurzívní krok*: převedeme úlohu na jednodušší akci (násobení číslem `x`) a jednodušší volání stejné úlohy (`mocnina` s nižším `n`). Další kroky ji budou stále zjednodušovat, až nakonec `n` dosáhne `1`. -We can also say that `pow` *recursively calls itself* till `n == 1`. +Můžeme také říci, že funkce `mocnina` *rekurzívně volá sebe sama*, dokud není `n == 1`. -![recursive diagram of pow](recursion-pow.svg) +![rekurzívní diagram funkce mocnina](recursion-pow.svg) -For example, to calculate `pow(2, 4)` the recursive variant does these steps: +Například při výpočtu `mocnina(2, 4)` rekurzívní varianta provádí tyto kroky: -1. `pow(2, 4) = 2 * pow(2, 3)` -2. `pow(2, 3) = 2 * pow(2, 2)` -3. `pow(2, 2) = 2 * pow(2, 1)` -4. `pow(2, 1) = 2` +1. `mocnina(2, 4) = 2 * mocnina(2, 3)` +2. `mocnina(2, 3) = 2 * mocnina(2, 2)` +3. `mocnina(2, 2) = 2 * mocnina(2, 1)` +4. `mocnina(2, 1) = 2` -So, the recursion reduces a function call to a simpler one, and then -- to even more simpler, and so on, until the result becomes obvious. +Rekurze tedy zredukuje volání funkce na jednodušší, pak na ještě jednodušší a tak dále, dokud výsledek nebude zřejmý. -````smart header="Recursion is usually shorter" -A recursive solution is usually shorter than an iterative one. +````smart header="Rekurze je obvykle kratší" +Rekurzívní řešení bývá obvykle kratší než iterativní. -Here we can rewrite the same using the conditional operator `?` instead of `if` to make `pow(x, n)` more terse and still very readable: +Zde můžeme přepsat totéž pomocí podmíněného operátoru `?` místo příkazu `if`, aby byla `mocnina(x, n)` ještě stručnější, ale stále velmi čitelná: ```js run -function pow(x, n) { - return (n == 1) ? x : (x * pow(x, n - 1)); +function mocnina(x, n) { + return (n == 1) ? x : (x * mocnina(x, n - 1)); } ``` ```` -The maximal number of nested calls (including the first one) is called *recursion depth*. In our case, it will be exactly `n`. +Maximální počet vnořených volání (včetně prvního) se nazývá *hloubka rekurze*. V našem případě to bude přesně `n`. -The maximal recursion depth is limited by JavaScript engine. We can rely on it being 10000, some engines allow more, but 100000 is probably out of limit for the majority of them. There are automatic optimizations that help alleviate this ("tail calls optimizations"), but they are not yet supported everywhere and work only in simple cases. +Maximální možná hloubka rekurze je omezena motorem JavaScriptu. Můžeme se spolehnout, že to bude aspoň 10 000, některé motory umožňují víc, ale 100 000 je pravděpodobně nad limit většiny z nich. Existují automatické optimalizace, které nám pomohou se s tím vyrovnat („optimalizace koncového volání“), ale ty zatím nejsou podporovány všude a fungují jen v jednoduchých případech. -That limits the application of recursion, but it still remains very wide. There are many tasks where recursive way of thinking gives simpler code, easier to maintain. +Použití rekurze je tím omezené, ale stále zůstává velmi široké. Existuje mnoho úloh, v nichž rekurzívní způsob myšlení dává jednodušší kód, snadnější na údržbu. -## The execution context and stack +## Prováděcí kontext a zásobník -Now let's examine how recursive calls work. For that we'll look under the hood of functions. +Nyní prozkoumejme, jak rekurzívní volání fungují. K tomu se podíváme funkcím pod čepici. -The information about the process of execution of a running function is stored in its *execution context*. +Informace o procesu spuštění právě běžící funkce je ukládána do jejího *prováděcího (exekučního) kontextu*. -The [execution context](https://tc39.github.io/ecma262/#sec-execution-contexts) is an internal data structure that contains details about the execution of a function: where the control flow is now, the current variables, the value of `this` (we don't use it here) and few other internal details. +[Prováděcí kontext](https://tc39.github.io/ecma262/#sec-execution-contexts) je interní datová struktura, která obsahuje podrobnosti o výkonu funkce: kde se nachází průběh řízení právě teď, aktuální proměnné, hodnotu `this` (tu zde nepoužíváme) a některé další vnitřní detaily. -One function call has exactly one execution context associated with it. +S každou funkcí je spojen právě jeden prováděcí kontext. -When a function makes a nested call, the following happens: +Když funkce vykoná vnořené volání, stane se následující: -- The current function is paused. -- The execution context associated with it is remembered in a special data structure called *execution context stack*. -- The nested call executes. -- After it ends, the old execution context is retrieved from the stack, and the outer function is resumed from where it stopped. +- Aktuální funkce je pozastavena. +- Prováděcí kontext s ní spojený se uloží do speciální datové struktury nazývané *zásobník prováděcích kontextů*. +- Spustí se vnořené volání. +- Až toto volání skončí, původní prováděcí kontext se vyjme ze zásobníku a vnější funkce se znovu rozběhne od místa, kde se zastavila. -Let's see what happens during the `pow(2, 3)` call. +Podívejme se, co se děje během volání `mocnina(2, 3)`. -### pow(2, 3) +### mocnina(2, 3) -In the beginning of the call `pow(2, 3)` the execution context will store variables: `x = 2, n = 3`, the execution flow is at line `1` of the function. +Na začátku volání `mocnina(2, 3)` si prováděcí kontext uloží proměnné: `x = 2, n = 3`, průběh řízení je na řádku `1` této funkce. -We can sketch it as: +Můžeme si to zapsat jako:
  • - Context: { x: 2, n: 3, at line 1 } - pow(2, 3) + Kontext: { x: 2, n: 3, na řádku 1 } + mocnina(2, 3)
-That's when the function starts to execute. The condition `n == 1` is falsy, so the flow continues into the second branch of `if`: +Na tomto místě začne výkon funkce. Podmínka `n == 1` není splněna, takže řízení pokračuje druhou větví `if`: ```js run -function pow(x, n) { +function mocnina(x, n) { if (n == 1) { return x; } else { *!* - return x * pow(x, n - 1); + return x * mocnina(x, n - 1); */!* } } -alert( pow(2, 3) ); +alert( mocnina(2, 3) ); ``` -The variables are same, but the line changes, so the context is now: +Proměnné jsou stejné, ale řádek se změní, takže kontext nyní je:
  • - Context: { x: 2, n: 3, at line 5 } - pow(2, 3) + Kontext: { x: 2, n: 3, na řádku 5 } + mocnina(2, 3)
-To calculate `x * pow(x, n - 1)`, we need to make a subcall of `pow` with new arguments `pow(2, 2)`. +K výpočtu `x * mocnina(x, n - 1)` musíme učinit vnořené volání funkce `mocnina` s novými argumenty: `mocnina(2, 2)`. -### pow(2, 2) +### mocnina(2, 2) -To do a nested call, JavaScript remembers the current execution context in the *execution context stack*. +Aby JavaScript mohl provést vnořené volání, zapamatuje si aktuální prováděcí kontext v *zásobníku prováděcích kontextů*. -Here we call the same function `pow`, but it absolutely doesn't matter. The process is the same for all functions: +Zde voláme stejnou funkci `mocnina`, ale na tom vůbec nezáleží. Proces je pro všechny funkce stejný: -1. The current context is "remembered" on top of the stack. -2. The new context is created for the subcall. -3. When the subcall is finished -- the previous context is popped from the stack, and its execution continues. +1. Aktuální kontext se uloží na vrchol zásobníku. +2. Pro vnořené volání se vytvoří nový kontext. +3. Až bude vnořené volání ukončeno, předchozí kontext se vyjme ze zásobníku a jeho vykonávání bude pokračovat. -Here's the context stack when we entered the subcall `pow(2, 2)`: +Takto vypadá zásobník kontextů ve chvíli, kdy jsme vstoupili do vnořeného volání `mocnina(2, 2)`:
  • - Context: { x: 2, n: 2, at line 1 } - pow(2, 2) + Kontext: { x: 2, n: 2, na řádku 1 } + mocnina(2, 2)
  • - Context: { x: 2, n: 3, at line 5 } - pow(2, 3) + Kontext: { x: 2, n: 3, na řádku 5 } + mocnina(2, 3)
-The new current execution context is on top (and bold), and previous remembered contexts are below. +Nový aktuální prováděcí kontext je na vrcholu (a uveden tučně), předchozí uložené kontexty jsou níže. -When we finish the subcall -- it is easy to resume the previous context, because it keeps both variables and the exact place of the code where it stopped. +Až vnořené volání skončí, bude snadné obnovit předchozí kontext, jelikož ten si pamatuje obě proměnné i přesné místo kódu, na němž se zastavil. ```smart -Here in the picture we use the word "line", as in our example there's only one subcall in line, but generally a single line of code may contain multiple subcalls, like `pow(…) + pow(…) + somethingElse(…)`. +Na tomto obrázku používáme slovo „řádek“, protože v našem příkladu je na řádku jen jediné volání, ale obecně jeden řádek kódu může obsahovat několik volání, například `mocnina(…) + mocnina(…) + něcoJiného(…)`. -So it would be more precise to say that the execution resumes "immediately after the subcall". +Bylo by tedy přesnější říkat, že provádění se obnoví „ihned za vnořeným voláním“. ``` -### pow(2, 1) +### mocnina(2, 1) -The process repeats: a new subcall is made at line `5`, now with arguments `x=2`, `n=1`. +Proces se opakuje: na řádku `5` se učiní nové vnořené volání, tentokrát s argumenty `x=2`, `n=1`. -A new execution context is created, the previous one is pushed on top of the stack: +Vytvoří se nový prováděcí kontext, předchozí se uloží na vrchol zásobníku:
  • - Context: { x: 2, n: 1, at line 1 } - pow(2, 1) + Kontext: { x: 2, n: 1, na řádku 1 } + mocnina(2, 1)
  • - Context: { x: 2, n: 2, at line 5 } - pow(2, 2) + Kontext: { x: 2, n: 2, na řádku 5 } + mocnina(2, 2)
  • - Context: { x: 2, n: 3, at line 5 } - pow(2, 3) + Kontext: { x: 2, n: 3, na řádku 5 } + mocnina(2, 3)
-There are 2 old contexts now and 1 currently running for `pow(2, 1)`. +Nyní máme 2 staré kontexty a 1 právě probíhající pro `mocnina(2, 1)`. -### The exit +### Konec -During the execution of `pow(2, 1)`, unlike before, the condition `n == 1` is truthy, so the first branch of `if` works: +Během provádění `mocnina(2, 1)` je na rozdíl od předchozích případů podmínka `n == 1` splněna, takže bude provedena první větev `if`: ```js -function pow(x, n) { +function mocnina(x, n) { if (n == 1) { *!* return x; */!* } else { - return x * pow(x, n - 1); + return x * mocnina(x, n - 1); } } ``` -There are no more nested calls, so the function finishes, returning `2`. - -As the function finishes, its execution context is not needed anymore, so it's removed from the memory. The previous one is restored off the top of the stack: +Další vnořená volání už nejsou, takže funkce skončí a vrátí `2`. +Až funkce skončí, její prováděcí kontext už nebude zapotřebí, takže bude odstraněn z paměti. Na vrcholu zásobníku se obnoví předchozí prováděcí kontext:
  • - Context: { x: 2, n: 2, at line 5 } - pow(2, 2) + Kontext: { x: 2, n: 2, na řádku 5 } + mocnina(2, 2)
  • - Context: { x: 2, n: 3, at line 5 } - pow(2, 3) + Kontext: { x: 2, n: 3, na řádku 5 } + mocnina(2, 3)
-The execution of `pow(2, 2)` is resumed. It has the result of the subcall `pow(2, 1)`, so it also can finish the evaluation of `x * pow(x, n - 1)`, returning `4`. +Obnoví se provádění `mocnina(2, 2)`. To zná výsledek vnořeného volání `mocnina(2, 1)`, takže může dokončit výpočet `x * mocnina(x, n - 1)` a vrátit `4`. -Then the previous context is restored: +Pak se obnoví předchozí kontext:
  • - Context: { x: 2, n: 3, at line 5 } - pow(2, 3) + Kontext: { x: 2, n: 3, na řádku 5 } + mocnina(2, 3)
-When it finishes, we have a result of `pow(2, 3) = 8`. +Až skončí, budeme mít výsledek `mocnina(2, 3) = 8`. -The recursion depth in this case was: **3**. +Hloubka rekurze v tomto případě byla **3**. -As we can see from the illustrations above, recursion depth equals the maximal number of context in the stack. +Jak vidíme z výše uvedených ilustrací, hloubka rekurze se rovná nejvyššímu počtu kontextů v zásobníku. -Note the memory requirements. Contexts take memory. In our case, raising to the power of `n` actually requires the memory for `n` contexts, for all lower values of `n`. +Všimněte si paměťových požadavků. Kontexty zabírají paměť. V našem případě umocnění na `n`-tou ve skutečnosti vyžaduje paměť pro `n` kontextů, jeden pro každou nižší hodnotu `n`. -A loop-based algorithm is more memory-saving: +Algoritmus založený na cyklu ušetří více paměti: ```js -function pow(x, n) { - let result = 1; +function mocnina(x, n) { + let výsledek = 1; for (let i = 0; i < n; i++) { - result *= x; + výsledek *= x; } - return result; + return výsledek; } ``` -The iterative `pow` uses a single context changing `i` and `result` in the process. Its memory requirements are small, fixed and do not depend on `n`. +Iterativní `mocnina` používá jediný kontext, v jehož procesu se mění `i` a `výsledek`. Její paměťové požadavky jsou malé, pevné a nezávisejí na velikosti `n`. -**Any recursion can be rewritten as a loop. The loop variant usually can be made more effective.** +**Každou rekurzi lze přepsat do cyklu. Variantu s cyklem lze obvykle napsat efektivněji.** -...But sometimes the rewrite is non-trivial, especially when a function uses different recursive subcalls depending on conditions and merges their results or when the branching is more intricate. And the optimization may be unneeded and totally not worth the efforts. +...Toto přepsání však někdy není triviální, zvláště když funkce používá různá rekurzívní volání v závislosti na podmínkách a spojuje jejich výsledky, nebo když je větvení složitější. A optimalizace může být nepotřebná a nemusí vůbec stát za vynaloženou námahu. -Recursion can give a shorter code, easier to understand and support. Optimizations are not required in every place, mostly we need a good code, that's why it's used. +Rekurze mohou vydat kratší kód, jednodušší na porozumění a údržbu. Optimalizace nejsou nutné všude, většinou potřebujeme dobrý kód, proto používáme rekurzi. -## Recursive traversals +## Rekurzívní traverzování -Another great application of the recursion is a recursive traversal. +Další skvělé využití rekurze je rekurzívní traverzování. -Imagine, we have a company. The staff structure can be presented as an object: +Představme si, že máme firmu. Struktura jejího personálu se dá vyjádřit jako objekt: ```js -let company = { - sales: [{ - name: 'John', - salary: 1000 +let firma = { + prodeje: [{ + jméno: 'Jan', + plat: 1000 }, { - name: 'Alice', - salary: 1600 + jméno: 'Alice', + plat: 1600 }], - development: { - sites: [{ - name: 'Peter', - salary: 2000 + vývoj: { + pobočky: [{ + jméno: 'Petr', + plat: 2000 }, { - name: 'Alex', - salary: 1800 + jméno: 'Aleš', + plat: 1800 }], - internals: [{ - name: 'Jack', - salary: 1300 + interní: [{ + jméno: 'Kuba', + plat: 1300 }] } }; ``` -In other words, a company has departments. +Jinými slovy, firma má různá oddělení. -- A department may have an array of staff. For instance, `sales` department has 2 employees: John and Alice. -- Or a department may split into subdepartments, like `development` has two branches: `sites` and `internals`. Each of them has their own staff. -- It is also possible that when a subdepartment grows, it divides into subsubdepartments (or teams). +- Oddělení může mít pole zaměstnanců. Například oddělení `prodeje` má 2 zaměstnance: Jana a Alici. +- Nebo se oddělení může větvit na nižší oddělení, například `vývoj` má dvě větve: `pobočky` a `interní`. Každá z nich má své vlastní zaměstnance. +- Je také možné, že když se nižší oddělení rozroste, rozdělí se na ještě nižší oddělení (nebo týmy). - For instance, the `sites` department in the future may be split into teams for `siteA` and `siteB`. And they, potentially, can split even more. That's not on the picture, just something to have in mind. + Například oddělení `pobočky` se v budoucnu může rozdělit na týmy pro `pobočkaA` a `pobočkaB`. A ty se mohou rozdělit ještě dál. To není na obrázku, je to jen něco, co musíme mít na paměti. -Now let's say we want a function to get the sum of all salaries. How can we do that? +Nyní řekněme, že chceme funkci, která vrátí součet všech platů. Jak ji můžeme napsat? -An iterative approach is not easy, because the structure is not simple. The first idea may be to make a `for` loop over `company` with nested subloop over 1st level departments. But then we need more nested subloops to iterate over the staff in 2nd level departments like `sites`... And then another subloop inside those for 3rd level departments that might appear in the future? If we put 3-4 nested subloops in the code to traverse a single object, it becomes rather ugly. +Iterativní přístup není snadný, protože struktura není jednoduchá. První myšlenkou může být vytvořit cyklus `for` nad objektem `firma` s vnořeným podcyklem nad odděleními 1. úrovně. Pak ale budeme potřebovat další vnořené podcykly, které budou iterovat nad personálem oddělení 2. úrovně, jako je `pobočky`... A v nich pak další podcyklus pro oddělení 3. úrovně, která se mohou objevit v budoucnu? Jestliže do kódu vložíme 3-4 vnořené podcykly, aby procházely jediný objekt, bude to poměrně ošklivé. -Let's try recursion. +Zkusme rekurzi. -As we can see, when our function gets a department to sum, there are two possible cases: +Jak vidíme, když naše funkce obdrží oddělení, jehož platy má sečíst, mohou nastat dva případy: -1. Either it's a "simple" department with an *array* of people -- then we can sum the salaries in a simple loop. -2. Or it's *an object* with `N` subdepartments -- then we can make `N` recursive calls to get the sum for each of the subdeps and combine the results. +1. Buď je to „jednoduché“ oddělení s *polem* zaměstnanců -- pak můžeme sečíst jejich platy v jediném cyklu. +2. Nebo je to *objekt* s `N` podřízenými odděleními -- pak můžeme učinit `N` rekurzívních volání, abychom získali součet pro každé nižší oddělení, a zkombinovat výsledky. -The 1st case is the base of recursion, the trivial case, when we get an array. +První případ je základem rekurze, triviální případ, když obdržíme pole. -The 2nd case when we get an object is the recursive step. A complex task is split into subtasks for smaller departments. They may in turn split again, but sooner or later the split will finish at (1). +Druhý případ, když obdržíme objekt, je rekurzívní krok. Složitý úkol rozdělíme na podúkoly pro menší oddělení. Ta se pak mohou opět rozdělit, ale dříve nebo později dělení skončí případem (1). -The algorithm is probably even easier to read from the code: +Algoritmus je pravděpodobně ještě snadnější vyčíst z kódu: ```js run -let company = { // the same object, compressed for brevity - sales: [{name: 'John', salary: 1000}, {name: 'Alice', salary: 1600 }], - development: { - sites: [{name: 'Peter', salary: 2000}, {name: 'Alex', salary: 1800 }], - internals: [{name: 'Jack', salary: 1300}] +let firma = { // stejný objekt, zkomprimovaný pro stručnost + platy: [{jméno: 'Jan', plat: 1000}, {jméno: 'Alice', plat: 1600 }], + vývoj: { + pobočky: [{jméno: 'Petr', plat: 2000}, {jméno: 'Aleš', plat: 1800 }], + interní: [{jméno: 'Kuba', plat: 1300}] } }; -// The function to do the job +// Funkce, která odvede práci *!* -function sumSalaries(department) { - if (Array.isArray(department)) { // case (1) - return department.reduce((prev, current) => prev + current.salary, 0); // sum the array - } else { // case (2) - let sum = 0; - for (let subdep of Object.values(department)) { - sum += sumSalaries(subdep); // recursively call for subdepartments, sum the results +function sečtiPlaty(oddělení) { + if (Array.isArray(oddělení)) { // případ (1) + return oddělení.reduce((předchozí, aktuální) => předchozí + aktuální.plat, 0); // sečteme pole + } else { // případ (2) + let součet = 0; + for (let pododdělení of Object.values(oddělení)) { + součet += sečtiPlaty(pododdělení); // rekurzívní volání pro nižší oddělení, sečteme výsledky } - return sum; + return součet; } } */!* -alert(sumSalaries(company)); // 7700 +alert(sečtiPlaty(firma)); // 7700 ``` -The code is short and easy to understand (hopefully?). That's the power of recursion. It also works for any level of subdepartment nesting. +Kód je krátký a snadno srozumitelný (doufejme?). V tom spočívá síla rekurze. Navíc funguje pro jakoukoli úroveň vnoření oddělení. -Here's the diagram of calls: +Zde je diagram volání: -![recursive salaries](recursive-salaries.svg) +![rekurzívní platy](recursive-salaries.svg) -We can easily see the principle: for an object `{...}` subcalls are made, while arrays `[...]` are the "leaves" of the recursion tree, they give immediate result. +Snadno vidíme princip: pro objekty `{...}` se učiní volání, zatímco pole `[...]` jsou „listy“ rekurzívního stromu a dávají okamžitý výsledek. -Note that the code uses smart features that we've covered before: +Všimněte si, že kód využívá elegantní prvky, které jsme uvedli již dříve: -- Method `arr.reduce` explained in the chapter to get the sum of the array. -- Loop `for(val of Object.values(obj))` to iterate over object values: `Object.values` returns an array of them. +- Metodu `pole.reduce` vysvětlenou v kapitole k získání součtu pole. +- Cyklus `for(hodnota of Object.values(obj))` k iteraci nad hodnotami objektu: `Object.values` vrací jejich pole. -## Recursive structures +## Rekurzívní struktury -A recursive (recursively-defined) data structure is a structure that replicates itself in parts. +Rekurzívní (rekurzívně definovaná) datová struktura je struktura, která částečně replikuje sama sebe. -We've just seen it in the example of a company structure above. +Ve výše uvedeném příkladu struktury firmy jsme ji právě viděli. -A company *department* is: -- Either an array of people. -- Or an object with *departments*. +Firemní *oddělení* je: +- buď pole lidí, +- nebo objekt s *odděleními*. -For web-developers there are much better-known examples: HTML and XML documents. +Pro vývojáře webů existují mnohem lépe známé příklady: HTML a XML dokumenty. -In the HTML document, an *HTML-tag* may contain a list of: -- Text pieces. -- HTML-comments. -- Other *HTML-tags* (that in turn may contain text pieces/comments or other tags etc). +V HTML dokumentu může *HTML značka (tag)* obsahovat seznam: +- úryvků textu, +- HTML komentářů, +- jiných *HTML značek* (které mohou opět obsahovat úryvky textu, komentáře nebo jiné značky atd.). -That's once again a recursive definition. +To je opět rekurzívní definice. -For better understanding, we'll cover one more recursive structure named "Linked list" that might be a better alternative for arrays in some cases. +Pro lepší porozumění uvedeme ještě jednu rekurzívní strukturu nazývanou „spojový seznam“, která by v některých případech mohla být lepší alternativou k polím. -### Linked list +### Spojový seznam -Imagine, we want to store an ordered list of objects. +Představme si, že si chceme uložit seřazený seznam objektů. -The natural choice would be an array: +Přirozenou volbou by bylo pole: ```js -let arr = [obj1, obj2, obj3]; +let pole = [obj1, obj2, obj3]; ``` -...But there's a problem with arrays. The "delete element" and "insert element" operations are expensive. For instance, `arr.unshift(obj)` operation has to renumber all elements to make room for a new `obj`, and if the array is big, it takes time. Same with `arr.shift()`. +...S poli je však problém. Operace „smazání prvku“ a „vložení prvku“ jsou nákladné. Například operace `pole.unshift(obj)` musí přečíslovat všechny prvky, aby uvolnila místo pro nový objekt `obj`, a je-li pole velké, zabere to čas. Totéž platí pro `pole.shift()`. -The only structural modifications that do not require mass-renumbering are those that operate with the end of array: `arr.push/pop`. So an array can be quite slow for big queues, when we have to work with the beginning. +Jediné strukturální modifikace nevyžadující masové přečíslování jsou ty, které pracují s koncem pole: `pole.push/pop`. Pro velké fronty tedy pole může být poměrně pomalé, musíme-li pracovat s jeho začátkem. -Alternatively, if we really need fast insertion/deletion, we can choose another data structure called a [linked list](https://en.wikipedia.org/wiki/Linked_list). +Alternativně, jestliže potřebujeme opravdu rychlé vkládání a mazání, si můžeme zvolit jinou datovou strukturu nazvanou [lineární spojový seznam](https://cs.wikipedia.org/wiki/Lineární_seznam). -The *linked list element* is recursively defined as an object with: -- `value`. -- `next` property referencing the next *linked list element* or `null` if that's the end. +*Prvek spojového seznamu* je rekurzívně definován jako objekt, který obsahuje: +- hodnotu `hodnota`. +- vlastnost `další`, která se odkazuje na další *prvek spojového seznamu* nebo, jestliže tento prvek je poslední, je rovna `null`. -For instance: +Příklad: ```js -let list = { - value: 1, - next: { - value: 2, - next: { - value: 3, - next: { - value: 4, - next: null +let seznam = { + hodnota: 1, + další: { + hodnota: 2, + další: { + hodnota: 3, + další: { + hodnota: 4, + další: null } } } }; ``` -Graphical representation of the list: +Grafické zobrazení seznamu: -![linked list](linked-list.svg) +![spojový seznam](linked-list.svg) -An alternative code for creation: +Alternativní kód pro vytvoření: ```js no-beautify -let list = { value: 1 }; -list.next = { value: 2 }; -list.next.next = { value: 3 }; -list.next.next.next = { value: 4 }; -list.next.next.next.next = null; +let seznam = { hodnota: 1 }; +seznam.další = { hodnota: 2 }; +seznam.další.další = { hodnota: 3 }; +seznam.další.další.další = { hodnota: 4 }; +seznam.další.další.další.další = null; ``` -Here we can even more clearly see that there are multiple objects, each one has the `value` and `next` pointing to the neighbour. The `list` variable is the first object in the chain, so following `next` pointers from it we can reach any element. +Tady můžeme jasně vidět, že zde je více objektů, každý z nich má hodnotu `hodnota` a prvek `další`, který ukazuje na souseda. Proměnná `seznam` je první objekt v řetězci, takže pomocí ukazatelů `další` se z ní můžeme dostat na kterýkoli prvek. -The list can be easily split into multiple parts and later joined back: +Seznam můžeme snadno rozdělit na více částí a pak znovu spojit: ```js -let secondList = list.next.next; -list.next.next = null; +let druhýSeznam = seznam.další.další; +seznam.další.další = null; ``` -![linked list split](linked-list-split.svg) +![rozdělený spojový seznam](linked-list-split.svg) -To join: +Spojení: ```js -list.next.next = secondList; +seznam.další.další = druhýSeznam; ``` -And surely we can insert or remove items in any place. +A samozřejmě můžeme na kterémkoli místě vkládat nebo odstraňovat prvky. -For instance, to prepend a new value, we need to update the head of the list: +Například chceme-li přidat novou hodnotu na začátek seznamu, musíme změnit jeho hlavičku: ```js -let list = { value: 1 }; -list.next = { value: 2 }; -list.next.next = { value: 3 }; -list.next.next.next = { value: 4 }; +let seznam = { hodnota: 1 }; +seznam.další = { hodnota: 2 }; +seznam.další.další = { hodnota: 3 }; +seznam.další.další.další = { hodnota: 4 }; *!* -// prepend the new value to the list -list = { value: "new item", next: list }; +// připojíme novou hodnotu na začátek seznamu +seznam = { hodnota: "nový prvek", další: seznam }; */!* ``` -![linked list](linked-list-0.svg) +![spojový seznam](linked-list-0.svg) -To remove a value from the middle, change `next` of the previous one: +Abychom odstranili prvek uprostřed, změníme `další` u předchozího prvku: ```js -list.next = list.next.next; +seznam.další = seznam.další.další; ``` ![linked list](linked-list-remove-1.svg) -We made `list.next` jump over `1` to value `2`. The value `1` is now excluded from the chain. If it's not stored anywhere else, it will be automatically removed from the memory. +Způsobili jsme, že `seznam.další` bude přeskakovat `1` rovnou na hodnotu `2`. Hodnota `1` je nyní z řetězce vyřazena. Pokud není uložena někde jinde, bude automaticky odstraněna z paměti. -Unlike arrays, there's no mass-renumbering, we can easily rearrange elements. +Na rozdíl od polí zde nedochází k masovému přečíslování, takže můžeme prvky snadno přeskupovat. -Naturally, lists are not always better than arrays. Otherwise everyone would use only lists. +Pochopitelně seznamy nejsou vždy lepší než pole, jinak by všichni používali jedině seznamy. -The main drawback is that we can't easily access an element by its number. In an array that's easy: `arr[n]` is a direct reference. But in the list we need to start from the first item and go `next` `N` times to get the Nth element. +Jejich hlavní nevýhodou je, že nemůžeme snadno přistupovat k prvku podle jeho čísla. V poli je to jednoduché: `pole[n]` je přímý odkaz. Ale v seznamu musíme začít od prvního prvku a jít na `další` celkem `N`-krát, abychom získali N-tý prvek. -...But we don't always need such operations. For instance, when we need a queue or even a [deque](https://en.wikipedia.org/wiki/Double-ended_queue) -- the ordered structure that must allow very fast adding/removing elements from both ends, but access to its middle is not needed. +...Takové operace však nepotřebujeme vždy. Například když potřebujeme frontu nebo dokonce [frontu s dvojitým koncem](https://en.wikipedia.org/wiki/Double-ended_queue) -- seřazenou strukturu, která musí umožňovat velmi rychlé přidávání a odstraňování prvků z obou konců, ale přístup doprostřed není nutný. -Lists can be enhanced: -- We can add property `prev` in addition to `next` to reference the previous element, to move back easily. -- We can also add a variable named `tail` referencing the last element of the list (and update it when adding/removing elements from the end). -- ...The data structure may vary according to our needs. +Seznamy můžeme vylepšit: +- Můžeme navíc k vlastnosti `další` přidat vlastnost `předchozí`, která bude odkazovat na předchozí prvek, abychom se mohli snadno vracet zpět. +- Můžeme také přidat proměnnou `konec` odkazující se na poslední prvek seznamu (a aktualizovat ji, když budeme přidávat nebo odebírat prvky z konce). +- ...Tato datová struktura se může lišit podle našich potřeb. -## Summary +## Shrnutí -Terms: -- *Recursion* is a programming term that means calling a function from itself. Recursive functions can be used to solve tasks in elegant ways. +Pojmy: +- *Rekurze* je programátorský pojem, který znamená volání funkce sebou samotnou. Pomocí rekurzívních funkcí můžeme řešit úlohy elegantním způsobem. - When a function calls itself, that's called a *recursion step*. The *basis* of recursion is function arguments that make the task so simple that the function does not make further calls. + Volání funkce sebou samotnou se nazývá *rekurzívní krok*. *Základ* rekurze jsou funkční argumenty, s nimiž je úloha natolik jednoduchá, že funkce už neučiní další volání. -- A [recursively-defined](https://en.wikipedia.org/wiki/Recursive_data_type) data structure is a data structure that can be defined using itself. +- [Rekurzívně definovaná](https://en.wikipedia.org/wiki/Recursive_data_type) datová struktura je datová struktura, která může být definována pomocí sebe sama. - For instance, the linked list can be defined as a data structure consisting of an object referencing a list (or null). + Například spojový seznam může být definován jako datová struktura, která se skládá z objektu odkazujícího se na seznam (nebo null). ```js - list = { value, next -> list } + seznam = { hodnota, další -> seznam } ``` - Trees like HTML elements tree or the department tree from this chapter are also naturally recursive: they have branches and every branch can have other branches. + Stromy jako strom HTML prvků nebo strom firemních oddělení z této kapitoly jsou rovněž přirozeně rekurzívní: obsahují větve a každá větev může obsahovat další větve. - Recursive functions can be used to walk them as we've seen in the `sumSalary` example. + K jejich procházení mohou být použity rekurzívní funkce, jak jsme viděli v příkladu `sečtiPlaty`. -Any recursive function can be rewritten into an iterative one. And that's sometimes required to optimize stuff. But for many tasks a recursive solution is fast enough and easier to write and support. +Každou rekurzívní funkci můžeme přepsat na iterativní. Někdy je to nutné kvůli optimalizaci. Pro mnoho úloh je však rekurzívní řešení dostatečně rychlé a snadnější na napsání i údržbu. diff --git a/1-js/06-advanced-functions/01-recursion/recursion-pow.svg b/1-js/06-advanced-functions/01-recursion/recursion-pow.svg index 2b970a04a..9a6081b50 100644 --- a/1-js/06-advanced-functions/01-recursion/recursion-pow.svg +++ b/1-js/06-advanced-functions/01-recursion/recursion-pow.svg @@ -1 +1 @@ -pow(x,n)xx * pow(x, n-1)n == 1 ?YesNorecursive call until n==1 \ No newline at end of file +pow(x,n)xx * pow(x, n-1)n == 1 ?AnoNerekurzívní volání až do n==1 \ No newline at end of file diff --git a/1-js/06-advanced-functions/02-rest-parameters-spread/article.md b/1-js/06-advanced-functions/02-rest-parameters-spread/article.md index dbdfbd6c0..eda7780b6 100644 --- a/1-js/06-advanced-functions/02-rest-parameters-spread/article.md +++ b/1-js/06-advanced-functions/02-rest-parameters-spread/article.md @@ -1,295 +1,294 @@ -# Rest parameters and spread syntax +# Zbytkové parametry a roztažená syntaxe -Many JavaScript built-in functions support an arbitrary number of arguments. +Mnoho vestavěných funkcí v JavaScriptu umožňuje uvést libovolný počet argumentů. -For instance: +Například: -- `Math.max(arg1, arg2, ..., argN)` -- returns the greatest of the arguments. -- `Object.assign(dest, src1, ..., srcN)` -- copies properties from `src1..N` into `dest`. -- ...and so on. +- `Math.max(arg1, arg2, ..., argN)` -- vrátí největší z argumentů. +- `Object.assign(cíl, zdroj1, ..., zdrojN)` -- zkopíruje vlastnosti ze `zdroj1..N` do `cíl`. +- ...a tak dále. -In this chapter we'll learn how to do the same. And also, how to pass arrays to such functions as parameters. +V této kapitole se naučíme, jak udělat totéž, a také, jak předávat do takových funkcí pole jako parametry. -## Rest parameters `...` +## Zbytkové parametry `...` -A function can be called with any number of arguments, no matter how it is defined. +Funkci můžeme volat s libovolným počtem argumentů, bez ohledu na to, jak je definována. -Like here: +Například zde: ```js run -function sum(a, b) { +function součet(a, b) { return a + b; } -alert( sum(1, 2, 3, 4, 5) ); +alert( součet(1, 2, 3, 4, 5) ); ``` -There will be no error because of "excessive" arguments. But of course in the result only the first two will be counted, so the result in the code above is `3`. +Kvůli „přebytečným“ argumentům nenastane chyba, ale do výsledku se samozřejmě budou počítat jen první dva, takže výsledek v uvedeném kódu je `3`. -The rest of the parameters can be included in the function definition by using three dots `...` followed by the name of the array that will contain them. The dots literally mean "gather the remaining parameters into an array". +Zbylé parametry můžeme zahrnout do definice funkce pomocí tří teček `...`, za nimiž následuje název pole, které je bude obsahovat. Tečky doslova znamenají „shromáždi zbývající parametry do pole“. -For instance, to gather all arguments into array `args`: +Například abychom shromáždili všechny argumenty do pole `argumenty`: ```js run -function sumAll(...args) { // args is the name for the array - let sum = 0; +function sečtiVše(...argumenty) { // argumenty je název pole + let součet = 0; - for (let arg of args) sum += arg; + for (let arg of argumenty) součet += arg; - return sum; + return součet; } -alert( sumAll(1) ); // 1 -alert( sumAll(1, 2) ); // 3 -alert( sumAll(1, 2, 3) ); // 6 +alert( sečtiVše(1) ); // 1 +alert( sečtiVše(1, 2) ); // 3 +alert( sečtiVše(1, 2, 3) ); // 6 ``` -We can choose to get the first parameters as variables, and gather only the rest. +Můžeme se rozhodnout, že první parametry uložíme do proměnných a shromáždíme pouze ty ostatní. -Here the first two arguments go into variables and the rest go into `titles` array: +Zde budou první dva argumenty uloženy do proměnných a ostatní se uloží do pole `tituly`: ```js run -function showName(firstName, lastName, ...titles) { - alert( firstName + ' ' + lastName ); // Julius Caesar - - // the rest go into titles array - // i.e. titles = ["Consul", "Imperator"] - alert( titles[0] ); // Consul - alert( titles[1] ); // Imperator - alert( titles.length ); // 2 +function zobrazJméno(křestníJméno, příjmení, ...tituly) { + alert( křestníJméno + ' ' + příjmení ); // Julius Caesar + + // ostatní přijdou do pole tituly + // tj. tituly = ["Konzul", "Imperátor"] + alert( tituly[0] ); // Konzul + alert( tituly[1] ); // Imperátor + alert( tituly.length ); // 2 } -showName("Julius", "Caesar", "Consul", "Imperator"); +zobrazJméno("Julius", "Caesar", "Konzul", "Imperátor"); ``` -````warn header="The rest parameters must be at the end" -The rest parameters gather all remaining arguments, so the following does not make sense and causes an error: +````warn header="Zbytkové parametry musejí být na konci" +Pole zbytkových parametrů shromažďuje všechny zbývající argumenty, takže následující zápis nedává smysl a vyvolá chybu: ```js -function f(arg1, ...rest, arg2) { // arg2 after ...rest ?! - // error +function f(arg1, ...zbytek, arg2) { // arg2 po ...zbytek ?! + // chyba } ``` -The `...rest` must always be last. +`...zbytek` musí být vždy poslední. ```` -## The "arguments" variable +## Proměnná „arguments“ -There is also a special array-like object named `arguments` that contains all arguments by their index. +Existuje také speciální objekt podobný poli nazvaný `arguments`, který obsahuje všechny argumenty uložené podle jejich indexu. -For instance: +Například: ```js run -function showName() { +function zobrazJméno() { alert( arguments.length ); alert( arguments[0] ); alert( arguments[1] ); - // it's iterable + // je iterovatelný // for(let arg of arguments) alert(arg); } -// shows: 2, Julius, Caesar -showName("Julius", "Caesar"); +// zobrazí: 2, Julius, Caesar +zobrazJméno("Julius", "Caesar"); -// shows: 1, Ilya, undefined (no second argument) -showName("Ilya"); +// zobrazí: 1, Ilja, undefined (druhý argument není) +zobrazJméno("Ilja"); ``` -In old times, rest parameters did not exist in the language, and using `arguments` was the only way to get all arguments of the function. And it still works, we can find it in the old code. +V dřívějších dobách zbytkové parametry v jazyce neexistovaly a jediný způsob, jak získat všechny argumenty funkce, bylo použití `arguments`. A to stále funguje, můžeme to nalézt ve starých kódech. -But the downside is that although `arguments` is both array-like and iterable, it's not an array. It does not support array methods, so we can't call `arguments.map(...)` for example. +Nevýhodou však je, že ačkoli objekt `arguments` je podobný poli a iterovatelný, není to pole. Nepodporuje metody polí, takže nemůžeme volat například `arguments.map(...)`. -Also, it always contains all arguments. We can't capture them partially, like we did with rest parameters. +Navíc obsahuje vždy všechny argumenty. Nemůžeme je zachytit jen částečně, jak to můžeme udělat u zbytkových parametrů. -So when we need these features, then rest parameters are preferred. +Když tedy tuto vlastnost potřebujeme, dáváme přednost zbytkovým parametrům. -````smart header="Arrow functions do not have `\"arguments\"`" -If we access the `arguments` object from an arrow function, it takes them from the outer "normal" function. +````smart header="Šipkové funkce nemají `„arguments“`" +Jestliže přistoupíme k objektu `arguments` v šipkové funkci, převezme se z vnější „normální“ funkce. -Here's an example: +Příklad: ```js run function f() { - let showArg = () => alert(arguments[0]); - showArg(); + let zobrazArgumenty = () => alert(arguments[0]); + zobrazArgumenty(); } f(1); // 1 ``` -As we remember, arrow functions don't have their own `this`. Now we know they don't have the special `arguments` object either. +Jak si pamatujeme, šipkové funkce nemají vlastní `this`. Nyní víme, že nemají ani speciální objekt `arguments`. ```` -## Spread syntax [#spread-syntax] +## Roztažená syntaxe [#spread-syntax] -We've just seen how to get an array from the list of parameters. +Právě jsme viděli, jak vytvořit pole ze seznamu parametrů. -But sometimes we need to do exactly the reverse. +Někdy však potřebujeme udělat pravý opak. -For instance, there's a built-in function [Math.max](mdn:js/Math/max) that returns the greatest number from a list: +Například existuje vestavěná funkce [Math.max](mdn:js/Math/max), která vrací největší číslo ze seznamu: ```js run alert( Math.max(3, 5, 1) ); // 5 ``` -Now let's say we have an array `[3, 5, 1]`. How do we call `Math.max` with it? +Nyní řekněme, že máme pole `[3, 5, 1]`. Jak na ně zavoláme `Math.max`? -Passing it "as is" won't work, because `Math.max` expects a list of numeric arguments, not a single array: +Předat pole „tak, jak je“ nebude fungovat, protože `Math.max` očekává seznam číselných argumentů, ne jediné pole: ```js run -let arr = [3, 5, 1]; +let pole = [3, 5, 1]; *!* -alert( Math.max(arr) ); // NaN +alert( Math.max(pole) ); // NaN */!* ``` -And surely we can't manually list items in the code `Math.max(arr[0], arr[1], arr[2])`, because we may be unsure how many there are. As our script executes, there could be a lot, or there could be none. And that would get ugly. +A samozřejmě nemůžeme v kódu ručně vyjmenovat prvky pole `Math.max(pole[0], pole[1], pole[2])`, protože nevíme jistě, kolik jich tam bude. Když se náš skript spustí, může jich tam být mnoho a nemusí tam být žádný. A to by mohlo špatně dopadnout. -*Spread syntax* to the rescue! It looks similar to rest parameters, also using `...`, but does quite the opposite. +Zachrání nás *roztažená (spread) syntaxe*! Podobá se zbytkovým parametrům v tom, že také používá `...`, ale činí to přesně naopak. -When `...arr` is used in the function call, it "expands" an iterable object `arr` into the list of arguments. +Když ve volání funkce použijeme `...pole`, iterovatelný objekt `pole` se „roztáhne“ do seznamu argumentů. -For `Math.max`: +Pro `Math.max`: ```js run -let arr = [3, 5, 1]; +let pole = [3, 5, 1]; -alert( Math.max(...arr) ); // 5 (spread turns array into a list of arguments) +alert( Math.max(...pole) ); // 5 (roztažení přetvoří pole na seznam argumentů) ``` -We also can pass multiple iterables this way: +Tímto způsobem můžeme předat i více iterovatelných objektů: ```js run -let arr1 = [1, -2, 3, 4]; -let arr2 = [8, 3, -8, 1]; +let pole1 = [1, -2, 3, 4]; +let pole2 = [8, 3, -8, 1]; -alert( Math.max(...arr1, ...arr2) ); // 8 +alert( Math.max(...pole1, ...pole2) ); // 8 ``` -We can even combine the spread syntax with normal values: +Můžeme dokonce kombinovat roztaženou syntaxi s běžnými hodnotami: ```js run -let arr1 = [1, -2, 3, 4]; -let arr2 = [8, 3, -8, 1]; +let pole1 = [1, -2, 3, 4]; +let pole2 = [8, 3, -8, 1]; -alert( Math.max(1, ...arr1, 2, ...arr2, 25) ); // 25 +alert( Math.max(1, ...pole1, 2, ...pole2, 25) ); // 25 ``` -Also, the spread syntax can be used to merge arrays: +Roztaženou syntaxi můžeme použít i ke spojení polí: ```js run -let arr = [3, 5, 1]; -let arr2 = [8, 9, 15]; +let pole = [3, 5, 1]; +let pole2 = [8, 9, 15]; *!* -let merged = [0, ...arr, 2, ...arr2]; +let spojené = [0, ...pole, 2, ...pole2]; */!* -alert(merged); // 0,3,5,1,2,8,9,15 (0, then arr, then 2, then arr2) +alert(spojené); // 0,3,5,1,2,8,9,15 (0, pak pole, pak 2, pak pole2) ``` -In the examples above we used an array to demonstrate the spread syntax, but any iterable will do. +Ve výše uvedených příkladech jsme při předvádění roztažené syntaxe použili pole, ale funguje to na jakémkoli iterovatelném objektu. -For instance, here we use the spread syntax to turn the string into array of characters: +Například zde použijeme roztaženou syntaxi k převedení řetězce na pole znaků: ```js run -let str = "Hello"; +let řetězec = "Ahoj"; -alert( [...str] ); // H,e,l,l,o +alert( [...řetězec] ); // A,h,o,j ``` -The spread syntax internally uses iterators to gather elements, the same way as `for..of` does. +Roztažená syntaxe vnitřně využívá iterátory ke shromažďování prvků stejným způsobem, jako cyklus `for..of`. -So, for a string, `for..of` returns characters and `...str` becomes `"H","e","l","l","o"`. The list of characters is passed to array initializer `[...str]`. +Pro řetězec tedy `for..of` vrátí znaky a `...řetězec` se převede na `"A","h","o","j"`. Seznam znaků se předá do inicializátoru pole `[...řetězec]`. -For this particular task we could also use `Array.from`, because it converts an iterable (like a string) into an array: +Pro tento konkrétní úkol bychom mohli použít i `Array.from`, protože tato metoda převádí iterovatelný objekt (např. řetězec) na pole: ```js run -let str = "Hello"; +let řetězec = "Ahoj"; -// Array.from converts an iterable into an array -alert( Array.from(str) ); // H,e,l,l,o +// Array.from převede iterovatelný objekt na pole +alert( Array.from(řetězec) ); // A,h,o,j ``` -The result is the same as `[...str]`. +Výsledek je stejný jako u `[...řetězec]`. -But there's a subtle difference between `Array.from(obj)` and `[...obj]`: +Existuje však drobný rozdíl mezi `Array.from(obj)` a `[...obj]`: -- `Array.from` operates on both array-likes and iterables. -- The spread syntax works only with iterables. +- `Array.from` funguje na objektech podobných poli i na iterovatelných objektech. +- Roztažená syntaxe funguje jen na iterovatelných objektech. -So, for the task of turning something into an array, `Array.from` tends to be more universal. +Pro účel převedení něčeho jiného na pole tedy `Array.from` bývá univerzálnější. +## Kopírování pole/objektu -## Copy an array/object +Pamatujete si, jak jsme [dříve](info:object-copy#cloning-and-merging-object-assign) hovořili o `Object.assign()`? -Remember when we talked about `Object.assign()` [in the past](info:object-copy#cloning-and-merging-object-assign)? - -It is possible to do the same thing with the spread syntax. +S roztaženou syntaxí můžeme udělat totéž. ```js run -let arr = [1, 2, 3]; +let pole = [1, 2, 3]; *!* -let arrCopy = [...arr]; // spread the array into a list of parameters - // then put the result into a new array +let kopiePole = [...pole]; // roztáhneme pole do seznamu parametrů + // pak uložíme výsledek do nového pole */!* -// do the arrays have the same contents? -alert(JSON.stringify(arr) === JSON.stringify(arrCopy)); // true +// mají tato pole stejný obsah? +alert(JSON.stringify(pole) === JSON.stringify(kopiePole)); // true -// are the arrays equal? -alert(arr === arrCopy); // false (not same reference) +// jsou si tato pole rovna? +alert(pole === kopiePole); // false (není to stejný odkaz) -// modifying our initial array does not modify the copy: -arr.push(4); -alert(arr); // 1, 2, 3, 4 -alert(arrCopy); // 1, 2, 3 +// modifikace našeho původního pole nezmění kopii: +pole.push(4); +alert(pole); // 1, 2, 3, 4 +alert(kopiePole); // 1, 2, 3 ``` -Note that it is possible to do the same thing to make a copy of an object: +Všimněte si, že můžeme udělat totéž, abychom vytvořili kopii objektu: ```js run -let obj = { a: 1, b: 2, c: 3 }; +let objekt = { a: 1, b: 2, c: 3 }; *!* -let objCopy = { ...obj }; // spread the object into a list of parameters - // then return the result in a new object +let kopieObjektu = { ...objekt }; // roztáhneme objekt do seznamu parametrů + // pak vrátíme výsledek v novém objektu */!* -// do the objects have the same contents? -alert(JSON.stringify(obj) === JSON.stringify(objCopy)); // true +// mají tyto objekty stejný obsah? +alert(JSON.stringify(objekt) === JSON.stringify(kopieObjektu)); // true -// are the objects equal? -alert(obj === objCopy); // false (not same reference) +// jsou si tyto objekty rovny? +alert(objekt === kopieObjektu); // false (není to stejný odkaz) -// modifying our initial object does not modify the copy: -obj.d = 4; -alert(JSON.stringify(obj)); // {"a":1,"b":2,"c":3,"d":4} -alert(JSON.stringify(objCopy)); // {"a":1,"b":2,"c":3} +// modifikace našeho původního objektu nezmění kopii: +objekt.d = 4; +alert(JSON.stringify(objekt)); // {"a":1,"b":2,"c":3,"d":4} +alert(JSON.stringify(kopieObjektu)); // {"a":1,"b":2,"c":3} ``` -This way of copying an object is much shorter than `let objCopy = Object.assign({}, obj)` or for an array `let arrCopy = Object.assign([], arr)` so we prefer to use it whenever we can. +Tento způsob kopírování objektu je mnohem kratší než `let kopieObjektu = Object.assign({}, objekt)` nebo pro pole `let kopiePole = Object.assign([], pole)`, takže mu dáváme přednost, kde jen můžeme. -## Summary +## Shrnutí -When we see `"..."` in the code, it is either rest parameters or the spread syntax. +Když v kódu vidíme `"..."`, jsou to buď zbytkové parametry, nebo roztažená syntaxe. -There's an easy way to distinguish between them: +Je možné mezi nimi snadno rozlišovat: -- When `...` is at the end of function parameters, it's "rest parameters" and gathers the rest of the list of arguments into an array. -- When `...` occurs in a function call or alike, it's called a "spread syntax" and expands an array into a list. +- Když je `...` na konci funkčních parametrů, jsou to „zbytkové parametry“ a shromažďují zbytek seznamu argumentů do pole. +- Když se `...` vyskytuje ve volání funkce nebo něčem podobném, nazývá se „roztažená syntaxe“ a roztáhne pole do seznamu. -Use patterns: +Vzory použití: -- Rest parameters are used to create functions that accept any number of arguments. -- The spread syntax is used to pass an array to functions that normally require a list of many arguments. +- Zbytkové parametry se používají k vytváření funkcí, které přijímají libovolný počet argumentů. +- Roztažená syntaxe se používá k předání pole do funkcí, které normálně vyžadují seznam mnoha argumentů. -Together they help to travel between a list and an array of parameters with ease. +Společně nám pomáhají snadno přepínat mezi seznamem a polem parametrů. -All arguments of a function call are also available in "old-style" `arguments`: array-like iterable object. +Všechny argumenty volání funkce jsou rovněž k dispozici „ve starém stylu“ v objektu `arguments`: iterovatelném objektu podobném poli. diff --git a/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/solution.md b/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/solution.md index 7cbd85ab7..18b1dc315 100644 --- a/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/solution.md +++ b/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/solution.md @@ -1,5 +1,5 @@ -The answer is: **Pete**. +Odpověď zní: **Petr**. -A function gets outer variables as they are now, it uses the most recent values. +Funkce načítá vnější proměnné tak, jak vypadají právě v tuto chvíli. Používá poslední hodnoty. -Old variable values are not saved anywhere. When a function wants a variable, it takes the current value from its own Lexical Environment or the outer one. +Staré hodnoty proměnných se nikam neukládají. Když funkce chce proměnnou, vezme její aktuální hodnotu ze svého vlastního lexikálního prostředí nebo z vnějšího. diff --git a/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/task.md b/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/task.md index 819189773..924b3fd52 100644 --- a/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/task.md +++ b/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/task.md @@ -2,22 +2,22 @@ importance: 5 --- -# Does a function pickup latest changes? +# Odrážejí se ve funkci poslední změny? -The function sayHi uses an external variable name. When the function runs, which value is it going to use? +Funkce `řekniAhoj` využívá název externí proměnné. Když bude spuštěna, kterou hodnotu použije? ```js -let name = "John"; +let jméno = "Jan"; -function sayHi() { - alert("Hi, " + name); +function řekniAhoj() { + alert("Ahoj, " + jméno); } -name = "Pete"; +jméno = "Petr"; -sayHi(); // what will it show: "John" or "Pete"? +řekniAhoj(); // co zobrazí: "Jan" nebo "Petr"? ``` -Such situations are common both in browser and server-side development. A function may be scheduled to execute later than it is created, for instance after a user action or a network request. +Takové situace jsou běžné při vývoji v prohlížeči i na straně serveru. Funkce může být navržena ke spuštění později, než byla vytvořena, například po uživatelské akci nebo síťovém požadavku. -So, the question is: does it pick up the latest changes? +Otázka tedy zní: odráží poslední změny? diff --git a/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/solution.js b/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/solution.js index a26578ae1..ca8e82a08 100644 --- a/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/solution.js +++ b/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/solution.js @@ -1,13 +1,13 @@ -function makeArmy() { +function vytvořArmádu() { - let shooters = []; + let střelci = []; for(let i = 0; i < 10; i++) { - let shooter = function() { // shooter function - alert( i ); // should show its number + let střelec = function() { // funkce střelec + alert( i ); // by měla zobrazit své číslo }; - shooters.push(shooter); + střelci.push(střelec); } - return shooters; + return střelci; } diff --git a/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/source.js b/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/source.js index 7c7aaa1e3..e908b1f0b 100644 --- a/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/source.js +++ b/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/source.js @@ -1,22 +1,22 @@ -function makeArmy() { - let shooters = []; +function vytvořArmádu() { + let střelci = []; let i = 0; while (i < 10) { - let shooter = function() { // shooter function - alert( i ); // should show its number + let střelec = function() { // funkce střelec + alert( i ); // by měla zobrazit své číslo }; - shooters.push(shooter); + střelci.push(střelec); i++; } - return shooters; + return střelci; } /* -let army = makeArmy(); +let armáda = vytvořArmádu(); -army[0](); // the shooter number 0 shows 10 -army[5](); // and number 5 also outputs 10... -// ... all shooters show 10 instead of their 0, 1, 2, 3... +armáda[0](); // střelec číslo 0 zobrazí 10 +armáda[5](); // a číslo 5 zobrazí také 10... +// ... všichni střelci zobrazí 10 místo svého čísla 0, 1, 2, 3... */ diff --git a/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/test.js b/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/test.js index b61e6e4db..f8c2c866c 100644 --- a/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/test.js +++ b/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/test.js @@ -1,20 +1,20 @@ -describe("army", function() { +describe("armáda", function() { - let army; + let armáda; before(function() { - army = makeArmy(); + armáda = vytvořArmádu(); window.alert = sinon.stub(window, "alert"); }); - it("army[0] shows 0", function() { - army[0](); + it("armáda[0] zobrazí 0", function() { + armáda[0](); assert(alert.calledWith(0)); }); - it("army[5] shows 5", function() { - army[5](); + it("armáda[5] zobrazí 5", function() { + armáda[5](); assert(alert.calledWith(5)); }); diff --git a/1-js/06-advanced-functions/03-closure/10-make-army/solution.md b/1-js/06-advanced-functions/03-closure/10-make-army/solution.md index 9d99aa717..fd6af39ff 100644 --- a/1-js/06-advanced-functions/03-closure/10-make-army/solution.md +++ b/1-js/06-advanced-functions/03-closure/10-make-army/solution.md @@ -1,17 +1,17 @@ -Let's examine what exactly happens inside `makeArmy`, and the solution will become obvious. +Prozkoumejme, co přesně se děje uvnitř funkce `vytvořArmádu`, a řešení bude zřejmé. -1. It creates an empty array `shooters`: +1. Vytvoří se prázdné pole `střelci`: ```js - let shooters = []; + let střelci = []; ``` -2. Fills it with functions via `shooters.push(function)` in the loop. +2. V cyklu se naplní funkcemi pomocí `střelci.push(function)`. - Every element is a function, so the resulting array looks like this: + Každý prvek je funkce, takže výsledné pole vypadá takto: ```js no-beautify - shooters = [ + střelci = [ function () { alert(i); }, function () { alert(i); }, function () { alert(i); }, @@ -25,105 +25,104 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco ]; ``` -3. The array is returned from the function. +3. Toto pole funkce vrátí. - Then, later, the call to any member, e.g. `army[5]()` will get the element `army[5]` from the array (which is a function) and calls it. + Pak později volání kteréhokoli jeho prvku, např. `armáda[5]()`, načte z pole prvek `armáda[5]` (což je funkce) a zavolá jej. - Now why do all such functions show the same value, `10`? + Proč nyní všechny tyto funkce zobrazí stejnou hodnotu, `10`? - That's because there's no local variable `i` inside `shooter` functions. When such a function is called, it takes `i` from its outer lexical environment. + Je to proto, že uvnitř funkcí `střelec` neexistuje žádná lokální proměnná `i`. Když je taková funkce volána, převezme `i` z vnějšího lexikálního prostředí. - Then, what will be the value of `i`? + Jaká pak bude hodnota proměnné `i`? - If we look at the source: + Když se podíváme na zdrojový kód: ```js - function makeArmy() { + function vytvořArmádu() { ... let i = 0; while (i < 10) { - let shooter = function() { // shooter function - alert( i ); // should show its number + let střelec = function() { // funkce střelec + alert( i ); // by měla zobrazit své číslo }; - shooters.push(shooter); // add function to the array + střelci.push(střelec); // přidá funkci do pole i++; } ... } ``` - We can see that all `shooter` functions are created in the lexical environment of `makeArmy()` function. But when `army[5]()` is called, `makeArmy` has already finished its job, and the final value of `i` is `10` (`while` stops at `i=10`). + Vidíme, že všechny funkce `střelec` jsou vytvořeny v lexikálním prostředí funkce `vytvořArmádu()`. Když je však volána `armáda[5]()`, funkce `vytvořArmádu` již ukončila svou práci a poslední hodnota `i` je `10` (`while` se zastaví na `i=10`). - As the result, all `shooter` functions get the same value from the outer lexical environment and that is, the last value, `i=10`. + Výsledkem je, že všechny funkce `střelec` převezmou z vnějšího lexikálního prostředí stejnou hodnotu a tou bude poslední hodnota, `i=10`. ![](lexenv-makearmy-empty.svg) - As you can see above, on each iteration of a `while {...}` block, a new lexical environment is created. So, to fix this, we can copy the value of `i` into a variable within the `while {...}` block, like this: + Jak vidíte výše, při každé iteraci bloku `while {...}` bude vytvořeno nové lexikální prostředí. Abychom to opravili, můžeme zkopírovat hodnotu `i` do proměnné uvnitř bloku `while {...}` třeba takto: ```js run - function makeArmy() { - let shooters = []; + function vytvořArmádu() { + let střelci = []; let i = 0; while (i < 10) { *!* let j = i; */!* - let shooter = function() { // shooter function - alert( *!*j*/!* ); // should show its number + let střelec = function() { // funkce střelec + alert( *!*j*/!* ); // by měla zobrazit své číslo }; - shooters.push(shooter); + střelci.push(střelec); i++; } - return shooters; + return střelci; } - let army = makeArmy(); + let armáda = vytvořArmádu(); - // Now the code works correctly - army[0](); // 0 - army[5](); // 5 + // Nyní kód funguje správně + armáda[0](); // 0 + armáda[5](); // 5 ``` - Here `let j = i` declares an "iteration-local" variable `j` and copies `i` into it. Primitives are copied "by value", so we actually get an independent copy of `i`, belonging to the current loop iteration. + Zde `let j = i` deklaruje „iteračně lokální“ proměnnou `j` a zkopíruje do ní `i`. Primitivy se kopírují „hodnotou“, takže ve skutečnosti získáme nezávislou kopii `i`, která patří do aktuální iterace cyklu. - The shooters work correctly, because the value of `i` now lives a little bit closer. Not in `makeArmy()` Lexical Environment, but in the Lexical Environment that corresponds to the current loop iteration: + Střelci budou fungovat správně, protože hodnota `i` nyní existuje trochu blíže. Není v lexikálním prostředí funkce `vytvořArmádu()`, ale v lexikálním prostředí, které odpovídá aktuální iteraci cyklu: ![](lexenv-makearmy-while-fixed.svg) - Such a problem could also be avoided if we used `for` in the beginning, like this: + Tomuto problému se lze vyhnout i tak, že na začátku použijeme `for`, třeba takto: ```js run demo - function makeArmy() { + function vytvořArmádu() { - let shooters = []; + let střelci = []; *!* for(let i = 0; i < 10; i++) { */!* - let shooter = function() { // shooter function - alert( i ); // should show its number + let střelec = function() { // funkce střelec + alert( i ); // by měla zobrazit své číslo }; - shooters.push(shooter); + střelci.push(střelec); } - return shooters; + return střelci; } - let army = makeArmy(); + let armáda = vytvořArmádu(); - army[0](); // 0 - army[5](); // 5 + armáda[0](); // 0 + armáda[5](); // 5 ``` - That's essentially the same, because `for` on each iteration generates a new lexical environment, with its own variable `i`. So `shooter` generated in every iteration references its own `i`, from that very iteration. + To je v zásadě totéž, protože `for` při každé své iteraci vygeneruje nové lexikální prostředí se svou vlastní proměnnou `i`. Takže `střelec` generovaný v každé iteraci odkazuje na své vlastní `i` přímo z této iterace. ![](lexenv-makearmy-for-fixed.svg) -Now, as you've put so much effort into reading this, and the final recipe is so simple - just use `for`, you may wonder -- was it worth that? +Když jste vložili tolik námahy do přečtení tohoto řešení a konečný recept je tak jednoduchý -- prostě použijeme `for`, můžete se divit -- mělo to cenu? -Well, if you could easily answer the question, you wouldn't read the solution. So, hopefully this task must have helped you to understand things a bit better. - -Besides, there are indeed cases when one prefers `while` to `for`, and other scenarios, where such problems are real. +Inu, kdybyste na tuto otázku dokázali snadno odpovědět, nečetli byste řešení. Snad vám tedy tato úloha pomohla trochu lépe všemu porozumět. +Kromě toho zajisté existují případy, kdy člověk dává přednost `while` před `for`, i jiné scénáře, v nichž takové problémy opravdu nastanou. diff --git a/1-js/06-advanced-functions/03-closure/10-make-army/task.md b/1-js/06-advanced-functions/03-closure/10-make-army/task.md index f50c7dc20..27f69e70c 100644 --- a/1-js/06-advanced-functions/03-closure/10-make-army/task.md +++ b/1-js/06-advanced-functions/03-closure/10-make-army/task.md @@ -2,40 +2,39 @@ importance: 5 --- -# Army of functions +# Armáda funkcí -The following code creates an array of `shooters`. +Následující kód vytvoří pole `střelci`. -Every function is meant to output its number. But something is wrong... +Každá funkce má vypsat své číslo. Ale něco je špatně... ```js run -function makeArmy() { - let shooters = []; +function vytvořArmádu() { + let střelci = []; let i = 0; while (i < 10) { - let shooter = function() { // create a shooter function, - alert( i ); // that should show its number + let střelec = function() { // vytvoříme funkci střelec, + alert( i ); // která by měla zobrazit své číslo }; - shooters.push(shooter); // and add it to the array + střelci.push(střelec); // a přidáme ji do pole i++; } - // ...and return the array of shooters - return shooters; + // ...a vrátíme pole střelci + return střelci; } -let army = makeArmy(); +let armáda = vytvořArmádu(); *!* -// all shooters show 10 instead of their numbers 0, 1, 2, 3... -army[0](); // 10 from the shooter number 0 -army[1](); // 10 from the shooter number 1 -army[2](); // 10 ...and so on. +// všichni střelci zobrazí 10 místo svých čísel 0, 1, 2, 3... +armáda[0](); // 10 od střelce číslo 0 +armáda[1](); // 10 od střelce číslo 1 +armáda[2](); // 10 ...a tak dále. */!* ``` -Why do all of the shooters show the same value? - -Fix the code so that they work as intended. +Proč všichni střelci zobrazují stejnou hodnotu? +Opravte kód, aby fungoval tak, jak je zamýšleno. diff --git a/1-js/06-advanced-functions/03-closure/2-closure-variable-access/solution.md b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/solution.md index 0a522132f..6ad8df764 100644 --- a/1-js/06-advanced-functions/03-closure/2-closure-variable-access/solution.md +++ b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/solution.md @@ -1,9 +1,9 @@ -The answer is: **Pete**. +Odpověď zní: **Petr**. -The `work()` function in the code below gets `name` from the place of its origin through the outer lexical environment reference: +Funkce `pracuj()` uvedená v následujícím kódu načte `jméno` z místa svého vzniku odkazem na vnější lexikální prostředí: ![](lexenv-nested-work.svg) -So, the result is `"Pete"` here. +Výsledkem zde je tedy `"Petr"`. -But if there were no `let name` in `makeWorker()`, then the search would go outside and take the global variable as we can see from the chain above. In that case the result would be `"John"`. +Kdyby však ve funkci `vytvořPracovníka()` nebylo `let jméno`, pak by hledání pokračovalo dál ven a převzalo globální proměnnou, jak vidíme v uvedeném řetězci. V tom případě by výsledek byl `"Jan"`. diff --git a/1-js/06-advanced-functions/03-closure/2-closure-variable-access/task.md b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/task.md index d12a385c8..bba9be2b1 100644 --- a/1-js/06-advanced-functions/03-closure/2-closure-variable-access/task.md +++ b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/task.md @@ -2,28 +2,28 @@ importance: 5 --- -# Which variables are available? +# Které proměnné jsou dostupné? -The function `makeWorker` below makes another function and returns it. That new function can be called from somewhere else. +Následující funkce `vytvořPracovníka` vytvoří jinou funkci a vrátí ji. Nová funkce může být volána odjinud. -Will it have access to the outer variables from its creation place, or the invocation place, or both? +Bude mít přístup k vnějším proměnným z místa svého vzniku, nebo z místa volání, nebo z obojího? ```js -function makeWorker() { - let name = "Pete"; +function vytvořPracovníka() { + let jméno = "Petr"; return function() { - alert(name); + alert(jméno); }; } -let name = "John"; +let jméno = "Jan"; -// create a function -let work = makeWorker(); +// vytvoření funkce +let pracuj = vytvořPracovníka(); -// call it -work(); // what will it show? +// její volání +pracuj(); // co zobrazí? ``` -Which value it will show? "Pete" or "John"? +Kterou hodnotu zobrazí? „Petr“ nebo „Jan“? diff --git a/1-js/06-advanced-functions/03-closure/3-counter-independent/solution.md b/1-js/06-advanced-functions/03-closure/3-counter-independent/solution.md index 25ecbea4c..b7fc9d64a 100644 --- a/1-js/06-advanced-functions/03-closure/3-counter-independent/solution.md +++ b/1-js/06-advanced-functions/03-closure/3-counter-independent/solution.md @@ -1,5 +1,5 @@ -The answer: **0,1.** +Odpověď: **0,1.** -Functions `counter` and `counter2` are created by different invocations of `makeCounter`. +Funkce `čítač` a `čítač2` byly vytvořeny různými voláními funkce `vytvořČítač`. -So they have independent outer Lexical Environments, each one has its own `count`. +Mají tedy nezávislá vnější lexikální prostředí, každé z nich má svůj vlastní `počet`. diff --git a/1-js/06-advanced-functions/03-closure/3-counter-independent/task.md b/1-js/06-advanced-functions/03-closure/3-counter-independent/task.md index e8c17dd31..f6bb4b42e 100644 --- a/1-js/06-advanced-functions/03-closure/3-counter-independent/task.md +++ b/1-js/06-advanced-functions/03-closure/3-counter-independent/task.md @@ -2,30 +2,30 @@ importance: 5 --- -# Are counters independent? +# Jsou čítače nezávislé? -Here we make two counters: `counter` and `counter2` using the same `makeCounter` function. +Zde vytvoříme dva čítače: `čítač` a `čítač2` pomocí téže funkce `vytvořČítač`. -Are they independent? What is the second counter going to show? `0,1` or `2,3` or something else? +Jsou nezávislé? Co zobrazí druhý čítač? `0,1` nebo `2,3` nebo něco jiného? ```js -function makeCounter() { - let count = 0; +function vytvořČítač() { + let počet = 0; return function() { - return count++; + return počet++; }; } -let counter = makeCounter(); -let counter2 = makeCounter(); +let čítač = vytvořČítač(); +let čítač2 = vytvořČítač(); -alert( counter() ); // 0 -alert( counter() ); // 1 +alert( čítač() ); // 0 +alert( čítač() ); // 1 *!* -alert( counter2() ); // ? -alert( counter2() ); // ? +alert( čítač2() ); // ? +alert( čítač2() ); // ? */!* ``` diff --git a/1-js/06-advanced-functions/03-closure/4-counter-object-independent/solution.md b/1-js/06-advanced-functions/03-closure/4-counter-object-independent/solution.md index cd4e641e4..9ece7f811 100644 --- a/1-js/06-advanced-functions/03-closure/4-counter-object-independent/solution.md +++ b/1-js/06-advanced-functions/03-closure/4-counter-object-independent/solution.md @@ -1,24 +1,22 @@ +Jistě že to bude fungovat správně. -Surely it will work just fine. - -Both nested functions are created within the same outer Lexical Environment, so they share access to the same `count` variable: +Obě vnořené funkce jsou vytvořeny uvnitř stejného vnějšího lexikálního prostředí, takže mají společný přístup ke stejné proměnné `počet`: ```js run -function Counter() { - let count = 0; +function Čítač() { + let počet = 0; - this.up = function() { - return ++count; + this.zvyš = function() { + return ++počet; }; - - this.down = function() { - return --count; + this.sniž = function() { + return --počet; }; } -let counter = new Counter(); +let čítač = new Čítač(); -alert( counter.up() ); // 1 -alert( counter.up() ); // 2 -alert( counter.down() ); // 1 +alert( čítač.zvyš() ); // 1 +alert( čítač.zvyš() ); // 2 +alert( čítač.sniž() ); // 1 ``` diff --git a/1-js/06-advanced-functions/03-closure/4-counter-object-independent/task.md b/1-js/06-advanced-functions/03-closure/4-counter-object-independent/task.md index d770b0ffc..785d64ba6 100644 --- a/1-js/06-advanced-functions/03-closure/4-counter-object-independent/task.md +++ b/1-js/06-advanced-functions/03-closure/4-counter-object-independent/task.md @@ -2,28 +2,28 @@ importance: 5 --- -# Counter object +# Objekt čítače -Here a counter object is made with the help of the constructor function. +Zde je vytvořen objekt čítače pomocí konstruktoru. -Will it work? What will it show? +Bude to fungovat? Co se zobrazí? ```js -function Counter() { - let count = 0; +function Čítač() { + let počet = 0; - this.up = function() { - return ++count; + this.zvyš = function() { + return ++počet; }; - this.down = function() { - return --count; + this.sniž = function() { + return --počet; }; } -let counter = new Counter(); +let čítač = new Čítač(); -alert( counter.up() ); // ? -alert( counter.up() ); // ? -alert( counter.down() ); // ? +alert( čítač.zvyš() ); // ? +alert( čítač.zvyš() ); // ? +alert( čítač.sniž() ); // ? ``` diff --git a/1-js/06-advanced-functions/03-closure/5-function-in-if/solution.md b/1-js/06-advanced-functions/03-closure/5-function-in-if/solution.md index e2e7a91b3..ed26d4887 100644 --- a/1-js/06-advanced-functions/03-closure/5-function-in-if/solution.md +++ b/1-js/06-advanced-functions/03-closure/5-function-in-if/solution.md @@ -1,3 +1,3 @@ -The result is **an error**. +Výsledkem bude **chyba**. -The function `sayHi` is declared inside the `if`, so it only lives inside it. There is no `sayHi` outside. \ No newline at end of file +Funkce `řekniAhoj` je deklarována uvnitř `if`, takže bude existovat jen uvnitř něj. Vně žádné `řekniAhoj` není. \ No newline at end of file diff --git a/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md b/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md index 4e386eec5..302f6037f 100644 --- a/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md +++ b/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md @@ -1,22 +1,22 @@ importance: 5 --- -# Function in if +# Funkce v if -Look at the code. What will be the result of the call at the last line? +Podívejte se na kód. Jaký bude výsledek volání na posledním řádku? ```js run -let phrase = "Hello"; +let věta = "Ahoj"; if (true) { - let user = "John"; + let uživatel = "Jan"; - function sayHi() { - alert(`${phrase}, ${user}`); + function řekniAhoj() { + alert(`${věta}, ${uživatel}`); } } *!* -sayHi(); +řekniAhoj(); */!* ``` diff --git a/1-js/06-advanced-functions/03-closure/6-closure-sum/solution.md b/1-js/06-advanced-functions/03-closure/6-closure-sum/solution.md index a6679cd20..8c426d44d 100644 --- a/1-js/06-advanced-functions/03-closure/6-closure-sum/solution.md +++ b/1-js/06-advanced-functions/03-closure/6-closure-sum/solution.md @@ -1,17 +1,17 @@ -For the second parentheses to work, the first ones must return a function. +Aby druhé závorky fungovaly, ty první musejí vrátit funkci. -Like this: +Například: ```js run -function sum(a) { +function sečti(a) { return function(b) { - return a + b; // takes "a" from the outer lexical environment + return a + b; // vezme "a" z vnějšího lexikálního prostředí }; } -alert( sum(1)(2) ); // 3 -alert( sum(5)(-1) ); // 4 +alert( sečti(1)(2) ); // 3 +alert( sečti(5)(-1) ); // 4 ``` diff --git a/1-js/06-advanced-functions/03-closure/6-closure-sum/task.md b/1-js/06-advanced-functions/03-closure/6-closure-sum/task.md index b45758562..5e0e66df1 100644 --- a/1-js/06-advanced-functions/03-closure/6-closure-sum/task.md +++ b/1-js/06-advanced-functions/03-closure/6-closure-sum/task.md @@ -2,16 +2,16 @@ importance: 4 --- -# Sum with closures +# Součet s uzávěry -Write function `sum` that works like this: `sum(a)(b) = a+b`. +Napište funkci `sečti`, která bude fungovat takto: `sečti(a)(b) = a+b`. -Yes, exactly this way, using double parentheses (not a mistype). +Ano, přesně takto, pomocí dvojích závorek (to není překlep). -For instance: +Například: ```js -sum(1)(2) = 3 -sum(5)(-1) = 4 +sečti(1)(2) = 3 +sečti(5)(-1) = 4 ``` diff --git a/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md b/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md index b16b35290..d24d73aa1 100644 --- a/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md +++ b/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md @@ -1,40 +1,40 @@ -The result is: **error**. +Výsledek bude: **chyba**. -Try running it: +Zkuste si to spustit: ```js run let x = 1; -function func() { +function funkce() { *!* - console.log(x); // ReferenceError: Cannot access 'x' before initialization + console.log(x); // ReferenceError: Nelze přistupovat k 'x' před inicializací */!* let x = 2; } -func(); +funkce(); ``` -In this example we can observe the peculiar difference between a "non-existing" and "uninitialized" variable. +V tomto příkladu můžeme vidět pozoruhodný rozdíl mezi „neexistující“ a „neinicializovanou“ proměnnou. -As you may have read in the article [](info:closure), a variable starts in the "uninitialized" state from the moment when the execution enters a code block (or a function). And it stays uninitalized until the corresponding `let` statement. +Jak jste si mohli přečíst v článku [](info:closure), proměnná začíná v „neinicializovaném“ stavu ve chvíli, kdy běh vstoupí do kódového bloku (nebo do funkce). A zůstane neinicializovaná až do příslušného příkazu `let`. -In other words, a variable technically exists, but can't be used before `let`. +Jinými slovy, před `let` proměnná technicky existuje, ale nemůže být používána. -The code above demonstrates it. +Uvedený kód to demonstruje. ```js -function func() { +function funkce() { *!* - // the local variable x is known to the engine from the beginning of the function, - // but "uninitialized" (unusable) until let ("dead zone") - // hence the error + // motor zná lokální proměnnou x od začátku této funkce, + // ale ta je „neinicializovaná“ (nepoužitelná) až do příkazu let („mrtvá zóna“) + // proto chyba */!* - console.log(x); // ReferenceError: Cannot access 'x' before initialization + console.log(x); // ReferenceError: Nelze přistupovat k 'x' před inicializací let x = 2; } ``` -This zone of temporary unusability of a variable (from the beginning of the code block till `let`) is sometimes called the "dead zone". +Tato zóna dočasné nepoužitelnosti proměnné (od začátku kódového bloku do `let`) se někdy nazývá „mrtvá zóna“. diff --git a/1-js/06-advanced-functions/03-closure/7-let-scope/task.md b/1-js/06-advanced-functions/03-closure/7-let-scope/task.md index fb7445e66..07c5fd889 100644 --- a/1-js/06-advanced-functions/03-closure/7-let-scope/task.md +++ b/1-js/06-advanced-functions/03-closure/7-let-scope/task.md @@ -2,20 +2,20 @@ importance: 4 --- -# Is variable visible? +# Je proměnná viditelná? -What will be the result of this code? +Jaký bude výsledek tohoto kódu? ```js let x = 1; -function func() { +function funkce() { console.log(x); // ? let x = 2; } -func(); +funkce(); ``` -P.S. There's a pitfall in this task. The solution is not obvious. +P.S. V tomto úkolu je chyták. Řešení není očividné. diff --git a/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/solution.js b/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/solution.js index 66a149d98..fc3e21b87 100644 --- a/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/solution.js +++ b/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/solution.js @@ -1,8 +1,8 @@ -function inArray(arr) { - return x => arr.includes(x); +function vPoli(pole) { + return x => pole.includes(x); } -function inBetween(a, b) { +function mezi(a, b) { return x => (x >= a && x <= b); } \ No newline at end of file diff --git a/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/source.js b/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/source.js index 74989df28..a6efd478b 100644 --- a/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/source.js +++ b/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/source.js @@ -1,10 +1,10 @@ -let arr = [1, 2, 3, 4, 5, 6, 7]; +let pole = [1, 2, 3, 4, 5, 6, 7]; -function inBetween(a, b) { - // ...your code... +function mezi(a, b) { + // ...váš kód... } -function inArray(arr) { - // ...your code... +function vPoli(pole) { + // ...váš kód... } diff --git a/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/test.js b/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/test.js index 86d2d3b48..701dbe103 100644 --- a/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/test.js +++ b/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/test.js @@ -1,21 +1,21 @@ -describe("inArray", function() { - let arr = [1, 2, 3, 4, 5, 6, 7]; +describe("vPoli", function() { + let pole = [1, 2, 3, 4, 5, 6, 7]; - it("returns the filter for values in array", function() { + it("vrátí filtr pro hodnoty v poli", function() { - let filter = inArray(arr); - assert.isTrue(filter(5)); - assert.isFalse(filter(0)); + let filtr = vPoli(pole); + assert.isTrue(filtr(5)); + assert.isFalse(filtr(0)); }); }); -describe("inBetween", function() { +describe("mezi", function() { - it("returns the filter for values between", function() { - let filter = inBetween(3, 6); - assert.isTrue(filter(5)); - assert.isFalse(filter(0)); + it("vrátí filtr pro hodnoty mezi", function() { + let filtr = mezi(3, 6); + assert.isTrue(filtr(5)); + assert.isFalse(filtr(0)); }); }); diff --git a/1-js/06-advanced-functions/03-closure/8-filter-through-function/solution.md b/1-js/06-advanced-functions/03-closure/8-filter-through-function/solution.md index 46c5514a8..96b031c67 100644 --- a/1-js/06-advanced-functions/03-closure/8-filter-through-function/solution.md +++ b/1-js/06-advanced-functions/03-closure/8-filter-through-function/solution.md @@ -1,26 +1,26 @@ -# Filter inBetween +# Filtr mezi ```js run -function inBetween(a, b) { +function mezi(a, b) { return function(x) { return x >= a && x <= b; }; } -let arr = [1, 2, 3, 4, 5, 6, 7]; -alert( arr.filter(inBetween(3, 6)) ); // 3,4,5,6 +let pole = [1, 2, 3, 4, 5, 6, 7]; +alert( pole.filter(mezi(3, 6)) ); // 3,4,5,6 ``` -# Filter inArray +# Filtr vPoli ```js run demo -function inArray(arr) { +function vPoli(pole) { return function(x) { - return arr.includes(x); + return pole.includes(x); }; } -let arr = [1, 2, 3, 4, 5, 6, 7]; -alert( arr.filter(inArray([1, 2, 10])) ); // 1,2 +let pole = [1, 2, 3, 4, 5, 6, 7]; +alert( pole.filter(vPoli([1, 2, 10])) ); // 1,2 ``` diff --git a/1-js/06-advanced-functions/03-closure/8-filter-through-function/task.md b/1-js/06-advanced-functions/03-closure/8-filter-through-function/task.md index d1c39f949..d88618381 100644 --- a/1-js/06-advanced-functions/03-closure/8-filter-through-function/task.md +++ b/1-js/06-advanced-functions/03-closure/8-filter-through-function/task.md @@ -2,28 +2,28 @@ importance: 5 --- -# Filter through function +# Filtrace pomocí funkce -We have a built-in method `arr.filter(f)` for arrays. It filters all elements through the function `f`. If it returns `true`, then that element is returned in the resulting array. +Pro pole máme vestavěnou metodu `pole.filter(f)`, která filtruje všechny prvky pomocí funkce `f`. Jestliže `f` vrátí `true`, bude prvek vrácen ve výsledném poli. -Make a set of "ready to use" filters: +Vytvořte sadu filtrů „připravených k použití“: -- `inBetween(a, b)` -- between `a` and `b` or equal to them (inclusively). -- `inArray([...])` -- in the given array. +- `mezi(a, b)` -- mezi `a` a `b` nebo rovno některému z nich (inkluzívně). +- `vPoli([...])` -- v zadaném poli. -The usage must be like this: +Použití musí být následující: -- `arr.filter(inBetween(3,6))` -- selects only values between 3 and 6. -- `arr.filter(inArray([1,2,3]))` -- selects only elements matching with one of the members of `[1,2,3]`. +- `pole.filter(mezi(3,6))` -- vybere jen hodnoty mezi 3 a 6. +- `pole.filter(vPoli([1,2,3]))` -- vybere jen prvky, které se rovnají některému z prvků pole `[1,2,3]`. -For instance: +Například: ```js -/* .. your code for inBetween and inArray */ -let arr = [1, 2, 3, 4, 5, 6, 7]; +/* .. váš kód funkcí mezi a vPoli */ +let pole = [1, 2, 3, 4, 5, 6, 7]; -alert( arr.filter(inBetween(3, 6)) ); // 3,4,5,6 +alert( pole.filter(mezi(3, 6)) ); // 3,4,5,6 -alert( arr.filter(inArray([1, 2, 10])) ); // 1,2 +alert( pole.filter(vPoli([1, 2, 10])) ); // 1,2 ``` diff --git a/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/solution.js b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/solution.js index 8a71c869d..db749fdfd 100644 --- a/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/solution.js +++ b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/solution.js @@ -1,3 +1,3 @@ -function byField(fieldName){ - return (a, b) => a[fieldName] > b[fieldName] ? 1 : -1; +function podleVlastnosti(názevVlastnosti){ + return (a, b) => a[názevVlastnosti] > b[názevVlastnosti] ? 1 : -1; } diff --git a/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/source.js b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/source.js index 23b433834..7721d03e2 100644 --- a/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/source.js +++ b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/source.js @@ -1,5 +1,5 @@ -function byField(fieldName){ +function podleVlastnosti(názevVlastnosti){ - // Your code goes here. + // Sem přijde váš kód. } diff --git a/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/test.js b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/test.js index 802f28c4d..62567103a 100644 --- a/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/test.js +++ b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/test.js @@ -1,39 +1,39 @@ -describe("byField", function(){ +describe("podleVlastnosti", function(){ - let users = [ - { name: "John", age: 20, surname: "Johnson" }, - { name: "Pete", age: 18, surname: "Peterson" }, - { name: "Ann", age: 19, surname: "Hathaway" }, + let uživatelé = [ + { jméno: "Jan", věk: 20, příjmení: "Janík" }, + { jméno: "Petr", věk: 18, příjmení: "Petřík" }, + { jméno: "Anna", věk: 19, příjmení: "Hadrabová" }, ]; - it("sorts users by name", function(){ - let nameSortedKey = [ - { name: "Ann", age: 19, surname: "Hathaway" }, - { name: "John", age: 20, surname: "Johnson"}, - { name: "Pete", age: 18, surname: "Peterson" }, + it("seřadíme uživatele podle jména", function(){ + let seřazeníPodleJménaKlíč = [ + { jméno: "Anna", věk: 19, příjmení: "Hadrabová" }, + { jméno: "Jan", věk: 20, příjmení: "Janík"}, + { jméno: "Petr", věk: 18, příjmení: "Petřík" }, ]; - let nameSortedAnswer = users.sort(byField("name")); - assert.deepEqual(nameSortedKey, nameSortedAnswer); + let seřazeníPodleJménaOdpověď = uživatelé.sort(podleVlastnosti("jméno")); + assert.deepEqual(seřazeníPodleJménaKlíč, seřazeníPodleJménaOdpověď); }); - it("sorts users by age", function(){ - let ageSortedKey = [ - { name: "Pete", age: 18, surname: "Peterson" }, - { name: "Ann", age: 19, surname: "Hathaway" }, - { name: "John", age: 20, surname: "Johnson"}, + it("seřadíme uživatele podle věku", function(){ + let seřazeníPodleVěkuKlíč = [ + { jméno: "Petr", věk: 18, příjmení: "Petřík" }, + { jméno: "Anna", věk: 19, příjmení: "Hadrabová" }, + { jméno: "Jan", věk: 20, příjmení: "Janík"}, ]; - let ageSortedAnswer = users.sort(byField("age")); - assert.deepEqual(ageSortedKey, ageSortedAnswer); + let seřazeníPodleVěkuOdpověď = uživatelé.sort(podleVlastnosti("věk")); + assert.deepEqual(seřazeníPodleVěkuKlíč, seřazeníPodleVěkuOdpověď); }); - it("sorts users by surname", function(){ - let surnameSortedKey = [ - { name: "Ann", age: 19, surname: "Hathaway" }, - { name: "John", age: 20, surname: "Johnson"}, - { name: "Pete", age: 18, surname: "Peterson" }, + it("seřadíme uživatele podle příjmení", function(){ + let seřazeníPodlePříjmeníKlíč = [ + { jméno: "Anna", věk: 19, příjmení: "Hadrabová" }, + { jméno: "Jan", věk: 20, příjmení: "Janík"}, + { jméno: "Petr", věk: 18, příjmení: "Petřík" }, ]; - let surnameSortedAnswer = users.sort(byField("surname")); - assert.deepEqual(surnameSortedAnswer, surnameSortedKey); + let seřazeníPodlePříjmeníOdpověď = uživatelé.sort(podleVlastnosti("příjmení")); + assert.deepEqual(seřazeníPodlePříjmeníOdpověď, seřazeníPodlePříjmeníKlíč); }); }); diff --git a/1-js/06-advanced-functions/03-closure/9-sort-by-field/solution.md b/1-js/06-advanced-functions/03-closure/9-sort-by-field/solution.md index 8b1378917..e69de29bb 100644 --- a/1-js/06-advanced-functions/03-closure/9-sort-by-field/solution.md +++ b/1-js/06-advanced-functions/03-closure/9-sort-by-field/solution.md @@ -1 +0,0 @@ - diff --git a/1-js/06-advanced-functions/03-closure/9-sort-by-field/task.md b/1-js/06-advanced-functions/03-closure/9-sort-by-field/task.md index 08fb5cc34..517f0aefc 100644 --- a/1-js/06-advanced-functions/03-closure/9-sort-by-field/task.md +++ b/1-js/06-advanced-functions/03-closure/9-sort-by-field/task.md @@ -2,35 +2,35 @@ importance: 5 --- -# Sort by field +# Řazení podle vlastnosti -We've got an array of objects to sort: +Máme pole objektů, které chceme seřadit: ```js -let users = [ - { name: "John", age: 20, surname: "Johnson" }, - { name: "Pete", age: 18, surname: "Peterson" }, - { name: "Ann", age: 19, surname: "Hathaway" } +let uživatelé = [ + { jméno: "Jan", věk: 20, příjmení: "Janík" }, + { jméno: "Petr", věk: 18, příjmení: "Petřík" }, + { jméno: "Anna", věk: 19, příjmení: "Hadrabová" } ]; ``` -The usual way to do that would be: +Obvyklý způsob, jak to udělat, by byl: ```js -// by name (Ann, John, Pete) -users.sort((a, b) => a.name > b.name ? 1 : -1); +// podle jména (Anna, Jan, Petr) +uživatelé.sort((a, b) => a.jméno > b.jméno ? 1 : -1); -// by age (Pete, Ann, John) -users.sort((a, b) => a.age > b.age ? 1 : -1); +// podle věku (Petr, Anna, Jan) +uživatelé.sort((a, b) => a.věk > b.věk ? 1 : -1); ``` -Can we make it even less verbose, like this? +Můžeme to učinit ještě stručněji, například takto? ```js -users.sort(byField('name')); -users.sort(byField('age')); +uživatelé.sort(podleVlastnosti('jméno')); +uživatelé.sort(podleVlastnosti('věk')); ``` -So, instead of writing a function, just put `byField(fieldName)`. +Místo psaní funkce tedy jednoduše napíšeme `podleVlastnosti(názevVlastnosti)`. -Write the function `byField` that can be used for that. +Napište funkci `podleVlastnosti`, kterou k tomu můžeme použít. diff --git a/1-js/06-advanced-functions/03-closure/article.md b/1-js/06-advanced-functions/03-closure/article.md index cb43a7968..edbc7b343 100644 --- a/1-js/06-advanced-functions/03-closure/article.md +++ b/1-js/06-advanced-functions/03-closure/article.md @@ -1,388 +1,387 @@ +# Oblast platnosti proměnné, uzávěr -# Variable scope, closure +JavaScript je značně funkcionálně orientovaný jazyk. Dává nám velké množství svobody. Funkci můžeme kdykoli vytvořit, předat ji jako argument jiné funkci a později ji volat z úplně jiného místa kódu. -JavaScript is a very function-oriented language. It gives us a lot of freedom. A function can be created at any moment, passed as an argument to another function, and then called from a totally different place of code later. +Víme již, že funkce může přistupovat k proměnným, které leží mimo ni (k „vnějším“ proměnným). -We already know that a function can access variables outside of it ("outer" variables). +Co se však stane, když se po vytvoření funkce vnější proměnné změní? Dostanou se do funkce jejich nové, nebo staré hodnoty? -But what happens if outer variables change since a function is created? Will the function get newer values or the old ones? +A co když je funkce předána jako argument a pak je volána z jiného místa kódu? Bude mít na novém místě přístup k vnějším proměnným? -And what if a function is passed along as an argument and called from another place of code, will it get access to outer variables at the new place? +Rozšiřme si znalosti, abychom porozuměli těmto i složitějším scénářům. -Let's expand our knowledge to understand these scenarios and more complex ones. +```smart header="Zde budeme hovořit o proměnných deklarovaných pomocí `let/const`" +V JavaScriptu jsou tři způsoby, jak deklarovat proměnnou: `let`, `const` (tyto dva jsou moderní) a `var` (pozůstatek minulosti). -```smart header="We'll talk about `let/const` variables here" -In JavaScript, there are 3 ways to declare a variable: `let`, `const` (the modern ones), and `var` (the remnant of the past). - -- In this article we'll use `let` variables in examples. -- Variables, declared with `const`, behave the same, so this article is about `const` too. -- The old `var` has some notable differences, they will be covered in the article . +- V tomto článku budeme v příkladech používat proměnné deklarované pomocí `let`. +- Proměnné deklarované pomocí `const` se chovají stejně, takže tento článek platí i pro `const`. +- Starý příkaz `var` má určité významné rozdíly, které probereme v článku . ``` -## Code blocks +## Kódové bloky -If a variable is declared inside a code block `{...}`, it's only visible inside that block. +Jestliže je proměnná deklarována uvnitř kódového bloku `{...}`, je viditelná jedině uvnitř tohoto bloku. -For example: +Příklad: ```js run { - // do some job with local variables that should not be seen outside + // provedeme nějakou práci s lokálními proměnnými, které nemají být vidět zvenčí - let message = "Hello"; // only visible in this block + let zpráva = "Ahoj"; // je viditelná jen v tomto bloku - alert(message); // Hello + alert(zpráva); // Ahoj } -alert(message); // Error: message is not defined +alert(zpráva); // Chyba: zpráva není definována ``` -We can use this to isolate a piece of code that does its own task, with variables that only belong to it: +Díky tomu můžeme izolovat část kódu, která odvede svou vlastní práci, s proměnnými, které budou patřit pouze jí: ```js run { - // show message - let message = "Hello"; - alert(message); + // zobrazí zprávu + let zpráva = "Ahoj"; + alert(zpráva); } { - // show another message - let message = "Goodbye"; - alert(message); + // zobrazí jinou zprávu + let zpráva = "Na shledanou"; + alert(zpráva); } ``` -````smart header="There'd be an error without blocks" -Please note, without separate blocks there would be an error, if we use `let` with the existing variable name: +````smart header="Bez bloků by nastala chyba" +Prosíme všimněte si, že bez oddělených bloků by nastala chyba, kdybychom použili `let` s již existujícím názvem proměnné: ```js run -// show message -let message = "Hello"; -alert(message); +// zobrazí zprávu +let zpráva = "Ahoj"; +alert(zpráva); -// show another message +// zobrazí jinou zprávu *!* -let message = "Goodbye"; // Error: variable already declared +let zpráva = "Na shledanou"; // Chyba: proměnná je již deklarována */!* -alert(message); +alert(zpráva); ``` ```` -For `if`, `for`, `while` and so on, variables declared in `{...}` are also only visible inside: +Také pro `if`, `for`, `while` a podobné jsou proměnné deklarované v `{...}` viditelné jedině uvnitř: ```js run if (true) { - let phrase = "Hello!"; + let věta = "Ahoj!"; - alert(phrase); // Hello! + alert(věta); // Ahoj! } -alert(phrase); // Error, no such variable! +alert(věta); // Chyba, taková proměnná neexistuje! ``` -Here, after `if` finishes, the `alert` below won't see the `phrase`, hence the error. +Zde po skončení `if` funkce `alert` pod ním neuvidí proměnnou `věta`, takže nastane chyba. -That's great, as it allows us to create block-local variables, specific to an `if` branch. +To je skvělé, protože nám to umožňuje vytvářet blokově lokální proměnné, specifické pro větev `if`. -The similar thing holds true for `for` and `while` loops: +Podobně to platí pro cykly `for` a `while`: ```js run for (let i = 0; i < 3; i++) { - // the variable i is only visible inside this for - alert(i); // 0, then 1, then 2 + // proměnná i je viditelná jen uvnitř tohoto cyklu for + alert(i); // 0, pak 1, pak 2 } -alert(i); // Error, no such variable +alert(i); // Chyba, taková proměnná neexistuje ``` -Visually, `let i` is outside of `{...}`. But the `for` construct is special here: the variable, declared inside it, is considered a part of the block. +Vizuálně je `let i` mimo `{...}`, avšak konstrukt `for` je v tomto ohledu speciální: proměnná, která je deklarována uvnitř něj, se považuje za součást bloku. -## Nested functions +## Vnořené funkce -A function is called "nested" when it is created inside another function. +Funkce se nazývá „vnořená“, když je vytvořena uvnitř jiné funkce. -It is easily possible to do this with JavaScript. +V JavaScriptu je to snadno možné. -We can use it to organize our code, like this: +Můžeme to využít k organizaci našeho kódu, například takto: ```js -function sayHiBye(firstName, lastName) { +function řekniAhojNashle(křestníJméno, příjmení) { - // helper nested function to use below - function getFullName() { - return firstName + " " + lastName; + // pomocná vnořená funkce, kterou použijeme níže + function vraťCeléJméno() { + return křestníJméno + " " + příjmení; } - alert( "Hello, " + getFullName() ); - alert( "Bye, " + getFullName() ); + alert( "Ahoj, " + vraťCeléJméno() ); + alert( "Nashle, " + vraťCeléJméno() ); } ``` -Here the *nested* function `getFullName()` is made for convenience. It can access the outer variables and so can return the full name. Nested functions are quite common in JavaScript. +Zde je *vnořená* funkce `vraťCeléJméno()` vytvořena pro naše pohodlí. Může přistupovat k vnějším proměnným, a tak může vrátit celé jméno. Vnořené funkce jsou v JavaScriptu poměrně běžné. -What's much more interesting, a nested function can be returned: either as a property of a new object or as a result by itself. It can then be used somewhere else. No matter where, it still has access to the same outer variables. +Ještě zajímavější je, že vnořenou funkci můžeme vrátit: buď jako vlastnost nového objektu, nebo jako samotný výsledek funkce. Pak ji můžeme použít někde jinde. Ať to bude kdekoli, stále bude mít přístup ke stejným vnějším proměnným. -Below, `makeCounter` creates the "counter" function that returns the next number on each invocation: +V následujícím příkladu `vytvořČítač` vytvoří funkci „čítače“, která při každém zavolání vrátí další číslo: ```js run -function makeCounter() { - let count = 0; +function vytvořČítač() { + let počet = 0; return function() { - return count++; + return počet++; }; } -let counter = makeCounter(); +let čítač = vytvořČítač(); -alert( counter() ); // 0 -alert( counter() ); // 1 -alert( counter() ); // 2 +alert( čítač() ); // 0 +alert( čítač() ); // 1 +alert( čítač() ); // 2 ``` -Despite being simple, slightly modified variants of that code have practical uses, for instance, as a [random number generator](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) to generate random values for automated tests. +Mírně upravené varianty tohoto kódu, třebaže jsou jednoduché, mají praktické využití, například jako [generátor pseudonáhodných čísel](https://cs.wikipedia.org/wiki/Generátor_pseudonáhodných_čísel), který generuje náhodné hodnoty pro automatizované testy. -How does this work? If we create multiple counters, will they be independent? What's going on with the variables here? +Jak to funguje? Když vytvoříme více čítačů, budou nezávislé? Co se bude dít se zdejšími proměnnými? -Understanding such things is great for the overall knowledge of JavaScript and beneficial for more complex scenarios. So let's go a bit in-depth. +Porozumět takovým věcem je skvělé pro všeobecnou znalost JavaScriptu a vyplatí se při složitějších scénářích. Pojďme tedy trochu do hloubky. -## Lexical Environment +## Lexikální prostředí -```warn header="Here be dragons!" -The in-depth technical explanation lies ahead. +```warn header="Zde jsou draci!" +Před námi leží hlubší technické vysvětlení. -As far as I'd like to avoid low-level language details, any understanding without them would be lacking and incomplete, so get ready. +Jakkoli se snažím vyhnout se nízkoúrovňovým detailům jazyka, bez nich by porozumění bylo děravé a neúplné, takže se na ně připravte. ``` -For clarity, the explanation is split into multiple steps. +Aby to bylo jasnější, rozdělíme vysvětlení na několik kroků. -### Step 1. Variables +### Krok 1. Proměnné -In JavaScript, every running function, code block `{...}`, and the script as a whole have an internal (hidden) associated object known as the *Lexical Environment*. +V JavaScriptu je ke každé spuštěné funkci, kódovému bloku `{...}` i celému skriptu připojen interní (skrytý) objekt, nazývaný *lexikální prostředí*. -The Lexical Environment object consists of two parts: +Objekt lexikálního prostředí se skládá ze dvou částí: -1. *Environment Record* -- an object that stores all local variables as its properties (and some other information like the value of `this`). -2. A reference to the *outer lexical environment*, the one associated with the outer code. +1. *Záznam prostředí* -- objekt, v němž jsou uloženy všechny lokální proměnné jako jeho vlastnosti (a některé další informace, např. hodnota `this`). +2. Odkaz na *vnější lexikální prostředí*, tedy to, které je spojeno s vnějším kódem. -**A "variable" is just a property of the special internal object, `Environment Record`. "To get or change a variable" means "to get or change a property of that object".** +**„Proměnná“ je jen vlastnost speciálního interního objektu, `záznamu prostředí`. „Načíst nebo změnit proměnnou“ znamená „načíst nebo změnit vlastnost tohoto objektu“.** -In this simple code without functions, there is only one Lexical Environment: +V tomto jednoduchém kódu bez funkcí existuje pouze jedno lexikální prostředí: -![lexical environment](lexical-environment-global.svg) +![lexikální prostředí](lexical-environment-global.svg) -This is the so-called *global* Lexical Environment, associated with the whole script. +To je tzv. *globální* lexikální prostředí, připojené k celému skriptu. -On the picture above, the rectangle means Environment Record (variable store) and the arrow means the outer reference. The global Lexical Environment has no outer reference, that's why the arrow points to `null`. +Obdélník v uvedeném obrázku znamená záznam prostředí (skladiště proměnných) a šipka znamená odkaz na vnější prostředí. Globální lexikální prostředí nemá žádný odkaz na vnější prostředí, proto šipka ukazuje na `null`. -As the code starts executing and goes on, the Lexical Environment changes. +Když se kód začne provádět, lexikální prostředí se s jeho během mění. -Here's a little bit longer code: +Zde je trochu delší kód: -![lexical environment](closure-variable-phrase.svg) +![lexikální prostředí](closure-variable-phrase.svg) -Rectangles on the right-hand side demonstrate how the global Lexical Environment changes during the execution: +Obdélníky napravo ukazují, jak se globální lexikální prostředí mění během provádění kódu: -1. When the script starts, the Lexical Environment is pre-populated with all declared variables. - - Initially, they are in the "Uninitialized" state. That's a special internal state, it means that the engine knows about the variable, but it cannot be referenced until it has been declared with `let`. It's almost the same as if the variable didn't exist. -2. Then `let phrase` definition appears. There's no assignment yet, so its value is `undefined`. We can use the variable from this point forward. -3. `phrase` is assigned a value. -4. `phrase` changes the value. +1. Když se skript spustí, lexikální prostředí se obsadí všemi deklarovanými proměnnými. + - Na začátku jsou ve stavu „neinicializováno“. To je speciální vnitřní stav, který znamená, že motor ví o proměnné, ale nelze se na ni odkazovat, dokud nebude deklarována pomocí `let`. Je to skoro totéž, jako by proměnná neexistovala. +2. Pak se objeví definice `let věta`. Zatím zde není žádné přiřazení, takže hodnota proměnné je `undefined`. Od této chvíle můžeme tuto proměnnou používat. +3. Do proměnné `věta` je přiřazena hodnota. +4. Hodnota proměnné `věta` se změní. -Everything looks simple for now, right? +Prozatím to všechno vypadá jednoduše, že? -- A variable is a property of a special internal object, associated with the currently executing block/function/script. -- Working with variables is actually working with the properties of that object. +- Proměnná je vlastností speciálního interního objektu, připojeného k právě vykonávanému bloku/funkci/skriptu. +- Práce s proměnnými je ve skutečnosti práce s vlastnostmi tohoto objektu. -```smart header="Lexical Environment is a specification object" -"Lexical Environment" is a specification object: it only exists "theoretically" in the [language specification](https://tc39.es/ecma262/#sec-lexical-environments) to describe how things work. We can't get this object in our code and manipulate it directly. +```smart header="Lexikální prostředí je objekt ze specifikace" +„Lexikální prostředí“ je objekt ze specifikace: existuje jen „teoreticky“ ve [specifikaci jazyka](https://tc39.es/ecma262/#sec-lexical-environments), aby popisoval, jak vše funguje. V našem kódu nemůžeme tento objekt získat a přímo s ním manipulovat. -JavaScript engines also may optimize it, discard variables that are unused to save memory and perform other internal tricks, as long as the visible behavior remains as described. +Motory JavaScriptu jej také mohou optimalizovat, vyřazovat nepoužívané proměnné, aby ušetřily paměť, a provádět jiné vnitřní triky, pokud jeho viditelné chování zůstává takové, jak je zde popsáno. ``` -### Step 2. Function Declarations +### Krok 2. Deklarace funkcí -A function is also a value, like a variable. +Funkce je také hodnota, stejně jako proměnná. -**The difference is that a Function Declaration is instantly fully initialized.** +**Rozdíl je v tom, že při deklaraci je funkce okamžitě plně inicializována.** -When a Lexical Environment is created, a Function Declaration immediately becomes a ready-to-use function (unlike `let`, that is unusable till the declaration). +Když je vytvořeno lexikální prostředí, deklarace funkce okamžitě vytvoří funkci připravenou k použití (na rozdíl od proměnné v `let`, která je před deklarací nepoužitelná). -That's why we can use a function, declared as Function Declaration, even before the declaration itself. +Z tohoto důvodu můžeme používat funkci, deklarovanou deklarací funkce, ještě před samotnou deklarací. -For example, here's the initial state of the global Lexical Environment when we add a function: +Například zde je úvodní stav globálního lexikálního prostředí, když přidáme funkci: ![](closure-function-declaration.svg) -Naturally, this behavior only applies to Function Declarations, not Function Expressions where we assign a function to a variable, such as `let say = function(name)...`. +Pochopitelně toto chování platí jen pro deklarace funkcí, ne pro funkční výrazy, v nichž přiřazujeme funkci do proměnné, například `let řekni = function(jméno)...`. -### Step 3. Inner and outer Lexical Environment +### Krok 3. Vnitřní a vnější lexikální prostředí -When a function runs, at the beginning of the call, a new Lexical Environment is created automatically to store local variables and parameters of the call. +Když se spustí funkce, na začátku jejího volání je automaticky vytvořeno nové lexikální prostředí, do něhož se ukládají lokální proměnné a parametry volání. -For instance, for `say("John")`, it looks like this (the execution is at the line, labelled with an arrow): +Například pro `řekni("Jan")` vypadá takto (běh je na řádku označeném šipkou): ![](lexical-environment-simple.svg) -During the function call we have two Lexical Environments: the inner one (for the function call) and the outer one (global): +Během volání funkce máme dvě lexikální prostředí: vnitřní (pro volání funkce) a vnější (globální): -- The inner Lexical Environment corresponds to the current execution of `say`. It has a single property: `name`, the function argument. We called `say("John")`, so the value of the `name` is `"John"`. -- The outer Lexical Environment is the global Lexical Environment. It has the `phrase` variable and the function itself. +- Vnitřní lexikální prostředí odpovídá aktuálnímu běhu funkce `řekni`. Má jedinou vlastnost: `jméno`, argument funkce. Voláme ji `řekni("Jan")`, takže hodnota vlastnosti `jméno` je `"Jan"`. +- Vnější lexikální prostředí je globální lexikální prostředí. Má proměnnou `věta` a samotnou funkci. -The inner Lexical Environment has a reference to the `outer` one. +Vnitřní lexikální prostředí obsahuje odkaz `outer` na vnější. -**When the code wants to access a variable -- the inner Lexical Environment is searched first, then the outer one, then the more outer one and so on until the global one.** +**Když kód chce přistupovat k proměnné -- nejprve se prohledá vnitřní lexikální prostředí, pak vnější, pak ještě vnější a tak dále, až ke globálnímu.** -If a variable is not found anywhere, that's an error in strict mode (without `use strict`, an assignment to a non-existing variable creates a new global variable, for compatibility with old code). +Není-li proměnná nikde nalezena, ve striktním režimu nastane chyba (bez `use strict` přiřazení do neexistující proměnné vytvoří novou globální proměnnou, aby byla zachována kompatibilita se starým kódem). -In this example the search proceeds as follows: +V tomto příkladu hledání postupuje následovně: -- For the `name` variable, the `alert` inside `say` finds it immediately in the inner Lexical Environment. -- When it wants to access `phrase`, then there is no `phrase` locally, so it follows the reference to the outer Lexical Environment and finds it there. +- Co se týče proměnné `jméno`, `alert` uvnitř `řekni` ji najde okamžitě ve vnitřním lexikálním prostředí. +- Když chce přistupovat k proměnné `věta`, pak lokálně žádnou proměnnou `věta` nenajde, takže pokračuje odkazem na vnější lexikální prostředí a najde ji v něm. -![lexical environment lookup](lexical-environment-simple-lookup.svg) +![náhled na lexikální prostředí](lexical-environment-simple-lookup.svg) -### Step 4. Returning a function +### Krok 4. Vrácení funkce -Let's return to the `makeCounter` example. +Vraťme se k příkladu `vytvořČítač`. ```js -function makeCounter() { - let count = 0; +function vytvořČítač() { + let počet = 0; return function() { - return count++; + return počet++; }; } -let counter = makeCounter(); +let čítač = vytvořČítač(); ``` -At the beginning of each `makeCounter()` call, a new Lexical Environment object is created, to store variables for this `makeCounter` run. +Na začátku každého volání `vytvořČítač()` se vytvoří nový objekt lexikálního prostředí, do něhož se uloží proměnné pro tento běh funkce `vytvořČítač`. -So we have two nested Lexical Environments, just like in the example above: +Máme tedy dvě vnořená lexikální prostředí, podobně jako ve výše uvedeném příkladu: ![](closure-makecounter.svg) -What's different is that, during the execution of `makeCounter()`, a tiny nested function is created of only one line: `return count++`. We don't run it yet, only create. +Rozdíl spočívá v tom, že během provádění funkce `vytvořČítač()` se vytvoří drobná vnořená funkce tvořená jediným řádkem: `return počet++`. Tuto funkci zatím nevoláme, jenom ji vytvoříme. -All functions remember the Lexical Environment in which they were made. Technically, there's no magic here: all functions have the hidden property named `[[Environment]]`, that keeps the reference to the Lexical Environment where the function was created: +Všechny funkce si pamatují lexikální prostředí, v němž byly vytvořeny. Technicky v tom není nic magického: všechny funkce mají skrytou vlastnost jménem `[[Environment]]`, která si udržuje odkaz na lexikální prostředí, v němž byla funkce vytvořena: ![](closure-makecounter-environment.svg) -So, `counter.[[Environment]]` has the reference to `{count: 0}` Lexical Environment. That's how the function remembers where it was created, no matter where it's called. The `[[Environment]]` reference is set once and forever at function creation time. +Takže `čítač.[[Environment]]` má odkaz na lexikální prostředí `{počet: 0}`. Tímto způsobem si funkce pamatuje, kde byla vytvořena, bez ohledu na to, kde je volána. Odkaz `[[Environment]]` se při vytvoření funkce nastaví jednou provždy. -Later, when `counter()` is called, a new Lexical Environment is created for the call, and its outer Lexical Environment reference is taken from `counter.[[Environment]]`: +Když je `čítač()` později volán, vytvoří se pro toto volání nové lexikální prostředí a odkaz na jeho vnější lexikální prostředí se převezme z `čítač.[[Environment]]`: ![](closure-makecounter-nested-call.svg) -Now when the code inside `counter()` looks for `count` variable, it first searches its own Lexical Environment (empty, as there are no local variables there), then the Lexical Environment of the outer `makeCounter()` call, where it finds and changes it. +Když nyní kód uvnitř funkce `čítač()` hledá proměnnou `počet`, nejprve prohledá své vlastní lexikální prostředí (prázdné, jelikož tady nejsou žádné lokální proměnné), pak lexikální prostředí vnějšího volání `vytvořČítač()`, kde ji najde a změní. -**A variable is updated in the Lexical Environment where it lives.** +**Proměnná je změněna v lexikálním prostředí, v němž přebývá.** -Here's the state after the execution: +Zde je stav po provedení funkce: ![](closure-makecounter-nested-call-2.svg) -If we call `counter()` multiple times, the `count` variable will be increased to `2`, `3` and so on, at the same place. +Jestliže voláme `čítač()` vícekrát, proměnná `počet` se zvýší na `2`, `3` a tak dále, a to na stejném místě. -```smart header="Closure" -There is a general programming term "closure", that developers generally should know. +```smart header="Uzávěr" +Existuje obecný programovací pojem „uzávěr“, který by vývojáři obecně měli znát. -A [closure](https://en.wikipedia.org/wiki/Closure_(computer_programming)) is a function that remembers its outer variables and can access them. In some languages, that's not possible, or a function should be written in a special way to make it happen. But as explained above, in JavaScript, all functions are naturally closures (there is only one exception, to be covered in ). +[Uzávěr](https://cs.wikipedia.org/wiki/Uz%C3%A1v%C4%9Br_(programov%C3%A1n%C3%AD)) je funkce, která si pamatuje své vnější proměnné a může k nim přistupovat. V některých jazycích to není možné nebo funkce musí být napsána speciálním způsobem, aby se to mohlo dít. Ale jak bylo vysvětleno výše, v JavaScriptu jsou všechny funkce přirozeně uzávěry (je tady jen jedna výjimka, kterou probereme v kapitole ). -That is: they automatically remember where they were created using a hidden `[[Environment]]` property, and then their code can access outer variables. +To znamená: pomocí skryté vlastnosti `[[Environment]]` si automaticky pamatují, kde byly vytvořeny, a jejich kód pak může přistupovat k vnějším proměnným. -When on an interview, a frontend developer gets a question about "what's a closure?", a valid answer would be a definition of the closure and an explanation that all functions in JavaScript are closures, and maybe a few more words about technical details: the `[[Environment]]` property and how Lexical Environments work. +Kdyby front-end vývojář v rozhovoru dostal otázku „co je to uzávěr?“, správná odpověď by byla definice uzávěru a vysvětlení, že v JavaScriptu jsou všechny funkce uzávěry, a možná několik dalších slov o technických detailech: o vlastnosti `[[Environment]]` a o tom, jak fungují lexikální prostředí. ``` -## Garbage collection +## Sběr odpadků -Usually, a Lexical Environment is removed from memory with all the variables after the function call finishes. That's because there are no references to it. As any JavaScript object, it's only kept in memory while it's reachable. +Lexikální prostředí funkce je zpravidla odstraněno z paměti i se všemi proměnnými poté, co volání funkce skončí. Je to proto, že pak už na ně neexistují žádné odkazy. Stejně jako všechny objekty v JavaScriptu je udržováno v paměti, jen dokud je dosažitelné. -However, if there's a nested function that is still reachable after the end of a function, then it has `[[Environment]]` property that references the lexical environment. +Jestliže však existuje vnořená funkce, která je po skončení funkce stále dosažitelná, pak tato funkce má vlastnost `[[Environment]]`, která se na toto lexikální prostředí odkazuje. -In that case the Lexical Environment is still reachable even after the completion of the function, so it stays alive. +V takovém případě je lexikální prostředí stále dostupné i po skončení funkce, takže bude nadále existovat. -For example: +Například: ```js function f() { - let value = 123; + let hodnota = 123; return function() { - alert(value); + alert(hodnota); } } -let g = f(); // g.[[Environment]] stores a reference to the Lexical Environment -// of the corresponding f() call +let g = f(); // g.[[Environment]] si uloží odkaz na lexikální prostředí + // příslušného volání f() ``` -Please note that if `f()` is called many times, and resulting functions are saved, then all corresponding Lexical Environment objects will also be retained in memory. In the code below, all 3 of them: +Prosíme všimněte si, že je-li `f()` volána mnohokrát a výsledné funkce jsou někam uloženy, pak zůstanou v paměti i všechny příslušné objekty lexikálních prostředí. V následujícím kódu to budou všechny tři: ```js function f() { - let value = Math.random(); + let hodnota = Math.random(); - return function() { alert(value); }; + return function() { alert(hodnota); }; } -// 3 functions in array, every one of them links to Lexical Environment -// from the corresponding f() run -let arr = [f(), f(), f()]; +// 3 funkce v poli, každá z nich se odkazuje na lexikální prostředí +// z příslušného spuštění f() +let pole = [f(), f(), f()]; ``` -A Lexical Environment object dies when it becomes unreachable (just like any other object). In other words, it exists only while there's at least one nested function referencing it. +Objekt lexikálního prostředí je zničen, když se stane nedosažitelným (stejně jako každý jiný objekt). Jinými slovy, bude existovat, jen dokud bude existovat nejméně jedna vnořená funkce, která se na něj odkazuje. -In the code below, after the nested function is removed, its enclosing Lexical Environment (and hence the `value`) is cleaned from memory: +V následujícím kódu je po odstranění vnořené funkce její uzavírající lexikální prostředí (a tedy i `hodnota`) vymazáno z paměti: ```js function f() { - let value = 123; + let hodnota = 123; return function() { - alert(value); + alert(hodnota); } } -let g = f(); // while g function exists, the value stays in memory +let g = f(); // dokud existuje funkce g, hodnota zůstane v paměti -g = null; // ...and now the memory is cleaned up +g = null; // ...a nyní bude paměť pročištěna ``` -### Real-life optimizations +### Optimalizace v reálném životě -As we've seen, in theory while a function is alive, all outer variables are also retained. +Jak jsme viděli, teoreticky dokud funkce existuje, jsou udržovány i všechny vnější proměnné. -But in practice, JavaScript engines try to optimize that. They analyze variable usage and if it's obvious from the code that an outer variable is not used -- it is removed. +V praxi se však JavaScriptové motory snaží o optimalizaci. Analyzují používání proměnných, a je-li z kódu zřejmé, že vnější proměnná není nikde použita, bude odstraněna. -**An important side effect in V8 (Chrome, Edge, Opera) is that such variable will become unavailable in debugging.** +**Důležitý vedlejší efekt ve V8 (Chrome, Edge, Opera) je, že taková proměnná přestane být dostupná při ladění.** -Try running the example below in Chrome with the Developer Tools open. +Zkuste si spustit níže uvedený příklad v Chrome s otevřenými vývojářskými nástroji. -When it pauses, in the console type `alert(value)`. +Když se zastaví, v konzoli zadejte `alert(hodnota)`. ```js run function f() { - let value = Math.random(); + let hodnota = Math.random(); function g() { - debugger; // in console: type alert(value); No such variable! + debugger; // v konzoli zadejte: alert(hodnota); taková proměnná neexistuje! } return g; @@ -392,18 +391,18 @@ let g = f(); g(); ``` -As you could see -- there is no such variable! In theory, it should be accessible, but the engine optimized it out. +Jak vidíme -- taková proměnná neexistuje! Teoreticky by měla být dostupná, ale motor ji vyřadil při optimalizaci. -That may lead to funny (if not such time-consuming) debugging issues. One of them -- we can see a same-named outer variable instead of the expected one: +To může vést k zábavným (kdyby nezabíraly tolik času) problémům při ladění. Jeden z nich -- můžeme vidět vnější proměnnou se stejným názvem namísto očekávané: ```js run global -let value = "Surprise!"; +let hodnota = "Překvapení!"; function f() { - let value = "the closest value"; + let hodnota = "nejbližší hodnota"; function g() { - debugger; // in console: type alert(value); Surprise! + debugger; // v konzoli zadejte: alert(hodnota); Překvapení! } return g; @@ -413,6 +412,6 @@ let g = f(); g(); ``` -This feature of V8 is good to know. If you are debugging with Chrome/Edge/Opera, sooner or later you will meet it. +Tuto vlastnost V8 je dobré znát. Jestliže ladíte v Chrome, Edge nebo Opeře, dříve nebo později se s ní setkáte. -That is not a bug in the debugger, but rather a special feature of V8. Perhaps it will be changed sometime. You can always check for it by running the examples on this page. +Není to chyba ladicího nástroje, ale spíše speciální vlastnost V8. Možná bude časem změněna. Vždy si ji můžete ověřit spuštěním příkladů na této stránce. diff --git a/1-js/06-advanced-functions/03-closure/lexenv-nested-makecounter-2.svg b/1-js/06-advanced-functions/03-closure/lexenv-nested-makecounter-2.svg index f37488537..8c9abe9f5 100644 --- a/1-js/06-advanced-functions/03-closure/lexenv-nested-makecounter-2.svg +++ b/1-js/06-advanced-functions/03-closure/lexenv-nested-makecounter-2.svg @@ -1 +1 @@ -makeCounter: functioncounter: undefinedcount: 0outerouternullglobal LexicalEnvironmentLexicalEnvironment of makeCounter() call \ No newline at end of file +makeCounter: functioncounter: undefinedcount: 0outerouternullglobální LexicalEnvironmentLexicalEnvironment volání makeCounter() \ No newline at end of file diff --git a/1-js/06-advanced-functions/03-closure/lexenv-nested-makecounter-6.svg b/1-js/06-advanced-functions/03-closure/lexenv-nested-makecounter-6.svg index 06d5b5060..289cacf90 100644 --- a/1-js/06-advanced-functions/03-closure/lexenv-nested-makecounter-6.svg +++ b/1-js/06-advanced-functions/03-closure/lexenv-nested-makecounter-6.svg @@ -1 +1 @@ -makeCounter: functioncounter: functioncount: 1outerouternull[[Environment]]modified here \ No newline at end of file +makeCounter: functioncounter: functioncount: 1outerouternull[[Environment]]zde změněno \ No newline at end of file diff --git a/1-js/06-advanced-functions/03-closure/lexical-environment-global-2.svg b/1-js/06-advanced-functions/03-closure/lexical-environment-global-2.svg index b6e576f0c..8572e73ab 100644 --- a/1-js/06-advanced-functions/03-closure/lexical-environment-global-2.svg +++ b/1-js/06-advanced-functions/03-closure/lexical-environment-global-2.svg @@ -1 +1 @@ -phrase: "Bye"phrase: "Hello"phrase: undefined<empty>outernullexecution start \ No newline at end of file +phrase: "Bye"phrase: "Hello"phrase: undefined<empty>outernullzačátek výkonu \ No newline at end of file diff --git a/1-js/06-advanced-functions/03-closure/lexical-environment-global-3.svg b/1-js/06-advanced-functions/03-closure/lexical-environment-global-3.svg index 1942a7e37..ec8c57a33 100644 --- a/1-js/06-advanced-functions/03-closure/lexical-environment-global-3.svg +++ b/1-js/06-advanced-functions/03-closure/lexical-environment-global-3.svg @@ -1 +1 @@ -say: function phrase: "Hello"say: functionouternullexecution start \ No newline at end of file +say: function phrase: "Hello"say: functionouternullzačátek výkonu \ No newline at end of file diff --git a/1-js/06-advanced-functions/04-var/article.md b/1-js/06-advanced-functions/04-var/article.md index 28d7a76ec..104045df6 100644 --- a/1-js/06-advanced-functions/04-var/article.md +++ b/1-js/06-advanced-functions/04-var/article.md @@ -1,287 +1,287 @@ -# The old "var" +# Starý příkaz „var“ -```smart header="This article is for understanding old scripts" -The information in this article is useful for understanding old scripts. +```smart header="Tento článek slouží k pochopení starých skriptů" +Informace v tomto článku jsou užitečné k tomu, abyste porozuměli starým skriptům. -That's not how we write new code. +Není to způsob, jak psát nový kód. ``` -In the very first chapter about [variables](info:variables), we mentioned three ways of variable declaration: +V úplně první kapitole o [proměnných](info:variables) jsme zmínili tři způsoby deklarace proměnných: 1. `let` 2. `const` 3. `var` -The `var` declaration is similar to `let`. Most of the time we can replace `let` by `var` or vice-versa and expect things to work: +Deklarace `var` je podobná `let`. Ve většině případů můžeme nahradit `let` za `var` nebo naopak a očekávat, že vše bude fungovat: ```js run -var message = "Hi"; -alert(message); // Hi +var zpráva = "Ahoj"; +alert(zpráva); // Ahoj ``` -But internally `var` is a very different beast, that originates from very old times. It's generally not used in modern scripts, but still lurks in the old ones. +Vnitřně je však `var` velmi odlišná potvůrka, která pochází z dřívějších časů. V moderních skriptech se obvykle nepoužívá, ale ve starých stále číhá. -If you don't plan on meeting such scripts you may even skip this chapter or postpone it. +Pokud neplánujete se s takovými skripty setkat, můžete tuto kapitolu přeskočit nebo odložit na později. -On the other hand, it's important to understand differences when migrating old scripts from `var` to `let`, to avoid odd errors. +Naproti tomu, když převádíte staré skripty z `var` na `let`, je důležité porozumět rozdílům, abyste se vyhnuli podivným chybám. -## "var" has no block scope +## „var“ nemá blokovou platnost -Variables, declared with `var`, are either function-scoped or global-scoped. They are visible through blocks. +Proměnné deklarované pomocí `var` mají rozsah platnosti buď funkční, nebo globální. Jsou viditelné i skrz bloky. -For instance: +Například: ```js run if (true) { - var test = true; // use "var" instead of "let" + var test = true; // použijeme „var“ namísto „let“ } *!* -alert(test); // true, the variable lives after if +alert(test); // true, proměnná existuje i za if */!* ``` -As `var` ignores code blocks, we've got a global variable `test`. +Protože `var` ignoruje kódové bloky, vytvořili jsme globální proměnnou `test`. -If we used `let test` instead of `var test`, then the variable would only be visible inside `if`: +Kdybychom použili `let test` namísto `var test`, pak by tato proměnná byla viditelná jen uvnitř `if`: ```js run if (true) { - let test = true; // use "let" + let test = true; // použijeme „let“ } *!* -alert(test); // ReferenceError: test is not defined +alert(test); // ReferenceError: test není definován */!* ``` -The same thing for loops: `var` cannot be block- or loop-local: +Totéž platí pro cykly: `var` nemůže být lokální v bloku nebo ve smyčce: ```js run for (var i = 0; i < 10; i++) { - var one = 1; + var jedna = 1; // ... } *!* -alert(i); // 10, "i" is visible after loop, it's a global variable -alert(one); // 1, "one" is visible after loop, it's a global variable +alert(i); // 10, „i“ je viditelná i za cyklem, je to globální proměnná +alert(jedna); // 1, „jedna“ je viditelná i za cyklem, je to globální proměnná */!* ``` -If a code block is inside a function, then `var` becomes a function-level variable: +Nachází-li se kódový blok uvnitř funkce, pak `var` deklaruje proměnnou na úrovni funkce: ```js run -function sayHi() { +function řekniAhoj() { if (true) { - var phrase = "Hello"; + var věta = "Ahoj"; } - alert(phrase); // works + alert(věta); // funguje } -sayHi(); -alert(phrase); // ReferenceError: phrase is not defined +řekniAhoj(); +alert(věta); // ReferenceError: věta není definována ``` -As we can see, `var` pierces through `if`, `for` or other code blocks. That's because a long time ago in JavaScript, blocks had no Lexical Environments, and `var` is a remnant of that. +Jak vidíme, `var` se probije skrz `if`, `for` a jiné kódové bloky. Je to proto, že před dlouhou dobou bloky v JavaScriptu neměly lexikální prostředí a `var` je toho pozůstatkem. -## "var" tolerates redeclarations +## „var“ toleruje opakované deklarace -If we declare the same variable with `let` twice in the same scope, that's an error: +Jestliže deklarujeme stejnou proměnnou pomocí `let` ve stejné oblasti dvakrát, nastane chyba: ```js run -let user; -let user; // SyntaxError: 'user' has already been declared +let uživatel; +let uživatel; // SyntaxError: 'uživatel' již byl deklarován ``` -With `var`, we can redeclare a variable any number of times. If we use `var` with an already-declared variable, it's just ignored: +Pomocí `var` můžeme znovu deklarovat proměnnou, kolikrát chceme. Použijeme-li `var` s již deklarovanou proměnnou, bude ignorováno: ```js run -var user = "Pete"; +var uživatel = "Petr"; -var user = "John"; // this "var" does nothing (already declared) -// ...it doesn't trigger an error +var uživatel = "Jan"; // tento „var“ neudělá nic (proměnná je již deklarována) +// ...nevyvolá chybu -alert(user); // John +alert(uživatel); // Jan ``` -## "var" variables can be declared below their use +## Pomocí „var“ můžeme proměnné deklarovat až po jejich použití -`var` declarations are processed when the function starts (or script starts for globals). +Deklarace `var` se zpracovávají, když se funkce spustí (nebo když se spustí skript, jsou-li globální). -In other words, `var` variables are defined from the beginning of the function, no matter where the definition is (assuming that the definition is not in the nested function). +Jinými slovy, proměnné deklarované pomocí `var` jsou definovány od začátku funkce bez ohledu na to, kde se jejich definice nachází (za předpokladu, že definice není uvnitř vnořené funkce). -So this code: +Takže tento kód: ```js run -function sayHi() { - phrase = "Hello"; +function řekniAhoj() { + věta = "Ahoj"; - alert(phrase); + alert(věta); *!* - var phrase; + var věta; */!* } -sayHi(); +řekniAhoj(); ``` -...Is technically the same as this (moved `var phrase` above): +...je technicky stejný jako tento (přesuneme `var věta` nahoru): ```js run -function sayHi() { +function řekniAhoj() { *!* - var phrase; + var věta; */!* - phrase = "Hello"; + věta = "Ahoj"; - alert(phrase); + alert(věta); } -sayHi(); +řekniAhoj(); ``` -...Or even as this (remember, code blocks are ignored): +...Nebo i jako tento (pamatujte, že kódové bloky jsou ignorovány): ```js run -function sayHi() { - phrase = "Hello"; // (*) +function řekniAhoj() { + věta = "Ahoj"; // (*) *!* if (false) { - var phrase; + var věta; } */!* - alert(phrase); + alert(věta); } -sayHi(); +řekniAhoj(); ``` -People also call such behavior "hoisting" (raising), because all `var` are "hoisted" (raised) to the top of the function. +Takovému chování se někdy říká „stoupání“ (anglicky „hoisting“ nebo „raising“), jelikož každý `var` „vystoupá“ („hoist“, „raise“) až k vrcholu funkce. -So in the example above, `if (false)` branch never executes, but that doesn't matter. The `var` inside it is processed in the beginning of the function, so at the moment of `(*)` the variable exists. +V uvedeném příkladu se větev `if (false)` nikdy nespustí, ale na tom nezáleží. Příkaz `var` uvnitř se zpracuje na začátku funkce, takže v okamžiku provedení řádku `(*)` proměnná existuje. -**Declarations are hoisted, but assignments are not.** +**Deklarace stoupají, ale přiřazení ne.** -That's best demonstrated with an example: +Nejlépe to uvidíme na příkladu: ```js run -function sayHi() { - alert(phrase); +function řekniAhoj() { + alert(věta); *!* - var phrase = "Hello"; + var věta = "Ahoj"; */!* } -sayHi(); +řekniAhoj(); ``` -The line `var phrase = "Hello"` has two actions in it: +Řádek `var věta = "Ahoj"` má v sobě dvě akce: -1. Variable declaration `var` -2. Variable assignment `=`. +1. Deklaraci proměnné `var`. +2. Přiřazení proměnné `=`. -The declaration is processed at the start of function execution ("hoisted"), but the assignment always works at the place where it appears. So the code works essentially like this: +Deklarace se vykonává na začátku spuštění funkce („stoupání“), ale přiřazení se provede vždy na místě, na němž se objevilo. Kód tedy funguje v zásadě následovně: ```js run -function sayHi() { +function řekniAhoj() { *!* - var phrase; // declaration works at the start... + var věta; // deklarace se provede na začátku... */!* - alert(phrase); // undefined + alert(věta); // undefined *!* - phrase = "Hello"; // ...assignment - when the execution reaches it. + věta = "Ahoj"; // ...přiřazení - když se běh dostane k němu. */!* } -sayHi(); +řekniAhoj(); ``` -Because all `var` declarations are processed at the function start, we can reference them at any place. But variables are undefined until the assignments. +Protože všechny deklarace `var` se zpracovávají na začátku funkce, můžeme je uvádět kdekoli. Ale proměnné jsou až do přiřazení nedefinované. -In both examples above, `alert` runs without an error, because the variable `phrase` exists. But its value is not yet assigned, so it shows `undefined`. +V obou uvedených příkladech se `alert` spustí bez chyby, protože proměnná `věta` existuje. Ale ještě jí není přiřazena hodnota, takže se zobrazí `undefined`. ## IIFE -In the past, as there was only `var`, and it has no block-level visibility, programmers invented a way to emulate it. What they did was called "immediately-invoked function expressions" (abbreviated as IIFE). +V minulosti, kdy bylo jenom `var` a neexistovala viditelnost na úrovni bloku, programátoři vymysleli způsob, jak ji emulovat. To, co vynalezli, bylo nazváno „okamžitě volané funkční výrazy“ („immediately-invoked function expressions“), zkráceně IIFE. -That's not something we should use nowadays, but you can find them in old scripts. +Není to nic, co bychom měli používat v současnosti, ale ve starých skriptech je stále můžete najít. -An IIFE looks like this: +IIFE vypadá následovně: ```js run (function() { - var message = "Hello"; + var zpráva = "Ahoj"; - alert(message); // Hello + alert(zpráva); // Ahoj })(); ``` -Here, a Function Expression is created and immediately called. So the code executes right away and has its own private variables. +Zde se vytvoří a okamžitě zavolá funkční výraz. Kód se tedy okamžitě spustí a má své vlastní soukromé proměnné. -The Function Expression is wrapped with parenthesis `(function {...})`, because when JavaScript engine encounters `"function"` in the main code, it understands it as the start of a Function Declaration. But a Function Declaration must have a name, so this kind of code will give an error: +Funkční výraz je uzavřen do závorek `(function {...})`, protože když motor JavaScriptu narazí v hlavním kódu na `„function“`, chápe to jako začátek deklarace funkce. Avšak deklarace funkce musí obsahovat název, takže tento kód vyvolá chybu: ```js run -// Tries to declare and immediately call a function -function() { // <-- SyntaxError: Function statements require a function name +// Snaží se deklarovat a okamžitě zavolat funkci +function() { // <-- SyntaxError: Deklarace funkce vyžaduje název funkce - var message = "Hello"; + var zpráva = "Ahoj"; - alert(message); // Hello + alert(zpráva); // Ahoj }(); ``` -Even if we say: "okay, let's add a name", that won't work, as JavaScript does not allow Function Declarations to be called immediately: +I kdybychom si řekli: „dobře, tak přidáme název“, nebude to fungovat, protože JavaScript neumožňuje, aby byla deklarace funkce okamžitě volána: ```js run -// syntax error because of parentheses below -function go() { +// závorky níže způsobí syntaktickou chybu +function jdi() { -}(); // <-- can't call Function Declaration immediately +}(); // <-- deklaraci funkce nemůžeme okamžitě volat ``` -So, the parentheses around the function is a trick to show JavaScript that the function is created in the context of another expression, and hence it's a Function Expression: it needs no name and can be called immediately. +Závorky kolem funkce jsou tedy trik, jak ukázat JavaScriptu, že funkce je vytvořena v kontextu jiného výrazu, a proto je to funkční výraz: nemusí mít název a může být okamžitě zavolán. -There exist other ways besides parentheses to tell JavaScript that we mean a Function Expression: +Kromě závorek existují i jiné způsoby, jak oznámit JavaScriptu, že máme na mysli funkční výraz: ```js run -// Ways to create IIFE +// Způsoby vytvoření IIFE *!*(*/!*function() { - alert("Parentheses around the function"); + alert("Závorky okolo funkce"); }*!*)*/!*(); *!*(*/!*function() { - alert("Parentheses around the whole thing"); + alert("Závorky okolo toho všeho"); }()*!*)*/!*; *!*!*/!*function() { - alert("Bitwise NOT operator starts the expression"); + alert("Bitový operátor NOT zahajuje výraz"); }(); *!*+*/!*function() { - alert("Unary plus starts the expression"); + alert("Unární plus zahajuje výraz"); }(); ``` -In all the above cases we declare a Function Expression and run it immediately. Let's note again: nowadays there's no reason to write such code. +Ve všech uvedených případech deklarujeme funkční výraz a okamžitě jej zavoláme. Znovu opakujeme, že v dnešní době není důvod takový kód psát. -## Summary +## Shrnutí -There are two main differences of `var` compared to `let/const`: +Mezi `var` a `let/const` existují dva hlavní rozdíly: -1. `var` variables have no block scope, their visibility is scoped to current function, or global, if declared outside function. -2. `var` declarations are processed at function start (script start for globals). +1. Proměnné deklarované pomocí `var` nemají blokovou platnost a oblast jejich viditelnosti je celá aktuální funkce. Jsou-li deklarovány mimo funkci, jsou globální. +2. Deklarace `var` se zpracovávají na začátku funkce (globální deklarace na začátku skriptu). -There's one more very minor difference related to the global object, that we'll cover in the next chapter. +Existuje ještě jeden velmi drobný rozdíl vztahující se ke globálnímu objektu, který probereme v příští kapitole. -These differences make `var` worse than `let` most of the time. Block-level variables is such a great thing. That's why `let` was introduced in the standard long ago, and is now a major way (along with `const`) to declare a variable. +Kvůli těmto rozdílům je `var` ve většině případů horší než `let`. Proměnné na úrovni bloku jsou vynikající věc. To je důvod, proč bylo do standardu již před dlouhou dobou zavedeno `let` a nyní je hlavním způsobem (spolu s `const`), jak deklarovat proměnné. diff --git a/1-js/06-advanced-functions/05-global-object/article.md b/1-js/06-advanced-functions/05-global-object/article.md index cf4839d94..3d54593db 100644 --- a/1-js/06-advanced-functions/05-global-object/article.md +++ b/1-js/06-advanced-functions/05-global-object/article.md @@ -1,89 +1,89 @@ -# Global object +# Globální objekt -The global object provides variables and functions that are available anywhere. By default, those that are built into the language or the environment. +Globální objekt poskytuje proměnné a funkce, které jsou dostupné všude. Standardně jsou to ty, které jsou vestavěny do jazyka nebo prostředí. -In a browser it is named `window`, for Node.js it is `global`, for other environments it may have another name. +V prohlížeči se jmenuje `window`, v Node.js je to `global`, v jiných prostředích může mít jiný název. -Recently, `globalThis` was added to the language, as a standardized name for a global object, that should be supported across all environments. It's supported in all major browsers. +Nedávno byl do jazyka přidán standardizovaný název globálního objektu `globalThis`, který by měla podporovat všechna prostředí. Všechny významné prohlížeče jej podporují. -We'll use `window` here, assuming that our environment is a browser. If your script may run in other environments, it's better to use `globalThis` instead. +Zde budeme používat `window`, jelikož předpokládáme, že naším prostředím je prohlížeč. Pokud váš skript má běžet v jiných prostředích, je lepší místo něj používat `globalThis`. -All properties of the global object can be accessed directly: +Ke všem vlastnostem globálního objektu lze přistupovat přímo: ```js run -alert("Hello"); -// is the same as -window.alert("Hello"); +alert("Ahoj"); +// je totéž jako +window.alert("Ahoj"); ``` -In a browser, global functions and variables declared with `var` (not `let/const`!) become the property of the global object: +V prohlížeči se globální funkce a proměnné deklarované pomocí `var` (ne `let/const`!) stávají vlastnostmi globálního objektu: ```js run untrusted refresh var gVar = 5; -alert(window.gVar); // 5 (became a property of the global object) +alert(window.gVar); // 5 (stala se vlastností globálního objektu) ``` -Function declarations have the same effect (statements with `function` keyword in the main code flow, not function expressions). +Stejný efekt mají deklarace funkcí (příkazy s klíčovým slovem `function` v běhu hlavního kódu, ne funkční výrazy). -Please don't rely on that! This behavior exists for compatibility reasons. Modern scripts use [JavaScript modules](info:modules) where such a thing doesn't happen. +Prosíme, nespoléhejte se na to! Toto chování existuje z důvodů kompatibility. Moderní skripty používají [JavaScriptové moduly](info:modules), v nichž se takové věci nedějí. -If we used `let` instead, such thing wouldn't happen: +Kdybychom místo toho použili `let`, toto by se nestalo: ```js run untrusted refresh let gLet = 5; -alert(window.gLet); // undefined (doesn't become a property of the global object) +alert(window.gLet); // undefined (nestala se vlastností globálního objektu) ``` -If a value is so important that you'd like to make it available globally, write it directly as a property: +Je-li hodnota tak důležitá, že byste ji chtěli učinit globálně dostupnou, uveďte ji rovnou jako vlastnost: ```js run *!* -// make current user information global, to let all scripts access it -window.currentUser = { - name: "John" +// učiní informaci o aktuálním uživateli globální, aby k ní mohly přistupovat všechny skripty +window.aktuálníUživatel = { + jméno: "Jan" }; */!* -// somewhere else in code -alert(currentUser.name); // John +// někde jinde v kódu +alert(aktuálníUživatel.jméno); // Jan -// or, if we have a local variable with the name "currentUser" -// get it from window explicitly (safe!) -alert(window.currentUser.name); // John +// nebo, máme-li lokální proměnnou s názvem „aktuálníUživatel“, +// načteme ji přímo z objektu window (bezpečně!) +alert(window.aktuálníUživatel.jméno); // Jan ``` -That said, using global variables is generally discouraged. There should be as few global variables as possible. The code design where a function gets "input" variables and produces certain "outcome" is clearer, less prone to errors and easier to test than if it uses outer or global variables. +Tím chceme říci, že používání globálních proměnných se obecně nedoporučuje. Mělo by jich být co nejméně. Návrh kódu, v němž funkce přijímá „vstupní“ proměnné a produkuje určitý „výstup“, je čistší, méně náchylný k chybám a snadnější na otestování, než když funkce používá vnější či globální proměnné. -## Using for polyfills +## Využití pro polyfilly -We use the global object to test for support of modern language features. +Globální objekt používáme k testování, zda jsou podporovány moderní vlastnosti jazyka. -For instance, test if a built-in `Promise` object exists (it doesn't in really old browsers): +Například otestujeme, zda existuje vestavěný objekt `Promise` (neexistuje v zastaralých prohlížečích): ```js run if (!window.Promise) { - alert("Your browser is really old!"); + alert("Máte zastaralý prohlížeč!"); } ``` -If there's none (say, we're in an old browser), we can create "polyfills": add functions that are not supported by the environment, but exist in the modern standard. +Pokud neexistuje (řekněme, že jsme ve starém prohlížeči), můžeme vytvořit „polyfilly“: přidáme funkce, které toto prostředí nepodporuje, ale v moderním standardu existují. ```js run if (!window.Promise) { - window.Promise = ... // custom implementation of the modern language feature + window.Promise = ... // vlastní implementace moderní vlastnosti jazyka } ``` -## Summary +## Shrnutí -- The global object holds variables that should be available everywhere. +- Globální objekt obsahuje proměnné, které by měly být dostupné odkudkoli. - That includes JavaScript built-ins, such as `Array` and environment-specific values, such as `window.innerHeight` -- the window height in the browser. -- The global object has a universal name `globalThis`. + Patří sem vestavěné prvky JavaScriptu, např. `Array`, a proměnné specifické pro určitá prostředí, např. `window.innerHeight` -- výška okna v prohlížeči. +- Globální objekt má univerzální název `globalThis`. - ...But more often is referred by "old-school" environment-specific names, such as `window` (browser) and `global` (Node.js). -- We should store values in the global object only if they're truly global for our project. And keep their number at minimum. -- In-browser, unless we're using [modules](info:modules), global functions and variables declared with `var` become a property of the global object. -- To make our code future-proof and easier to understand, we should access properties of the global object directly, as `window.x`. + ...Častěji se na něj však odkazují názvy „ze staré školy“ specifické pro jednotlivá prostředí, např. `window` (prohlížeč) nebo `global` (Node.js). +- Do globálního objektu bychom měli ukládat hodnoty jen tehdy, pokud jsou v našem projektu doopravdy globální, a udržovat jejich počet na minimu. +- V prohlížeči, pokud nepoužíváme [moduly](info:modules), se globální funkce a proměnné deklarované pomocí `var` stávají vlastnostmi globálního objektu. +- Aby náš kód zůstal do budoucna odolný a lépe srozumitelný, měli bychom přistupovat k vlastnostem globálního objektu přímo, např. `window.x`. diff --git a/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/_js.view/solution.js b/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/_js.view/solution.js index ce894698d..848d4b3c5 100644 --- a/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/_js.view/solution.js +++ b/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/_js.view/solution.js @@ -1,13 +1,13 @@ -function makeCounter() { - let count = 0; +function vytvořČítač() { + let počet = 0; - function counter() { - return count++; + function čítač() { + return počet++; } - counter.set = value => count = value; + čítač.nastav = hodnota => počet = hodnota; - counter.decrease = () => count--; + čítač.sniž = () => počet--; - return counter; + return čítač; } diff --git a/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/_js.view/source.js b/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/_js.view/source.js index 5bf29aa2d..8b071b8bf 100644 --- a/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/_js.view/source.js +++ b/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/_js.view/source.js @@ -1,18 +1,18 @@ -function makeCounter() { - let count = 0; +function vytvořČítač() { + let počet = 0; - // ... your code ... + // ... váš kód ... } -let counter = makeCounter(); +let čítač = vytvořČítač(); -alert( counter() ); // 0 -alert( counter() ); // 1 +alert( čítač() ); // 0 +alert( čítač() ); // 1 -counter.set(10); // set the new count +čítač.nastav(10); // nastaví nový počet -alert( counter() ); // 10 +alert( čítač() ); // 10 -counter.decrease(); // decrease the count by 1 +čítač.sniž(); // sníží počet o 1 -alert( counter() ); // 10 (instead of 11) +alert( čítač() ); // 10 (místo 11) diff --git a/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/_js.view/test.js b/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/_js.view/test.js index 0e613aba7..02c5b30bc 100644 --- a/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/_js.view/test.js +++ b/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/_js.view/test.js @@ -1,39 +1,39 @@ -describe("counter", function() { +describe("čítač", function() { - it("increases from call to call", function() { + it("zvýší se při každém volání", function() { - let counter = makeCounter(); + let čítač = vytvořČítač(); - assert.equal( counter(), 0 ); - assert.equal( counter(), 1 ); - assert.equal( counter(), 2 ); + assert.equal( čítač(), 0 ); + assert.equal( čítač(), 1 ); + assert.equal( čítač(), 2 ); }); - describe("counter.set", function() { - it("sets the count", function() { + describe("čítač.nastav", function() { + it("nastaví počet", function() { - let counter = makeCounter(); + let čítač = vytvořČítač(); - counter.set(10); + čítač.nastav(10); - assert.equal( counter(), 10 ); - assert.equal( counter(), 11 ); + assert.equal( čítač(), 10 ); + assert.equal( čítač(), 11 ); }); }); - describe("counter.decrease", function() { - it("decreases the count", function() { + describe("čítač.sniž", function() { + it("sníží počet", function() { - let counter = makeCounter(); + let čítač = vytvořČítač(); - counter.set(10); + čítač.nastav(10); - assert.equal( counter(), 10 ); + assert.equal( čítač(), 10 ); - counter.decrease(); + čítač.sniž(); - assert.equal( counter(), 10 ); + assert.equal( čítač(), 10 ); }); }); diff --git a/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/solution.md b/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/solution.md index e829d96ee..c2456431f 100644 --- a/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/solution.md +++ b/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/solution.md @@ -1,2 +1,2 @@ -The solution uses `count` in the local variable, but addition methods are written right into the `counter`. They share the same outer lexical environment and also can access the current `count`. +Řešení využívá `počet` v lokální proměnné, ale přidané metody jsou vepsány přímo do funkce `čítač`. Sdílejí stejné vnější lexikální prostředí a mohou také přistupovat k aktuální hodnotě proměnné `počet`. diff --git a/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/task.md b/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/task.md index a11821d67..4479ff70f 100644 --- a/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/task.md +++ b/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/task.md @@ -2,14 +2,14 @@ importance: 5 --- -# Set and decrease for counter +# Nastavení a snížení čítače -Modify the code of `makeCounter()` so that the counter can also decrease and set the number: +Upravte kód funkce `vytvořČítač()` tak, aby tento čítač uměl také snížit a nastavit svou hodnotu: -- `counter()` should return the next number (as before). -- `counter.set(value)` should set the counter to `value`. -- `counter.decrease()` should decrease the counter by 1. +- `čítač()` by měl vracet další číslo (jako dříve). +- `čítač.nastav(hodnota)` by měl nastavit čítač na hodnotu `hodnota`. +- `čítač.sniž()` by měl snížit čítač o 1. -See the sandbox code for the complete usage example. +Úplný příklad použití uvidíte na kódu z pískoviště. -P.S. You can use either a closure or the function property to keep the current count. Or write both variants. +P.S. K uchovávání aktuálního počtu můžete využívat buď uzávěr, nebo vlastnost funkce. Nebo napsat obě varianty. diff --git a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/solution.js b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/solution.js index c7d7d734e..3fd3f67c9 100644 --- a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/solution.js +++ b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/solution.js @@ -1,14 +1,14 @@ -function sum(a) { +function sečti(a) { - let currentSum = a; + let aktuálníSoučet = a; function f(b) { - currentSum += b; + aktuálníSoučet += b; return f; } f.toString = function() { - return currentSum; + return aktuálníSoučet; }; return f; diff --git a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/source.js b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/source.js index f10dca5dc..e22e81757 100644 --- a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/source.js +++ b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/source.js @@ -1,12 +1,12 @@ -function sum(a){ - // Your code goes here. +function sečti(a){ + // Sem přijde váš kód. } /* -sum(1)(2) == 3; // 1 + 2 -sum(1)(2)(3) == 6; // 1 + 2 + 3 -sum(5)(-1)(2) == 6 -sum(6)(-1)(-2)(-3) == 0 -sum(0)(1)(2)(3)(4)(5) == 15 +sečti(1)(2) == 3; // 1 + 2 +sečti(1)(2)(3) == 6; // 1 + 2 + 3 +sečti(5)(-1)(2) == 6 +sečti(6)(-1)(-2)(-3) == 0 +sečti(0)(1)(2)(3)(4)(5) == 15 */ diff --git a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/test.js b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/test.js index ed567d330..5e988aaa4 100644 --- a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/test.js +++ b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/test.js @@ -1,19 +1,19 @@ -describe("sum", function(){ +describe("sečti", function(){ - it("sum(1)(2) == 3", function(){ - assert.equal(3, sum(1)(2)); + it("sečti(1)(2) == 3", function(){ + assert.equal(3, sečti(1)(2)); }); - it("sum(5)(-1)(2) == 6", function(){ - assert.equal(6, sum(5)(-1)(2)); + it("sečti(5)(-1)(2) == 6", function(){ + assert.equal(6, sečti(5)(-1)(2)); }); - it("sum(6)(-1)(-2)(-3) == 0", function(){ - assert.equal(0, sum(6)(-1)(-2)(-3)); + it("sečti(6)(-1)(-2)(-3) == 0", function(){ + assert.equal(0, sečti(6)(-1)(-2)(-3)); }); - it("sum(0)(1)(2)(3)(4)(5) == 15", function(){ - assert.equal(15, sum(0)(1)(2)(3)(4)(5)); + it("sečti(0)(1)(2)(3)(4)(5) == 15", function(){ + assert.equal(15, sečti(0)(1)(2)(3)(4)(5)); }); }); diff --git a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/solution.md b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/solution.md index e97039f72..ec9fbcc47 100644 --- a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/solution.md +++ b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/solution.md @@ -1,55 +1,55 @@ -1. For the whole thing to work *anyhow*, the result of `sum` must be function. -2. That function must keep in memory the current value between calls. -3. According to the task, the function must become the number when used in `==`. Functions are objects, so the conversion happens as described in the chapter , and we can provide our own method that returns the number. +1. Aby to celé *jakkoli* fungovalo, výsledek funkce `sečti` musí být funkce. +2. Tato funkce si musí udržovat v paměti aktuální hodnotu mezi voláními. +3. Podle zadání se funkce musí stát číslem, když je použita v `==`. Funkce jsou objekty, takže konverze se odehrává tak, jak je popsáno v kapitole , a my můžeme poskytnout svou vlastní metodu, která toto číslo vrátí. -Now the code: +Nyní kód: ```js demo run -function sum(a) { +function sečti(a) { - let currentSum = a; + let aktuálníSoučet = a; function f(b) { - currentSum += b; + aktuálníSoučet += b; return f; } f.toString = function() { - return currentSum; + return aktuálníSoučet; }; return f; } -alert( sum(1)(2) ); // 3 -alert( sum(5)(-1)(2) ); // 6 -alert( sum(6)(-1)(-2)(-3) ); // 0 -alert( sum(0)(1)(2)(3)(4)(5) ); // 15 +alert( sečti(1)(2) ); // 3 +alert( sečti(5)(-1)(2) ); // 6 +alert( sečti(6)(-1)(-2)(-3) ); // 0 +alert( sečti(0)(1)(2)(3)(4)(5) ); // 15 ``` -Please note that the `sum` function actually works only once. It returns function `f`. +Prosíme všimněte si, že funkce `sečti` se ve skutečnosti spustí jenom jednou. Vrátí funkci `f`. -Then, on each subsequent call, `f` adds its parameter to the sum `currentSum`, and returns itself. +Pak funkce `f` při každém následném volání přičte svůj parametr k součtu `aktuálníSoučet` a vrátí sebe sama. -**There is no recursion in the last line of `f`.** +**Na posledním řádku funkce `f` není rekurze.** -Here is what recursion looks like: +Rekurze by vypadala takto: ```js function f(b) { - currentSum += b; - return f(); // <-- recursive call + aktuálníSoučet += b; + return f(); // <-- rekurzívní volání } ``` -And in our case, we just return the function, without calling it: +V našem případě vracíme jen funkci, aniž bychom ji volali: ```js function f(b) { - currentSum += b; - return f; // <-- does not call itself, returns itself + aktuálníSoučet += b; + return f; // <-- nevolá sama sebe, vrací sama sebe } ``` -This `f` will be used in the next call, again return itself, as many times as needed. Then, when used as a number or a string -- the `toString` returns the `currentSum`. We could also use `Symbol.toPrimitive` or `valueOf` here for the conversion. +Tato funkce `f` bude použita při dalším volání a opět vrátí sebe sama, tolikrát, kolikrát je zapotřebí. Když ji pak použijeme jako číslo nebo řetězec, `toString` vrátí `aktuálníSoučet`. Zde bychom pro konverzi mohli také použít `Symbol.toPrimitive` nebo `valueOf`. diff --git a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/task.md b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/task.md index dc13f260b..aad266a59 100644 --- a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/task.md +++ b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/task.md @@ -2,16 +2,16 @@ importance: 2 --- -# Sum with an arbitrary amount of brackets +# Sčítání s libovolným počtem závorek -Write function `sum` that would work like this: +Napište funkci `sečti`, která bude fungovat takto: ```js -sum(1)(2) == 3; // 1 + 2 -sum(1)(2)(3) == 6; // 1 + 2 + 3 -sum(5)(-1)(2) == 6 -sum(6)(-1)(-2)(-3) == 0 -sum(0)(1)(2)(3)(4)(5) == 15 +sečti(1)(2) == 3; // 1 + 2 +sečti(1)(2)(3) == 6; // 1 + 2 + 3 +sečti(5)(-1)(2) == 6 +sečti(6)(-1)(-2)(-3) == 0 +sečti(0)(1)(2)(3)(4)(5) == 15 ``` -P.S. Hint: you may need to setup custom object to primitive conversion for your function. \ No newline at end of file +P.S. Rada: možná budete pro svou funkci potřebovat nastavit vlastní konverzi objektu na primitiv. \ No newline at end of file diff --git a/1-js/06-advanced-functions/06-function-object/article.md b/1-js/06-advanced-functions/06-function-object/article.md index c84f4e52f..68749baf6 100644 --- a/1-js/06-advanced-functions/06-function-object/article.md +++ b/1-js/06-advanced-functions/06-function-object/article.md @@ -1,353 +1,351 @@ -# Function object, NFE +# Funkční objekt, NFE -As we already know, a function in JavaScript is a value. +Jak již víme, funkce v JavaScriptu je hodnota. -Every value in JavaScript has a type. What type is a function? +Každá hodnota v JavaScriptu má svůj typ. Jakého typu je funkce? -In JavaScript, functions are objects. +V JavaScriptu jsou funkce objekty. -A good way to imagine functions is as callable "action objects". We can not only call them, but also treat them as objects: add/remove properties, pass by reference etc. +Dobrý způsob, jak si představit funkce, je představit si je jako „akční objekty“, které lze volat. Můžeme je nejenom volat, ale i zacházet s nimi jako s objekty: přidávat a ubírat vlastnosti, předávat je odkazem a tak dále. -## The "name" property +## Vlastnost „name“ -Function objects contain some useable properties. +Funkční objekty obsahují některé užitečné vlastnosti. -For instance, a function's name is accessible as the "name" property: +Například název funkce je dostupný ve vlastnosti `name`: ```js run -function sayHi() { - alert("Hi"); +function řekniAhoj() { + alert("Ahoj"); } -alert(sayHi.name); // sayHi +alert(řekniAhoj.name); // řekniAhoj ``` -What's kind of funny, the name-assigning logic is smart. It also assigns the correct name to a function even if it's created without one, and then immediately assigned: +Zábavné je, že logika přiřazení názvu je chytrá a přiřadí korektní název i funkci, která je vytvořena bez názvu a pak okamžitě přiřazena: ```js run -let sayHi = function() { - alert("Hi"); +let řekniAhoj = function() { + alert("Ahoj"); }; -alert(sayHi.name); // sayHi (there's a name!) +alert(řekniAhoj.name); // řekniAhoj (je tady název!) ``` -It also works if the assignment is done via a default value: +Funguje to i tehdy, je-li přiřazena jako standardní hodnota: ```js run -function f(sayHi = function() {}) { - alert(sayHi.name); // sayHi (works!) +function f(řekniAhoj = function() {}) { + alert(řekniAhoj.name); // řekniAhoj (funguje!) } f(); ``` -In the specification, this feature is called a "contextual name". If the function does not provide one, then in an assignment it is figured out from the context. +Ve specifikaci se tato vlastnost nazývá „kontextuální název“ („contextual name“). Jestliže funkce neobsahuje vlastní název, je při přiřazení detekován z kontextu. -Object methods have names too: +I metody objektů mají názvy: ```js run -let user = { +let uživatel = { - sayHi() { + řekniAhoj() { // ... }, - sayBye: function() { + řekniNashle: function() { // ... } } -alert(user.sayHi.name); // sayHi -alert(user.sayBye.name); // sayBye +alert(uživatel.řekniAhoj.name); // řekniAhoj +alert(uživatel.řekniNashle.name); // řekniNashle ``` -There's no magic though. There are cases when there's no way to figure out the right name. In that case, the name property is empty, like here: +Není v tom ovšem nic magického. Existují případy, kdy není způsob, jak zjistit skutečný název. V takovém případě je vlastnost `name` prázdná, například zde: ```js run -// function created inside array -let arr = [function() {}]; +// funkce vytvořená uvnitř pole +let pole = [function() {}]; -alert( arr[0].name ); // -// the engine has no way to set up the right name, so there is none +alert( pole[0].name ); // +// motor nemá jak zjistit správný název, takže tady žádný není ``` -In practice, however, most functions do have a name. +V praxi však většina funkcí název má. -## The "length" property +## Vlastnost „length“ -There is another built-in property "length" that returns the number of function parameters, for instance: +Další vestavěná vlastnost je `length`, která vrací počet parametrů funkce, například: ```js run function f1(a) {} function f2(a, b) {} -function many(a, b, ...more) {} +function mnoho(a, b, ...další) {} alert(f1.length); // 1 alert(f2.length); // 2 -alert(many.length); // 2 +alert(mnoho.length); // 2 ``` -Here we can see that rest parameters are not counted. +Zde vidíme, že zbytkové parametry se nepočítají. -The `length` property is sometimes used for [introspection](https://en.wikipedia.org/wiki/Type_introspection) in functions that operate on other functions. +Vlastnost `length` se někdy používá pro [introspekci](https://en.wikipedia.org/wiki/Type_introspection) ve funkcích, které operují s jinými funkcemi. -For instance, in the code below the `ask` function accepts a `question` to ask and an arbitrary number of `handler` functions to call. +Například v níže uvedeném kódu funkce `zeptejSe` přijímá parametr `otázka`, kterou položí, a libovolný počet funkčních handlerů v parametru `handlery`, které zavolá. -Once a user provides their answer, the function calls the handlers. We can pass two kinds of handlers: +Jakmile uživatel poskytne odpověď, funkce zavolá handlery. Můžeme předávat dva druhy handlerů: -- A zero-argument function, which is only called when the user gives a positive answer. -- A function with arguments, which is called in either case and returns an answer. +- Funkci bez argumentů, která se volá jedině tehdy, když uživatel zadá kladnou odpověď. +- Funkci s argumenty, která se volá v každém případě a vrátí nějakou odpověď. -To call `handler` the right way, we examine the `handler.length` property. +Abychom zavolali `handler` správně, prozkoumáme vlastnost `handler.length`. -The idea is that we have a simple, no-arguments handler syntax for positive cases (most frequent variant), but are able to support universal handlers as well: +Myšlenkou je, že máme jednoduchou syntaxi handleru bez argumentů pro kladné případy (nejčastější varianta), ale jsme schopni podporovat i univerzální handlery: ```js run -function ask(question, ...handlers) { - let isYes = confirm(question); +function zeptejSe(otázka, ...handlery) { + let jeAno = confirm(otázka); - for(let handler of handlers) { + for(let handler of handlery) { if (handler.length == 0) { - if (isYes) handler(); + if (jeAno) handler(); } else { - handler(isYes); + handler(jeAno); } } } -// for positive answer, both handlers are called -// for negative answer, only the second one -ask("Question?", () => alert('You said yes'), result => alert(result)); +// při kladné odpovědi se volají oba handlery +// při záporné odpovědi se volá jen druhý +zeptejSe("Otázka?", () => alert('Řekl jste ano'), výsledek => alert(výsledek)); ``` -This is a particular case of so-called [polymorphism](https://en.wikipedia.org/wiki/Polymorphism_(computer_science)) -- treating arguments differently depending on their type or, in our case depending on the `length`. The idea does have a use in JavaScript libraries. +Toto je zvláštní případ tzv. [polymorfismu](https://cs.wikipedia.org/wiki/Polymorfismus_(programování)) -- odlišného zacházení s argumenty v závislosti na jejich typu nebo v našem případě v závislosti na jejich počtu v `length`. Tato myšlenka je často využívána v knihovnách JavaScriptu. -## Custom properties +## Vlastní vlastnosti -We can also add properties of our own. +Můžeme si také přidávat svoje vlastní vlastnosti. -Here we add the `counter` property to track the total calls count: +Zde přidáme vlastnost `čítač`, která počítá celkový počet volání: ```js run -function sayHi() { - alert("Hi"); +function řekniAhoj() { + alert("Ahoj"); *!* - // let's count how many times we run - sayHi.counter++; + // spočítáme, kolikrát jsme tuto funkci volali + řekniAhoj.čítač++; */!* } -sayHi.counter = 0; // initial value +řekniAhoj.čítač = 0; // počáteční hodnota -sayHi(); // Hi -sayHi(); // Hi +řekniAhoj(); // Ahoj +řekniAhoj(); // Ahoj -alert( `Called ${sayHi.counter} times` ); // Called 2 times +alert( `Voláno ${řekniAhoj.čítač}krát` ); // Voláno 2krát ``` -```warn header="A property is not a variable" -A property assigned to a function like `sayHi.counter = 0` does *not* define a local variable `counter` inside it. In other words, a property `counter` and a variable `let counter` are two unrelated things. +```warn header="Vlastnost není proměnná" +Vlastnost přiřazená funkci, např. `řekniAhoj.čítač = 0`, *nedefinuje* uvnitř funkce lokální proměnnou `čítač`. Jinými slovy, vlastnost `čítač` a proměnná `let čítač` jsou dvě různé věci. -We can treat a function as an object, store properties in it, but that has no effect on its execution. Variables are not function properties and vice versa. These are just parallel worlds. +Můžeme s funkcí zacházet jako s objektem, ukládat do ní vlastnosti, ale to nemá žádný vliv na její provádění. Proměnné nejsou vlastnosti funkce a naopak. Jsou to dva paralelní světy. ``` -Function properties can replace closures sometimes. For instance, we can rewrite the counter function example from the chapter to use a function property: +Vlastnosti funkce někdy mohou nahradit uzávěry. Například můžeme přepsat příklad funkce čítače z kapitoly tak, že použijeme vlastnost funkce: ```js run -function makeCounter() { - // instead of: - // let count = 0 +function vytvořČítač() { + // namísto: + // let počet = 0 - function counter() { - return counter.count++; + function čítač() { + return čítač.počet++; }; - counter.count = 0; + čítač.počet = 0; - return counter; + return čítač; } -let counter = makeCounter(); -alert( counter() ); // 0 -alert( counter() ); // 1 +let čítač = vytvořČítač(); +alert( čítač() ); // 0 +alert( čítač() ); // 1 ``` -The `count` is now stored in the function directly, not in its outer Lexical Environment. +Nyní je `počet` uložen přímo ve funkci, ne v jejím vnějším lexikálním prostředí. -Is it better or worse than using a closure? +Je to lepší nebo horší, než použít uzávěr? -The main difference is that if the value of `count` lives in an outer variable, then external code is unable to access it. Only nested functions may modify it. And if it's bound to a function, then such a thing is possible: +Hlavním rozdílem je, že jestliže hodnota `počet` přebývá ve vnější proměnné, externí kód není schopen k ní přistupovat. Mohou ji modifikovat jedině vnořené funkce. Ale jestliže je vázána na funkci, pak je něco takového možné: ```js run -function makeCounter() { +function vytvořČítač() { - function counter() { - return counter.count++; + function čítač() { + return čítač.počet++; }; - counter.count = 0; + čítač.počet = 0; - return counter; + return čítač; } -let counter = makeCounter(); +let čítač = vytvořČítač(); *!* -counter.count = 10; -alert( counter() ); // 10 +čítač.počet = 10; +alert( čítač() ); // 10 */!* ``` -So the choice of implementation depends on our aims. +Volba implementace tedy závisí na našich potřebách. -## Named Function Expression +## Pojmenovaný funkční výraz -Named Function Expression, or NFE, is a term for Function Expressions that have a name. +Pojmenovaný funkční výraz („Named Function Expression“), zkráceně NFE, je termín označující funkční výraz, který má nějaký název. -For instance, let's take an ordinary Function Expression: +Vezměme si například obyčejný funkční výraz: ```js -let sayHi = function(who) { - alert(`Hello, ${who}`); +let řekniAhoj = function(kdo) { + alert(`Ahoj, ${kdo}`); }; ``` -And add a name to it: +A přidejme mu název: ```js -let sayHi = function *!*func*/!*(who) { - alert(`Hello, ${who}`); +let řekniAhoj = function *!*funkce*/!*(kdo) { + alert(`Ahoj, ${kdo}`); }; ``` -Did we achieve anything here? What's the purpose of that additional `"func"` name? +Dosáhli jsme tím něčeho? Jaký je smysl přidaného názvu `„funkce“`? -First let's note, that we still have a Function Expression. Adding the name `"func"` after `function` did not make it a Function Declaration, because it is still created as a part of an assignment expression. +Nejprve si všimněme, že stále máme funkční výraz. Přidání názvu `„funkce“` za `function` z něj neučinilo deklaraci funkce, protože funkce je stále vytvořena jako součást přiřazovacího výrazu. -Adding such a name also did not break anything. +Přidání takového názvu rovněž nic nerozbilo. -The function is still available as `sayHi()`: +Funkce je stále dostupná jako `řekniAhoj()`: ```js run -let sayHi = function *!*func*/!*(who) { - alert(`Hello, ${who}`); +let řekniAhoj = function *!*funkce*/!*(kdo) { + alert(`Ahoj, ${kdo}`); }; -sayHi("John"); // Hello, John +řekniAhoj("Jan"); // Ahoj, Jan ``` -There are two special things about the name `func`, that are the reasons for it: +Název `funkce` má dvě speciální věci, které jsou důvodem pro jeho použití: -1. It allows the function to reference itself internally. -2. It is not visible outside of the function. +1. Název umožňuje funkci odkazovat se uvnitř sebe na sebe sama. +2. Název není viditelný zvnějšku funkce. -For instance, the function `sayHi` below calls itself again with `"Guest"` if no `who` is provided: +Například následující funkce `řekniAhoj` volá sama sebe s parametrem `"Host"`, není-li předáno `kdo`: ```js run -let sayHi = function *!*func*/!*(who) { - if (who) { - alert(`Hello, ${who}`); +let řekniAhoj = function *!*funkce*/!*(kdo) { + if (kdo) { + alert(`Ahoj, ${kdo}`); } else { *!* - func("Guest"); // use func to re-call itself + funkce("Host"); // použijeme „funkce“ k volání sebe sama */!* } }; -sayHi(); // Hello, Guest +řekniAhoj(); // Ahoj, Host -// But this won't work: -func(); // Error, func is not defined (not visible outside of the function) +// Ale tohle nebude fungovat: +funkce(); // Chyba, funkce není definována (není viditelná zvnějšku funkce) ``` -Why do we use `func`? Maybe just use `sayHi` for the nested call? +Proč používáme `funkce`? Možná by pro vnořené volání stačilo použít `řekniAhoj`? - -Actually, in most cases we can: +Ve skutečnosti ve většině případů ano: ```js -let sayHi = function(who) { - if (who) { - alert(`Hello, ${who}`); +let řekniAhoj = function(kdo) { + if (kdo) { + alert(`Ahoj, ${kdo}`); } else { *!* - sayHi("Guest"); + řekniAhoj("Host"); */!* } }; ``` -The problem with that code is that `sayHi` may change in the outer code. If the function gets assigned to another variable instead, the code will start to give errors: +Problém s tímto kódem je, že `řekniAhoj` se může ve vnějším kódu změnit. Jestliže funkce bude přiřazena do jiné proměnné, tento kód začne způsobovat chyby: ```js run -let sayHi = function(who) { - if (who) { - alert(`Hello, ${who}`); +let řekniAhoj = function(kdo) { + if (kdo) { + alert(`Ahoj, ${kdo}`); } else { *!* - sayHi("Guest"); // Error: sayHi is not a function + řekniAhoj("Host"); // Chyba: řekniAhoj není funkce */!* } }; -let welcome = sayHi; -sayHi = null; +let vítej = řekniAhoj; +řekniAhoj = null; -welcome(); // Error, the nested sayHi call doesn't work any more! +vítej(); // Chyba, vnořené volání řekniAhoj už nefunguje! ``` -That happens because the function takes `sayHi` from its outer lexical environment. There's no local `sayHi`, so the outer variable is used. And at the moment of the call that outer `sayHi` is `null`. +To se stane proto, že funkce přebírá `řekniAhoj` ze svého vnějšího lexikálního prostředí. Neexistuje lokální `řekniAhoj`, takže se použije vnější proměnná. A v okamžiku volání je vnější `řekniAhoj` rovno `null`. -The optional name which we can put into the Function Expression is meant to solve exactly these kinds of problems. +Nepovinný název, který můžeme vložit do funkčního výrazu, je určen právě k řešení problémů tohoto druhu. -Let's use it to fix our code: +Použijme jej k opravě našeho kódu: ```js run -let sayHi = function *!*func*/!*(who) { - if (who) { - alert(`Hello, ${who}`); +let řekniAhoj = function *!*funkce*/!*(kdo) { + if (kdo) { + alert(`Ahoj, ${kdo}`); } else { *!* - func("Guest"); // Now all fine + funkce("Host"); // Nyní je vše v pořádku */!* } }; -let welcome = sayHi; -sayHi = null; +let vítej = řekniAhoj; +řekniAhoj = null; -welcome(); // Hello, Guest (nested call works) +vítej(); // Ahoj, Host (vnořené volání funguje) ``` -Now it works, because the name `"func"` is function-local. It is not taken from outside (and not visible there). The specification guarantees that it will always reference the current function. +Nyní to funguje, protože název `„funkce“` je funkčně lokální. Nepřebírá se zvnějšku (a není tam viditelný). Specifikace zaručuje, že se bude vždy odkazovat na aktuální funkci. -The outer code still has its variable `sayHi` or `welcome`. And `func` is an "internal function name", the way for the function to can call itself reliably. +Vnější kód stále má svou proměnnou `řekniAhoj` nebo `vítej`. A `funkce` je „interní funkční název“, způsob, jakým tato funkce může spolehlivě volat sama sebe. -```smart header="There's no such thing for Function Declaration" -The "internal name" feature described here is only available for Function Expressions, not for Function Declarations. For Function Declarations, there is no syntax for adding an "internal" name. +```smart header="Pro deklarace funkce nic takového neexistuje" +Popsaná vlastnost „interní název“ je k dispozici jen pro funkční výrazy, ne pro deklarace funkcí. V deklaracích funkcí neexistuje žádná syntaxe, jak přidat „interní“ název. -Sometimes, when we need a reliable internal name, it's the reason to rewrite a Function Declaration to Named Function Expression form. +Někdy, když potřebujeme spolehlivý interní název, je to důvod, proč přepsat deklaraci funkce do formy pojmenovaného funkčního výrazu. ``` -## Summary - -Functions are objects. +## Shrnutí -Here we covered their properties: +Funkce jsou objekty. -- `name` -- the function name. Usually taken from the function definition, but if there's none, JavaScript tries to guess it from the context (e.g. an assignment). -- `length` -- the number of arguments in the function definition. Rest parameters are not counted. +Zde jsme probrali jejich vlastnosti: -If the function is declared as a Function Expression (not in the main code flow), and it carries the name, then it is called a Named Function Expression. The name can be used inside to reference itself, for recursive calls or such. +- `name` -- název funkce. Obvykle se přebírá z definice funkce, ale pokud tam není, JavaScript se pokusí odhadnout jej z kontextu (tj. z přiřazení). +- `length` -- počet argumentů v definici funkce. Zbytkové parametry se nepočítají. -Also, functions may carry additional properties. Many well-known JavaScript libraries make great use of this feature. +Je-li funkce deklarována jako funkční výraz (ne v hlavním běhu kódu) a ten obsahuje název, nazývá se pojmenovaný funkční výraz. Název lze používat uvnitř funkce, aby se na ni odkazoval, pro rekurzívní volání a podobně. -They create a "main" function and attach many other "helper" functions to it. For instance, the [jQuery](https://jquery.com) library creates a function named `$`. The [lodash](https://lodash.com) library creates a function `_`, and then adds `_.clone`, `_.keyBy` and other properties to it (see the [docs](https://lodash.com/docs) when you want to learn more about them). Actually, they do it to lessen their pollution of the global space, so that a single library gives only one global variable. That reduces the possibility of naming conflicts. +Funkce si také může uchovávat přidané vlastnosti. Tuto vlastnost zhusta využívá mnoho dobře známých JavaScriptových knihoven. +Vytvářejí „hlavní“ funkci a přidávají k ní mnoho dalších „pomocných“ funkcí. Například knihovna [jQuery](https://jquery.com) vytváří funkci jménem `$`. Knihovna [lodash](https://lodash.com) vytváří funkci jménem `_` a pak do ní přidává `_.clone`, `_.keyBy` a jiné vlastnosti (pokud se o nich chcete dozvědět víc, nahlédněte do [dokumentace](https://lodash.com/docs)). Ve skutečnosti to dělají proto, aby snížily zamoření globálního prostoru, takže jedna knihovna vytváří pouze jednu globální proměnnou. Tím se snižuje pravděpodobnost konfliktů názvů. -So, a function can do a useful job by itself and also carry a bunch of other functionality in properties. +Funkce tedy může sama o sobě odvádět užitečnou práci a může také obsahovat hromadu jiných funkcionalit ve svých vlastnostech. diff --git a/1-js/06-advanced-functions/07-new-function/article.md b/1-js/06-advanced-functions/07-new-function/article.md index ffe264a4e..cfeb3ff05 100644 --- a/1-js/06-advanced-functions/07-new-function/article.md +++ b/1-js/06-advanced-functions/07-new-function/article.md @@ -1,123 +1,123 @@ -# The "new Function" syntax +# Syntaxe „new Function“ -There's one more way to create a function. It's rarely used, but sometimes there's no alternative. +Existuje ještě jeden způsob, jak vytvořit funkci. Používá se jen zřídka, ale někdy nemáme jinou možnost. -## Syntax +## Syntaxe -The syntax for creating a function: +Syntaxe vytvoření funkce: ```js -let func = new Function ([arg1, arg2, ...argN], functionBody); +let funkce = new Function ([arg1, arg2, ...argN], těloFunkce); ``` -The function is created with the arguments `arg1...argN` and the given `functionBody`. +Funkce je vytvořena s argumenty `arg1...argN` a zadaným tělem `těloFunkce`. -It's easier to understand by looking at an example. Here's a function with two arguments: +Je snadnější tomu porozumět, když se podíváme na příklad. Toto je funkce se dvěma argumenty: ```js run -let sum = new Function('a', 'b', 'return a + b'); +let sečti = new Function('a', 'b', 'return a + b'); -alert( sum(1, 2) ); // 3 +alert( sečti(1, 2) ); // 3 ``` -And here there's a function without arguments, with only the function body: +A zde je funkce bez argumentů, jenom s tělem: ```js run -let sayHi = new Function('alert("Hello")'); +let řekniAhoj = new Function('alert("Ahoj")'); -sayHi(); // Hello +řekniAhoj(); // Ahoj ``` -The major difference from other ways we've seen is that the function is created literally from a string, that is passed at run time. +Hlavní rozdíl oproti ostatním způsobům, jaké jsme viděli, je, že funkce je vytvořena doslovně z řetězce, který je předán za běhu skriptu. -All previous declarations required us, programmers, to write the function code in the script. +Všechny předchozí deklarace po nás programátorech požadovaly, abychom zapsali kód funkce do skriptu. -But `new Function` allows to turn any string into a function. For example, we can receive a new function from a server and then execute it: +Avšak `new Function` umožňuje převést libovolný řetězec na funkci. Například můžeme získat novou funkci ze serveru a pak ji spustit: ```js -let str = ... receive the code from a server dynamically ... +let řetězec = ... dynamické získání kódu ze serveru ... -let func = new Function(str); -func(); +let funkce = new Function(řetězec); +funkce(); ``` -It is used in very specific cases, like when we receive code from a server, or to dynamically compile a function from a template, in complex web-applications. +Používá se jen ve velmi specifických případech, například když získáme kód ze serveru, nebo když chceme dynamicky kompilovat funkci ze šablony ve složitých webových aplikacích. -## Closure +## Uzávěr -Usually, a function remembers where it was born in the special property `[[Environment]]`. It references the Lexical Environment from where it's created (we covered that in the chapter ). +Funkce si zpravidla pamatuje, kde se zrodila, ve speciální vlastnosti `[[Environment]]`. Ta se odkazuje na lexikální prostředí, z něhož byla funkce vytvořena (probrali jsme to v kapitole ). -But when a function is created using `new Function`, its `[[Environment]]` is set to reference not the current Lexical Environment, but the global one. +Když je však funkce vytvořena pomocí `new Function`, její vlastnost `[[Environment]]` se nenastaví na odkaz na aktuální lexikální prostředí, ale na globální. -So, such function doesn't have access to outer variables, only to the global ones. +Taková funkce tedy nemá přístup k vnějším proměnným, jedině ke globálním. ```js run -function getFunc() { - let value = "test"; +function vraťFunkci() { + let hodnota = "test"; *!* - let func = new Function('alert(value)'); + let funkce = new Function('alert(hodnota)'); */!* - return func; + return funkce; } -getFunc()(); // error: value is not defined +vraťFunkci()(); // chyba: hodnota není definována ``` -Compare it with the regular behavior: +Porovnejte si to s běžným chováním: ```js run -function getFunc() { - let value = "test"; +function vraťFunkci() { + let hodnota = "test"; *!* - let func = function() { alert(value); }; + let funkce = function() { alert(hodnota); }; */!* - return func; + return funkce; } -getFunc()(); // *!*"test"*/!*, from the Lexical Environment of getFunc +vraťFunkci()(); // *!*"test"*/!*, z lexikálního prostředí funkce vraťFunkci ``` -This special feature of `new Function` looks strange, but appears very useful in practice. +Tato speciální vlastnost `new Function` vypadá zvláštně, ale v praxi se ukazuje být velmi užitečná. -Imagine that we must create a function from a string. The code of that function is not known at the time of writing the script (that's why we don't use regular functions), but will be known in the process of execution. We may receive it from the server or from another source. +Představme si, že musíme vytvořit funkci z řetězce. Kód této funkce není znám v době psaní skriptu (to je důvod, proč nepoužijeme obvyklou funkci), ale bude znám při jeho běhu. Můžeme jej získat ze serveru nebo z jiného zdroje. -Our new function needs to interact with the main script. +Naše nová funkce musí interagovat s hlavním skriptem. -What if it could access the outer variables? +Co kdyby mohla přistupovat k vnějším proměnným? -The problem is that before JavaScript is published to production, it's compressed using a *minifier* -- a special program that shrinks code by removing extra comments, spaces and -- what's important, renames local variables into shorter ones. +Problém je v tom, že předtím, než je JavaScriptový skript zveřejněn k používání, je zkomprimován *minifikátorem* -- speciálním programem, který zkrátí kód tím, že odstraní komentáře, přebytečné mezery a -- co je důležité, přejmenuje názvy lokálních proměnných na kratší. -For instance, if a function has `let userName`, minifier replaces it with `let a` (or another letter if this one is occupied), and does it everywhere. That's usually a safe thing to do, because the variable is local, nothing outside the function can access it. And inside the function, minifier replaces every mention of it. Minifiers are smart, they analyze the code structure, so they don't break anything. They're not just a dumb find-and-replace. +Například jestliže funkce obsahuje `let uživatelskéJméno`, minifikátor je nahradí za `let a` (nebo jiné písmeno, které ještě není použito) a učiní tak všude. To je obvykle bezpečné, jelikož proměnná je lokální a nic mimo funkci k ní nemůže přistupovat. A uvnitř funkce minifikátor nahradí tuto proměnnou všude, kde je uvedena. Minifikátory jsou chytré, analyzují strukturu kódu, takže nic nerozbíjejí. Není to jen tupé najdi a nahraď. -So if `new Function` had access to outer variables, it would be unable to find renamed `userName`. +Kdyby tedy `new Function` měla přístup k vnějším proměnným, nedokázala by najít přejmenované `uživatelskéJméno`. -**If `new Function` had access to outer variables, it would have problems with minifiers.** +**Kdyby `new Function` měla přístup k vnějším proměnným, měla by problémy s minifikátory.** -Besides, such code would be architecturally bad and prone to errors. +Navíc by takový kód byl architektonicky špatný a náchylný k chybám. -To pass something to a function, created as `new Function`, we should use its arguments. +K tomu, abychom něco předali funkci vytvořené pomocí `new Function`, bychom měli používat její argumenty. -## Summary +## Shrnutí -The syntax: +Syntaxe: ```js -let func = new Function ([arg1, arg2, ...argN], functionBody); +let funkce = new Function ([arg1, arg2, ...argN], těloFunkce); ``` -For historical reasons, arguments can also be given as a comma-separated list. +Z historických důvodů můžeme argumenty uvést i jako seznam oddělený čárkou. -These three declarations mean the same: +Tyto tři deklarace znamenají totéž: ```js -new Function('a', 'b', 'return a + b'); // basic syntax -new Function('a,b', 'return a + b'); // comma-separated -new Function('a , b', 'return a + b'); // comma-separated with spaces +new Function('a', 'b', 'return a + b'); // základní syntaxe +new Function('a,b', 'return a + b'); // oddělené čárkou +new Function('a , b', 'return a + b'); // oddělené čárkou s mezerami ``` -Functions created with `new Function`, have `[[Environment]]` referencing the global Lexical Environment, not the outer one. Hence, they cannot use outer variables. But that's actually good, because it insures us from errors. Passing parameters explicitly is a much better method architecturally and causes no problems with minifiers. +Vlastnost `[[Environment]]` funkcí vytvořených pomocí `new Function` se odkazuje na globální lexikální prostředí, ne na vnější. Proto tyto funkce nemohou používat vnější proměnné. To je však ve skutečnosti dobře, protože nás to ochraňuje před chybami. Výslovné předávání parametrů je architektonicky mnohem lepší způsob a nezpůsobuje problémy s minifikátory. diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/1-output-numbers-100ms/solution.md b/1-js/06-advanced-functions/08-settimeout-setinterval/1-output-numbers-100ms/solution.md index b5b1da7a6..3f6350805 100644 --- a/1-js/06-advanced-functions/08-settimeout-setinterval/1-output-numbers-100ms/solution.md +++ b/1-js/06-advanced-functions/08-settimeout-setinterval/1-output-numbers-100ms/solution.md @@ -1,64 +1,64 @@ -Using `setInterval`: +Pomocí `setInterval`: ```js run -function printNumbers(from, to) { - let current = from; +function vypišČísla(začátek, konec) { + let aktuální = začátek; - let timerId = setInterval(function() { - alert(current); - if (current == to) { - clearInterval(timerId); + let idČasovače = setInterval(function() { + alert(aktuální); + if (aktuální == konec) { + clearInterval(idČasovače); } - current++; + aktuální++; }, 1000); } -// usage: -printNumbers(5, 10); +// použití: +vypišČísla(5, 10); ``` -Using nested `setTimeout`: +Pomocí vnořeného `setTimeout`: ```js run -function printNumbers(from, to) { - let current = from; +function vypišČísla(začátek, konec) { + let aktuální = začátek; - setTimeout(function go() { - alert(current); - if (current < to) { - setTimeout(go, 1000); + setTimeout(function spusť() { + alert(aktuální); + if (aktuální < konec) { + setTimeout(spusť, 1000); } - current++; + aktuální++; }, 1000); } -// usage: -printNumbers(5, 10); +// použití: +vypišČísla(5, 10); ``` -Note that in both solutions, there is an initial delay before the first output. The function is called after `1000ms` the first time. +Všimněte si, že v obou řešeních je úvodní prodleva před prvním výstupem. Funkce je poprvé volána za `1000 ms`. -If we also want the function to run immediately, then we can add an additional call on a separate line, like this: +Jestliže chceme, aby se funkce spustila okamžitě, můžeme přidat další volání na samostatný řádek, například takto: ```js run -function printNumbers(from, to) { - let current = from; +function vypišČísla(začátek, konec) { + let aktuální = začátek; - function go() { - alert(current); - if (current == to) { - clearInterval(timerId); + function spusť() { + alert(aktuální); + if (aktuální == konec) { + clearInterval(idČasovače); } - current++; + aktuální++; } *!* - go(); + spusť(); */!* - let timerId = setInterval(go, 1000); + let idČasovače = setInterval(spusť, 1000); } -printNumbers(5, 10); +vypišČísla(5, 10); ``` diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/1-output-numbers-100ms/task.md b/1-js/06-advanced-functions/08-settimeout-setinterval/1-output-numbers-100ms/task.md index 84bb0c39c..2dcbf2777 100644 --- a/1-js/06-advanced-functions/08-settimeout-setinterval/1-output-numbers-100ms/task.md +++ b/1-js/06-advanced-functions/08-settimeout-setinterval/1-output-numbers-100ms/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# Output every second +# Výstup každou sekundu -Write a function `printNumbers(from, to)` that outputs a number every second, starting from `from` and ending with `to`. +Napište funkci `vypišČísla(začátek, konec)`, která každou sekundu vypíše číslo, přičemž začne číslem `začátek` a skončí číslem `konec`. -Make two variants of the solution. +Vytvořte dvě varianty řešení. -1. Using `setInterval`. -2. Using nested `setTimeout`. +1. Pomocí `setInterval`. +2. Pomocí vnořeného `setTimeout`. diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/4-settimeout-result/solution.md b/1-js/06-advanced-functions/08-settimeout-setinterval/4-settimeout-result/solution.md index e652a3b36..1124d9621 100644 --- a/1-js/06-advanced-functions/08-settimeout-setinterval/4-settimeout-result/solution.md +++ b/1-js/06-advanced-functions/08-settimeout-setinterval/4-settimeout-result/solution.md @@ -1,14 +1,14 @@ -Any `setTimeout` will run only after the current code has finished. +Každý `setTimeout` se spustí teprve po dokončení aktuálního kódu. -The `i` will be the last one: `100000000`. +Proměnná `i` bude obsahovat poslední hodnotu: `100000000`. ```js run let i = 0; setTimeout(() => alert(i), 100); // 100000000 -// assume that the time to execute this function is >100ms +// předpokládáme, že doba běhu této funkce je větší než 100 ms for(let j = 0; j < 100000000; j++) { i++; } diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/4-settimeout-result/task.md b/1-js/06-advanced-functions/08-settimeout-setinterval/4-settimeout-result/task.md index 667c8ffa6..308922fca 100644 --- a/1-js/06-advanced-functions/08-settimeout-setinterval/4-settimeout-result/task.md +++ b/1-js/06-advanced-functions/08-settimeout-setinterval/4-settimeout-result/task.md @@ -2,25 +2,25 @@ importance: 5 --- -# What will setTimeout show? +# Co zobrazí setTimeout? -In the code below there's a `setTimeout` call scheduled, then a heavy calculation is run, that takes more than 100ms to finish. +V následujícím kódu je načasováno volání `setTimeout`, pak proběhne náročný výpočet, jehož dokončení bude trvat více než 100 ms. -When will the scheduled function run? +Kdy se načasovaná funkce spustí? -1. After the loop. -2. Before the loop. -3. In the beginning of the loop. +1. Po cyklu. +2. Před cyklem. +3. Na začátku cyklu. -What is `alert` going to show? +Co zobrazí `alert`? ```js let i = 0; setTimeout(() => alert(i), 100); // ? -// assume that the time to execute this function is >100ms +// předpokládáme, že doba výkonu této funkce je větší než 100 ms for(let j = 0; j < 100000000; j++) { i++; } diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/article.md b/1-js/06-advanced-functions/08-settimeout-setinterval/article.md index f96959988..bc961cfd6 100644 --- a/1-js/06-advanced-functions/08-settimeout-setinterval/article.md +++ b/1-js/06-advanced-functions/08-settimeout-setinterval/article.md @@ -1,302 +1,302 @@ -# Scheduling: setTimeout and setInterval +# Časování: setTimeout a setInterval -We may decide to execute a function not right now, but at a certain time later. That's called "scheduling a call". +Můžeme se rozhodnout, že funkci nespustíme právě teď, ale až za nějakou dobu. To se nazývá „časování volání“ („scheduling a call“). -There are two methods for it: +K tomu existují dvě metody: -- `setTimeout` allows us to run a function once after the interval of time. -- `setInterval` allows us to run a function repeatedly, starting after the interval of time, then repeating continuously at that interval. +- `setTimeout` nám umožňuje spustit funkci jednou po uplynutí zadaného časového intervalu. +- `setInterval` nám umožňuje spouštět funkci opakovaně, nejprve po uplynutí zadaného časového intervalu a pak bude neustále v tomto intervalu opakována. -These methods are not a part of JavaScript specification. But most environments have the internal scheduler and provide these methods. In particular, they are supported in all browsers and Node.js. +Tyto metody nejsou součástí specifikace JavaScriptu, ale většina prostředí obsahuje interní plánovač a tyto metody poskytuje. Konkrétně jsou podporovány ve všech prohlížečích a v Node.js. ## setTimeout -The syntax: +Syntaxe: ```js -let timerId = setTimeout(func|code, [delay], [arg1], [arg2], ...) +let idČasovače = setTimeout(funkce|kód, [prodleva], [arg1], [arg2], ...) ``` -Parameters: +Parametry: -`func|code` -: Function or a string of code to execute. -Usually, that's a function. For historical reasons, a string of code can be passed, but that's not recommended. +`funkce|kód` +: Funkce nebo řetězec kódu, který se má spustit. +Obvykle to bývá funkce. Z historických důvodů lze předat i řetězec kódu, ale to se nedoporučuje. -`delay` -: The delay before run, in milliseconds (1000 ms = 1 second), by default 0. +`prodleva` +: Prodleva před spuštěním v milisekundách (1000 ms = 1 sekunda), standardně 0. `arg1`, `arg2`... -: Arguments for the function +: Argumenty této funkce. -For instance, this code calls `sayHi()` after one second: +Například tento kód zavolá `řekniAhoj()` po uplynutí jedné sekundy: ```js run -function sayHi() { - alert('Hello'); +function řekniAhoj() { + alert('Ahoj'); } *!* -setTimeout(sayHi, 1000); +setTimeout(řekniAhoj, 1000); */!* ``` -With arguments: +S argumenty: ```js run -function sayHi(phrase, who) { - alert( phrase + ', ' + who ); +function řekniAhoj(věta, kdo) { + alert( věta + ', ' + kdo ); } *!* -setTimeout(sayHi, 1000, "Hello", "John"); // Hello, John +setTimeout(řekniAhoj, 1000, "Ahoj", "Jan"); // Ahoj, Jan */!* ``` -If the first argument is a string, then JavaScript creates a function from it. +Je-li první argument řetězec, pak z něj JavaScript vytvoří funkci. -So, this will also work: +Bude tedy fungovat i tohle: ```js run no-beautify -setTimeout("alert('Hello')", 1000); +setTimeout("alert('Ahoj')", 1000); ``` -But using strings is not recommended, use arrow functions instead of them, like this: +Používání řetězců se však nedoporučuje, místo nich používejte šipkové funkce, například takto: ```js run no-beautify -setTimeout(() => alert('Hello'), 1000); +setTimeout(() => alert('Ahoj'), 1000); ``` -````smart header="Pass a function, but don't run it" -Novice developers sometimes make a mistake by adding brackets `()` after the function: +````smart header="Předejte funkci, ale nevolejte ji" +Začínající vývojáři někdy dělají chybu v tom, že za funkci přidají závorky `()`: ```js -// wrong! -setTimeout(sayHi(), 1000); +// špatně! +setTimeout(řekniAhoj(), 1000); ``` -That doesn't work, because `setTimeout` expects a reference to a function. And here `sayHi()` runs the function, and the *result of its execution* is passed to `setTimeout`. In our case the result of `sayHi()` is `undefined` (the function returns nothing), so nothing is scheduled. +To nefunguje, protože `setTimeout` očekává odkaz na funkci. A zde `řekniAhoj()` zavolá funkci a teprve *výsledek jejího volání* se předá funkci `setTimeout`. V našem případě výsledek `řekniAhoj()` je `undefined` (funkce nic nevrací), takže se nic nenačasuje. ```` -### Canceling with clearTimeout +### Zrušení pomocí clearTimeout -A call to `setTimeout` returns a "timer identifier" `timerId` that we can use to cancel the execution. +Volání `setTimeout` vrátí „identifikátor časovače“ `idČasovače`, který můžeme použít ke zrušení načasovaného spuštění. -The syntax to cancel: +Syntaxe zrušení: ```js -let timerId = setTimeout(...); -clearTimeout(timerId); +let idČasovače = setTimeout(...); +clearTimeout(idČasovače); ``` -In the code below, we schedule the function and then cancel it (changed our mind). As a result, nothing happens: +V následujícím kódu načasujeme funkci a pak ji zrušíme (rozmysleli jsme si to). Výsledkem bude, že se nic nestane: ```js run no-beautify -let timerId = setTimeout(() => alert("never happens"), 1000); -alert(timerId); // timer identifier +let idČasovače = setTimeout(() => alert("tohle se nikdy nestane"), 1000); +alert(idČasovače); // identifikátor časovače -clearTimeout(timerId); -alert(timerId); // same identifier (doesn't become null after canceling) +clearTimeout(idČasovače); +alert(idČasovače); // stejný identifikátor (po zrušení se nevynuloval) ``` -As we can see from `alert` output, in a browser the timer identifier is a number. In other environments, this can be something else. For instance, Node.js returns a timer object with additional methods. +Jak vidíme z výstupu `alert`, v prohlížeči je identifikátorem časovače číslo. V jiných prostředích to může být něco jiného, například Node.js vrací objekt časovače s dalšími metodami. -Again, there is no universal specification for these methods, so that's fine. +Opakujeme, že pro tyto metody neexistuje žádná univerzální specifikace, takže je to v pořádku. -For browsers, timers are described in the [timers section](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers) of HTML Living Standard. +Pro prohlížeče jsou časovače popsány v [kapitole o časovačích](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers) HTML Living Standardu. ## setInterval -The `setInterval` method has the same syntax as `setTimeout`: +Metoda `setInterval` má stejnou syntaxi jako `setTimeout`: ```js -let timerId = setInterval(func|code, [delay], [arg1], [arg2], ...) +let idČasovače = setInterval(funkce|kód, [prodleva], [arg1], [arg2], ...) ``` -All arguments have the same meaning. But unlike `setTimeout` it runs the function not only once, but regularly after the given interval of time. +Všechny argumenty mají stejný význam. Na rozdíl od `setTimeout` však funkce nebude spuštěna jenom jednou, ale pravidelně vždy po uplynutí zadaného časového intervalu. -To stop further calls, we should call `clearInterval(timerId)`. +Chceme-li zastavit další volání, měli bychom zavolat `clearInterval(idČasovače)`. -The following example will show the message every 2 seconds. After 5 seconds, the output is stopped: +Následující příklad zobrazí zprávu každé 2 sekundy. Po 5 sekundách bude výstup zastaven: ```js run -// repeat with the interval of 2 seconds -let timerId = setInterval(() => alert('tick'), 2000); +// opakovat s intervalem 2 sekundy +let idČasovače = setInterval(() => alert('tik'), 2000); -// after 5 seconds stop -setTimeout(() => { clearInterval(timerId); alert('stop'); }, 5000); +// konec po 5 sekundách +setTimeout(() => { clearInterval(idČasovače); alert('stop'); }, 5000); ``` -```smart header="Time goes on while `alert` is shown" -In most browsers, including Chrome and Firefox the internal timer continues "ticking" while showing `alert/confirm/prompt`. +```smart header="Zatímco je zobrazen `alert`, čas plyne dál" +Ve většině prohlížečů včetně Chrome a Firefoxu v době, kdy je zobrazeno `alert/confirm/prompt`, vnitřní časovač „tiká“ dál. -So if you run the code above and don't dismiss the `alert` window for some time, then the next `alert` will be shown immediately as you do it. The actual interval between alerts will be shorter than 2 seconds. +Když si tedy spustíte výše uvedený kód a okno `alert` nějakou dobu nezrušíte, pak bude následující `alert` zobrazen hned, jakmile to uděláte. Skutečný interval mezi zobrazeními tedy bude kratší než 2 sekundy. ``` -## Nested setTimeout +## Vnořený setTimeout -There are two ways of running something regularly. +Existují dva způsoby, jak něco pravidelně spouštět. -One is `setInterval`. The other one is a nested `setTimeout`, like this: +První je `setInterval`. Druhý je vnořený `setTimeout`, například takto: ```js -/** instead of: -let timerId = setInterval(() => alert('tick'), 2000); +/** namísto: +let idČasovače = setInterval(() => alert('tik'), 2000); */ -let timerId = setTimeout(function tick() { - alert('tick'); +let idČasovače = setTimeout(function tik() { + alert('tik'); *!* - timerId = setTimeout(tick, 2000); // (*) + idČasovače = setTimeout(tik, 2000); // (*) */!* }, 2000); ``` -The `setTimeout` above schedules the next call right at the end of the current one `(*)`. +Uvedený `setTimeout` načasuje další volání na konci aktuálního na řádku `(*)`. -The nested `setTimeout` is a more flexible method than `setInterval`. This way the next call may be scheduled differently, depending on the results of the current one. +Vnořený `setTimeout` je flexibilnější metoda než `setInterval`. Tímto způsobem můžeme příští volání načasovat za jinou dobu, podle výsledků aktuálního volání. -For instance, we need to write a service that sends a request to the server every 5 seconds asking for data, but in case the server is overloaded, it should increase the interval to 10, 20, 40 seconds... +Například potřebujeme napsat službu, která každých 5 sekund pošle na server žádost o data, ale v případě, že je server přetížen, by tento interval měla zvýšit na 10, 20, 40 sekund... -Here's the pseudocode: +Zde je pseudokód: ```js -let delay = 5000; +let prodleva = 5000; -let timerId = setTimeout(function request() { - ...send request... +let idČasovače = setTimeout(function požadavek() { + ...pošle požadavek... - if (request failed due to server overload) { - // increase the interval to the next run - delay *= 2; + if (požadavek neuspěl kvůli přetížení serveru) { + // zvýšíme interval dalšího spuštění + prodleva *= 2; } - timerId = setTimeout(request, delay); + idČasovače = setTimeout(požadavek, prodleva); -}, delay); +}, prodleva); ``` +A jestliže funkce, které časujeme, zatěžují CPU, můžeme měřit dobu, jakou trvá jejich spuštění, a naplánovat si další volání na dříve nebo později. -And if the functions that we're scheduling are CPU-hungry, then we can measure the time taken by the execution and plan the next call sooner or later. +**Vnořený `setTimeout` nám umožňuje nastavovat prodlevu mezi voláními přesněji než `setInterval`.** -**Nested `setTimeout` allows to set the delay between the executions more precisely than `setInterval`.** - -Let's compare two code fragments. The first one uses `setInterval`: +Porovnejme si dva fragmenty kódu. První používá `setInterval`: ```js let i = 1; setInterval(function() { - func(i++); + funkce(i++); }, 100); ``` -The second one uses nested `setTimeout`: +Druhý používá vnořený `setTimeout`: ```js let i = 1; -setTimeout(function run() { - func(i++); - setTimeout(run, 100); +setTimeout(function spusť() { + funkce(i++); + setTimeout(spusť, 100); }, 100); ``` -For `setInterval` the internal scheduler will run `func(i++)` every 100ms: +Pro `setInterval` vnitřní plánovač spustí `funkce(i++)` každých 100 ms: ![](setinterval-interval.svg) -Did you notice? +Všimli jste si? -**The real delay between `func` calls for `setInterval` is less than in the code!** +**Skutečná prodleva mezi voláními `funkce` pro `setInterval` je nižší, než uvedená v kódu!** -That's normal, because the time taken by `func`'s execution "consumes" a part of the interval. +To je normální, protože doba, kterou zabere výkon `funkce`, „spotřebuje“ část intervalu. -It is possible that `func`'s execution turns out to be longer than we expected and takes more than 100ms. +Může se stát, že výkon `funkce` bude trvat déle, než jsme očekávali, a vyžádá si více než 100 ms. -In this case the engine waits for `func` to complete, then checks the scheduler and if the time is up, runs it again *immediately*. +V takovém případě motor počká, až se `funkce` dokončí, pak zkontroluje plánovač, a pokud jeho čas vypršel, spustí funkci *okamžitě* znovu. -In the edge case, if the function always executes longer than `delay` ms, then the calls will happen without a pause at all. +V krajním případě, jestliže výkon funkce trvá vždy déle než `prodleva` ms, bude k voláním docházet úplně bez prodlevy. -And here is the picture for the nested `setTimeout`: +A zde je obrázek pro vnořený `setTimeout`: ![](settimeout-interval.svg) -**The nested `setTimeout` guarantees the fixed delay (here 100ms).** +**Vnořený `setTimeout` zaručuje pevnou prodlevu (zde 100 ms).** -That's because a new call is planned at the end of the previous one. +Je to proto, že nové volání je naplánováno na konci předchozího. -````smart header="Garbage collection and setInterval/setTimeout callback" -When a function is passed in `setInterval/setTimeout`, an internal reference is created to it and saved in the scheduler. It prevents the function from being garbage collected, even if there are no other references to it. +````smart header="Sběr odpadků a callback funkce setInterval/setTimeout" +Když je do `setInterval/setTimeout` předána funkce, vytvoří se na ni interní odkaz a ten se uloží do plánovače. To brání sběrači odpadků, aby funkci odstranil, i když na ni nejsou žádné jiné odkazy. ```js -// the function stays in memory until the scheduler calls it +// funkce zůstane v paměti, dokud ji plánovač nezavolá setTimeout(function() {...}, 100); ``` -For `setInterval` the function stays in memory until `clearInterval` is called. +Pro `setInterval` funkce zůstane v paměti, dokud není zavolán `clearInterval`. -There's a side effect. A function references the outer lexical environment, so, while it lives, outer variables live too. They may take much more memory than the function itself. So when we don't need the scheduled function anymore, it's better to cancel it, even if it's very small. +To má vedlejší efekt. Funkce se odkazuje na vnější lexikální prostředí, takže dokud existuje, existují i vnější proměnné. Ty mohou zabrat mnohem více paměti než samotná funkce. Když tedy načasovanou funkci už nepotřebujeme, je lepší ji zrušit, i kdyby byla velmi malá. ```` -## Zero delay setTimeout +## setTimeout s nulovou prodlevou -There's a special use case: `setTimeout(func, 0)`, or just `setTimeout(func)`. +Existuje speciální způsob použití: `setTimeout(funkce, 0)` nebo jen `setTimeout(funkce)`. -This schedules the execution of `func` as soon as possible. But the scheduler will invoke it only after the currently executing script is complete. +To načasuje výkon `funkce` na co nejdříve. Plánovač ji však spustí až poté, co bude dokončen aktuálně běžící skript. -So the function is scheduled to run "right after" the current script. +Funkce je tedy načasována ke spuštění „hned po“ aktuálním skriptu. -For instance, this outputs "Hello", then immediately "World": +Například tohle vypíše „Ahoj“ a hned pak „světe“: ```js run -setTimeout(() => alert("World")); +setTimeout(() => alert("světe")); -alert("Hello"); +alert("Ahoj"); ``` -The first line "puts the call into calendar after 0ms". But the scheduler will only "check the calendar" after the current script is complete, so `"Hello"` is first, and `"World"` -- after it. +První řádek „uloží volání do kalendáře za 0 ms“. Avšak plánovač „zkontroluje kalendář“ až poté, co bude aktuální skript dokončen, takže `"Ahoj"` půjde jako první a `"světe"` až po něm. + +V prohlížečích existují i pokročilejší způsoby použití načasování s nulovou prodlevou, které probereme v kapitole . -There are also advanced browser-related use cases of zero-delay timeout, that we'll discuss in the chapter . +````smart header="Nulová prodleva není ve skutečnosti nulová (v prohlížeči)" -````smart header="Zero delay is in fact not zero (in a browser)" -In the browser, there's a limitation of how often nested timers can run. The [HTML Living Standard](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers) says: "after five nested timers, the interval is forced to be at least 4 milliseconds.". +V prohlížeči je omezení, jak často se mohou vnořené časovače spouštět. [HTML Living Standard](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers) říká: „po pěti vnořených časovačích musí být interval alespoň 4 milisekundy.“ -Let's demonstrate what it means with the example below. The `setTimeout` call in it re-schedules itself with zero delay. Each call remembers the real time from the previous one in the `times` array. What do the real delays look like? Let's see: +Na následujícím příkladu si předvedeme, co to znamená. Volání `setTimeout` v něm načasuje samo sebe s nulovou prodlevou. Každé volání si pamatuje v poli `časy` skutečný čas, který uplynul od předchozího. Jak budou vypadat skutečné prodlevy? Podívejme se: ```js run -let start = Date.now(); -let times = []; +let začátek = Date.now(); +let časy = []; -setTimeout(function run() { - times.push(Date.now() - start); // remember delay from the previous call +setTimeout(function spusť() { + časy.push(Date.now() - začátek); // zapamatujeme si prodlevu od předchozího volání - if (start + 100 < Date.now()) alert(times); // show the delays after 100ms - else setTimeout(run); // else re-schedule + if (začátek + 100 < Date.now()) alert(časy); // za 100 ms zobrazíme prodlevy + else setTimeout(spusť); // jinak znovu načasujeme }); -// an example of the output: +// příklad výstupu: // 1,1,1,1,9,15,20,24,30,35,40,45,50,55,59,64,70,75,80,85,90,95,100 ``` -First timers run immediately (just as written in the spec), and then we see `9, 15, 20, 24...`. The 4+ ms obligatory delay between invocations comes into play. +Nejprve se časovače spustí okamžitě (tak, jak je uvedeno ve specifikaci) a pak vidíme `9, 15, 20, 24...`. Povinná prodleva aspoň 4 ms mezi voláními vstupuje do hry. -The similar thing happens if we use `setInterval` instead of `setTimeout`: `setInterval(f)` runs `f` few times with zero-delay, and afterwards with 4+ ms delay. +Podobná věc se stane, jestliže použijeme `setInterval` namísto `setTimeout`: `setInterval(f)` spustí `f` několikrát s nulovou prodlevou a poté s prodlevou nejméně 4 ms. -That limitation comes from ancient times and many scripts rely on it, so it exists for historical reasons. +Toto omezení pochází ze starých časů a mnoho skriptů se na ně spoléhá, takže existuje z historických důvodů. -For server-side JavaScript, that limitation does not exist, and there exist other ways to schedule an immediate asynchronous job, like [setImmediate](https://nodejs.org/api/timers.html#timers_setimmediate_callback_args) for Node.js. So this note is browser-specific. +Pro JavaScript na straně serveru toto omezení neexistuje a jsou tam jiné způsoby, jak načasovat okamžitou asynchronní činnost, například [setImmediate](https://nodejs.org/api/timers.html#timers_setimmediate_callback_args) pro Node.js. Tato poznámka je tedy specifická pro prohlížeče. ```` -## Summary +## Shrnutí -- Methods `setTimeout(func, delay, ...args)` and `setInterval(func, delay, ...args)` allow us to run the `func` once/regularly after `delay` milliseconds. -- To cancel the execution, we should call `clearTimeout/clearInterval` with the value returned by `setTimeout/setInterval`. -- Nested `setTimeout` calls are a more flexible alternative to `setInterval`, allowing us to set the time *between* executions more precisely. -- Zero delay scheduling with `setTimeout(func, 0)` (the same as `setTimeout(func)`) is used to schedule the call "as soon as possible, but after the current script is complete". -- The browser limits the minimal delay for five or more nested calls of `setTimeout` or for `setInterval` (after 5th call) to 4ms. That's for historical reasons. +- Metody `setTimeout(funkce, prodleva, ...argumenty)` a `setInterval(funkce, prodleva, ...argumenty)` nám umožňují spustit funkci `funkce` jednou/pravidelně po `prodleva` milisekundách. +- Chceme-li spuštění zrušit, měli bychom volat `clearTimeout/clearInterval` s hodnotou, kterou vrátila funkce `setTimeout/setInterval`. +- Flexibilnější alternativou k `setInterval` jsou vnořená volání `setTimeout`, která nám umožňují nastavit čas *mezi* voláními přesněji. +- Nulová prodleva v `setTimeout(funkce, 0)` (totéž jako `setTimeout(funkce)`) se používá k načasování volání „co nejdříve, ale až po dokončení aktuálního skriptu“. +- Prohlížeč omezuje minimální prodlevu pro pět nebo více vnořených volání `setTimeout` nebo pro `setInterval` (po 5. volání) na 4 ms. Je tomu tak z historických důvodů. -Please note that all scheduling methods do not *guarantee* the exact delay. +Prosíme všimněte si, že žádná časovací metoda *nezaručuje* přesnou prodlevu. -For example, the in-browser timer may slow down for a lot of reasons: -- The CPU is overloaded. -- The browser tab is in the background mode. -- The laptop is on battery saving mode. +Například časovač v prohlížeči může zpomalit z mnoha důvodů: +- CPU je přetížen. +- Záložka prohlížeče běží na pozadí. +- Laptop je v režimu úspory baterie. -All that may increase the minimal timer resolution (the minimal delay) to 300ms or even 1000ms depending on the browser and OS-level performance settings. +To všechno může zvýšit minimální rozlišení časovače (minimální prodlevu) na 300 ms nebo dokonce 1000 ms v závislosti na prohlížeči a nastavení výkonu na úrovni OS. diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/solution.js b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/solution.js index d5a09efb3..13daa3a8b 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/solution.js +++ b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/solution.js @@ -1,12 +1,13 @@ -function spy(func) { +function špión(funkce) { - function wrapper(...args) { - // using ...args instead of arguments to store "real" array in wrapper.calls - wrapper.calls.push(args); - return func.apply(this, args); + function obal(...argumenty) { + // použijeme ...argumenty místo arguments, abychom do obal.volání uložili „skutečné“ pole + obal.volání.push(argumenty); + return funkce.apply(this, argumenty); } - wrapper.calls = []; + obal.volání = []; - return wrapper; + return obal; } + \ No newline at end of file diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/source.js b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/source.js index 38da0105f..7ad5afa68 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/source.js +++ b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/source.js @@ -1,5 +1,5 @@ -function spy(func) { - // your code +function špión(funkce) { + // váš kód } diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/test.js b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/test.js index 5adfcb978..f89cd0808 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/test.js +++ b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/test.js @@ -1,44 +1,44 @@ -describe("spy", function() { - it("records calls into its property", function() { - function work() {} +describe("špión", function() { + it("zapisuje volání do své vlastnosti", function() { + function práce() {} - work = spy(work); - assert.deepEqual(work.calls, []); + práce = špión(práce); + assert.deepEqual(práce.volání, []); - work(1, 2); - assert.deepEqual(work.calls, [ + práce(1, 2); + assert.deepEqual(práce.volání, [ [1, 2] ]); - work(3, 4); - assert.deepEqual(work.calls, [ + práce(3, 4); + assert.deepEqual(práce.volání, [ [1, 2], [3, 4] ]); }); - it("transparently wraps functions", function() { + it("transparentně obaluje funkce", function() { - let sum = sinon.spy((a, b) => a + b); + let sečti = sinon.spy((a, b) => a + b); - let wrappedSum = spy(sum); + let obalenéSečti = špión(sečti); - assert.equal(wrappedSum(1, 2), 3); - assert(sum.calledWith(1, 2)); + assert.equal(obalenéSečti(1, 2), 3); + assert(sečti.calledWith(1, 2)); }); - it("transparently wraps methods", function() { + it("transparentně obaluje metody", function() { - let calc = { - sum: sinon.spy((a, b) => a + b) + let vypočítej = { + sečti: sinon.spy((a, b) => a + b) }; - calc.wrappedSum = spy(calc.sum); + vypočítej.obalenéSečti = špión(vypočítej.sečti); - assert.equal(calc.wrappedSum(1, 2), 3); - assert(calc.sum.calledWith(1, 2)); - assert(calc.sum.calledOn(calc)); + assert.equal(vypočítej.obalenéSečti(1, 2), 3); + assert(vypočítej.sečti.calledWith(1, 2)); + assert(vypočítej.sečti.calledOn(vypočítej)); }); }); diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md index 0c8a211b4..d75d1870e 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md @@ -1 +1 @@ -The wrapper returned by `spy(f)` should store all arguments and then use `f.apply` to forward the call. +Obal, který vrátí `špión(f)`, by si měl uložit všechny argumenty a pak pomocí `f.apply` přesměrovat volání. diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md index a3843107c..bfa09fd08 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md @@ -2,29 +2,29 @@ importance: 5 --- -# Spy decorator +# Špiónský dekorátor -Create a decorator `spy(func)` that should return a wrapper that saves all calls to function in its `calls` property. +Vytvořte dekorátor `špión(funkce)`, který by měl vrátit obal, který si bude ukládat všechna volání funkce do své vlastnosti `volání`. -Every call is saved as an array of arguments. +Každé volání bude uloženo jako pole argumentů. -For instance: +Například: ```js -function work(a, b) { - alert( a + b ); // work is an arbitrary function or method +function práce(a, b) { + alert( a + b ); // práce je jakákoli funkce nebo metoda } *!* -work = spy(work); +práce = špión(práce); */!* -work(1, 2); // 3 -work(4, 5); // 9 +práce(1, 2); // 3 +práce(4, 5); // 9 -for (let args of work.calls) { - alert( 'call:' + args.join() ); // "call:1,2", "call:4,5" +for (let argumenty of práce.volání) { + alert( 'volání:' + argumenty.join() ); // "volání:1,2", "volání:4,5" } ``` -P.S. That decorator is sometimes useful for unit-testing. Its advanced form is `sinon.spy` in [Sinon.JS](http://sinonjs.org/) library. +P.S. Takový dekorátor je někdy užitečný pro jednotkové testování. Jeho pokročilá forma je `sinon.spy` v knihovně [Sinon.JS](http://sinonjs.org/). diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/_js.view/solution.js b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/_js.view/solution.js index 127cff988..ec80a9e66 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/_js.view/solution.js +++ b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/_js.view/solution.js @@ -1,4 +1,4 @@ -function delay(f, ms) { +function zpozdi(f, ms) { return function() { setTimeout(() => f.apply(this, arguments), ms); diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/_js.view/test.js b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/_js.view/test.js index d9295da51..4cf787a4f 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/_js.view/test.js +++ b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/_js.view/test.js @@ -1,46 +1,46 @@ -describe("delay", function() { +describe("zpozdi", function() { before(function() { - this.clock = sinon.useFakeTimers(); + this.hodiny = sinon.useFakeTimers(); }); after(function() { - this.clock.restore(); + this.hodiny.restore(); }); - it("calls the function after the specified timeout", function() { - let start = Date.now(); + it("volá funkci až po specifikované době", function() { + let začátek = Date.now(); function f(x) { - assert.equal(Date.now() - start, 1000); + assert.equal(Date.now() - začátek, 1000); } f = sinon.spy(f); - let f1000 = delay(f, 1000); + let f1000 = zpozdi(f, 1000); f1000("test"); - this.clock.tick(2000); - assert(f.calledOnce, 'calledOnce check fails'); + this.hodiny.tick(2000); + assert(f.calledOnce, 'ověření calledOnce selhalo'); }); - it("passes arguments and this", function() { - let start = Date.now(); - let user = { - sayHi: function(phrase, who) { - assert.equal(this, user); - assert.equal(phrase, "Hello"); - assert.equal(who, "John"); - assert.equal(Date.now() - start, 1500); + it("předává argumenty a this", function() { + let začátek = Date.now(); + let uživatel = { + řekniAhoj: function(věta, kdo) { + assert.equal(this, uživatel); + assert.equal(věta, "Ahoj"); + assert.equal(kdo, "Jan"); + assert.equal(Date.now() - začátek, 1500); } }; - user.sayHi = sinon.spy(user.sayHi); + uživatel.řekniAhoj = sinon.spy(uživatel.řekniAhoj); - let spy = user.sayHi; - user.sayHi = delay(user.sayHi, 1500); + let špión = uživatel.řekniAhoj; + uživatel.řekniAhoj = zpozdi(uživatel.řekniAhoj, 1500); - user.sayHi("Hello", "John"); + uživatel.řekniAhoj("Ahoj", "Jan"); - this.clock.tick(2000); + this.hodiny.tick(2000); - assert(spy.calledOnce, 'calledOnce check failed'); + assert(špión.calledOnce, 'ověření calledOnce selhalo'); }); }); diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md index 24bb4d448..15a434536 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md @@ -1,7 +1,7 @@ -The solution: +Řešení: ```js run demo -function delay(f, ms) { +function zpozdi(f, ms) { return function() { setTimeout(() => f.apply(this, arguments), ms); @@ -9,24 +9,24 @@ function delay(f, ms) { } -let f1000 = delay(alert, 1000); +let f1000 = zpozdi(alert, 1000); -f1000("test"); // shows "test" after 1000ms +f1000("test"); // zobrazí "test" za 1000 ms ``` -Please note how an arrow function is used here. As we know, arrow functions do not have own `this` and `arguments`, so `f.apply(this, arguments)` takes `this` and `arguments` from the wrapper. +Prosíme všimněte si, jak je zde použita šipková funkce. Jak víme, šipkové funkce nemají vlastní `this` ani `arguments`, takže `f.apply(this, arguments)` převezme `this` a `arguments` z obalu. -If we pass a regular function, `setTimeout` would call it without arguments and `this=window` (assuming we're in the browser). +Předáme-li běžnou funkci, `setTimeout` ji bude volat bez argumentů a `this=window` (za předpokladu, že jsme v prohlížeči). -We still can pass the right `this` by using an intermediate variable, but that's a little bit more cumbersome: +Můžeme také předávat skutečné `this` pomocí mezilehlé proměnné, ale to je trochu pracnější: ```js -function delay(f, ms) { +function zpozdi(f, ms) { - return function(...args) { - let savedThis = this; // store this into an intermediate variable + return function(...argumenty) { + let uloženéThis = this; // uloží this do mezilehlé proměnné setTimeout(function() { - f.apply(savedThis, args); // use it here + f.apply(uloženéThis, argumenty); // zde ji použijeme }, ms); }; diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/task.md index c04c68d7e..a78b53de8 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/task.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/task.md @@ -2,25 +2,25 @@ importance: 5 --- -# Delaying decorator +# Zpožďovací dekorátor -Create a decorator `delay(f, ms)` that delays each call of `f` by `ms` milliseconds. +Vytvořte dekorátor `zpozdi(f, ms)`, který zpozdí každé volání funkce `f` o `ms` milisekund. -For instance: +Například: ```js function f(x) { alert(x); } -// create wrappers -let f1000 = delay(f, 1000); -let f1500 = delay(f, 1500); +// vytvoření obalů +let f1000 = zpozdi(f, 1000); +let f1500 = zpozdi(f, 1500); -f1000("test"); // shows "test" after 1000ms -f1500("test"); // shows "test" after 1500ms +f1000("test"); // zobrazí "test" za 1000 ms +f1500("test"); // zobrazí "test" za 1500 ms ``` -In other words, `delay(f, ms)` returns a "delayed by `ms`" variant of `f`. +Jinými slovy, `zpozdi(f, ms)` vrátí variantu `f` „zpožděnou o `ms`“. -In the code above, `f` is a function of a single argument, but your solution should pass all arguments and the context `this`. +V uvedeném kódu je `f` funkce s jediným argumentem, ale vaše řešení by mělo předávat všechny argumenty a kontextové `this`. diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js index 661dd0cf4..16bc6bc57 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js +++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js @@ -1,7 +1,7 @@ -function debounce(func, ms) { - let timeout; +function vyčkej(funkce, ms) { + let časovač; return function() { - clearTimeout(timeout); - timeout = setTimeout(() => func.apply(this, arguments), ms); + clearTimeout(časovač); + časovač = setTimeout(() => funkce.apply(this, arguments), ms); }; } diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/test.js b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/test.js index 750e649f8..558220a13 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/test.js +++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/test.js @@ -1,48 +1,48 @@ -describe('debounce', function () { +describe('vyčkej', function () { before(function () { - this.clock = sinon.useFakeTimers(); + this.hodiny = sinon.useFakeTimers(); }); after(function () { - this.clock.restore(); + this.hodiny.restore(); }); - it('for one call - runs it after given ms', function () { + it('pro jedno volání - spustí je po zadané době v ms', function () { const f = sinon.spy(); - const debounced = debounce(f, 1000); + const vyčkáváno = vyčkej(f, 1000); - debounced('test'); - assert(f.notCalled, 'not called immediately'); - this.clock.tick(1000); - assert(f.calledOnceWith('test'), 'called after 1000ms'); + vyčkáváno('test'); + assert(f.notCalled, 'nevolá se okamžitě'); + this.hodiny.tick(1000); + assert(f.calledOnceWith('test'), 'voláno po 1000 ms'); }); - it('for 3 calls - runs the last one after given ms', function () { + it('pro 3 volání - spustí poslední po zadané době v ms', function () { const f = sinon.spy(); - const debounced = debounce(f, 1000); + const vyčkáváno = vyčkej(f, 1000); - debounced('a'); - setTimeout(() => debounced('b'), 200); // ignored (too early) - setTimeout(() => debounced('c'), 500); // runs (1000 ms passed) - this.clock.tick(1000); + vyčkáváno('a'); + setTimeout(() => vyčkáváno('b'), 200); // ignorováno (příliš brzy) + setTimeout(() => vyčkáváno('c'), 500); // spustí se (1000 ms uplynulo) + this.hodiny.tick(1000); - assert(f.notCalled, 'not called after 1000ms'); + assert(f.notCalled, 'nevoláno po 1000 ms'); - this.clock.tick(500); + this.hodiny.tick(500); - assert(f.calledOnceWith('c'), 'called after 1500ms'); + assert(f.calledOnceWith('c'), 'voláno po 1500 ms'); }); - it('keeps the context of the call', function () { + it('udržuje si kontext volání', function () { let obj = { f() { assert.equal(this, obj); }, }; - obj.f = debounce(obj.f, 1000); + obj.f = vyčkej(obj.f, 1000); obj.f('test'); - this.clock.tick(5000); + this.hodiny.tick(5000); }); }); diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.view/index.html b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.view/index.html index e3b4d5842..b03998aa2 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.view/index.html +++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.view/index.html @@ -1,22 +1,22 @@ -Function handler is called on this input: +Funkce handler je volána na tomto vstupu:

-Debounced function debounce(handler, 1000) is called on this input: +Vyčkávací funkce debounce(handler, 1000) je volána na tomto vstupu:

- + diff --git a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/clock.js b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/clock.js index d701c0cae..68ac3fa70 100644 --- a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/clock.js +++ b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/clock.js @@ -1,34 +1,34 @@ -class Clock { - constructor({ template }) { - this.template = template; +class Hodiny { + constructor({ šablona }) { + this.šablona = šablona; } - render() { - let date = new Date(); + vypiš() { + let datum = new Date(); - let hours = date.getHours(); - if (hours < 10) hours = '0' + hours; + let hodiny = datum.getHours(); + if (hodiny < 10) hodiny = '0' + hodiny; - let mins = date.getMinutes(); - if (mins < 10) mins = '0' + mins; + let minuty = datum.getMinutes(); + if (minuty < 10) minuty = '0' + minuty; - let secs = date.getSeconds(); - if (secs < 10) secs = '0' + secs; + let sekundy = datum.getSeconds(); + if (sekundy < 10) sekundy = '0' + sekundy; - let output = this.template - .replace('h', hours) - .replace('m', mins) - .replace('s', secs); + let výstup = this.šablona + .replace('h', hodiny) + .replace('m', minuty) + .replace('s', sekundy); - console.log(output); + console.log(výstup); } stop() { - clearInterval(this.timer); + clearInterval(this.časovač); } start() { - this.render(); - this.timer = setInterval(() => this.render(), 1000); + this.vypiš(); + this.časovač = setInterval(() => this.vypiš(), 1000); } } diff --git a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html index c0609858b..c1747c1c8 100644 --- a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html +++ b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html @@ -1,21 +1,21 @@ diff --git a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md index bbc2c6a43..82ee41cff 100644 --- a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md +++ b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md @@ -2,14 +2,14 @@ importance: 5 --- -# Extended clock +# Rozšířené hodiny -We've got a `Clock` class. As of now, it prints the time every second. +Máme třídu `Hodiny`, která nyní vypíše čas každou sekundu. [js src="https://github.com/source.view/clock.js"] -Create a new class `ExtendedClock` that inherits from `Clock` and adds the parameter `precision` -- the number of `ms` between "ticks". Should be `1000` (1 second) by default. +Vytvořte novou třídu `RozšířenéHodiny`, která je zděděna z třídy `Hodiny` a přidává parametr `přesnost` -- počet milisekund mezi „tiky“. Standardně by měla být `1000` (1 sekunda). -- Your code should be in the file `extended-clock.js` -- Don't modify the original `clock.js`. Extend it. +- Váš kód by měl být v souboru `extended-clock.js`. +- Neměňte originální soubor `clock.js`. Rozšiřte jej. diff --git a/1-js/09-classes/02-class-inheritance/animal-rabbit-extends.svg b/1-js/09-classes/02-class-inheritance/animal-rabbit-extends.svg index 63b5a18a1..cb98dc7de 100644 --- a/1-js/09-classes/02-class-inheritance/animal-rabbit-extends.svg +++ b/1-js/09-classes/02-class-inheritance/animal-rabbit-extends.svg @@ -1 +1 @@ -constructor: Animal run: function stop: functionAnimal.prototypeconstructor: Rabbit hide: functionRabbit.prototypeAnimalRabbitnew Rabbit[[Prototype]][[Prototype]]prototypeprototypename: "White Rabbit"constructorconstructorextends \ No newline at end of file +constructor: Zvíře běž: function stůj: functionZvíře.prototypeconstructor: Králík schovejSe: functionKrálík.prototypeZvířeKrálíknew Králík[[Prototype]][[Prototype]]prototypeprototypejméno: "Bílý králík"constructorconstructorextends \ No newline at end of file diff --git a/1-js/09-classes/02-class-inheritance/article.md b/1-js/09-classes/02-class-inheritance/article.md index 464042d82..5b763a810 100644 --- a/1-js/09-classes/02-class-inheritance/article.md +++ b/1-js/09-classes/02-class-inheritance/article.md @@ -1,221 +1,221 @@ -# Class inheritance +# Třídní dědičnost -Class inheritance is a way for one class to extend another class. +Třídní dědičnost je způsob, jak může jedna třída rozšířit jinou. -So we can create new functionality on top of the existing. +Můžeme tedy vytvořit novou funkcionalitu nad existující. -## The "extends" keyword +## Klíčové slovo „extends“ -Let's say we have class `Animal`: +Řekněme, že máme třídu `Zvíře`: ```js -class Animal { - constructor(name) { - this.speed = 0; - this.name = name; +class Zvíře { + constructor(jméno) { + this.rychlost = 0; + this.jméno = jméno; } - run(speed) { - this.speed = speed; - alert(`${this.name} runs with speed ${this.speed}.`); + běž(rychlost) { + this.rychlost = rychlost; + alert(`${this.jméno} běží rychlostí ${this.rychlost}.`); } - stop() { - this.speed = 0; - alert(`${this.name} stands still.`); + stůj() { + this.rychlost = 0; + alert(`${this.jméno} klidně stojí.`); } } -let animal = new Animal("My animal"); +let zvíře = new Zvíře("Moje zvíře"); ``` -Here's how we can represent `animal` object and `Animal` class graphically: +Graficky můžeme zobrazit objekt `zvíře` a třídu `Zvíře` takto: ![](rabbit-animal-independent-animal.svg) -...And we would like to create another `class Rabbit`. +...A rádi bychom vytvořili další třídu `Králík`. -As rabbits are animals, `Rabbit` class should be based on `Animal`, have access to animal methods, so that rabbits can do what "generic" animals can do. +Protože králíci jsou zvířata, třída `Králík` by měla být založena na třídě `Zvíře` a mít přístup k metodám zvířete, aby králíci mohli dělat to, co dělají „obecná“ zvířata. -The syntax to extend another class is: `class Child extends Parent`. +Syntaxe pro rozšíření jiné třídy je: `class Dítě extends Rodič`. -Let's create `class Rabbit` that inherits from `Animal`: +Vytvořme třídu `Králík`, která bude zděděna z třídy `Zvíře`: ```js *!* -class Rabbit extends Animal { +class Králík extends Zvíře { */!* - hide() { - alert(`${this.name} hides!`); + schovejSe() { + alert(`${this.jméno} se schovává!`); } } -let rabbit = new Rabbit("White Rabbit"); +let králík = new Králík("Bílý králík"); -rabbit.run(5); // White Rabbit runs with speed 5. -rabbit.hide(); // White Rabbit hides! +králík.běž(5); // Bílý králík běží rychlostí 5. +králík.schovejSe(); // Bílý králík se schovává! ``` -Object of `Rabbit` class have access both to `Rabbit` methods, such as `rabbit.hide()`, and also to `Animal` methods, such as `rabbit.run()`. +Objekt třídy `Králík` má přístup jak k metodám třídy `Králík`, např. `králík.schovejSe()`, tak k metodám třídy `Zvíře`, např. `králík.běž()`. -Internally, `extends` keyword works using the good old prototype mechanics. It sets `Rabbit.prototype.[[Prototype]]` to `Animal.prototype`. So, if a method is not found in `Rabbit.prototype`, JavaScript takes it from `Animal.prototype`. +Klíčové slovo `extends` vnitřně funguje na principu staré dobré mechaniky prototypů. Nastaví `Králík.prototype.[[Prototype]]` na `Zvíře.prototype`. Jestliže tedy metoda není nalezena v `Králík.prototype`, JavaScript ji vezme ze `Zvíře.prototype`. ![](animal-rabbit-extends.svg) -For instance, to find `rabbit.run` method, the engine checks (bottom-up on the picture): -1. The `rabbit` object (has no `run`). -2. Its prototype, that is `Rabbit.prototype` (has `hide`, but not `run`). -3. Its prototype, that is (due to `extends`) `Animal.prototype`, that finally has the `run` method. +Například aby motor nalezl metodu `králík.běž`, prověří (na obrázku zdola nahoru): +1. Objekt `králík` (nemá žádné `běž`). +2. Jeho prototyp, tedy `Králík.prototype` (má `schovejSe`, ale ne `běž`). +3. Jeho prototyp, což je (důsledkem `extends`) `Zvíře.prototype`, který konečně má metodu `běž`. -As we can recall from the chapter , JavaScript itself uses prototypal inheritance for built-in objects. E.g. `Date.prototype.[[Prototype]]` is `Object.prototype`. That's why dates have access to generic object methods. +Jak si můžeme pamatovat z kapitoly , samotný JavaScript používá prototypovou dědičnost pro vestavěné objekty. Například `Date.prototype.[[Prototype]]` je `Object.prototype`. Proto mají data přístup k obecným objektovým metodám. -````smart header="Any expression is allowed after `extends`" -Class syntax allows to specify not just a class, but any expression after `extends`. +````smart header="Za `extends` smí být jakýkoli výraz" +Syntaxe třídy umožňuje za `extends` specifikovat nejenom třídu, ale jakýkoli výraz. -For instance, a function call that generates the parent class: +Například volání funkce, které generuje rodičovskou třídu: ```js run -function f(phrase) { +function f(věta) { return class { - sayHi() { alert(phrase); } + řekniAhoj() { alert(věta); } }; } *!* -class User extends f("Hello") {} +class Uživatel extends f("Ahoj") {} */!* -new User().sayHi(); // Hello +new Uživatel().řekniAhoj(); // Ahoj ``` -Here `class User` inherits from the result of `f("Hello")`. +Zde je třída `Uživatel` zděděna z výsledku volání `f("Ahoj")`. -That may be useful for advanced programming patterns when we use functions to generate classes depending on many conditions and can inherit from them. +To může být užitečné pro pokročilé programovací vzory, když používáme funkce ke generování tříd závisejících na mnoha podmínkách a můžeme z nich dědit. ```` -## Overriding a method +## Přepisování metod -Now let's move forward and override a method. By default, all methods that are not specified in `class Rabbit` are taken directly "as is" from `class Animal`. +Nyní pojďme dál a přepišme metodu. Standardně se všechny metody, které nejsou uvedeny v `class Králík`, berou z `class Zvíře` rovnou beze změn. -But if we specify our own method in `Rabbit`, such as `stop()` then it will be used instead: +Jestliže však specifikujeme ve třídě `Králík` svou vlastní metodu, např. `stůj()`, bude místo toho použita ona: ```js -class Rabbit extends Animal { - stop() { - // ...now this will be used for rabbit.stop() - // instead of stop() from class Animal +class Králík extends Zvíře { + stůj() { + // ...nyní bude při volání králík.stůj() použita tato metoda + // namísto stůj() ze třídy Zvíře } } ``` -Usually, however, we don't want to totally replace a parent method, but rather to build on top of it to tweak or extend its functionality. We do something in our method, but call the parent method before/after it or in the process. +Obvykle však nechceme rodičovskou metodu úplně nahradit, ale spíše na ní stavět, abychom její funkcionalitu vylepšili nebo rozšířili. Uděláme něco v naší metodě, ale v tomto procesu, před ním nebo po něm voláme rodičovskou metodu. -Classes provide `"super"` keyword for that. +K tomuto účelu třídy poskytují klíčové slovo `„super“`. -- `super.method(...)` to call a parent method. -- `super(...)` to call a parent constructor (inside our constructor only). +- `super.metoda(...)` volá rodičovskou metodu. +- `super(...)` volá rodičovský konstruktor (pouze uvnitř našeho konstruktoru). -For instance, let our rabbit autohide when stopped: +Například nechme našeho králíka, aby se po zastavení automaticky schoval: ```js run -class Animal { +class Zvíře { - constructor(name) { - this.speed = 0; - this.name = name; + constructor(jméno) { + this.rychlost = 0; + this.jméno = jméno; } - run(speed) { - this.speed = speed; - alert(`${this.name} runs with speed ${this.speed}.`); + běž(rychlost) { + this.rychlost = rychlost; + alert(`${this.jméno} běží rychlostí ${this.rychlost}.`); } - stop() { - this.speed = 0; - alert(`${this.name} stands still.`); + stůj() { + this.rychlost = 0; + alert(`${this.jméno} klidně stojí.`); } } -class Rabbit extends Animal { - hide() { - alert(`${this.name} hides!`); +class Králík extends Zvíře { + schovejSe() { + alert(`${this.jméno} se schovává!`); } *!* - stop() { - super.stop(); // call parent stop - this.hide(); // and then hide + stůj() { + super.stůj(); // volá rodičovskou metodu stůj + this.schovejSe(); // a poté schovejSe } */!* } -let rabbit = new Rabbit("White Rabbit"); +let králík = new Králík("Bílý králík"); -rabbit.run(5); // White Rabbit runs with speed 5. -rabbit.stop(); // White Rabbit stands still. White Rabbit hides! +králík.běž(5); // Bílý králík běží rychlostí 5. +králík.stůj(); // Bílý králík klidně stojí. Bílý králík se schovává! ``` -Now `Rabbit` has the `stop` method that calls the parent `super.stop()` in the process. +Nyní má `Králík` metodu `stůj`, která při provádění volá rodičovskou metodu `super.stůj()`. -````smart header="Arrow functions have no `super`" -As was mentioned in the chapter , arrow functions do not have `super`. +````smart header="Šipkové funkce nemají `super`" +Jak jsme zmínili v kapitole , šipkové funkce nemají `super`. -If accessed, it's taken from the outer function. For instance: +Pokud k němu přistoupíme, převezme se z vnější funkce. Například: ```js -class Rabbit extends Animal { - stop() { - setTimeout(() => super.stop(), 1000); // call parent stop after 1sec +class Králík extends Zvíře { + stůj() { + setTimeout(() => super.stůj(), 1000); // za 1 sekundu volá rodičovskou metodu stůj } } ``` -The `super` in the arrow function is the same as in `stop()`, so it works as intended. If we specified a "regular" function here, there would be an error: +`super` v šipkové funkci je stejné jako ve `stůj()`, funguje tedy tak, jak je zamýšleno. Kdybychom zde uvedli „obyčejnou“ funkci, nastala by chyba: ```js -// Unexpected super -setTimeout(function() { super.stop() }, 1000); +// Neočekávaný super +setTimeout(function() { super.stůj() }, 1000); ``` ```` -## Overriding constructor +## Přepisování konstruktorů -With constructors it gets a little bit tricky. +S konstruktory se to začíná trochu zamotávat. -Until now, `Rabbit` did not have its own `constructor`. +Až dosud `Králík` neměl svůj vlastní `constructor`. -According to the [specification](https://tc39.github.io/ecma262/#sec-runtime-semantics-classdefinitionevaluation), if a class extends another class and has no `constructor`, then the following "empty" `constructor` is generated: +Jestliže třída rozšiřuje jinou třídu a nemá `constructor`, podle [specifikace](https://tc39.github.io/ecma262/#sec-runtime-semantics-classdefinitionevaluation) se vygeneruje následující „prázdný“ `constructor`: ```js -class Rabbit extends Animal { - // generated for extending classes without own constructors +class Králík extends Zvíře { + // generován pro rozšiřující třídy bez vlastního konstruktoru *!* - constructor(...args) { - super(...args); + constructor(...argumenty) { + super(...argumenty); } */!* } ``` -As we can see, it basically calls the parent `constructor` passing it all the arguments. That happens if we don't write a constructor of our own. +Jak vidíme, v zásadě volá rodičovský `constructor` a předá mu všechny argumenty. To se stane, když si nenapíšeme svůj vlastní konstruktor. -Now let's add a custom constructor to `Rabbit`. It will specify the `earLength` in addition to `name`: +Nyní přidejme do třídy `Králík` vlastní konstruktor, který bude navíc k vlastnosti `jméno` specifikovat vlastnost `délkaUcha`: ```js run -class Animal { - constructor(name) { - this.speed = 0; - this.name = name; +class Zvíře { + constructor(jméno) { + this.rychlost = 0; + this.jméno = jméno; } // ... } -class Rabbit extends Animal { +class Králík extends Zvíře { *!* - constructor(name, earLength) { - this.speed = 0; - this.name = name; - this.earLength = earLength; + constructor(jméno, délkaUcha) { + this.rychlost = 0; + this.jméno = jméno; + this.délkaUcha = délkaUcha; } */!* @@ -223,405 +223,405 @@ class Rabbit extends Animal { } *!* -// Doesn't work! -let rabbit = new Rabbit("White Rabbit", 10); // Error: this is not defined. +// Nefunguje! +let králík = new Králík("Bílý králík", 10); // Chyba: this není definováno. */!* ``` -Whoops! We've got an error. Now we can't create rabbits. What went wrong? +Ouha! Obdrželi jsme chybu. Nyní nemůžeme vytvářet králíky. Co bylo špatně? -The short answer is: +Stručná odpověď zní: -- **Constructors in inheriting classes must call `super(...)`, and (!) do it before using `this`.** +- **Konstruktory ve zděděných třídách musejí volat `super(...)` a (!) musejí to udělat před použitím `this`.** -...But why? What's going on here? Indeed, the requirement seems strange. +...Ale proč? Co se tady děje? Tento požadavek zajisté vypadá podivně. -Of course, there's an explanation. Let's get into details, so you'll really understand what's going on. +Samozřejmě vysvětlení existuje. Pojďme do detailů, abyste doopravdy pochopili, co se tady odehrává. -In JavaScript, there's a distinction between a constructor function of an inheriting class (so-called "derived constructor") and other functions. A derived constructor has a special internal property `[[ConstructorKind]]:"derived"`. That's a special internal label. +V JavaScriptu je rozdíl mezi konstruktorem zděděné třídy (tzv. „odvozeným konstruktorem“) a jinými funkcemi. Odvozený konstruktor má speciální interní vlastnost `[[ConstructorKind]]:"derived"`. To je speciální vnitřní štítek. -That label affects its behavior with `new`. +Tato vlastnost ovlivňuje jeho chování s `new`. -- When a regular function is executed with `new`, it creates an empty object and assigns it to `this`. -- But when a derived constructor runs, it doesn't do this. It expects the parent constructor to do this job. +- Když je pomocí `new` volána obvyklá funkce, vytvoří prázdný objekt a přiřadí jej do `this`. +- Ale když se spustí odvozený konstruktor, neudělá to. Očekává, že tuto práci odvede rodičovský konstruktor. -So a derived constructor must call `super` in order to execute its parent (base) constructor, otherwise the object for `this` won't be created. And we'll get an error. +Odvozený konstruktor tedy musí volat `super`, aby spustil svůj rodičovský (základní, bázový) konstruktor, jinak objekt pro `this` nebude vytvořen a my dostaneme chybu. -For the `Rabbit` constructor to work, it needs to call `super()` before using `this`, like here: +Aby konstruktor `Králík` fungoval, musí volat `super()` ještě před použitím `this`, například: ```js run -class Animal { +class Zvíře { - constructor(name) { - this.speed = 0; - this.name = name; + constructor(jméno) { + this.rychlost = 0; + this.jméno = jméno; } // ... } -class Rabbit extends Animal { +class Králík extends Zvíře { - constructor(name, earLength) { + constructor(jméno, délkaUcha) { *!* - super(name); + super(jméno); */!* - this.earLength = earLength; + this.délkaUcha = délkaUcha; } // ... } *!* -// now fine -let rabbit = new Rabbit("White Rabbit", 10); -alert(rabbit.name); // White Rabbit -alert(rabbit.earLength); // 10 +// nyní je to v pořádku +let králík = new Králík("Bílý králík", 10); +alert(králík.jméno); // Bílý králík +alert(králík.délkaUcha); // 10 */!* ``` -### Overriding class fields: a tricky note +### Přepisování třídních polí: záludnost -```warn header="Advanced note" -This note assumes you have a certain experience with classes, maybe in other programming languages. +```warn header="Pokročilá poznámka" +Tato poznámka předpokládá, že již máte s třídami určité zkušenosti, možná i z jiných programovacích jazyků. -It provides better insight into the language and also explains the behavior that might be a source of bugs (but not very often). +Poskytuje lepší náhled do jazyka a rovněž vysvětluje chování, které může být zdrojem chyb (ale ne příliš často). -If you find it difficult to understand, just go on, continue reading, then return to it some time later. +Pokud se vám bude zdát obtížné jí porozumět, prostě ji přeskočte a pokračujte ve čtení. Pak se k ní vraťte někdy později. ``` -We can override not only methods, but also class fields. +Přepisovat můžeme nejen metody, ale i třídní pole. -Although, there's a tricky behavior when we access an overridden field in parent constructor, quite different from most other programming languages. +Nicméně když přistoupíme k přepsanému poli v rodičovském konstruktoru, nastane ošidné chování, poněkud odlišné od většiny ostatních programovacích jazyků. -Consider this example: +Uvažujme tento příklad: ```js run -class Animal { - name = 'animal'; +class Zvíře { + jméno = 'zvíře'; constructor() { - alert(this.name); // (*) + alert(this.jméno); // (*) } } -class Rabbit extends Animal { - name = 'rabbit'; +class Králík extends Zvíře { + jméno = 'králík'; } -new Animal(); // animal +new Zvíře(); // zvíře *!* -new Rabbit(); // animal +new Králík(); // zvíře */!* ``` -Here, class `Rabbit` extends `Animal` and overrides the `name` field with its own value. +Zde třída `Králík` rozšiřuje třídu `Zvíře` a přepisuje pole `jméno` svou vlastní hodnotou. -There's no own constructor in `Rabbit`, so `Animal` constructor is called. +Ve třídě `Králík` není vlastní konstruktor, takže se zavolá konstruktor třídy `Zvíře`. -What's interesting is that in both cases: `new Animal()` and `new Rabbit()`, the `alert` in the line `(*)` shows `animal`. +Zajímavé je, že v obou případech `new Zvíře()` i `new Králík()` volání `alert` na řádku `(*)` zobrazí `zvíře`. -**In other words, the parent constructor always uses its own field value, not the overridden one.** +**Jinými slovy, rodičovský konstruktor vždy používá svou vlastní hodnotu pole, ne přepsanou.** -What's odd about it? +Co je na tom zvláštního? -If it's not clear yet, please compare with methods. +Pokud to ještě není jasné, prosíme porovnejte si to s metodami. -Here's the same code, but instead of `this.name` field we call `this.showName()` method: +Zde je stejný kód, ale místo pole `this.jméno` voláme metodu `this.zobrazJméno()`: ```js run -class Animal { - showName() { // instead of this.name = 'animal' - alert('animal'); +class Zvíře { + zobrazJméno() { // namísto this.jméno = 'zvíře' + alert('zvíře'); } constructor() { - this.showName(); // instead of alert(this.name); + this.zobrazJméno(); // namísto alert(this.jméno); } } -class Rabbit extends Animal { - showName() { - alert('rabbit'); +class Králík extends Zvíře { + zobrazJméno() { + alert('králík'); } } -new Animal(); // animal +new Zvíře(); // zvíře *!* -new Rabbit(); // rabbit +new Králík(); // králík */!* ``` -Please note: now the output is different. +Prosíme všimněte si: nyní je výstup odlišný. -And that's what we naturally expect. When the parent constructor is called in the derived class, it uses the overridden method. +A to je to, co přirozeně očekáváme. Když je v odvozené třídě volán rodičovský konstruktor, použije přepsanou metodu. -...But for class fields it's not so. As said, the parent constructor always uses the parent field. +...Ale pro třídní pole tomu tak není. Jak bylo uvedeno, rodičovský konstruktor vždy používá rodičovské pole. -Why is there a difference? +Proč je zde tento rozdíl? -Well, the reason is the field initialization order. The class field is initialized: -- Before constructor for the base class (that doesn't extend anything), -- Immediately after `super()` for the derived class. +Důvod spočívá v pořadí inicializace polí. Třídní pole je inicializováno: +- v bázové třídě (která žádnou třídu nerozšiřuje) před konstruktorem, +- v odvozené třídě ihned po `super()`. -In our case, `Rabbit` is the derived class. There's no `constructor()` in it. As said previously, that's the same as if there was an empty constructor with only `super(...args)`. +V našem případě je `Králík` odvozená třída. Není v ní žádný `constructor()`. Jak bylo dříve uvedeno, je to totéž, jako by tam byl prázdný konstruktor obsahující pouze `super(...argumenty)`. -So, `new Rabbit()` calls `super()`, thus executing the parent constructor, and (per the rule for derived classes) only after that its class fields are initialized. At the time of the parent constructor execution, there are no `Rabbit` class fields yet, that's why `Animal` fields are used. +Takže `new Králík()` volá `super()`, tím spustí rodičovský konstruktor, a (podle pravidla pro odvozené třídy) jsou teprve poté inicializována jeho třídní pole. Ve chvíli spuštění rodičovského konstruktoru ještě neexistují žádná pole třídy `Králík`, takže se použijí pole třídy `Zvíře`. -This subtle difference between fields and methods is specific to JavaScript. +Tento drobný rozdíl mezi poli a metodami je specifický pro JavaScript. -Luckily, this behavior only reveals itself if an overridden field is used in the parent constructor. Then it may be difficult to understand what's going on, so we're explaining it here. +Naštěstí se toto chování projevuje jen tehdy, když je přepsané pole použito v rodičovském konstruktoru. Pak může být obtížné pochopit, co se děje, proto to tady vysvětlujeme. -If it becomes a problem, one can fix it by using methods or getters/setters instead of fields. +Kdyby to byl problém, můžeme ho opravit použitím metod nebo getterů/setterů namísto polí. -## Super: internals, [[HomeObject]] +## Super: vnitřní mechanismy, [[HomeObject]] -```warn header="Advanced information" -If you're reading the tutorial for the first time - this section may be skipped. +```warn header="Pokročilá informace" +Jestliže tento tutoriál čtete poprvé, můžete tuto část přeskočit. -It's about the internal mechanisms behind inheritance and `super`. +Pojednává o vnitřních mechanismech v pozadí dědičnosti a `super`. ``` -Let's get a little deeper under the hood of `super`. We'll see some interesting things along the way. +Pronikněme trochu hlouběji pod povrch `super`. Uvidíme tam zajímavé věci. -First to say, from all that we've learned till now, it's impossible for `super` to work at all! +Nejprve je třeba říci, že podle všeho, čemu jsme se dosud naučili, je nemožné, aby `super` vůbec fungovalo! -Yeah, indeed, let's ask ourselves, how it should technically work? When an object method runs, it gets the current object as `this`. If we call `super.method()` then, the engine needs to get the `method` from the prototype of the current object. But how? +Ano, zajisté, zeptejme se sami sebe, jak by to mělo technicky fungovat? Když se spustí objektová metoda, dostane jako `this` aktuální objekt. Pokud pak zavoláme `super.metoda()`, motor musí získat metodu `metoda` z prototypu aktuálního objektu. Ale jak? -The task may seem simple, but it isn't. The engine knows the current object `this`, so it could get the parent `method` as `this.__proto__.method`. Unfortunately, such a "naive" solution won't work. +Tento úkol se může zdát jednoduchý, ale není. Motor zná aktuální objekt `this`, takže může získat rodičovskou metodu `metoda` jako `this.__proto__.metoda`. Naneštěstí takové „naivní“ řešení nebude fungovat. -Let's demonstrate the problem. Without classes, using plain objects for the sake of simplicity. +Demonstrujme si problém. Pro zjednodušení bez tříd, jen s použitím planých objektů. -You may skip this part and go below to the `[[HomeObject]]` subsection if you don't want to know the details. That won't harm. Or read on if you're interested in understanding things in-depth. +Pokud nechcete znát detaily, můžete tuto část přeskočit a pokračovat k podkapitole `[[HomeObject]]`. Neuškodí vám to. Pokud chcete porozumět věcem do hloubky, pokračujte ve čtení. -In the example below, `rabbit.__proto__ = animal`. Now let's try: in `rabbit.eat()` we'll call `animal.eat()`, using `this.__proto__`: +V následujícím příkladu `králík.__proto__ = zvíře`. Nyní to zkusme: v `králík.žer()` zavolejme `zvíře.žer()` pomocí `this.__proto__`: ```js run -let animal = { - name: "Animal", - eat() { - alert(`${this.name} eats.`); +let zvíře = { + jméno: "Zvíře", + žer() { + alert(`${this.jméno} žere.`); } }; -let rabbit = { - __proto__: animal, - name: "Rabbit", - eat() { +let králík = { + __proto__: zvíře, + jméno: "Králík", + žer() { *!* - // that's how super.eat() could presumably work - this.__proto__.eat.call(this); // (*) + // předpokládáme, že takto funguje super.žer() + this.__proto__.žer.call(this); // (*) */!* } }; -rabbit.eat(); // Rabbit eats. +králík.žer(); // Králík žere. ``` -At the line `(*)` we take `eat` from the prototype (`animal`) and call it in the context of the current object. Please note that `.call(this)` is important here, because a simple `this.__proto__.eat()` would execute parent `eat` in the context of the prototype, not the current object. +Na řádku `(*)` převezmeme metodu `žer` z prototypu (`zvíře`) a zavoláme ji v kontextu aktuálního objektu. Prosíme všimněte si, že zde je důležité `.call(this)`, protože pouhé `this.__proto__.žer()` by volalo rodičovskou metodu `žer` v kontextu prototypu, ne aktuálního objektu. -And in the code above it actually works as intended: we have the correct `alert`. +A ve výše uvedeném kódu to skutečně funguje tak, jak zamýšlíme: máme správné `alert`. -Now let's add one more object to the chain. We'll see how things break: +Nyní přidáme do řetězce jeden další objekt. Uvidíme, jak se to rozbije: ```js run -let animal = { - name: "Animal", - eat() { - alert(`${this.name} eats.`); +let zvíře = { + jméno: "Zvíře", + žer() { + alert(`${this.jméno} žere.`); } }; -let rabbit = { - __proto__: animal, - eat() { - // ...bounce around rabbit-style and call parent (animal) method - this.__proto__.eat.call(this); // (*) +let králík = { + __proto__: zvíře, + žer() { + // ...poskakujeme po okolí králičím stylem a zavoláme metodu rodiče (zvíře) + this.__proto__.žer.call(this); // (*) } }; -let longEar = { - __proto__: rabbit, - eat() { - // ...do something with long ears and call parent (rabbit) method - this.__proto__.eat.call(this); // (**) +let ušatý = { + __proto__: králík, + žer() { + // ...uděláme něco s dlouhýma ušima a zavoláme metodu rodiče (králík) + this.__proto__.žer.call(this); // (**) } }; *!* -longEar.eat(); // Error: Maximum call stack size exceeded +ušatý.žer(); // Chyba: Překročena maximální velikost zásobníku */!* ``` -The code doesn't work anymore! We can see the error trying to call `longEar.eat()`. +Kód už nefunguje! Když se pokusíme zavolat `ušatý.žer()`, uvidíme chybu. -It may be not that obvious, but if we trace `longEar.eat()` call, then we can see why. In both lines `(*)` and `(**)` the value of `this` is the current object (`longEar`). That's essential: all object methods get the current object as `this`, not a prototype or something. +Nemusí to být zcela zřejmé, ale když si projdeme volání `ušatý.žer()`, uvidíme proč. Na obou řádcích `(*)` i `(**)` je hodnota `this` aktuální objekt (`ušatý`). To je podstatné: všechny objektové metody dostanou jako `this` aktuální objekt, ne prototyp nebo něco jiného. -So, in both lines `(*)` and `(**)` the value of `this.__proto__` is exactly the same: `rabbit`. They both call `rabbit.eat` without going up the chain in the endless loop. +Na obou řádcích `(*)` a `(**)` je tedy hodnota `this.__proto__` naprosto stejná: `králík`. Oba volají `králík.žer` v nekonečné smyčce, aniž by v řetězci postoupily výš. -Here's the picture of what happens: +Na obrázku je vidět, co se stane: ![](this-super-loop.svg) -1. Inside `longEar.eat()`, the line `(**)` calls `rabbit.eat` providing it with `this=longEar`. +1. Uvnitř `ušatý.žer()` řádek `(**)` volá `králík.žer` a poskytne mu `this=ušatý`. ```js - // inside longEar.eat() we have this = longEar - this.__proto__.eat.call(this) // (**) - // becomes - longEar.__proto__.eat.call(this) - // that is - rabbit.eat.call(this); + // uvnitř ušatý.žer() máme this = ušatý + this.__proto__.žer.call(this) // (**) + // se promění na + ušatý.__proto__.žer.call(this) + // to je + králík.žer.call(this); ``` -2. Then in the line `(*)` of `rabbit.eat`, we'd like to pass the call even higher in the chain, but `this=longEar`, so `this.__proto__.eat` is again `rabbit.eat`! +2. Pak na řádku `(*)` metody `králík.žer` bychom rádi předali volání v řetězci ještě výš, ale `this=ušatý`, takže `this.__proto__.žer` je opět `králík.žer`! ```js - // inside rabbit.eat() we also have this = longEar - this.__proto__.eat.call(this) // (*) - // becomes - longEar.__proto__.eat.call(this) - // or (again) - rabbit.eat.call(this); + // uvnitř králík.žer() máme rovněž this = ušatý + this.__proto__.žer.call(this) // (*) + // se promění na + ušatý.__proto__.žer.call(this) + // neboli (opět) + králík.žer.call(this); ``` -3. ...So `rabbit.eat` calls itself in the endless loop, because it can't ascend any further. +3. ...Takže `králík.žer` volá sama sebe v nekonečné smyčce, protože nemůže postoupit nikam výš. -The problem can't be solved by using `this` alone. +Tento problém nelze vyřešit pouze pomocí `this`. ### `[[HomeObject]]` -To provide the solution, JavaScript adds one more special internal property for functions: `[[HomeObject]]`. +Aby JavaScript poskytl řešení, přidává navíc jednu speciální interní vlastnost funkcí: `[[HomeObject]]`. -When a function is specified as a class or object method, its `[[HomeObject]]` property becomes that object. +Když je funkce specifikována jako metoda třídy nebo objektu, tento objekt se stane hodnotou její vlastnosti `[[HomeObject]]`. -Then `super` uses it to resolve the parent prototype and its methods. +Pak jej `super` používá k tomu, aby vyhodnotil rodičovský prototyp a jeho metody. -Let's see how it works, first with plain objects: +Podívejme se, jak to funguje, nejprve s planými objekty: ```js run -let animal = { - name: "Animal", - eat() { // animal.eat.[[HomeObject]] == animal - alert(`${this.name} eats.`); +let zvíře = { + jméno: "Zvíře", + žer() { // zvíře.žer.[[HomeObject]] == zvíře + alert(`${this.jméno} žere.`); } }; -let rabbit = { - __proto__: animal, - name: "Rabbit", - eat() { // rabbit.eat.[[HomeObject]] == rabbit - super.eat(); +let králík = { + __proto__: zvíře, + jméno: "Králík", + žer() { // králík.žer.[[HomeObject]] == králík + super.žer(); } }; -let longEar = { - __proto__: rabbit, - name: "Long Ear", - eat() { // longEar.eat.[[HomeObject]] == longEar - super.eat(); +let ušatý = { + __proto__: králík, + jméno: "Ušoun", + žer() { // ušatý.žer.[[HomeObject]] == ušatý + super.žer(); } }; *!* -// works correctly -longEar.eat(); // Long Ear eats. +// funguje správně +ušatý.žer(); // Ušoun žere. */!* ``` -It works as intended, due to `[[HomeObject]]` mechanics. A method, such as `longEar.eat`, knows its `[[HomeObject]]` and takes the parent method from its prototype. Without any use of `this`. +Díky mechanice `[[HomeObject]]` to funguje tak, jak jsme zamýšleli. Metoda, např. `ušatý.žer`, zná svůj `[[HomeObject]]` a převezme rodičovskou metodu z jeho prototypu. Bez jakéhokoli použití `this`. -### Methods are not "free" +### Metody nejsou „volné“ -As we've known before, generally functions are "free", not bound to objects in JavaScript. So they can be copied between objects and called with another `this`. +Jak již víme, funkce jsou v JavaScriptu obecně „volné“, nevázané k objektům. Mohou tedy být kopírovány mezi objekty a volány s jiným `this`. -The very existence of `[[HomeObject]]` violates that principle, because methods remember their objects. `[[HomeObject]]` can't be changed, so this bond is forever. +Samotná existence `[[HomeObject]]` však tento princip porušuje, jelikož metody si pamatují své objekty. `[[HomeObject]]` nemůže být změněn, takže tato vazba je trvalá. -The only place in the language where `[[HomeObject]]` is used -- is `super`. So, if a method does not use `super`, then we can still consider it free and copy between objects. But with `super` things may go wrong. +Jediné místo v jazyce, kde je `[[HomeObject]]` používán, je `super`. Jestliže tedy metoda nepoužívá `super`, můžeme ji stále považovat za volnou a kopírovat ji mezi objekty. Ale se `super` se to může pokazit. -Here's the demo of a wrong `super` result after copying: +Následuje příklad špatného výsledku `super` po kopírování: ```js run -let animal = { - sayHi() { - alert(`I'm an animal`); +let zvíře = { + řekniAhoj() { + alert(`Jsem zvíře`); } }; -// rabbit inherits from animal -let rabbit = { - __proto__: animal, - sayHi() { - super.sayHi(); +// králík je zděděn ze zvířete +let králík = { + __proto__: zvíře, + řekniAhoj() { + super.řekniAhoj(); } }; -let plant = { - sayHi() { - alert("I'm a plant"); +let rostlina = { + řekniAhoj() { + alert("Jsem rostlina"); } }; -// tree inherits from plant -let tree = { - __proto__: plant, +// strom je zděděn z rostliny +let strom = { + __proto__: rostlina, *!* - sayHi: rabbit.sayHi // (*) + řekniAhoj: králík.řekniAhoj // (*) */!* }; *!* -tree.sayHi(); // I'm an animal (?!?) +strom.řekniAhoj(); // Jsem zvíře (?!?) */!* ``` -A call to `tree.sayHi()` shows "I'm an animal". Definitely wrong. +Volání `strom.řekniAhoj()` zobrazí „Jsem zvíře“. To je rozhodně špatně. -The reason is simple: -- In the line `(*)`, the method `tree.sayHi` was copied from `rabbit`. Maybe we just wanted to avoid code duplication? -- Its `[[HomeObject]]` is `rabbit`, as it was created in `rabbit`. There's no way to change `[[HomeObject]]`. -- The code of `tree.sayHi()` has `super.sayHi()` inside. It goes up from `rabbit` and takes the method from `animal`. +Důvod je prostý: +- Na řádku `(*)` je metoda `strom.řekniAhoj` zkopírována z objektu `králík`. Možná jsme se chtěli zdržet zdvojení kódu? +- Její `[[HomeObject]]` je `králík`, protože byla vytvořena v objektu `králík`. Není žádný způsob, jak `[[HomeObject]]` změnit. +- Uvnitř kódu metody `strom.řekniAhoj()` je obsaženo `super.řekniAhoj()`. Toto volání postupuje nahoru od objektu `králík` a přebere tuto metodu z objektu `zvíře`. -Here's the diagram of what happens: +Na diagramu je vidět, co se stane: ![](super-homeobject-wrong.svg) -### Methods, not function properties +### Metody, ne funkční vlastnosti -`[[HomeObject]]` is defined for methods both in classes and in plain objects. But for objects, methods must be specified exactly as `method()`, not as `"method: function()"`. +`[[HomeObject]]` je definován pro metody ve třídách i v planých objektech. Pro objekty však metody musejí být specifikovány přímo jako `metoda()`, ne jako `„metoda: function()“`. -The difference may be non-essential for us, but it's important for JavaScript. +Rozdíl pro nás nemusí být důležitý, ale pro JavaScript je podstatný. -In the example below a non-method syntax is used for comparison. `[[HomeObject]]` property is not set and the inheritance doesn't work: +Pro srovnání v následujícím příkladu použijeme syntaxi bez metod. Vlastnost `[[HomeObject]]` se nenastaví a dědičnost nefunguje: ```js run -let animal = { - eat: function() { // intentionally writing like this instead of eat() {... +let zvíře = { + žer: function() { // toto píšeme úmyslně namísto žer() {... // ... } }; -let rabbit = { - __proto__: animal, - eat: function() { - super.eat(); +let králík = { + __proto__: zvíře, + žer: function() { + super.žer(); } }; *!* -rabbit.eat(); // Error calling super (because there's no [[HomeObject]]) +králík.žer(); // Chyba při volání super (protože není žádný [[HomeObject]]) */!* ``` -## Summary +## Shrnutí -1. To extend a class: `class Child extends Parent`: - - That means `Child.prototype.__proto__` will be `Parent.prototype`, so methods are inherited. -2. When overriding a constructor: - - We must call parent constructor as `super()` in `Child` constructor before using `this`. -3. When overriding another method: - - We can use `super.method()` in a `Child` method to call `Parent` method. -4. Internals: - - Methods remember their class/object in the internal `[[HomeObject]]` property. That's how `super` resolves parent methods. - - So it's not safe to copy a method with `super` from one object to another. +1. Pro rozšíření třídy: `class Dítě extends Rodič`: + - To znamená, že `Dítě.prototype.__proto__` bude `Rodič.prototype`, takže metody budou zděděny. +2. Když přepisujeme konstruktor: + - V konstruktoru třídy `Dítě` musíme před použitím `this` zavolat rodičovský konstruktor pomocí `super()`. +3. Když přepisujeme jinou metodu: + - V metodě třídy `Dítě` můžeme pomocí `super.metoda()` volat metodu třídy `Rodič`. +4. Vnitřní záležitosti: + - Metody si pamatují svou třídu nebo objekt v interní vlastnosti `[[HomeObject]]`. Tímto způsobem `super` vyhodnocuje rodičovské metody. + - Není tedy bezpečné kopírovat metodu obsahující `super` z jednoho objektu do jiného. -Also: -- Arrow functions don't have their own `this` or `super`, so they transparently fit into the surrounding context. +Navíc: +- Šipkové funkce nemají vlastní `this` ani `super`, takže průhledně zapadají do okolního kontextu. diff --git a/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2.svg b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2.svg index 72e47e34c..2de4c43c4 100644 --- a/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2.svg +++ b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2.svg @@ -1 +1 @@ -jump: functionRabbit.prototyperabbiteat: functionAnimal.prototypename: "White Rabbit"[[Prototype]][[Prototype]]Rabbit.prototype.__proto__ = Animal.prototype sets thistoString: function hasOwnProperty: function ...Object.prototype[[Prototype]][[Prototype]]null \ No newline at end of file +jump: functionRabbit.prototyperabbiteat: functionAnimal.prototypejméno: "Bílý králík"[[Prototype]][[Prototype]]Rabbit.prototype.__proto__ = Animal.prototype sets thistoString: function hasOwnProperty: function ...Object.prototype[[Prototype]][[Prototype]]null \ No newline at end of file diff --git a/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal.svg b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal.svg index bced3d355..1a8198a9a 100644 --- a/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal.svg +++ b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal.svg @@ -1 +1 @@ -methods of RabbitRabbit.prototyperabbitmethods of AnimalAnimal.prototype[[Prototype]][[Prototype]]properties of rabbit \ No newline at end of file +metody KrálíkaRabbit.prototyperabbitmetody ZvířeteAnimal.prototype[[Prototype]][[Prototype]]vlastnosti králíka \ No newline at end of file diff --git a/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-animal.svg b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-animal.svg index f53fc92de..5a1adb5db 100644 --- a/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-animal.svg +++ b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-animal.svg @@ -1 +1 @@ - constructor: Animal run: function stop: functionAnimal.prototypeAnimalnew Animal[[Prototype]]prototypename: "My animal" \ No newline at end of file + constructor: Zvíře běž: function stůj: functionZvíře.prototypeZvířenew Zvíře[[Prototype]]prototypejméno: "Moje zvíře" \ No newline at end of file diff --git a/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-rabbit.svg b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-rabbit.svg index 2f30a3a90..c1a74190c 100644 --- a/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-rabbit.svg +++ b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-rabbit.svg @@ -1 +1 @@ - constructor: Rabbit hide: functionRabbit.prototypeRabbitnew Rabbit[[Prototype]]prototypename: "My rabbit" \ No newline at end of file + constructor: Rabbit hide: functionRabbit.prototypeRabbitnew Rabbit[[Prototype]]prototypejméno: "Můj králík" \ No newline at end of file diff --git a/1-js/09-classes/02-class-inheritance/super-homeobject-wrong.svg b/1-js/09-classes/02-class-inheritance/super-homeobject-wrong.svg index f6450ddc4..e2bc74459 100644 --- a/1-js/09-classes/02-class-inheritance/super-homeobject-wrong.svg +++ b/1-js/09-classes/02-class-inheritance/super-homeobject-wrong.svg @@ -1 +1 @@ -sayHiplantsayHitreesayHianimalrabbit[[HomeObject]]sayHi \ No newline at end of file +řekniAhojrostlinařekniAhojstromřekniAhojzvířekrálík[[HomeObject]]řekniAhoj \ No newline at end of file diff --git a/1-js/09-classes/02-class-inheritance/this-super-loop.svg b/1-js/09-classes/02-class-inheritance/this-super-loop.svg index 4f5f45034..a1c2460d1 100644 --- a/1-js/09-classes/02-class-inheritance/this-super-loop.svg +++ b/1-js/09-classes/02-class-inheritance/this-super-loop.svg @@ -1 +1 @@ -rabbitlongEarrabbitlongEar \ No newline at end of file +králíkušatýkrálíkušatý \ No newline at end of file diff --git a/1-js/09-classes/03-static-properties-methods/3-class-extend-object/rabbit-extends-object.svg b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/rabbit-extends-object.svg index 915ab9aa6..452776ca4 100644 --- a/1-js/09-classes/03-static-properties-methods/3-class-extend-object/rabbit-extends-object.svg +++ b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/rabbit-extends-object.svg @@ -1 +1 @@ -call: function bind: function ...Function.prototypeconstructorObjectRabbit[[Prototype]][[Prototype]]constructorcall: function bind: function ...Function.prototypeRabbit[[Prototype]]constructorclass Rabbitclass Rabbit extends Object \ No newline at end of file +call: function bind: function ...Function.prototypeconstructorObjectKrálík[[Prototype]][[Prototype]]constructorcall: function bind: function ...Function.prototypeKrálík[[Prototype]]constructorclass Králíkclass Králík extends Object \ No newline at end of file diff --git a/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md index cb9829ce0..cd874efa3 100644 --- a/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md +++ b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md @@ -1,81 +1,81 @@ -First, let's see why the latter code doesn't work. +Nejprve se podívejme, proč poslední uvedený kód nefunguje. -The reason becomes obvious if we try to run it. An inheriting class constructor must call `super()`. Otherwise `"this"` won't be "defined". +Důvod bude zřejmý, když se ho pokusíme spustit. Konstruktor zděděné třídy musí volat `super()`, jinak nebude „definováno“ `„this“`. -So here's the fix: +Zde je tedy oprava: ```js run -class Rabbit extends Object { - constructor(name) { +class Králík extends Object { + constructor(jméno) { *!* - super(); // need to call the parent constructor when inheriting + super(); // při dědění je nutné volat rodičovský konstruktor */!* - this.name = name; + this.jméno = jméno; } } -let rabbit = new Rabbit("Rab"); +let králík = new Králík("Bobek"); -alert( rabbit.hasOwnProperty('name') ); // true +alert( králík.hasOwnProperty('jméno') ); // true ``` -But that's not all yet. +To však ještě není všechno. -Even after the fix, there's still an important difference between `"class Rabbit extends Object"` and `class Rabbit`. +I po této opravě bude stále existovat důležitý rozdíl mezi `„class Králík extends Object“` a `class Králík`. -As we know, the "extends" syntax sets up two prototypes: +Jak víme, syntaxe „extends“ nastavuje dva prototypy: -1. Between `"prototype"` of the constructor functions (for methods). -2. Between the constructor functions themselves (for static methods). +1. Mezi `"prototype"` konstruktorů (pro metody). +2. Mezi samotnými konstruktory (pro statické metody). -In the case of `class Rabbit extends Object` it means: +V případě `class Králík extends Object` to znamená: ```js run -class Rabbit extends Object {} +class Králík extends Object {} -alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true -alert( Rabbit.__proto__ === Object ); // (2) true +alert( Králík.prototype.__proto__ === Object.prototype ); // (1) true +alert( Králík.__proto__ === Object ); // (2) true ``` -So `Rabbit` now provides access to the static methods of `Object` via `Rabbit`, like this: +`Králík` tedy nyní poskytuje přístup ke statickým metodám třídy `Object` přes třídu `Králík`, například: ```js run -class Rabbit extends Object {} +class Králík extends Object {} *!* -// normally we call Object.getOwnPropertyNames -alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b +// běžně voláme Object.getOwnPropertyNames +alert ( Králík.getOwnPropertyNames({a: 1, b: 2})); // a,b */!* ``` -But if we don't have `extends Object`, then `Rabbit.__proto__` is not set to `Object`. +Jestliže však nemáme `extends Object`, pak se `Králík.__proto__` nenastaví na `Object`. -Here's the demo: +Zde je ukázka: ```js run -class Rabbit {} +class Králík {} -alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true -alert( Rabbit.__proto__ === Object ); // (2) false (!) -alert( Rabbit.__proto__ === Function.prototype ); // as any function by default +alert( Králík.prototype.__proto__ === Object.prototype ); // (1) true +alert( Králík.__proto__ === Object ); // (2) false (!) +alert( Králík.__proto__ === Function.prototype ); // jako standardně kterákoli funkce *!* -// error, no such function in Rabbit -alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error +// chyba, ve třídě Králík taková funkce není +alert ( Králík.getOwnPropertyNames({a: 1, b: 2})); // Chyba */!* ``` -So `Rabbit` doesn't provide access to static methods of `Object` in that case. +`Králík` tedy v tomto případě neposkytuje přístup ke statickým metodám třídy `Object`. -By the way, `Function.prototype` also has "generic" function methods, like `call`, `bind` etc. They are ultimately available in both cases, because for the built-in `Object` constructor, `Object.__proto__ === Function.prototype`. +Mimochodem, `Function.prototype` obsahuje „obecné“ funkční metody, např. `call`, `bind` atd. Ty jsou definitivně dostupné v obou případech, protože pro zabudovaný konstruktor třídy `Object` platí `Object.__proto__ === Function.prototype`. -Here's the picture: +Zde je obrázek: ![](rabbit-extends-object.svg) -So, to put it short, there are two differences: +Abychom to tedy zkrátili, existují dva rozdíly: -| class Rabbit | class Rabbit extends Object | +| class Králík | class Králík extends Object | |--------------|------------------------------| -| -- | needs to call `super()` in constructor | -| `Rabbit.__proto__ === Function.prototype` | `Rabbit.__proto__ === Object` | +| -- | musí v konstruktoru volat `super()` | +| `Králík.__proto__ === Function.prototype` | `Králík.__proto__ === Object` | diff --git a/1-js/09-classes/03-static-properties-methods/3-class-extend-object/task.md b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/task.md index 1d0f98a74..af0e33844 100644 --- a/1-js/09-classes/03-static-properties-methods/3-class-extend-object/task.md +++ b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/task.md @@ -2,41 +2,41 @@ importance: 3 --- -# Class extends Object? +# Třída rozšiřuje Object? -As we know, all objects normally inherit from `Object.prototype` and get access to "generic" object methods like `hasOwnProperty` etc. +Jak víme, všechny objekty běžně dědí z `Object.prototype` a získávají přístup k „obecným“ objektovým metodám jako `hasOwnProperty` a podobně. -For instance: +Například: ```js run -class Rabbit { - constructor(name) { - this.name = name; +class Králík { + constructor(jméno) { + this.jméno = jméno; } } -let rabbit = new Rabbit("Rab"); +let králík = new Králík("Bobek"); *!* -// hasOwnProperty method is from Object.prototype -alert( rabbit.hasOwnProperty('name') ); // true +// metoda hasOwnProperty je z Object.prototype +alert( králík.hasOwnProperty('jméno') ); // true */!* ``` -But if we spell it out explicitly like `"class Rabbit extends Object"`, then the result would be different from a simple `"class Rabbit"`? +Pokud však výslovně uvedeme `„class Králík extends Object“`, bude se výsledek lišit od prostého `„class Králík“`? -What's the difference? +Jaký je rozdíl? -Here's an example of such code (it doesn't work -- why? fix it?): +Zde je příklad takového kódu (nefunguje -- proč? opravte ho): ```js -class Rabbit extends Object { - constructor(name) { - this.name = name; +class Králík extends Object { + constructor(jméno) { + this.jméno = jméno; } } -let rabbit = new Rabbit("Rab"); +let králík = new Králík("Bobek"); -alert( rabbit.hasOwnProperty('name') ); // Error +alert( králík.hasOwnProperty('jméno') ); // Chyba ``` diff --git a/1-js/09-classes/03-static-properties-methods/animal-rabbit-static.svg b/1-js/09-classes/03-static-properties-methods/animal-rabbit-static.svg index 3e354b895..dbbf94a96 100644 --- a/1-js/09-classes/03-static-properties-methods/animal-rabbit-static.svg +++ b/1-js/09-classes/03-static-properties-methods/animal-rabbit-static.svg @@ -1 +1 @@ -constructor: Animal run: functionAnimal.prototypeconstructor: Rabbit hide: functionRabbit.prototypeAnimalRabbitrabbit[[Prototype]][[Prototype]][[Prototype]]prototypeprototypecomparename: "White Rabbit" \ No newline at end of file +constructor: Zvíře běž: functionZvíře.prototypeconstructor: Králík schovejSe: functionKrálík.prototypeZvířeKrálíkkrálík[[Prototype]][[Prototype]][[Prototype]]prototypeprototypeporovnejjméno: "Bílý králík" \ No newline at end of file diff --git a/1-js/09-classes/03-static-properties-methods/article.md b/1-js/09-classes/03-static-properties-methods/article.md index 4b493a5e8..109f39cc8 100644 --- a/1-js/09-classes/03-static-properties-methods/article.md +++ b/1-js/09-classes/03-static-properties-methods/article.md @@ -1,249 +1,249 @@ -# Static properties and methods +# Statické vlastnosti a metody -We can also assign a method to the class as a whole. Such methods are called *static*. +Metodu můžeme také přiřadit samotné třídě jako celku. Takové metody se nazývají *statické*. -In a class declaration, they are prepended by `static` keyword, like this: +V deklaraci třídy jsou předznamenány klíčovým slovem `static`, například: ```js run -class User { +class Uživatel { *!* - static staticMethod() { + static statickáMetoda() { */!* - alert(this === User); + alert(this === Uživatel); } } -User.staticMethod(); // true +Uživatel.statickáMetoda(); // true ``` -That actually does the same as assigning it as a property directly: +To ve skutečnosti udělá totéž, jako kdybychom tuto metodu přímo přiřadili jako vlastnost: ```js run -class User { } +class Uživatel { } -User.staticMethod = function() { - alert(this === User); +Uživatel.statickáMetoda = function() { + alert(this === Uživatel); }; -User.staticMethod(); // true +Uživatel.statickáMetoda(); // true ``` -The value of `this` in `User.staticMethod()` call is the class constructor `User` itself (the "object before dot" rule). +Hodnota `this` ve volání `Uživatel.statickáMetoda()` je samotný třídní konstruktor `Uživatel` (podle pravidla „objekt před tečkou“). -Usually, static methods are used to implement functions that belong to the class as a whole, but not to any particular object of it. +Statické metody se obvykle používají k implementaci funkcí, které patří třídě jako celku, ale nepatří žádnému jejímu konkrétnímu objektu. -For instance, we have `Article` objects and need a function to compare them. +Například máme objekty třídy `Článek` a potřebujeme funkci, která je bude porovnávat. -A natural solution would be to add `Article.compare` static method: +Přirozené řešení by bylo přidat statickou metodu `Článek.porovnej`: ```js run -class Article { - constructor(title, date) { - this.title = title; - this.date = date; +class Článek { + constructor(titulek, datum) { + this.titulek = titulek; + this.datum = datum; } *!* - static compare(articleA, articleB) { - return articleA.date - articleB.date; + static porovnej(článekA, článekB) { + return článekA.datum - článekB.datum; } */!* } -// usage -let articles = [ - new Article("HTML", new Date(2019, 1, 1)), - new Article("CSS", new Date(2019, 0, 1)), - new Article("JavaScript", new Date(2019, 11, 1)) +// použití +let články = [ + new Článek("HTML", new Date(2019, 1, 1)), + new Článek("CSS", new Date(2019, 0, 1)), + new Článek("JavaScript", new Date(2019, 11, 1)) ]; *!* -articles.sort(Article.compare); +články.sort(Článek.porovnej); */!* -alert( articles[0].title ); // CSS +alert( články[0].titulek ); // CSS ``` -Here `Article.compare` method stands "above" articles, as a means to compare them. It's not a method of an article, but rather of the whole class. +Zde metoda `Článek.porovnej` stojí „nad“ články jako způsob jejich porovnávání. Není to metoda článku, ale metoda celé třídy. -Another example would be a so-called "factory" method. +Jiným příkladem může být tzv. „tovární“ metoda. -Let's say, we need multiple ways to create an article: +Dejme tomu, že potřebujeme více způsobů, jak vytvořit článek: -1. Create by given parameters (`title`, `date` etc). -2. Create an empty article with today's date. -3. ...or else somehow. +1. Vytvořit jej ze zadaných parametrů (`titulek`, `datum` atd.). +2. Vytvořit prázdný článek s dnešním datem. +3. ...nebo nějak jinak. -The first way can be implemented by the constructor. And for the second one we can make a static method of the class. +První způsob můžeme implementovat konstruktorem. A pro druhý můžeme vytvořit statickou metodu třídy. -Such as `Article.createTodays()` here: +Například `Článek.vytvořDnešní()` zde: ```js run -class Article { - constructor(title, date) { - this.title = title; - this.date = date; +class Článek { + constructor(titulek, datum) { + this.titulek = titulek; + this.datum = datum; } *!* - static createTodays() { - // remember, this = Article - return new this("Today's digest", new Date()); + static vytvořDnešní() { + // pamatujte, že this = Článek + return new this("Dnešní přehled", new Date()); } */!* } -let article = Article.createTodays(); +let článek = Článek.vytvořDnešní(); -alert( article.title ); // Today's digest +alert( článek.titulek ); // Dnešní přehled ``` -Now every time we need to create a today's digest, we can call `Article.createTodays()`. Once again, that's not a method of an article, but a method of the whole class. +Nyní pokaždé, když budeme potřebovat vytvořit dnešní přehled, můžeme volat `Článek.vytvořDnešní()`. Opět to není metoda článku, ale metoda celé třídy. -Static methods are also used in database-related classes to search/save/remove entries from the database, like this: +Statické metody se také používají ve třídách vztahujících se k databázím pro hledání, ukládání a odstraňování záznamů z databáze, například: ```js -// assuming Article is a special class for managing articles -// static method to remove the article by id: -Article.remove({id: 12345}); +// předpokládejme, že Článek je speciální třída pro práci s články +// statická metoda pro odstranění článku podle jeho id: +Článek.odstraň({id: 12345}); ``` -````warn header="Static methods aren't available for individual objects" -Static methods are callable on classes, not on individual objects. +````warn header="Statické metody nejsou dostupné pro jednotlivé objekty" +Statické metody lze volat na třídách, ale ne na jednotlivých objektech. -E.g. such code won't work: +Nebude fungovat například tento kód: ```js // ... -article.createTodays(); /// Error: article.createTodays is not a function +článek.vytvořDnešní(); /// Chyba: článek.vytvořDnešní není funkce ``` ```` -## Static properties +## Statické vlastnosti [recent browser=Chrome] -Static properties are also possible, they look like regular class properties, but prepended by `static`: +Můžeme vytvářet i statické vlastnosti. Vypadají jako regulérní třídní vlastnosti, ale jsou předznamenány `static`: ```js run -class Article { - static publisher = "Ilya Kantor"; +class Článek { + static vydavatel = "Ilja Kantor"; } -alert( Article.publisher ); // Ilya Kantor +alert( Článek.vydavatel ); // Ilja Kantor ``` -That is the same as a direct assignment to `Article`: +To je totéž jako přímé přiřazení do třídy `Článek`: ```js -Article.publisher = "Ilya Kantor"; +Článek.vydavatel = "Ilja Kantor"; ``` -## Inheritance of static properties and methods [#statics-and-inheritance] +## Dědičnost statických vlastností a metod [#statics-and-inheritance] -Static properties and methods are inherited. +Statické vlastnosti a metody se dědí. -For instance, `Animal.compare` and `Animal.planet` in the code below are inherited and accessible as `Rabbit.compare` and `Rabbit.planet`: +Například `Zvíře.porovnej` a `Zvíře.planeta` v následujícím kódu budou zděděny a budou dostupné jako `Králík.porovnej` a `Králík.planeta`: ```js run -class Animal { - static planet = "Earth"; +class Zvíře { + static planeta = "Země"; - constructor(name, speed) { - this.speed = speed; - this.name = name; + constructor(jméno, rychlost) { + this.rychlost = rychlost; + this.jméno = jméno; } - run(speed = 0) { - this.speed += speed; - alert(`${this.name} runs with speed ${this.speed}.`); + běž(rychlost = 0) { + this.rychlost += rychlost; + alert(`${this.jméno} běží rychlostí ${this.rychlost}.`); } *!* - static compare(animalA, animalB) { - return animalA.speed - animalB.speed; + static porovnej(zvířeA, zvířeB) { + return zvířeA.rychlost - zvířeB.rychlost; } */!* } -// Inherit from Animal -class Rabbit extends Animal { - hide() { - alert(`${this.name} hides!`); +// Zděděn ze Zvíře +class Králík extends Zvíře { + schovejSe() { + alert(`${this.jméno} se schovává!`); } } -let rabbits = [ - new Rabbit("White Rabbit", 10), - new Rabbit("Black Rabbit", 5) +let králíci = [ + new Králík("Bílý králík", 10), + new Králík("Černý králík", 5) ]; *!* -rabbits.sort(Rabbit.compare); +králíci.sort(Králík.porovnej); */!* -rabbits[0].run(); // Black Rabbit runs with speed 5. +králíci[0].běž(); // Černý králík běží rychlostí 5. -alert(Rabbit.planet); // Earth +alert(Králík.planeta); // Země ``` -Now when we call `Rabbit.compare`, the inherited `Animal.compare` will be called. +Když nyní zavoláme `Králík.porovnej`, bude volána zděděná metoda `Zvíře.porovnej`. -How does it work? Again, using prototypes. As you might have already guessed, `extends` gives `Rabbit` the `[[Prototype]]` reference to `Animal`. +Jak to funguje? Opět pomocí prototypů. Jak jste už možná uhádli, `extends` vloží třídě `Králík` do `[[Prototype]]` odkaz na třídu `Zvíře`. ![](animal-rabbit-static.svg) -So, `Rabbit extends Animal` creates two `[[Prototype]]` references: +`Králík extends Zvíře` tedy vytvoří dva odkazy `[[Prototype]]`: -1. `Rabbit` function prototypally inherits from `Animal` function. -2. `Rabbit.prototype` prototypally inherits from `Animal.prototype`. +1. Funkce `Králík` je prototypově zděděna z funkce `Zvíře`. +2. `Králík.prototype` je prototypově zděděn ze `Zvíře.prototype`. -As a result, inheritance works both for regular and static methods. +Výsledkem je, že dědičnost funguje pro regulérní i pro statické metody. -Here, let's check that by code: +Ověřme si to kódem: ```js run -class Animal {} -class Rabbit extends Animal {} +class Zvíře {} +class Králík extends Zvíře {} -// for statics -alert(Rabbit.__proto__ === Animal); // true +// pro statické metody +alert(Králík.__proto__ === Zvíře); // true -// for regular methods -alert(Rabbit.prototype.__proto__ === Animal.prototype); // true +// pro regulérní metody +alert(Králík.prototype.__proto__ === Zvíře.prototype); // true ``` -## Summary +## Shrnutí -Static methods are used for the functionality that belongs to the class "as a whole". It doesn't relate to a concrete class instance. +Statické metody se používají pro funkcionalitu, která patří třídě „jako celku“ a nevztahuje se ke konkrétní instanci třídy. -For example, a method for comparison `Article.compare(article1, article2)` or a factory method `Article.createTodays()`. +Například metoda pro porovnání `Článek.porovnej(článek1, článek2)` nebo tovární metoda `Článek.vytvořDnešní()`. -They are labeled by the word `static` in class declaration. +V deklaraci třídy jsou označeny klíčovým slovem `static`. -Static properties are used when we'd like to store class-level data, also not bound to an instance. +Statické vlastnosti používáme tehdy, když chceme uložit data na úrovni třídy, rovněž nespojená s žádnou instancí. -The syntax is: +Syntaxe je: ```js -class MyClass { - static property = ...; +class MojeTřída { + static vlastnost = ...; - static method() { + static metoda() { ... } } ``` -Technically, static declaration is the same as assigning to the class itself: +Technicky je statická deklarace totéž jako přiřazení samotné třídě: ```js -MyClass.property = ... -MyClass.method = ... +MojeTřída.vlastnost = ... +MojeTřída.metoda = ... ``` -Static properties and methods are inherited. +Statické vlastnosti a metody se dědí. -For `class B extends A` the prototype of the class `B` itself points to `A`: `B.[[Prototype]] = A`. So if a field is not found in `B`, the search continues in `A`. +Pro `class B extends A` prototyp samotné třídy `B` ukazuje na třídu `A`: `B.[[Prototype]] = A`. Jestliže se tedy pole nenajde v `B`, hledání bude pokračovat v `A`. diff --git a/1-js/09-classes/04-private-protected-properties-methods/article.md b/1-js/09-classes/04-private-protected-properties-methods/article.md index 91efb89ee..a2c76d68a 100644 --- a/1-js/09-classes/04-private-protected-properties-methods/article.md +++ b/1-js/09-classes/04-private-protected-properties-methods/article.md @@ -1,322 +1,322 @@ -# Private and protected properties and methods +# Soukromé a chráněné vlastnosti a metody -One of the most important principles of object oriented programming -- delimiting internal interface from the external one. +Jeden z nejdůležitějších principů objektově orientovaného programování je oddělení interního rozhraní od externího. -That is "a must" practice in developing anything more complex than a "hello world" app. +Je to „nezbytná“ praxe při vývoji čehokoli složitějšího než aplikace vypisující „ahoj světe“. -To understand this, let's break away from development and turn our eyes into the real world. +Abychom to pochopili, odtrhněme se od programování a upřeme oči na skutečný svět. -Usually, devices that we're using are quite complex. But delimiting the internal interface from the external one allows to use them without problems. +Zařízení, která používáme, jsou obvykle docela složitá. Ale oddělení interního rozhraní od externího nám umožňuje používat je bez problémů. -## A real-life example +## Příklad z reálného života -For instance, a coffee machine. Simple from outside: a button, a display, a few holes...And, surely, the result -- great coffee! :) +Například kávovar. Zvenčí vypadá jednoduše: tlačítko, displej, několik otvorů... A samozřejmě výsledek -- výtečná káva! :) ![](coffee.jpg) -But inside... (a picture from the repair manual) +Ale zevnitř... (obrázek z manuálu pro opraváře) ![](coffee-inside.jpg) -A lot of details. But we can use it without knowing anything. +Spousta detailů. My ho však můžeme používat, aniž bychom cokoli z nich znali. -Coffee machines are quite reliable, aren't they? We can use one for years, and only if something goes wrong -- bring it for repairs. +Kávovary jsou docela spolehlivé, ne? Můžeme je používat léta, a teprve až se něco pokazí, zaneseme je do opravy. -The secret of reliability and simplicity of a coffee machine -- all details are well-tuned and *hidden* inside. +Tajemství spolehlivosti a jednoduchosti kávovaru -- veškeré detaily jsou dobře vyladěny a *ukryty* uvnitř. -If we remove the protective cover from the coffee machine, then using it will be much more complex (where to press?), and dangerous (it can electrocute). +Jestliže z kávovaru odstraníme ochranný kryt, bude jeho používání mnohem složitější (kde to máme zmáčknout?) a nebezpečnější (může nás zasáhnout elektřina). -As we'll see, in programming objects are like coffee machines. +Jak uvidíme, objekty v programování se podobají kávovarům. -But in order to hide inner details, we'll use not a protective cover, but rather special syntax of the language and conventions. +Abychom však ukryli vnitřní detaily, nebudeme používat ochranný kryt, ale speciální syntaxi jazyka a konvence. -## Internal and external interface +## Interní a externí rozhraní -In object-oriented programming, properties and methods are split into two groups: +V objektově orientovaném programování jsou vlastnosti a metody rozděleny do dvou skupin: -- *Internal interface* -- methods and properties, accessible from other methods of the class, but not from the outside. -- *External interface* -- methods and properties, accessible also from outside the class. +- *Interní rozhraní* -- metody a vlastnosti dostupné z jiných metod stejné třídy, ale ne zvnějšku. +- *Externí rozhraní* -- metody a vlastnosti dostupné i zvnějšku třídy. -If we continue the analogy with the coffee machine -- what's hidden inside: a boiler tube, heating element, and so on -- is its internal interface. +Budeme-li pokračovat v analogii s kávovarem -- co je skryto uvnitř: ohřívací trubice, topné těleso a tak dále -- to je jeho interní rozhraní. -An internal interface is used for the object to work, its details use each other. For instance, a boiler tube is attached to the heating element. +Interní rozhraní se používá k tomu, aby objekt fungoval, a jeho detaily se používají navzájem mezi sebou. Například ohřívací trubice je připojena k topnému tělesu. -But from the outside a coffee machine is closed by the protective cover, so that no one can reach those. Details are hidden and inaccessible. We can use its features via the external interface. +Zvenčí je však kávovar uzavřen ochranným krytem, takže na ně nikdo nemůže sahat. Detaily jsou skryté a nepřístupné. Můžeme používat jejich vlastnosti pomocí externího rozhraní. -So, all we need to use an object is to know its external interface. We may be completely unaware how it works inside, and that's great. +Vše, co potřebujeme znát, abychom mohli objekt používat, je tedy jeho externí rozhraní. Vůbec nás nemusí zajímat, jak to funguje uvnitř, a to je skvělé. -That was a general introduction. +To byl obecný úvod. -In JavaScript, there are two types of object fields (properties and methods): +V JavaScriptu existují dva druhy objektových polí (vlastností a metod): -- Public: accessible from anywhere. They comprise the external interface. Until now we were only using public properties and methods. -- Private: accessible only from inside the class. These are for the internal interface. +- Veřejná: dostupná odkudkoli. Ta utvářejí externí rozhraní. Doposud jsme používali výhradně veřejné vlastnosti a metody. +- Soukromá: dostupná jedině zevnitř třídy. Ta jsou určena pro interní rozhraní. -In many other languages there also exist "protected" fields: accessible only from inside the class and those extending it (like private, but plus access from inheriting classes). They are also useful for the internal interface. They are in a sense more widespread than private ones, because we usually want inheriting classes to gain access to them. +V mnoha jiných jazycích existují také „chráněná“ pole: dostupná jedině zevnitř třídy a tříd, které ji rozšiřují (obdobně jako soukromá, ale navíc s přístupem ze zděděných tříd). I ta jsou užitečná pro interní rozhraní. V určitém smyslu mají širší využití než soukromá, protože obvykle chceme, aby zděděné třídy měly k polím přístup. -Protected fields are not implemented in JavaScript on the language level, but in practice they are very convenient, so they are emulated. +V JavaScriptu nejsou chráněná pole implementována na úrovni jazyka, ale v praxi jsou velice užitečná, takže bývají emulována. -Now we'll make a coffee machine in JavaScript with all these types of properties. A coffee machine has a lot of details, we won't model them to stay simple (though we could). +Nyní vytvořme v JavaScriptu kávovar se všemi těmito druhy vlastností. Kávovar má spoustu detailů, které pro jednoduchost nebudeme modelovat (ačkoli bychom mohli). -## Protecting "waterAmount" +## Ochrana „množstvíVody“ -Let's make a simple coffee machine class first: +Nejprve si vytvořme jednoduchou třídu pro kávovar: ```js run -class CoffeeMachine { - waterAmount = 0; // the amount of water inside +class Kávovar { + množstvíVody = 0; // množství vody uvnitř - constructor(power) { - this.power = power; - alert( `Created a coffee-machine, power: ${power}` ); + constructor(výkon) { + this.výkon = výkon; + alert( `Kávovar vytvořen, výkon: ${výkon}` ); } } -// create the coffee machine -let coffeeMachine = new CoffeeMachine(100); +// vytvoříme kávovar +let kávovar = new Kávovar(100); -// add water -coffeeMachine.waterAmount = 200; +// přidáme vodu +kávovar.množstvíVody = 200; ``` -Right now the properties `waterAmount` and `power` are public. We can easily get/set them from the outside to any value. +Nyní jsou vlastnosti `množstvíVody` a `výkon` veřejné. Snadno je můžeme zvenčí číst a nastavit do nich jakoukoli hodnotu. -Let's change `waterAmount` property to protected to have more control over it. For instance, we don't want anyone to set it below zero. +Změňme vlastnost `množstvíVody` na chráněnou, abychom nad ní měli větší kontrolu. Například nechceme, aby ji někdo nastavil na menší hodnotu než 0. -**Protected properties are usually prefixed with an underscore `_`.** +**Názvy chráněných vlastností obvykle začínají podtržítkem `_`.** -That is not enforced on the language level, but there's a well-known convention between programmers that such properties and methods should not be accessed from the outside. +To není vyžadováno na úrovni jazyka, ale mezi programátory existuje dobře známá konvence, že k takovým vlastnostem a metodám by se nemělo přistupovat zvenčí. -So our property will be called `_waterAmount`: +Naše vlastnost se tedy bude nazývat `_množstvíVody`: ```js run -class CoffeeMachine { - _waterAmount = 0; +class Kávovar { + _množstvíVody = 0; - set waterAmount(value) { - if (value < 0) { - value = 0; + set množstvíVody(hodnota) { + if (hodnota < 0) { + hodnota = 0; } - this._waterAmount = value; + this._množstvíVody = hodnota; } - get waterAmount() { - return this._waterAmount; + get množstvíVody() { + return this._množstvíVody; } - constructor(power) { - this._power = power; + constructor(výkon) { + this._výkon = výkon; } } -// create the coffee machine -let coffeeMachine = new CoffeeMachine(100); +// vytvoříme kávovar +let kávovar = new Kávovar(100); -// add water -coffeeMachine.waterAmount = -10; // _waterAmount will become 0, not -10 +// přidáme vodu +kávovar.množstvíVody = -10; // _množstvíVody bude 0, ne -10 ``` -Now the access is under control, so setting the water amount below zero becomes impossible. +Nyní máme přístup pod kontrolou, takže nebude možné nastavit množství vody nižší než 0. -## Read-only "power" +## „výkon“ pouze pro čtení -For `power` property, let's make it read-only. It sometimes happens that a property must be set at creation time only, and then never modified. +Co se týče vlastnosti `výkon`, učiňme ji dostupnou pouze pro čtení. Někdy se stává, že vlastnost musí být nastavena pouze v okamžiku vytvoření objektu a pak už nikdy nesmí být změněna. -That's exactly the case for a coffee machine: power never changes. +To je přesně případ kávovaru: výkon se nikdy nemění. -To do so, we only need to make getter, but not the setter: +Abychom toho dosáhli, musíme vytvořit pouze getter, ale ne setter: ```js run -class CoffeeMachine { +class Kávovar { // ... - constructor(power) { - this._power = power; + constructor(výkon) { + this._výkon = výkon; } - get power() { - return this._power; + get výkon() { + return this._výkon; } } -// create the coffee machine -let coffeeMachine = new CoffeeMachine(100); +// vytvoříme kávovar +let kávovar = new Kávovar(100); -alert(`Power is: ${coffeeMachine.power}W`); // Power is: 100W +alert(`Výkon je: ${kávovar.výkon} W`); // Výkon je: 100 W -coffeeMachine.power = 25; // Error (no setter) +kávovar.výkon = 25; // Chyba (není setter) ``` -````smart header="Getter/setter functions" -Here we used getter/setter syntax. +````smart header="Gettery a settery" +Zde jsme použili gettery a settery. -But most of the time `get.../set...` functions are preferred, like this: +Většinou se však dává přednost funkcím `vrať.../nastav...` (v angličtině `get.../set...`), např. takto: ```js -class CoffeeMachine { - _waterAmount = 0; +class Kávovar { + _množstvíVody = 0; - *!*setWaterAmount(value)*/!* { - if (value < 0) value = 0; - this._waterAmount = value; + *!*nastavMnožstvíVody(hodnota)*/!* { + if (hodnota < 0) hodnota = 0; + this._množstvíVody = hodnota; } - *!*getWaterAmount()*/!* { - return this._waterAmount; + *!*vraťMnožstvíVody()*/!* { + return this._množstvíVody; } } -new CoffeeMachine().setWaterAmount(100); +new Kávovar().nastavMnožstvíVody(100); ``` -That looks a bit longer, but functions are more flexible. They can accept multiple arguments (even if we don't need them right now). +Vypadá to trochu delší, ale funkce jsou flexibilnější. Mohou přijímat více argumentů (i když je zrovna teď nepotřebujeme). -On the other hand, get/set syntax is shorter, so ultimately there's no strict rule, it's up to you to decide. +Naproti tomu syntaxe get/set je kratší. Žádné pevné pravidlo tedy neexistuje, rozhodnutí je na vás. ```` -```smart header="Protected fields are inherited" -If we inherit `class MegaMachine extends CoffeeMachine`, then nothing prevents us from accessing `this._waterAmount` or `this._power` from the methods of the new class. +```smart header="Chráněná pole se dědí" +Jestliže zdědíme `class Megastroj extends Kávovar`, pak nám nic nebrání přistupovat k `this._množstvíVody` nebo `this._výkon` z metod nové třídy. -So protected fields are naturally inheritable. Unlike private ones that we'll see below. +Chráněná pole jsou tedy přirozeně dědičná. Na rozdíl od soukromých, jak uvidíme dále. ``` -## Private "#waterLimit" +## Soukromý „#limitVody“ [recent browser=none] -There's a finished JavaScript proposal, almost in the standard, that provides language-level support for private properties and methods. +V JavaScriptu existuje dokončený návrh, je již téměř ve standardu, který poskytuje podporu soukromých vlastností a metod na úrovni jazyka. -Privates should start with `#`. They are only accessible from inside the class. +Názvy soukromých vlastností a metod by měly začínat na `#`. Pak budou dostupné jen zevnitř třídy. -For instance, here's a private `#waterLimit` property and the water-checking private method `#fixWaterAmount`: +Například zde je soukromá vlastnost `#maximumVody` a soukromá metoda `#opravMnožstvíVody`, která zkontroluje množství vody: ```js run -class CoffeeMachine { +class Kávovar { *!* - #waterLimit = 200; + #maximumVody = 200; */!* *!* - #fixWaterAmount(value) { - if (value < 0) return 0; - if (value > this.#waterLimit) return this.#waterLimit; + #opravMnožstvíVody(hodnota) { + if (hodnota < 0) return 0; + if (hodnota > this.#maximumVody) return this.#maximumVody; } */!* - setWaterAmount(value) { - this.#waterLimit = this.#fixWaterAmount(value); + nastavMnožstvíVody(hodnota) { + this.#maximumVody = this.#opravMnožstvíVody(hodnota); } } -let coffeeMachine = new CoffeeMachine(); +let kávovar = new Kávovar(); *!* -// can't access privates from outside of the class -coffeeMachine.#fixWaterAmount(123); // Error -coffeeMachine.#waterLimit = 1000; // Error +// nelze přistupovat k soukromým polím zvnějšku třídy +kávovar.#opravMnožstvíVody(123); // Chyba +kávovar.#maximumVody = 1000; // Chyba */!* ``` -On the language level, `#` is a special sign that the field is private. We can't access it from outside or from inheriting classes. +Na úrovni jazyka je `#` speciální znak, který znamená, že pole je soukromé. Nemůžeme k němu přistupovat zvenčí ani ze zděděných tříd. -Private fields do not conflict with public ones. We can have both private `#waterAmount` and public `waterAmount` fields at the same time. +Soukromá pole nejsou v konfliktu s veřejnými. Můžeme mít současně soukromé pole `#množstvíVody` a veřejné `množstvíVody`. -For instance, let's make `waterAmount` an accessor for `#waterAmount`: +Vytvořme například přístupovou vlastnost `množstvíVody` pro `#množstvíVody`: ```js run -class CoffeeMachine { +class Kávovar { - #waterAmount = 0; + #množstvíVody = 0; - get waterAmount() { - return this.#waterAmount; + get množstvíVody() { + return this.#množstvíVody; } - set waterAmount(value) { - if (value < 0) value = 0; - this.#waterAmount = value; + set množstvíVody(hodnota) { + if (hodnota < 0) hodnota = 0; + this.#množstvíVody = hodnota; } } -let machine = new CoffeeMachine(); +let stroj = new Kávovar(); -machine.waterAmount = 100; -alert(machine.#waterAmount); // Error +stroj.množstvíVody = 100; +alert(stroj.#množstvíVody); // Chyba ``` -Unlike protected ones, private fields are enforced by the language itself. That's a good thing. +Na rozdíl od chráněných polí jsou soukromá pole vynucována samotným jazykem. To je dobrá věc. -But if we inherit from `CoffeeMachine`, then we'll have no direct access to `#waterAmount`. We'll need to rely on `waterAmount` getter/setter: +Pokud však zdědíme z třídy `Kávovar` jinou třídu, nebudeme v ní mít k `#množstvíVody` přímý přístup. Budeme se muset spolehnout na getter/setter `množstvíVody`: ```js -class MegaCoffeeMachine extends CoffeeMachine { - method() { +class MegaKávovar extends Kávovar { + metoda() { *!* - alert( this.#waterAmount ); // Error: can only access from CoffeeMachine + alert( this.#množstvíVody ); // Chyba: přístup může být jen ze třídy Kávovar */!* } } ``` -In many scenarios such limitation is too severe. If we extend a `CoffeeMachine`, we may have legitimate reasons to access its internals. That's why protected fields are used more often, even though they are not supported by the language syntax. +V mnoha scénářích je takové omezení příliš přísné. Jestliže rozšíříme `Kávovar`, můžeme mít legitimní důvody pro přístup k jeho interním polím. Proto se častěji používají chráněná pole, i když je syntaxe jazyka nepodporuje. -````warn header="Private fields are not available as this[name]" -Private fields are special. +````warn header="Soukromá pole nejsou dostupná jako this[název]" +Soukromá pole jsou speciální. -As we know, usually we can access fields using `this[name]`: +Jak víme, obvykle můžeme přistupovat k polím pomocí `this[název]`: ```js -class User { +class Uživatel { ... - sayHi() { - let fieldName = "name"; - alert(`Hello, ${*!*this[fieldName]*/!*}`); + řekniAhoj() { + let názevPole = "jméno"; + alert(`Ahoj, ${*!*this[názevPole]*/!*}`); } } ``` -With private fields that's impossible: `this['#name']` doesn't work. That's a syntax limitation to ensure privacy. +U soukromých polí to není možné: `this['#název']` nefunguje. To je syntaktické omezení, jehož účelem je zajistit soukromí. ```` -## Summary +## Shrnutí -In terms of OOP, delimiting of the internal interface from the external one is called [encapsulation](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)). +V terminologii OOP se oddělení interního rozhraní od externího nazývá [zapouzdření](https://cs.wikipedia.org/wiki/Zapouzdření_(programování)). -It gives the following benefits: +Poskytuje nám následující výhody: -Protection for users, so that they don't shoot themselves in the foot -: Imagine, there's a team of developers using a coffee machine. It was made by the "Best CoffeeMachine" company, and works fine, but a protective cover was removed. So the internal interface is exposed. +Ochranu uživatelů, aby se nemohli postřelit +: Představme si tým vývojářů, který používá kávovar. Vyrobila jej firma „Nejlepší kávovary s.r.o.“ a funguje dobře, ale někdo odstranil ochranný kryt. Interní rozhraní je tedy odhaleno. - All developers are civilized -- they use the coffee machine as intended. But one of them, John, decided that he's the smartest one, and made some tweaks in the coffee machine internals. So the coffee machine failed two days later. + Všichni vývojáři jsou civilizovaní -- používají kávovar tak, jak mají. Ale jeden z nich, Jan, se rozhodl, že je ten nejchytřejší, a udělal ve vnitřnostech kávovaru nějaká vylepšení. O dva dny později se kávovar kvůli tomu pokazil. - That's surely not John's fault, but rather the person who removed the protective cover and let John do his manipulations. + Není to určitě vina Jana, ale spíše člověka, který odstranil ochranný kryt a umožnil Janovi s kávovarem manipulovat. - The same in programming. If a user of a class will change things not intended to be changed from the outside -- the consequences are unpredictable. + V programování platí totéž. Jestliže uživatel třídy změní věci, které neměly být měněny zvenčí, důsledky jsou nepředvídatelné. -Supportable -: The situation in programming is more complex than with a real-life coffee machine, because we don't just buy it once. The code constantly undergoes development and improvement. +Podporovatelnost +: Situace v programování je složitější než kávovar ve skutečném životě, protože kávovar jen koupíme a konec. Zato kód je neustále vyvíjen a vylepšován. - **If we strictly delimit the internal interface, then the developer of the class can freely change its internal properties and methods, even without informing the users.** + **Jestliže striktně oddělíme interní rozhraní, pak vývojář třídy bude moci svobodně měnit její interní vlastnosti a metody, dokonce aniž by informoval uživatele.** - If you're a developer of such class, it's great to know that private methods can be safely renamed, their parameters can be changed, and even removed, because no external code depends on them. + Jste-li vývojářem takové třídy, je pro vás skvělé vědět, že soukromé metody mohou být bezpečně přejmenovány, jejich parametry mohou být měněny a dokonce odstraňovány, protože na nich nezávisí žádný externí kód. - For users, when a new version comes out, it may be a total overhaul internally, but still simple to upgrade if the external interface is the same. + Když vyjde nová verze, může být uvnitř totálně přepracována, ale jestliže externí rozhraní bude stejné, aktualizace bude pro uživatele stále jednoduchá. -Hiding complexity -: People adore using things that are simple. At least from outside. What's inside is a different thing. +Ukrytí složitosti +: Lidé rádi používají věci, které jsou jednoduché. Aspoň zvenčí. Co je uvnitř, to je druhá věc. - Programmers are not an exception. + Programátoři nejsou výjimkou. - **It's always convenient when implementation details are hidden, and a simple, well-documented external interface is available.** + **Vždy se hodí, když jsou implementační detaily skryté a k dispozici je jednoduché, dobře dokumentované externí rozhraní.** -To hide an internal interface we use either protected or private properties: +Pro skrytí interního rozhraní používáme chráněné nebo soukromé vlastnosti: -- Protected fields start with `_`. That's a well-known convention, not enforced at the language level. Programmers should only access a field starting with `_` from its class and classes inheriting from it. -- Private fields start with `#`. JavaScript makes sure we can only access those from inside the class. +- Názvy chráněných polí začínají na `_`. To je dobře známá konvence, nevyžadovaná na úrovni jazyka. Programátoři by měli k polím, jejichž název začíná na `_`, přistupovat jen z jejich třídy a tříd, které jsou z ní zděděny. +- Názvy soukromých polí začínají na `#`. JavaScript zajišťuje, že k nim můžeme přistupovat jedině zevnitř třídy. -Right now, private fields are not well-supported among browsers, but can be polyfilled. +V současnosti ještě nejsou soukromá pole v prohlížečích široce podporována, ale to může být opraveno polyfillem. diff --git a/1-js/09-classes/05-extend-natives/article.md b/1-js/09-classes/05-extend-natives/article.md index 28b4c6eb6..b174de3ca 100644 --- a/1-js/09-classes/05-extend-natives/article.md +++ b/1-js/09-classes/05-extend-natives/article.md @@ -1,89 +1,89 @@ -# Extending built-in classes +# Rozšiřování vestavěných tříd -Built-in classes like Array, Map and others are extendable also. +Rozšiřovat lze i vestavěné třídy, například Array, Map a jiné. -For instance, here `PowerArray` inherits from the native `Array`: +Například zde `SilnéPole` je zděděno z nativního `Array`: ```js run -// add one more method to it (can do more) -class PowerArray extends Array { - isEmpty() { +// přidáme do něj jednu další metodu (můžeme i víc) +class SilnéPole extends Array { + jePrázdné() { return this.length === 0; } } -let arr = new PowerArray(1, 2, 5, 10, 50); -alert(arr.isEmpty()); // false +let pole = new SilnéPole(1, 2, 5, 10, 50); +alert(pole.jePrázdné()); // false -let filteredArr = arr.filter(item => item >= 10); -alert(filteredArr); // 10, 50 -alert(filteredArr.isEmpty()); // false +let filtrovanéPole = pole.filter(prvek => prvek >= 10); +alert(filtrovanéPole); // 10, 50 +alert(filtrovanéPole.jePrázdné()); // false ``` -Please note a very interesting thing. Built-in methods like `filter`, `map` and others -- return new objects of exactly the inherited type `PowerArray`. Their internal implementation uses the object's `constructor` property for that. +Všimněte si prosíme velmi zajímavé věci. Vestavěné metody jako `filter`, `map` a jiné vracejí nové objekty přesně zděděného typu `SilnéPole`. Jejich vnitřní implementace k tomu využívá vlastnost `constructor` objektu, na němž je metoda volána. -In the example above, +V uvedeném příkladu: ```js -arr.constructor === PowerArray +pole.constructor === SilnéPole ``` -When `arr.filter()` is called, it internally creates the new array of results using exactly `arr.constructor`, not basic `Array`. That's actually very cool, because we can keep using `PowerArray` methods further on the result. +Když je voláno `pole.filter()`, vnitřně vytvoří nové pole výsledků voláním přesně `pole.constructor`, ne základního `Array`. To je vskutku vynikající, protože i nadále můžeme na výsledku používat metody třídy `SilnéPole`. -Even more, we can customize that behavior. +A navíc si můžeme toto chování sami nastavit. -We can add a special static getter `Symbol.species` to the class. If it exists, it should return the constructor that JavaScript will use internally to create new entities in `map`, `filter` and so on. +Můžeme do třídy přidat speciální statický getter `Symbol.species`. Pokud existuje, měl by vracet konstruktor, který bude JavaScriptem vnitřně používán k vytvoření nových entit ve funkcích `map`, `filter` a podobně. -If we'd like built-in methods like `map` or `filter` to return regular arrays, we can return `Array` in `Symbol.species`, like here: +Kdybychom chtěli, aby vestavěné metody jako `map` nebo `filter` vracely regulérní pole, můžeme v `Symbol.species` vracet `Array`, například zde: ```js run -class PowerArray extends Array { - isEmpty() { +class SilnéPole extends Array { + jePrázdné() { return this.length === 0; } *!* - // built-in methods will use this as the constructor + // vestavěné metody budou jako konstruktor používat toto static get [Symbol.species]() { return Array; } */!* } -let arr = new PowerArray(1, 2, 5, 10, 50); -alert(arr.isEmpty()); // false +let pole = new SilnéPole(1, 2, 5, 10, 50); +alert(pole.jePrázdné()); // false -// filter creates new array using arr.constructor[Symbol.species] as constructor -let filteredArr = arr.filter(item => item >= 10); +// filter vytvoří nové pole s použitím pole.constructor[Symbol.species] jako konstruktoru +let filtrovanéPole = pole.filter(prvek => prvek >= 10); *!* -// filteredArr is not PowerArray, but Array +// filtrovanéPole není SilnéPole, ale Array */!* -alert(filteredArr.isEmpty()); // Error: filteredArr.isEmpty is not a function +alert(filtrovanéPole.jePrázdné()); // Chyba: filtrovanéPole.jePrázdné není funkce ``` -As you can see, now `.filter` returns `Array`. So the extended functionality is not passed any further. +Jak vidíte, nyní `.filter` vrací `Array`. Rozšířená funkcionalita se tedy dál nepředává. -```smart header="Other collections work similarly" -Other collections, such as `Map` and `Set`, work alike. They also use `Symbol.species`. +```smart header="Obdobně fungují ostatní kolekce" +Obdobně fungují i ostatní kolekce, např. `Map` a `Set`. I ty používají `Symbol.species`. ``` -## No static inheritance in built-ins +## Zabudované objekty nemají statickou dědičnost -Built-in objects have their own static methods, for instance `Object.keys`, `Array.isArray` etc. +Zabudované objekty mají své vlastní statické metody, například `Object.keys`, `Array.isArray` atd. -As we already know, native classes extend each other. For instance, `Array` extends `Object`. +Jak už víme, nativní třídy se navzájem rozšiřují. Například třída `Array` rozšiřuje třídu `Object`. -Normally, when one class extends another, both static and non-static methods are inherited. That was thoroughly explained in the article [](info:static-properties-methods#statics-and-inheritance). +Když jedna třída rozšiřuje druhou, zpravidla z ní dědí statické i nestatické metody. To bylo podrobně vysvětleno v článku [](info:static-properties-methods#statics-and-inheritance). -But built-in classes are an exception. They don't inherit statics from each other. +Avšak vestavěné třídy jsou výjimkou. Ty od sebe navzájem nedědí statická pole. -For example, both `Array` and `Date` inherit from `Object`, so their instances have methods from `Object.prototype`. But `Array.[[Prototype]]` does not reference `Object`, so there's no, for instance, `Array.keys()` (or `Date.keys()`) static method. +Například třídy `Array` i `Date` dědí ze třídy `Object`, takže jejich instance obsahují metody z `Object.prototype`. Ale `Array.[[Prototype]]` se neodkazuje na `Object`, takže neexistuje například statická metoda `Array.keys()` (nebo `Date.keys()`). -Here's the picture structure for `Date` and `Object`: +Na obrázku vidíme strukturu pro `Date` a `Object`: ![](object-date-inheritance.svg) -As you can see, there's no link between `Date` and `Object`. They are independent, only `Date.prototype` inherits from `Object.prototype`. +Jak vidíte, mezi `Date` a `Object` neexistuje žádné spojení. Jsou nezávislé, jedině `Date.prototype` dědí z `Object.prototype`. -That's an important difference of inheritance between built-in objects compared to what we get with `extends`. +To je důležitý rozdíl v dědičnosti mezi vestavěnými objekty oproti tomu, co získáme použitím `extends`. diff --git a/1-js/09-classes/05-extend-natives/object-date-inheritance.svg b/1-js/09-classes/05-extend-natives/object-date-inheritance.svg index be47d7fd9..95fda7e24 100644 --- a/1-js/09-classes/05-extend-natives/object-date-inheritance.svg +++ b/1-js/09-classes/05-extend-natives/object-date-inheritance.svg @@ -1 +1 @@ -constructor: Object toString: function hasOwnProperty: function ...Object.prototypeconstructor: Date toString: function getDate: function ...Date.prototypeObjectDatenew Date()[[Prototype]][[Prototype]]prototypeprototypedefineProperty keys ...now parse ...1 Jan 2019 \ No newline at end of file +constructor: Object toString: function hasOwnProperty: function ...Object.prototypeconstructor: Date toString: function getDate: function ...Date.prototypeObjectDatenew Date()[[Prototype]][[Prototype]]prototypeprototypedefineProperty keys ...now parse ...1. leden 2019 \ No newline at end of file diff --git a/1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md b/1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md index d41d90edf..95cb79110 100644 --- a/1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md +++ b/1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md @@ -1,7 +1,7 @@ -Yeah, looks strange indeed. +Ano, určitě to vypadá podivně. -But `instanceof` does not care about the function, but rather about its `prototype`, that it matches against the prototype chain. +Ale `instanceof` se nezajímá o funkci, nýbrž jen o její `prototype`, který porovnává s prototypovým řetězcem. -And here `a.__proto__ == B.prototype`, so `instanceof` returns `true`. +A zde je `a.__proto__ == B.prototype`, takže `instanceof` vrátí `true`. -So, by the logic of `instanceof`, the `prototype` actually defines the type, not the constructor function. +Podle logiky `instanceof` je tedy typ ve skutečnosti definován vlastností `prototype`, ne samotným konstruktorem. diff --git a/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md b/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md index 5b8dc7de3..70b95fd19 100644 --- a/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md +++ b/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# Strange instanceof +# Podivné instanceof -In the code below, why does `instanceof` return `true`? We can easily see that `a` is not created by `B()`. +Proč v následujícím kódu `instanceof` vrací `true`? Vidíme přece, že `a` není vytvořeno pomocí `B()`. ```js run function A() {} diff --git a/1-js/09-classes/06-instanceof/article.md b/1-js/09-classes/06-instanceof/article.md index f9db989ca..5cbce8868 100644 --- a/1-js/09-classes/06-instanceof/article.md +++ b/1-js/09-classes/06-instanceof/article.md @@ -1,168 +1,168 @@ -# Class checking: "instanceof" +# Ověřování tříd: „instanceof“ -The `instanceof` operator allows to check whether an object belongs to a certain class. It also takes inheritance into account. +Operátor `instanceof` umožňuje ověřit, zda objekt patří do určité třídy. Bere v úvahu i dědičnost. -Such a check may be necessary in many cases. For example, it can be used for building a *polymorphic* function, the one that treats arguments differently depending on their type. +Toto ověření může být zapotřebí v mnoha případech. Například může být použito k vytvoření *polymorfní* funkce, takové, která zachází se svými argumenty různě v závislosti na jejich typu. -## The instanceof operator [#ref-instanceof] +## Operátor instanceof [#ref-instanceof] -The syntax is: +Syntaxe je: ```js -obj instanceof Class +obj instanceof Třída ``` -It returns `true` if `obj` belongs to the `Class` or a class inheriting from it. +Vrací `true`, jestliže `obj` patří do třídy `Třída` nebo do třídy, která je z ní zděděna. -For instance: +Například: ```js run -class Rabbit {} -let rabbit = new Rabbit(); +class Králík {} +let králík = new Králík(); -// is it an object of Rabbit class? +// je to objekt třídy Králík? *!* -alert( rabbit instanceof Rabbit ); // true +alert( králík instanceof Králík ); // true */!* ``` -It also works with constructor functions: +Funguje to i pro konstruktory: ```js run *!* -// instead of class -function Rabbit() {} +// namísto třídy +function Králík() {} */!* -alert( new Rabbit() instanceof Rabbit ); // true +alert( new Králík() instanceof Králík ); // true ``` -...And with built-in classes like `Array`: +...A pro zabudované třídy jako `Array`: ```js run -let arr = [1, 2, 3]; -alert( arr instanceof Array ); // true -alert( arr instanceof Object ); // true +let pole = [1, 2, 3]; +alert( pole instanceof Array ); // true +alert( pole instanceof Object ); // true ``` -Please note that `arr` also belongs to the `Object` class. That's because `Array` prototypically inherits from `Object`. +Prosíme všimněte si, že `pole` patří i do třídy `Object`. Je to proto, že třída `Array` je prototypově zděděna z třídy `Object`. -Normally, `instanceof` examines the prototype chain for the check. We can also set a custom logic in the static method `Symbol.hasInstance`. +Normálně `instanceof` při ověřování prozkoumává prototypový řetězec. Můžeme si však také nastavit vlastní logiku ve statické metodě `Symbol.hasInstance`. -The algorithm of `obj instanceof Class` works roughly as follows: +Algoritmus operátoru `obj instanceof Třída` funguje zhruba následovně: -1. If there's a static method `Symbol.hasInstance`, then just call it: `Class[Symbol.hasInstance](obj)`. It should return either `true` or `false`, and we're done. That's how we can customize the behavior of `instanceof`. +1. Pokud existuje statická metoda `Symbol.hasInstance`, pak ji jen zavolá: `Třída[Symbol.hasInstance](obj)`. Ta by měla vrátit buď `true`, nebo `false`, a jsme hotovi. Tímto způsobem si můžeme chování `instanceof` sami nastavit. - For example: + Například: ```js run - // setup instanceOf check that assumes that - // anything with canEat property is an animal - class Animal { + // nastavíme ověření instanceOf tak, aby předpokládalo, + // že všechno, co má vlastnost můžeŽrát, je zvíře + class Zvíře { static [Symbol.hasInstance](obj) { - if (obj.canEat) return true; + if (obj.můžeŽrát) return true; } } - let obj = { canEat: true }; + let obj = { můžeŽrát: true }; - alert(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj) is called + alert(obj instanceof Zvíře); // true: zavolá se Zvíře[Symbol.hasInstance](obj) ``` -2. Most classes do not have `Symbol.hasInstance`. In that case, the standard logic is used: `obj instanceOf Class` checks whether `Class.prototype` is equal to one of the prototypes in the `obj` prototype chain. +2. Většina tříd nemá `Symbol.hasInstance`. V tom případě je použita standardní logika: `obj instanceOf Třída` zjistí, zda se `Třída.prototype` rovná některému z prototypů v prototypovém řetězci objektu `obj`. - In other words, compare one after another: + Jinými slovy, porovnává jeden po druhém: ```js - obj.__proto__ === Class.prototype? - obj.__proto__.__proto__ === Class.prototype? - obj.__proto__.__proto__.__proto__ === Class.prototype? + obj.__proto__ === Třída.prototype? + obj.__proto__.__proto__ === Třída.prototype? + obj.__proto__.__proto__.__proto__ === Třída.prototype? ... - // if any answer is true, return true - // otherwise, if we reached the end of the chain, return false + // je-li kterákoli odpověď true, vrátí true + // jinak, pokud jsme dosáhli konce řetězce, vrátí false ``` - In the example above `rabbit.__proto__ === Rabbit.prototype`, so that gives the answer immediately. + V uvedeném příkladu `králík.__proto__ === Králík.prototype`, takže odpověď je vydána okamžitě. - In the case of an inheritance, the match will be at the second step: + V případě dědičnosti bude shoda nalezena ve druhém kroku: ```js run - class Animal {} - class Rabbit extends Animal {} + class Zvíře {} + class Králík extends Zvíře {} - let rabbit = new Rabbit(); + let králík = new Králík(); *!* - alert(rabbit instanceof Animal); // true + alert(králík instanceof Zvíře); // true */!* - // rabbit.__proto__ === Animal.prototype (no match) + // králík.__proto__ === Zvíře.prototype (není shoda) *!* - // rabbit.__proto__.__proto__ === Animal.prototype (match!) + // králík.__proto__.__proto__ === Zvíře.prototype (shoda!) */!* ``` -Here's the illustration of what `rabbit instanceof Animal` compares with `Animal.prototype`: +Na tomto obrázku je vidět, co `králík instanceof Zvíře` porovnává se `Zvíře.prototype`: ![](instanceof.svg) -By the way, there's also a method [objA.isPrototypeOf(objB)](mdn:js/object/isPrototypeOf), that returns `true` if `objA` is somewhere in the chain of prototypes for `objB`. So the test of `obj instanceof Class` can be rephrased as `Class.prototype.isPrototypeOf(obj)`. +Mimochodem, existuje také metoda [objA.isPrototypeOf(objB)](mdn:js/object/isPrototypeOf), která vrátí `true`, jestliže se `objA` nachází někde v prototypovém řetězci objektu `objB`. Test `obj instanceof Třída` tedy lze přepsat na `Třída.prototype.isPrototypeOf(obj)`. -It's funny, but the `Class` constructor itself does not participate in the check! Only the chain of prototypes and `Class.prototype` matters. +Veselé je, že samotný konstruktor `Třída` se na ověřování nepodílí! Záleží jen na prototypovém řetězci a na `Třída.prototype`. -That can lead to interesting consequences when a `prototype` property is changed after the object is created. +To může vést k zajímavým důsledkům, když je vlastnost `prototype` změněna po vytvoření objektu. -Like here: +Například zde: ```js run -function Rabbit() {} -let rabbit = new Rabbit(); +function Králík() {} +let králík = new Králík(); -// changed the prototype -Rabbit.prototype = {}; +// změníme prototyp +Králík.prototype = {}; -// ...not a rabbit any more! +// ...už to není králík! *!* -alert( rabbit instanceof Rabbit ); // false +alert( králík instanceof Králík ); // false */!* ``` -## Bonus: Object.prototype.toString for the type +## Bonus: Object.prototype.toString pro typ -We already know that plain objects are converted to string as `[object Object]`: +Už víme, že plané objekty se převádějí na řetězec jako `[object Object]`: ```js run let obj = {}; alert(obj); // [object Object] -alert(obj.toString()); // the same +alert(obj.toString()); // totéž ``` -That's their implementation of `toString`. But there's a hidden feature that makes `toString` actually much more powerful than that. We can use it as an extended `typeof` and an alternative for `instanceof`. +Taková je jejich implementace metody `toString`. Existuje však skrytá vlastnost, která činí `toString` ve skutečnosti mnohem silnější. Můžeme ji používat jako rozšířený `typeof` a alternativu pro `instanceof`. -Sounds strange? Indeed. Let's demystify. +Zní to zvláštně? Určitě ano. Odhalme to. -By [specification](https://tc39.github.io/ecma262/#sec-object.prototype.tostring), the built-in `toString` can be extracted from the object and executed in the context of any other value. And its result depends on that value. +Podle [specifikace](https://tc39.github.io/ecma262/#sec-object.prototype.tostring) může být vestavěný `toString` extrahován z objektu a spuštěn v kontextu jakékoli jiné hodnoty. A na oné hodnotě pak závisí jeho výsledek. -- For a number, it will be `[object Number]` -- For a boolean, it will be `[object Boolean]` -- For `null`: `[object Null]` -- For `undefined`: `[object Undefined]` -- For arrays: `[object Array]` -- ...etc (customizable). +- Pro číslo to bude `[object Number]` +- Pro boolean to bude `[object Boolean]` +- Pro `null`: `[object Null]` +- Pro `undefined`: `[object Undefined]` +- Pro pole: `[object Array]` +- ...atd. (nastavitelně). -Let's demonstrate: +Předveďme si to: ```js run -// copy toString method into a variable for convenience -let objectToString = Object.prototype.toString; +// pro přehlednost si zkopírujeme metodu toString do proměnné +let metodaToString = Object.prototype.toString; -// what type is this? -let arr = []; +// jakého typu je tohle? +let pole = []; -alert( objectToString.call(arr) ); // [object *!*Array*/!*] +alert( metodaToString.call(pole) ); // [object *!*Array*/!*] ``` -Here we used [call](mdn:js/function/call) as described in the chapter [](info:call-apply-decorators) to execute the function `objectToString` in the context `this=arr`. +Zde jsme použili metodu [call](mdn:js/function/call), popsanou v kapitole [](info:call-apply-decorators), ke spuštění funkce `metodaToString` v kontextu `this=pole`. -Internally, the `toString` algorithm examines `this` and returns the corresponding result. More examples: +Vnitřně algoritmus metody `toString` prozkoumává `this` a vrací odpovídající výsledek. Další příklady: ```js run let s = Object.prototype.toString; @@ -174,22 +174,22 @@ alert( s.call(alert) ); // [object Function] ### Symbol.toStringTag -The behavior of Object `toString` can be customized using a special object property `Symbol.toStringTag`. +Chování metody `toString` můžeme nastavit pomocí speciální objektové vlastnosti `Symbol.toStringTag`. -For instance: +Například: ```js run -let user = { - [Symbol.toStringTag]: "User" +let uživatel = { + [Symbol.toStringTag]: "Uživatel" }; -alert( {}.toString.call(user) ); // [object User] +alert( {}.toString.call(uživatel) ); // [object Uživatel] ``` -For most environment-specific objects, there is such a property. Here are some browser specific examples: +Tato vlastnost existuje u většiny objektů specifických pro určité prostředí. Uvedeme některé příklady specifické pro prohlížeč: ```js run -// toStringTag for the environment-specific object and class: +// toStringTag v objektu a třídě specifické pro určité prostředí: alert( window[Symbol.toStringTag]); // Window alert( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest @@ -197,22 +197,22 @@ alert( {}.toString.call(window) ); // [object Window] alert( {}.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest] ``` -As you can see, the result is exactly `Symbol.toStringTag` (if exists), wrapped into `[object ...]`. +Jak vidíte, výsledkem je přesně `Symbol.toStringTag` (pokud existuje), zabalený do `[object ...]`. -At the end we have "typeof on steroids" that not only works for primitive data types, but also for built-in objects and even can be customized. +Nakonec tedy máme „typeof na steroidech“, který funguje nejen pro primitivní datové typy, ale i pro zabudované objekty a dokonce se dá nastavit. -We can use `{}.toString.call` instead of `instanceof` for built-in objects when we want to get the type as a string rather than just to check. +Když tedy chceme u vestavěných objektů zjistit název typu jako řetězec a ne ho jen ověřit, můžeme místo `instanceof` používat `{}.toString.call`. -## Summary +## Shrnutí -Let's summarize the type-checking methods that we know: +Shrňme si metody pro ověření typu, které známe: -| | works for | returns | +| | funguje pro | vrací | |---------------|-------------|---------------| -| `typeof` | primitives | string | -| `{}.toString` | primitives, built-in objects, objects with `Symbol.toStringTag` | string | -| `instanceof` | objects | true/false | +| `typeof` | primitivy | řetězec | +| `{}.toString` | primitivy, vestavěné objekty, objekty se `Symbol.toStringTag` | řetězec | +| `instanceof` | objekty | true/false | -As we can see, `{}.toString` is technically a "more advanced" `typeof`. +Jak vidíme, `{}.toString` je technicky „pokročilejší“ `typeof`. -And `instanceof` operator really shines when we are working with a class hierarchy and want to check for the class taking into account inheritance. +A když pracujeme s třídní hierarchií a chceme si ověřit třídu, přičemž chceme vzít v úvahu dědičnost, opravdu se zaleskne operátor `instanceof`. diff --git a/1-js/09-classes/06-instanceof/instanceof.svg b/1-js/09-classes/06-instanceof/instanceof.svg index d63b03a8a..a09623f89 100644 --- a/1-js/09-classes/06-instanceof/instanceof.svg +++ b/1-js/09-classes/06-instanceof/instanceof.svg @@ -1 +1 @@ -Animal.prototypeObject.prototypeRabbit.prototype[[Prototype]]rabbit[[Prototype]][[Prototype]]null[[Prototype]]= Animal.prototype? \ No newline at end of file +Zvíře.prototypeObject.prototypeKrálík.prototype[[Prototype]]králík[[Prototype]][[Prototype]]null[[Prototype]]= Zvíře.prototype? \ No newline at end of file diff --git a/1-js/09-classes/07-mixins/article.md b/1-js/09-classes/07-mixins/article.md index 526b832ef..ba36c62de 100644 --- a/1-js/09-classes/07-mixins/article.md +++ b/1-js/09-classes/07-mixins/article.md @@ -1,208 +1,208 @@ -# Mixins +# Mixiny -In JavaScript we can only inherit from a single object. There can be only one `[[Prototype]]` for an object. And a class may extend only one other class. +V JavaScriptu můžeme dědit jen z jednoho objektu. Objekt může mít jen jeden `[[Prototype]]` a třída může rozšiřovat pouze jednu jinou třídu. -But sometimes that feels limiting. For instance, we have a class `StreetSweeper` and a class `Bicycle`, and want to make their mix: a `StreetSweepingBicycle`. +To se však někdy může zdát omezující. Máme například třídu `ZametačUlic` a třídu `Bicykl` a chtěli bychom vytvořit jejich směs: `ZametacíBicykl`. -Or we have a class `User` and a class `EventEmitter` that implements event generation, and we'd like to add the functionality of `EventEmitter` to `User`, so that our users can emit events. +Nebo máme třídu `Uživatel` a třídu `GenerátorUdálostí`, která implementuje generování událostí, a rádi bychom přidali funkcionalitu třídy `GenerátorUdálostí` do třídy `Uživatel`, aby naši uživatelé mohli generovat události. -There's a concept that can help here, called "mixins". +Koncept, který nám s tím pomůže, existuje a nazývá se „mixiny“. -As defined in Wikipedia, a [mixin](https://en.wikipedia.org/wiki/Mixin) is a class containing methods that can be used by other classes without a need to inherit from it. +Jak je definováno ve Wikipedii, [mixin](https://cs.wikipedia.org/wiki/Mixin) je třída obsahující metody, které mohou být používány v jiných třídách, aniž by z ní tyto třídy musely být zděděny. -In other words, a *mixin* provides methods that implement a certain behavior, but we do not use it alone, we use it to add the behavior to other classes. +Jinými slovy, *mixin* poskytuje metody, které implementují určité chování, ale nepoužíváme ho samostatně, nýbrž přidáváme jeho chování do jiných tříd. -## A mixin example +## Příklad mixinu -The simplest way to implement a mixin in JavaScript is to make an object with useful methods, so that we can easily merge them into a prototype of any class. +Nejjednodušší způsob, jak implementovat mixin v JavaScriptu, je vytvořit objekt s užitečnými metodami, abychom je mohli snadno připojit do prototypu libovolné třídy. -For instance here the mixin `sayHiMixin` is used to add some "speech" for `User`: +Například zde je použit mixin `mixinŘekniAhoj`, aby do třídy `Uživatel` přidal nějaké „mluvení“: ```js run *!* // mixin */!* -let sayHiMixin = { - sayHi() { - alert(`Hello ${this.name}`); +let mixinŘekniAhoj = { + řekniAhoj() { + alert(`Ahoj ${this.jméno}`); }, - sayBye() { - alert(`Bye ${this.name}`); + řekniNashle() { + alert(`Nashle ${this.jméno}`); } }; *!* -// usage: +// použití: */!* -class User { - constructor(name) { - this.name = name; +class Uživatel { + constructor(jméno) { + this.jméno = jméno; } } -// copy the methods -Object.assign(User.prototype, sayHiMixin); +// zkopírujeme metody +Object.assign(Uživatel.prototype, mixinŘekniAhoj); -// now User can say hi -new User("Dude").sayHi(); // Hello Dude! +// nyní Uživatel může říci ahoj +new Uživatel("Jan").řekniAhoj(); // Ahoj Jan ``` -There's no inheritance, but a simple method copying. So `User` may inherit from another class and also include the mixin to "mix-in" the additional methods, like this: +Není tady žádná dědičnost, ale jen prosté kopírování metod. `Uživatel` tedy může dědit z jiné třídy a současně zahrnout mixin, aby „přimíchal“ („mix-in“) další metody, například: ```js -class User extends Person { +class Uživatel extends Osoba { // ... } -Object.assign(User.prototype, sayHiMixin); +Object.assign(Uživatel.prototype, mixinŘekniAhoj); ``` -Mixins can make use of inheritance inside themselves. +Mixiny mohou využívat dědičnost mezi sebou. -For instance, here `sayHiMixin` inherits from `sayMixin`: +Například zde `mixinŘekniAhoj` dědí z `mixinŘekni`: ```js run -let sayMixin = { - say(phrase) { - alert(phrase); +let mixinŘekni = { + řekni(věta) { + alert(věta); } }; -let sayHiMixin = { - __proto__: sayMixin, // (or we could use Object.setPrototypeOf to set the prototype here) +let mixinŘekniAhoj = { + __proto__: mixinŘekni, // (nebo můžeme k nastavení prototypu použít Object.setPrototypeOf) - sayHi() { + řekniAhoj() { *!* - // call parent method + // volání rodičovské metody */!* - super.say(`Hello ${this.name}`); // (*) + super.řekni(`Ahoj ${this.jméno}`); // (*) }, - sayBye() { - super.say(`Bye ${this.name}`); // (*) + řekniNashle() { + super.řekni(`Nashle ${this.jméno}`); // (*) } }; -class User { - constructor(name) { - this.name = name; +class Uživatel { + constructor(jméno) { + this.jméno = jméno; } } -// copy the methods -Object.assign(User.prototype, sayHiMixin); +// zkopírujeme metody +Object.assign(Uživatel.prototype, mixinŘekniAhoj); -// now User can say hi -new User("Dude").sayHi(); // Hello Dude! +// nyní Uživatel může říci ahoj +new Uživatel("Jan").řekniAhoj(); // Ahoj Jan ``` -Please note that the call to the parent method `super.say()` from `sayHiMixin` (at lines labelled with `(*)`) looks for the method in the prototype of that mixin, not the class. +Prosíme všimněte si, že volání rodičovské metody `super.řekni()` z `mixinŘekniAhoj` (na řádcích označených `(*)`) hledá metodu v prototypu onoho mixinu, ne této třídy. -Here's the diagram (see the right part): +Zde je diagram (viz pravou část): ![](mixin-inheritance.svg) -That's because methods `sayHi` and `sayBye` were initially created in `sayHiMixin`. So even though they got copied, their `[[HomeObject]]` internal property references `sayHiMixin`, as shown in the picture above. +Je to proto, že metody `řekniAhoj` a `řekniNashle` byly původně vytvořeny v `mixinŘekniAhoj`. I když jsou tedy zkopírovány, jejich interní vlastnost `[[HomeObject]]` se odkazuje na `mixinŘekniAhoj`, jak je vidět na uvedeném obrázku. -As `super` looks for parent methods in `[[HomeObject]].[[Prototype]]`, that means it searches `sayHiMixin.[[Prototype]]`. +Když `super` hledá rodičovské metody v `[[HomeObject]].[[Prototype]]`, znamená to, že prohledává `mixinŘekniAhoj.[[Prototype]]`. -## EventMixin +## MixinUdálosti -Now let's make a mixin for real life. +Vytvořme nyní mixin pro skutečný život. -An important feature of many browser objects (for instance) is that they can generate events. Events are a great way to "broadcast information" to anyone who wants it. So let's make a mixin that allows us to easily add event-related functions to any class/object. +Důležitou vlastností mnoha objektů prohlížeče (například) je, že mohou generovat události. Události jsou skvělý způsob, jak „vysílat informaci“ každému, kdo ji chce. Vytvořme tedy mixin, který nám umožní snadno přidat funkce vztažené k události do jakékoli třídy nebo objektu. -- The mixin will provide a method `.trigger(name, [...data])` to "generate an event" when something important happens to it. The `name` argument is a name of the event, optionally followed by additional arguments with event data. -- Also the method `.on(name, handler)` that adds `handler` function as the listener to events with the given name. It will be called when an event with the given `name` triggers, and get the arguments from the `.trigger` call. -- ...And the method `.off(name, handler)` that removes the `handler` listener. +- Mixin bude poskytovat metodu `.spusť(název, [...data])`, která bude „generovat událost“, když se stane něco důležitého. Argument `název` je název události, za nímž mohou následovat další argumenty s daty události. +- Dále metodu `.zapni(název, handler)`, která přidá funkci `handler` jako posluchače událostí se zadaným názvem. Funkce `handler` bude volána, když se spustí událost se zadaným názvem `název`, a převezme argumenty z volání `.spusť`. +- ...A metodu `.vypni(název, handler)`, která odstraní posluchače `handler`. -After adding the mixin, an object `user` will be able to generate an event `"login"` when the visitor logs in. And another object, say, `calendar` may want to listen for such events to load the calendar for the logged-in person. +Po přidání mixinu bude objekt `uživatel` moci generovat událost `"přihlášen"`, když se uživatel přihlásí. A jiný objekt, třeba `kalendář`, bude moci takovým událostem naslouchat, aby pak načetl kalendář pro přihlášenou osobu. -Or, a `menu` can generate the event `"select"` when a menu item is selected, and other objects may assign handlers to react on that event. And so on. +Nebo `menu` může generovat událost `"vybrán"`, když je vybrán jeho prvek, a jiné objekty mohou přiřazovat handlery, které budou na tuto událost reagovat. A tak dále. -Here's the code: +Zde je kód: ```js run -let eventMixin = { +let mixinUdálosti = { /** - * Subscribe to event, usage: - * menu.on('select', function(item) { ... } + * Přihlášení k naslouchání události, použití: + * menu.zapni('vybrán', function(prvek) { ... }) */ - on(eventName, handler) { - if (!this._eventHandlers) this._eventHandlers = {}; - if (!this._eventHandlers[eventName]) { - this._eventHandlers[eventName] = []; + zapni(názevUdálosti, handler) { + if (!this._handleryUdálostí) this._handleryUdálostí = {}; + if (!this._handleryUdálostí[názevUdálosti]) { + this._handleryUdálostí[názevUdálosti] = []; } - this._eventHandlers[eventName].push(handler); + this._handleryUdálostí[názevUdálosti].push(handler); }, /** - * Cancel the subscription, usage: - * menu.off('select', handler) + * Odhlášení z naslouchání události, použití: + * menu.vypni('vybrán', handler) */ - off(eventName, handler) { - let handlers = this._eventHandlers?.[eventName]; - if (!handlers) return; - for (let i = 0; i < handlers.length; i++) { - if (handlers[i] === handler) { - handlers.splice(i--, 1); + vypni(názevUdálosti, handler) { + let handlery = this._handleryUdálostí?.[názevUdálosti]; + if (!handlery) return; + for (let i = 0; i < handlery.length; i++) { + if (handlery[i] === handler) { + handlery.splice(i--, 1); } } }, /** - * Generate an event with the given name and data - * this.trigger('select', data1, data2); + * Generování události se zadaným názvem a daty + * this.spusť('vybrán', data1, data2); */ - trigger(eventName, ...args) { - if (!this._eventHandlers?.[eventName]) { - return; // no handlers for that event name + spusť(názevUdálosti, ...argumenty) { + if (!this._handleryUdálostí?.[názevUdálosti]) { + return; // pro událost s tímto názvem nejsou žádné handlery } - // call the handlers - this._eventHandlers[eventName].forEach(handler => handler.apply(this, args)); + // volání handlerů + this._handleryUdálostí[názevUdálosti].forEach(handler => handler.apply(this, argumenty)); } }; ``` -- `.on(eventName, handler)` -- assigns function `handler` to run when the event with that name occurs. Technically, there's an `_eventHandlers` property that stores an array of handlers for each event name, and it just adds it to the list. -- `.off(eventName, handler)` -- removes the function from the handlers list. -- `.trigger(eventName, ...args)` -- generates the event: all handlers from `_eventHandlers[eventName]` are called, with a list of arguments `...args`. +- `.zapni(názevUdálosti, handler)` -- přiřadí funkci `handler`, která se má spustit vždy, když nastane událost s uvedeným názvem. Technicky je zde vlastnost `_handleryUdálostí`, do níž se ukládá pole handlerů pro každý název události, a funkce je prostě přidána do tohoto seznamu. +- `.vypni(názevUdálosti, handler)` -- odstraní funkci ze seznamu handlerů. +- `.spusť(názevUdálosti, ...argumenty)` -- generuje událost: všechny handlery z `_handleryUdálostí[názevUdálosti]` jsou volány se seznamem argumentů `...argumenty`. -Usage: +Použití: ```js run -// Make a class +// Vytvoříme třídu class Menu { - choose(value) { - this.trigger("select", value); + vyber(hodnota) { + this.spusť("vybrán", hodnota); } } -// Add the mixin with event-related methods -Object.assign(Menu.prototype, eventMixin); +// Přidáme mixin s metodami vztahujícími se k událostem +Object.assign(Menu.prototype, mixinUdálosti); let menu = new Menu(); -// add a handler, to be called on selection: +// přidáme handler, který bude volán při výběru: *!* -menu.on("select", value => alert(`Value selected: ${value}`)); +menu.zapni("vybrán", hodnota => alert(`Vybrána hodnota: ${hodnota}`)); */!* -// triggers the event => the handler above runs and shows: -// Value selected: 123 -menu.choose("123"); +// spustí událost => výše uvedený handler se spustí a zobrazí: +// Vybrána hodnota: 123 +menu.vyber("123"); ``` -Now, if we'd like any code to react to a menu selection, we can listen for it with `menu.on(...)`. +Kdybychom nyní chtěli přidat jakýkoli kód, který bude reagovat na výběr z menu, můžeme mu naslouchat pomocí `menu.zapni(...)`. -And `eventMixin` mixin makes it easy to add such behavior to as many classes as we'd like, without interfering with the inheritance chain. +A mixin `mixinUdálosti` usnadňuje přidání takového chování do tolika tříd, do kolika bychom chtěli, aniž bychom narušovali řetězec dědičnosti. -## Summary +## Shrnutí -*Mixin* -- is a generic object-oriented programming term: a class that contains methods for other classes. +*Mixin* -- je generický pojem objektově orientovaného programování: třída, která obsahuje metody pro jiné třídy. -Some other languages allow multiple inheritance. JavaScript does not support multiple inheritance, but mixins can be implemented by copying methods into prototype. +Některé jiné jazyky umožňují vícenásobnou dědičnost. JavaScript ji nepodporuje, ale mixiny mohou být implementovány zkopírováním metod do prototypu. -We can use mixins as a way to augment a class by adding multiple behaviors, like event-handling as we have seen above. +Mixiny můžeme používat jako způsob rozšiřování třídy přidáváním dalšího chování, například ošetřování událostí, jak jsme viděli výše. -Mixins may become a point of conflict if they accidentally overwrite existing class methods. So generally one should think well about the naming methods of a mixin, to minimize the probability of that happening. +Mixiny se mohou stát příčinou konfliktu, jestliže náhodou přepíší již existující metody třídy. Obecně bychom si tedy měli dobře rozmyslet názvy metod v mixinu, abychom minimalizovali pravděpodobnost, že se tak stane. diff --git a/1-js/09-classes/07-mixins/head.html b/1-js/09-classes/07-mixins/head.html index 20e3a6354..d2d9293b9 100644 --- a/1-js/09-classes/07-mixins/head.html +++ b/1-js/09-classes/07-mixins/head.html @@ -1,43 +1,42 @@ diff --git a/1-js/09-classes/07-mixins/mixin-inheritance.svg b/1-js/09-classes/07-mixins/mixin-inheritance.svg index 1fdc22393..d82c704f0 100644 --- a/1-js/09-classes/07-mixins/mixin-inheritance.svg +++ b/1-js/09-classes/07-mixins/mixin-inheritance.svg @@ -1 +1 @@ -sayHi: function sayBye: functionsayHiMixinsay: functionsayMixin[[Prototype]]constructor: User sayHi: function sayBye: functionUser.prototype[[Prototype]]name: ...user[[HomeObject] \ No newline at end of file +řekniAhoj: function řekniNashle: functionmixinŘekniAhojřekni: functionmixinŘekni[[Prototype]]constructor: Uživatel řekniAhoj: function řekniNashle: functionUživatel: prototype[[Prototype]]jméno: ...uživatel[[HomeObject] \ No newline at end of file diff --git a/1-js/09-classes/index.md b/1-js/09-classes/index.md index 87846ef6b..ed3bad014 100644 --- a/1-js/09-classes/index.md +++ b/1-js/09-classes/index.md @@ -1 +1 @@ -# Classes +# Třídy diff --git a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md index ec0dabc9a..bc9ed4624 100644 --- a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md +++ b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md @@ -1,47 +1,47 @@ -The difference becomes obvious when we look at the code inside a function. +Rozdíl uvidíme, když se podíváme na kód uvnitř funkce. -The behavior is different if there's a "jump out" of `try...catch`. +Chování se liší, pokud v něm je „vyskočení“ z `try...catch`. -For instance, when there's a `return` inside `try...catch`. The `finally` clause works in case of *any* exit from `try...catch`, even via the `return` statement: right after `try...catch` is done, but before the calling code gets the control. +Například když uvnitř `try...catch` je `return`. Klauzule `finally` se spustí při *jakémkoli* opuštění `try...catch`, dokonce i příkazem `return`: ihned po ukončení `try...catch`, ale ještě předtím, než řízení převezme volající kód. ```js run function f() { try { - alert('start'); + alert('začátek'); *!* - return "result"; + return "výsledek"; */!* - } catch (err) { + } catch (chyba) { /// ... } finally { - alert('cleanup!'); + alert('úklid!'); } } -f(); // cleanup! +f(); // úklid! ``` -...Or when there's a `throw`, like here: +...Nebo když je tam `throw`, například: ```js run function f() { try { - alert('start'); - throw new Error("an error"); - } catch (err) { + alert('začátek'); + throw new Error("chyba"); + } catch (chyba) { // ... - if("can't handle the error") { + if("nemůžeme ošetřit chybu") { *!* - throw err; + throw chyba; */!* } } finally { - alert('cleanup!') + alert('úklid!') } } -f(); // cleanup! +f(); // úklid! ``` -It's `finally` that guarantees the cleanup here. If we just put the code at the end of `f`, it wouldn't run in these situations. +Úklid nám zde zajistí právě `finally`. Kdybychom umístili kód na konec funkce `f`, v těchto situacích by se nespustil. diff --git a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md index b6dc81326..e2fac1d16 100644 --- a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md +++ b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md @@ -2,37 +2,37 @@ importance: 5 --- -# Finally or just the code? +# Klauzule finally nebo jen kód? -Compare the two code fragments. +Porovnejte si tyto dva fragmenty kódu. -1. The first one uses `finally` to execute the code after `try...catch`: +1. První používá `finally` ke spuštění kódu po `try...catch`: ```js try { - work work - } catch (err) { - handle errors + pracuj pracuj + } catch (chyba) { + ošetření chyb } finally { *!* - cleanup the working space + úklid pracovního prostoru */!* } ``` -2. The second fragment puts the cleaning right after `try...catch`: +2. Druhý fragment umisťuje úklid hned za `try...catch`: ```js try { - work work - } catch (err) { - handle errors + pracuj pracuj + } catch (chyba) { + ošetření chyb } *!* - cleanup the working space + úklid pracovního prostoru */!* ``` -We definitely need the cleanup after the work, doesn't matter if there was an error or not. +Úklid po práci potřebujeme provést v každém případě, ať už nastala chyba nebo ne. -Is there an advantage here in using `finally` or both code fragments are equal? If there is such an advantage, then give an example when it matters. +Je zde nějaká výhoda v použití `finally`, nebo jsou oba fragmenty kódu rovnocenné? Pokud je nějaká výhoda, vymyslete příklad, v němž se projeví. diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index bf548373a..798d3c111 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -1,556 +1,555 @@ -# Error handling, "try...catch" +# Ošetřování chyb, „try...catch“ -No matter how great we are at programming, sometimes our scripts have errors. They may occur because of our mistakes, an unexpected user input, an erroneous server response, and for a thousand other reasons. +Ať jsme sebelepší programátoři, v našich skriptech se někdy vyskytnou chyby. Může se to stát naší vinou, kvůli neočekávanému uživatelskému vstupu, chybné odpovědi serveru nebo z tisíce jiných důvodů. -Usually, a script "dies" (immediately stops) in case of an error, printing it to console. +V případě chyby skript obvykle „spadne“ (okamžitě se zastaví) a vypíše chybu na konzoli. -But there's a syntax construct `try...catch` that allows us to "catch" errors so the script can, instead of dying, do something more reasonable. +Existuje však syntaktická konstrukce `try...catch`, která nám umožňuje „zachytávat“ chyby, takže skript může místo spadnutí udělat něco rozumnějšího. -## The "try...catch" syntax +## Syntaxe „try...catch“ -The `try...catch` construct has two main blocks: `try`, and then `catch`: +Konstrukt `try...catch` má dva hlavní bloky: `try` a za ním `catch`: ```js try { - // code... + // kód... -} catch (err) { +} catch (chyba) { - // error handling + // ošetření chyby } ``` -It works like this: +Funguje následovně: -1. First, the code in `try {...}` is executed. -2. If there were no errors, then `catch (err)` is ignored: the execution reaches the end of `try` and goes on, skipping `catch`. -3. If an error occurs, then the `try` execution is stopped, and control flows to the beginning of `catch (err)`. The `err` variable (we can use any name for it) will contain an error object with details about what happened. +1. Nejprve se spustí kód v bloku `try {...}`. +2. Pokud v něm nejsou chyby, blok `catch (chyba)` je ignorován: běh dosáhne konce `try`, přeskočí blok `catch` a pokračuje dál. +3. Pokud nastane chyba, výkon bloku `try` se ukončí a běh pokračuje začátkem bloku `catch (chyba)`. Proměnná `chyba` (můžeme ji pojmenovat jakkoli) bude obsahovat chybový objekt s podrobnostmi o tom, co se stalo. ![](try-catch-flow.svg) -So, an error inside the `try {...}` block does not kill the script -- we have a chance to handle it in `catch`. +Chyba uvnitř bloku `try {...}` tedy neshodí skript -- máme šanci ji zpracovat v bloku `catch`. -Let's look at some examples. +Podívejme se na příklady. -- An errorless example: shows `alert` `(1)` and `(2)`: +- Příklad bez chyby: zobrazí `alert` `(1)` a `(2)`: ```js run try { - alert('Start of try runs'); // *!*(1) <--*/!* + alert('Spuštěn začátek bloku try'); // *!*(1) <--*/!* - // ...no errors here + // ...zde nejsou žádné chyby - alert('End of try runs'); // *!*(2) <--*/!* + alert('Spuštěn konec bloku try'); // *!*(2) <--*/!* - } catch (err) { + } catch (chyba) { - alert('Catch is ignored, because there are no errors'); // (3) + alert('Blok catch je ignorován, protože nenastaly žádné chyby'); // (3) } ``` -- An example with an error: shows `(1)` and `(3)`: +- Příklad s chybou: zobrazí `(1)` a `(3)`: ```js run try { - alert('Start of try runs'); // *!*(1) <--*/!* + alert('Spuštěn začátek bloku try'); // *!*(1) <--*/!* *!* - lalala; // error, variable is not defined! + lalala; // chyba, proměnná není definována! */!* - alert('End of try (never reached)'); // (2) + alert('Spuštěn konec bloku try (nikdy nedosaženo)'); // (2) - } catch (err) { + } catch (chyba) { - alert(`Error has occurred!`); // *!*(3) <--*/!* + alert(`Nastala chyba!`); // *!*(3) <--*/!* } ``` -````warn header="`try...catch` only works for runtime errors" -For `try...catch` to work, the code must be runnable. In other words, it should be valid JavaScript. +````warn header="`try...catch` funguje jen pro běhové chyby" +Aby `try...catch` fungoval, kód musí být spustitelný. Jinými slovy, musí to být platný kód v JavaScriptu. -It won't work if the code is syntactically wrong, for instance it has unmatched curly braces: +Nebude fungovat, když bude kód syntakticky nesprávný, například bude obsahovat neuzavřené složené závorky: ```js run try { {{{{{{{{{{{{ -} catch (err) { - alert("The engine can't understand this code, it's invalid"); +} catch (chyba) { + alert("Motor tomuto kódu nerozumí, kód je nesprávný"); } ``` -The JavaScript engine first reads the code, and then runs it. The errors that occur on the reading phase are called "parse-time" errors and are unrecoverable (from inside that code). That's because the engine can't understand the code. +JavaScriptový motor nejdříve načte kód a pak jej spustí. Chyby, které nastanou při fázi načítání, se nazývají „překladové“ (parse-time) chyby a nelze se z nich zotavit (zevnitř kódu). Je to proto, že motor takovému kódu nedokáže porozumět. -So, `try...catch` can only handle errors that occur in valid code. Such errors are called "runtime errors" or, sometimes, "exceptions". +Blok `try...catch` tedy umí ošetřit jen chyby, které se vyskytnou v platném kódu. Takové chyby se nazývají „běhové (runtime) chyby“ nebo někdy „výjimky“. ```` -````warn header="`try...catch` works synchronously" -If an exception happens in "scheduled" code, like in `setTimeout`, then `try...catch` won't catch it: +````warn header="`try...catch` funguje synchronně" +Jestliže výjimka nastane v „naplánovaném“ kódu, např. v `setTimeout`, pak ji `try...catch` neodchytí: ```js run try { setTimeout(function() { - noSuchVariable; // script will die here + neexistujícíProměnná; // skript tady spadne }, 1000); -} catch (err) { - alert( "won't work" ); +} catch (chyba) { + alert( "nebude to fungovat" ); } ``` -That's because the function itself is executed later, when the engine has already left the `try...catch` construct. +Je to proto, že samotná funkce se spustí později, když motor již opustil konstrukt `try...catch`. -To catch an exception inside a scheduled function, `try...catch` must be inside that function: +Abychom zachytili výjimku uvnitř naplánované funkce, `try...catch` musí být uvnitř této funkce: ```js run setTimeout(function() { try { - noSuchVariable; // try...catch handles the error! + neexistujícíProměnná; // try...catch tuto chybu zpracuje! } catch { - alert( "error is caught here!" ); + alert( "zde je odchycena chyba!" ); } }, 1000); ``` ```` -## Error object +## Chybový objekt -When an error occurs, JavaScript generates an object containing the details about it. The object is then passed as an argument to `catch`: +Když nastane chyba, JavaScript vygeneruje objekt obsahující podrobnosti o této chybě. Tento objekt je pak předán jako argument do bloku `catch`: ```js try { // ... -} catch (err) { // <-- the "error object", could use another word instead of err +} catch (chyba) { // <-- „chybový objekt“, místo „chyba“ můžeme použít jakýkoli název // ... } ``` -For all built-in errors, the error object has two main properties: +U všech vestavěných chyb má chybový objekt dvě hlavní vlastnosti: -`name` -: Error name. For instance, for an undefined variable that's `"ReferenceError"`. +`name` (název) +: Název chyby. Například pro nedefinovanou proměnnou je to `"ReferenceError"`. -`message` -: Textual message about error details. +`message` (zpráva) +: Textová zpráva o podrobnostech chyby. -There are other non-standard properties available in most environments. One of most widely used and supported is: +Ve většině prostředí jsou k dispozici i další nestandardní vlastnosti. Jedna z nejpoužívanějších a nejpodporovanějších je: -`stack` -: Current call stack: a string with information about the sequence of nested calls that led to the error. Used for debugging purposes. +`stack` (zásobník) +: Aktuální zásobník volání: řetězec s informací o posloupnosti vnořených volání, která vedla k chybě. Používá se pro účely ladění. -For instance: +Například: ```js run untrusted try { *!* - lalala; // error, variable is not defined! + lalala; // chyba, proměnná není definována! */!* -} catch (err) { - alert(err.name); // ReferenceError - alert(err.message); // lalala is not defined - alert(err.stack); // ReferenceError: lalala is not defined at (...call stack) - - // Can also show an error as a whole - // The error is converted to string as "name: message" - alert(err); // ReferenceError: lalala is not defined +} catch (chyba) { + alert(chyba.name); // ReferenceError + alert(chyba.message); // lalala is not defined + alert(chyba.stack); // ReferenceError: lalala is not defined at (...zásobník volání) + + // Můžeme také zobrazit chybu jako celek + // Chyba se pak převede na řetězec ve tvaru "name: message" + alert(chyba); // ReferenceError: lalala is not defined } ``` -## Optional "catch" binding +## Objekt chyby v „catch“ je nepovinný [recent browser=new] -If we don't need error details, `catch` may omit it: +Pokud nepotřebujeme podrobnosti o chybě, `catch` ji může vynechat: ```js try { // ... -} catch { // <-- without (err) +} catch { // <-- bez (chyba) // ... } ``` -## Using "try...catch" +## Použití „try...catch“ -Let's explore a real-life use case of `try...catch`. +Prozkoumejme případ použití `try...catch` z reálného života. -As we already know, JavaScript supports the [JSON.parse(str)](mdn:js/JSON/parse) method to read JSON-encoded values. +Jak už víme, JavaScript podporuje metodu [JSON.parse(str)](mdn:js/JSON/parse) k načtení hodnot zakódovaných do JSONu. -Usually it's used to decode data received over the network, from the server or another source. +Obvykle se používá k dekódování dat získaných po síti, ze serveru nebo z jiného zdroje. -We receive it and call `JSON.parse` like this: +Načteme data a zavoláme `JSON.parse` následovně: ```js run -let json = '{"name":"John", "age": 30}'; // data from the server +let json = '{"jméno": "Jan", "věk": 30}'; // data ze serveru *!* -let user = JSON.parse(json); // convert the text representation to JS object +let uživatel = JSON.parse(json); // převedeme textovou reprezentaci na objekt JS */!* -// now user is an object with properties from the string -alert( user.name ); // John -alert( user.age ); // 30 +// nyní je uživatel objekt s vlastnostmi z řetězce +alert( uživatel.jméno ); // Jan +alert( uživatel.věk ); // 30 ``` -You can find more detailed information about JSON in the chapter. +Podrobnější informace o JSON naleznete v kapitole . -**If `json` is malformed, `JSON.parse` generates an error, so the script "dies".** +**Je-li `json` poškozen, pak `JSON.parse` vygeneruje chybu, takže skript „spadne“.** -Should we be satisfied with that? Of course not! +Měli bychom se s tím spokojit? Ovšemže ne! -This way, if something's wrong with the data, the visitor will never know that (unless they open the developer console). And people really don't like when something "just dies" without any error message. +Pokud je v datech něco špatně, tímto způsobem se o tom návštěvník nikdy nedozví (pokud si neotevře vývojářskou konzoli). A lidé opravdu nemají rádi, když něco „jen tak spadne“ bez jakéhokoli chybového hlášení. -Let's use `try...catch` to handle the error: +Použijme tedy k ošetření chyby `try...catch`: ```js run -let json = "{ bad json }"; +let json = "{ špatný json }"; try { *!* - let user = JSON.parse(json); // <-- when an error occurs... + let uživatel = JSON.parse(json); // <-- když nastane chyba... */!* - alert( user.name ); // doesn't work + alert( uživatel.jméno ); // nespustí se -} catch (err) { +} catch (chyba) { *!* - // ...the execution jumps here - alert( "Our apologies, the data has errors, we'll try to request it one more time." ); - alert( err.name ); - alert( err.message ); + // ...provádění skočí sem + alert( "Omlouváme se, v datech byly chyby, pokusíme se o ně požádat ještě jednou." ); + alert( chyba.name ); + alert( chyba.message ); */!* } ``` -Here we use the `catch` block only to show the message, but we can do much more: send a new network request, suggest an alternative to the visitor, send information about the error to a logging facility, ... . All much better than just dying. +Zde používáme blok `catch` jen k zobrazení zprávy, ale můžeme toho udělat mnohem víc: poslat nový požadavek po síti, nabídnout návštěvníkovi alternativu, poslat informace o chybě na logovací zařízení... Všechno je mnohem lepší než pouhé spadnutí. -## Throwing our own errors +## Vyvolávání našich vlastních chyb -What if `json` is syntactically correct, but doesn't have a required `name` property? +Co když je `json` syntakticky správně, ale neobsahuje požadovanou vlastnost `jméno`? -Like this: +Například: ```js run -let json = '{ "age": 30 }'; // incomplete data +let json = '{ "věk": 30 }'; // neúplná data try { - let user = JSON.parse(json); // <-- no errors + let uživatel = JSON.parse(json); // <-- žádná chyba *!* - alert( user.name ); // no name! + alert( uživatel.jméno ); // jméno není! */!* -} catch (err) { - alert( "doesn't execute" ); +} catch (chyba) { + alert( "toto se nespustí" ); } ``` -Here `JSON.parse` runs normally, but the absence of `name` is actually an error for us. +Zde `JSON.parse` proběhl normálně, ale absence vlastnosti `jméno` pro nás ve skutečnosti představuje chybu. -To unify error handling, we'll use the `throw` operator. +Abychom sjednotili ošetřování chyb, použijeme operátor `throw`. -### "Throw" operator +### Operátor „throw“ -The `throw` operator generates an error. +Operátor `throw` vygeneruje chybu. -The syntax is: +Jeho syntaxe je: ```js -throw +throw ``` -Technically, we can use anything as an error object. That may be even a primitive, like a number or a string, but it's better to use objects, preferably with `name` and `message` properties (to stay somewhat compatible with built-in errors). +Technicky můžeme jako chybový objekt použít cokoli. Může to být dokonce i primitiv, např. číslo nebo řetězec, ale je lepší používat objekty, přednostně s vlastnostmi `name` a `message` (abychom zůstali alespoň zčásti kompatibilní se zabudovanými chybami). -JavaScript has many built-in constructors for standard errors: `Error`, `SyntaxError`, `ReferenceError`, `TypeError` and others. We can use them to create error objects as well. +JavaScript obsahuje mnoho vestavěných konstruktorů pro standardní chyby: `Error`, `SyntaxError`, `ReferenceError`, `TypeError` a jiné. I ty můžeme použít k vytvoření chybových objektů. -Their syntax is: +Jejich syntaxe je: ```js -let error = new Error(message); -// or -let error = new SyntaxError(message); -let error = new ReferenceError(message); +let chyba = new Error(zpráva); +// nebo +let chyba = new SyntaxError(zpráva); +let chyba = new ReferenceError(zpráva); // ... ``` -For built-in errors (not for any objects, just for errors), the `name` property is exactly the name of the constructor. And `message` is taken from the argument. +Ve vestavěných chybách (ne ve všech objektech, pouze v chybách) je vlastnost `name` přesný název konstruktoru a `message` se převezme z argumentu. -For instance: +Například: ```js run -let error = new Error("Things happen o_O"); +let chyba = new Error("Dějí se věci o_O"); -alert(error.name); // Error -alert(error.message); // Things happen o_O +alert(chyba.name); // Error +alert(chyba.message); // Dějí se věci o_O ``` -Let's see what kind of error `JSON.parse` generates: +Podívejme se, jaký druh chyby generuje `JSON.parse`: ```js run try { - JSON.parse("{ bad json o_O }"); -} catch (err) { + JSON.parse("{ špatný json o_O }"); +} catch (chyba) { *!* - alert(err.name); // SyntaxError + alert(chyba.name); // SyntaxError */!* - alert(err.message); // Unexpected token b in JSON at position 2 + alert(chyba.message); // Unexpected token š in JSON at position 2 } ``` -As we can see, that's a `SyntaxError`. +Jak vidíme, je to `SyntaxError`. -And in our case, the absence of `name` is an error, as users must have a `name`. +A v našem případě je absence vlastnosti `jméno` chyba, jelikož `jméno` musí mít každý uživatel. -So let's throw it: +Vyvolejme tedy chybu: ```js run -let json = '{ "age": 30 }'; // incomplete data +let json = '{ "věk": 30 }'; // neúplná data try { - let user = JSON.parse(json); // <-- no errors + let uživatel = JSON.parse(json); // <-- žádná chyba - if (!user.name) { + if (!uživatel.jméno) { *!* - throw new SyntaxError("Incomplete data: no name"); // (*) + throw new SyntaxError("Neúplná data: chybí jméno"); // (*) */!* } - alert( user.name ); + alert( uživatel.jméno ); -} catch (err) { - alert( "JSON Error: " + err.message ); // JSON Error: Incomplete data: no name +} catch (chyba) { + alert( "Chyba JSONu: " + chyba.message ); // Chyba JSONu: Neúplná data: chybí jméno } ``` -In the line `(*)`, the `throw` operator generates a `SyntaxError` with the given `message`, the same way as JavaScript would generate it itself. The execution of `try` immediately stops and the control flow jumps into `catch`. +Na řádku `(*)` operátor `throw` generuje chybu `SyntaxError` se zadanou zprávou `message`, stejným způsobem, jakým by ji vygeneroval samotný JavaScript. Výkon bloku `try` okamžitě skončí a běh skočí do bloku `catch`. -Now `catch` became a single place for all error handling: both for `JSON.parse` and other cases. +Nyní se `catch` stalo jediným místem pro ošetření všech chyb: jak pro `JSON.parse`, tak pro jiné případy. -## Rethrowing +## Opětovné vyvolání -In the example above we use `try...catch` to handle incorrect data. But is it possible that *another unexpected error* occurs within the `try {...}` block? Like a programming error (variable is not defined) or something else, not just this "incorrect data" thing. +V uvedeném příkladu jsme použili `try...catch` ke zpracování nekorektních dat. Je však možné, že uprostřed bloku `try {...}` nastane i *jiná neočekávaná chyba*? Například programátorská chyba (proměnná není definována) nebo něco jiného, nejenom tahle věc s „nekorektními daty“. -For example: +Například: ```js run -let json = '{ "age": 30 }'; // incomplete data +let json = '{ "věk": 30 }'; // neúplná data try { - user = JSON.parse(json); // <-- forgot to put "let" before user + uživatel = JSON.parse(json); // <-- zapomněli jsme uvést „let“ před proměnnou uživatel // ... -} catch (err) { - alert("JSON Error: " + err); // JSON Error: ReferenceError: user is not defined - // (no JSON Error actually) +} catch (chyba) { + alert("Chyba JSONu: " + chyba); // Chyba JSONu: ReferenceError: uživatel is not defined + // (ve skutečnosti to není chyba JSONu) } ``` -Of course, everything's possible! Programmers do make mistakes. Even in open-source utilities used by millions for decades -- suddenly a bug may be discovered that leads to terrible hacks. +Samozřejmě, všechno je možné! Programátoři dělají chyby. I v utilitách se zveřejněným zdrojovým kódem, které používají milióny lidí desítky let, může být náhle odhalena chyba, která vede ke strašlivým útokům hackerů. -In our case, `try...catch` is placed to catch "incorrect data" errors. But by its nature, `catch` gets *all* errors from `try`. Here it gets an unexpected error, but still shows the same `"JSON Error"` message. That's wrong and also makes the code more difficult to debug. +V našem případě je `try...catch` použit k tomu, aby zachytil chyby „nekorektních dat“. Ze své povahy však `catch` zachytí *všechny* chyby zevnitř `try`. Tady obdrží nečekanou chybu, ale stále zobrazí stejnou zprávu `"Chyba JSONu"`. To je špatně a ztěžuje to ladění kódu. -To avoid such problems, we can employ the "rethrowing" technique. The rule is simple: +Abychom se takovým problémům vyhnuli, můžeme využít techniku „opětovného vyvolání“. Pravidlo je jednoduché: -**Catch should only process errors that it knows and "rethrow" all others.** +**Blok catch by měl zpracovávat jen chyby, které zná, a „opětovně vyvolat“ všechny ostatní.** -The "rethrowing" technique can be explained in more detail as: +Techniku „opětovného vyvolání“ můžeme podrobněji vysvětlit takto: -1. Catch gets all errors. -2. In the `catch (err) {...}` block we analyze the error object `err`. -3. If we don't know how to handle it, we do `throw err`. +1. Blok catch zachytí všechny chyby. +2. V bloku `catch (chyba) {...}` analyzujeme chybový objekt `chyba`. +3. Pokud jej neumíme zpracovat, vyvoláme `throw chyba`. -Usually, we can check the error type using the `instanceof` operator: +Obvykle můžeme ověřit typ chyby operátorem `instanceof`: ```js run try { - user = { /*...*/ }; -} catch (err) { + uživatel = { /*...*/ }; +} catch (chyba) { *!* - if (err instanceof ReferenceError) { + if (chyba instanceof ReferenceError) { */!* - alert('ReferenceError'); // "ReferenceError" for accessing an undefined variable + alert('ReferenceError'); // "ReferenceError" kvůli přístupu k nedefinované proměnné } } ``` -We can also get the error class name from `err.name` property. All native errors have it. Another option is to read `err.constructor.name`. +Můžeme také získat název třídy chyby z vlastnosti `chyba.name`. Tu mají všechny nativní chyby. Další možností je načíst `chyba.constructor.name`. -In the code below, we use rethrowing so that `catch` only handles `SyntaxError`: +V následujícím kódu můžeme využít opětovné vyvolání tak, že `catch` bude zpracovávat pouze `SyntaxError`: ```js run -let json = '{ "age": 30 }'; // incomplete data +let json = '{ "věk": 30 }'; // neúplná data try { - let user = JSON.parse(json); + let uživatel = JSON.parse(json); - if (!user.name) { - throw new SyntaxError("Incomplete data: no name"); + if (!uživatel.jméno) { + throw new SyntaxError("Neúplná data: chybí jméno"); } *!* - blabla(); // unexpected error + blabla(); // neočekávaná chyba */!* - alert( user.name ); + alert( uživatel.jméno ); -} catch (err) { +} catch (chyba) { *!* - if (err instanceof SyntaxError) { - alert( "JSON Error: " + err.message ); + if (chyba instanceof SyntaxError) { + alert( "Chyba JSONu: " + chyba.message ); } else { - throw err; // rethrow (*) + throw chyba; // opětovné vyvolání (*) } */!* } ``` -The error throwing on line `(*)` from inside `catch` block "falls out" of `try...catch` and can be either caught by an outer `try...catch` construct (if it exists), or it kills the script. +Chyba vyvolaná na řádku `(*)` zevnitř bloku `catch` „vypadne“ z bloku `try...catch` a buď může být zachycena vnějším konstruktem `try...catch` (pokud existuje), nebo shodí skript. -So the `catch` block actually handles only errors that it knows how to deal with and "skips" all others. +Blok `catch` tedy ve skutečnosti ošetří jen chyby, s nimiž si umí poradit, a všechny ostatní „přeskočí“. -The example below demonstrates how such errors can be caught by one more level of `try...catch`: +Následující příklad předvádí, jak lze takové chyby zachytit další úrovní `try...catch`: ```js run -function readData() { - let json = '{ "age": 30 }'; +function načtiData() { + let json = '{ "věk": 30 }'; try { // ... *!* - blabla(); // error! + blabla(); // chyba! */!* - } catch (err) { + } catch (chyba) { // ... - if (!(err instanceof SyntaxError)) { + if (!(chyba instanceof SyntaxError)) { *!* - throw err; // rethrow (don't know how to deal with it) + throw chyba; // opětovné vyvolání (neumíme si s ní poradit) */!* } } } try { - readData(); -} catch (err) { + načtiData(); +} catch (chyba) { *!* - alert( "External catch got: " + err ); // caught it! + alert( "Vnější catch zachytil chybu: " + chyba ); // chytili jsme ji! */!* } ``` -Here `readData` only knows how to handle `SyntaxError`, while the outer `try...catch` knows how to handle everything. +Zde funkce `načtiData` umí ošetřit jedině `SyntaxError`, zatímco vnější `try...catch` umí ošetřit všechno. ## try...catch...finally -Wait, that's not all. +Počkat, to ještě není všechno. -The `try...catch` construct may have one more code clause: `finally`. +Konstrukt `try...catch` může mít ještě jednu kódovou klauzuli: `finally`. -If it exists, it runs in all cases: +Pokud existuje, spustí se ve všech případech: -- after `try`, if there were no errors, -- after `catch`, if there were errors. +- po `try`, pokud nenastaly žádné chyby, +- po `catch`, pokud nastaly chyby. -The extended syntax looks like this: +Rozšířená syntaxe vypadá následovně: ```js *!*try*/!* { - ... try to execute the code ... -} *!*catch*/!* (err) { - ... handle errors ... + ... pokusíme se spustit kód ... +} *!*catch*/!* (chyba) { + ... ošetříme chyby ... } *!*finally*/!* { - ... execute always ... + ... toto se vždy spustí ... } ``` -Try running this code: +Zkuste si spustit tento kód: ```js run try { alert( 'try' ); - if (confirm('Make an error?')) BAD_CODE(); -} catch (err) { + if (confirm('Vyvolat chybu?')) CHYBNÝ_KÓD(); +} catch (chyba) { alert( 'catch' ); } finally { alert( 'finally' ); } ``` -The code has two ways of execution: +Tento kód může běžet dvěma možnými cestami: -1. If you answer "Yes" to "Make an error?", then `try -> catch -> finally`. -2. If you say "No", then `try -> finally`. +1. Pokud odpovíte „Ano“ na „Vyvolat chybu?“, pak `try -> catch -> finally`. +2. Pokud odpovíte „Ne“, pak `try -> finally`. -The `finally` clause is often used when we start doing something and want to finalize it in any case of outcome. +Klauzule `finally` se často používá, když začneme něco dělat a chceme to ukončit, ať je výsledek jakýkoli. -For instance, we want to measure the time that a Fibonacci numbers function `fib(n)` takes. Naturally, we can start measuring before it runs and finish afterwards. But what if there's an error during the function call? In particular, the implementation of `fib(n)` in the code below returns an error for negative or non-integer numbers. +Například chceme změřit čas, jaký spotřebuje funkce `fib(n)` pro výpočet Fibonacciho čísel. Přirozeně můžeme zahájit měření předtím, než se spustí, a ukončit je posléze. Co když však během volání funkce nastane chyba? Konkrétně implementace `fib(n)` v následujícím kódu vrátí chybu pro záporná nebo necelá čísla. -The `finally` clause is a great place to finish the measurements no matter what. +Klauzule `finally` je vhodné místo, v němž můžeme ukončit měření, ať funkce dopadne jakkoli. -Here `finally` guarantees that the time will be measured correctly in both situations -- in case of a successful execution of `fib` and in case of an error in it: +Zde `finally` zaručuje, že čas bude správně změřen v obou situacích -- v případě úspěšného spuštění `fib` i v případě, že během něj nastane chyba: ```js run -let num = +prompt("Enter a positive integer number?", 35) +let číslo = +prompt("Zadejte kladné celé číslo", 35) -let diff, result; +let rozdíl, výsledek; function fib(n) { if (n < 0 || Math.trunc(n) != n) { - throw new Error("Must not be negative, and also an integer."); + throw new Error("Číslo nesmí být záporné a musí být celé."); } return n <= 1 ? n : fib(n - 1) + fib(n - 2); } -let start = Date.now(); +let začátek = Date.now(); try { - result = fib(num); -} catch (err) { - result = 0; + výsledek = fib(číslo); +} catch (chyba) { + výsledek = 0; *!* } finally { - diff = Date.now() - start; + rozdíl = Date.now() - začátek; } */!* -alert(result || "error occurred"); +alert(výsledek || "nastala chyba"); -alert( `execution took ${diff}ms` ); +alert( `výkon funkce trval ${rozdíl} ms` ); ``` -You can check by running the code with entering `35` into `prompt` -- it executes normally, `finally` after `try`. And then enter `-1` -- there will be an immediate error, and the execution will take `0ms`. Both measurements are done correctly. +Můžete si to ověřit, když spustíte kód a do `prompt` zadáte `35` -- spustí se normálně, `finally` přijde po `try`. A pak zadejte `-1` -- okamžitě nastane chyba a výkon funkce bude trvat `0 ms`. Obě měření proběhla správně. -In other words, the function may finish with `return` or `throw`, that doesn't matter. The `finally` clause executes in both cases. +Jinými slovy, funkce může skončit pomocí `return` nebo `throw`, na tom nezáleží. Klauzule `finally` se spustí v obou případech. +```smart header="Proměnné uvnitř `try...catch...finally` jsou lokální" +Prosíme všimněte si, že proměnné `výsledek` a `rozdíl` v uvedeném kódu jsou deklarovány *před* `try...catch`. -```smart header="Variables are local inside `try...catch...finally`" -Please note that `result` and `diff` variables in the code above are declared *before* `try...catch`. - -Otherwise, if we declared `let` in `try` block, it would only be visible inside of it. +Jinak kdybychom deklarovali `let` v bloku `try`, proměnné by byly viditelné jen uvnitř bloku. ``` -````smart header="`finally` and `return`" -The `finally` clause works for *any* exit from `try...catch`. That includes an explicit `return`. +````smart header="`finally` a `return`" +Klauzule `finally` funguje při *jakémkoli* opuštění bloku `try...catch`. To platí i pro výslovně uvedený `return`. -In the example below, there's a `return` in `try`. In this case, `finally` is executed just before the control returns to the outer code. +V následujícím příkladu je `return` uvnitř `try`. V tom případě se `finally` spustí právě předtím, než se běh vrátí do vnějšího kódu. ```js run -function func() { +function funkce() { try { *!* return 1; */!* - } catch (err) { + } catch (chyba) { /* ... */ } finally { *!* @@ -559,117 +558,117 @@ function func() { } } -alert( func() ); // first works alert from finally, and then this one +alert( funkce() ); // nejprve se spustí alert z finally a pak tento ``` ```` ````smart header="`try...finally`" -The `try...finally` construct, without `catch` clause, is also useful. We apply it when we don't want to handle errors here (let them fall through), but want to be sure that processes that we started are finalized. +Konstrukt `try...finally` je užitečný i bez klauzule `catch`. Používáme jej, když zde nechceme ošetřovat chyby (necháme je vypadnout ven), ale chceme mít jistotu, že procesy, které jsme zahájili, budou dokončeny. ```js -function func() { - // start doing something that needs completion (like measurements) +function funkce() { + // začneme dělat něco, co musíme dokončit (např. měření) try { // ... } finally { - // complete that thing even if all dies + // dokončíme to, i když všechno spadne } } ``` -In the code above, an error inside `try` always falls out, because there's no `catch`. But `finally` works before the execution flow leaves the function. +V uvedeném kódu chyba vzniklá uvnitř `try` vždy vypadne, protože zde není `catch`. Ale `finally` se vykoná ještě předtím, než běh opustí funkci. ```` -## Global catch +## Globální zachycení -```warn header="Environment-specific" -The information from this section is not a part of the core JavaScript. +```warn header="Specifické pro určité prostředí" +Informace z této části nejsou součástí jádra JavaScriptu. ``` -Let's imagine we've got a fatal error outside of `try...catch`, and the script died. Like a programming error or some other terrible thing. +Představme si, že jsme získali fatální chybu mimo `try...catch` a skript spadl. Například programátorskou chybu nebo něco jiného strašného. -Is there a way to react on such occurrences? We may want to log the error, show something to the user (normally they don't see error messages), etc. +Existuje způsob, jak na takové výskyty reagovat? Můžeme chtít chybu zalogovat, zobrazit něco uživateli (ten obvykle chybové zprávy nevidí) a podobně. -There is none in the specification, but environments usually provide it, because it's really useful. For instance, Node.js has [`process.on("uncaughtException")`](https://nodejs.org/api/process.html#process_event_uncaughtexception) for that. And in the browser we can assign a function to the special [window.onerror](mdn:api/GlobalEventHandlers/onerror) property, that will run in case of an uncaught error. +Ve specifikaci žádný není, ale prostředí jej obvykle poskytují, protože je opravdu užitečný. Například Node.js má k tomuto účelu [`process.on("uncaughtException")`](https://nodejs.org/api/process.html#process_event_uncaughtexception). A v prohlížeči můžeme přiřadit speciální vlastnosti [window.onerror](mdn:api/GlobalEventHandlers/onerror) funkci, která se spustí v případě nezachycené chyby. -The syntax: +Syntaxe: ```js -window.onerror = function(message, url, line, col, error) { +window.onerror = function(zpráva, url, řádek, sloupec, chyba) { // ... }; ``` -`message` -: Error message. +`zpráva` +: Chybová zpráva. `url` -: URL of the script where error happened. +: URL skriptu, v němž došlo k chybě. -`line`, `col` -: Line and column numbers where error happened. +`řádek`, `sloupec` +: Číslo řádku a číslo sloupce, v nichž chyba nastala. -`error` -: Error object. +`chyba` +: Chybový objekt. -For instance: +Například: ```html run untrusted refresh height=1 ``` -The role of the global handler `window.onerror` is usually not to recover the script execution -- that's probably impossible in case of programming errors, but to send the error message to developers. +Úkolem globálního handleru `window.onerror` obvykle není obnovit běh skriptu -- to je v případě programátorských chyb už zřejmě nemožné, ale poslat vývojářům chybovou zprávu. -There are also web-services that provide error-logging for such cases, like or . +Existují i webové služby, které poskytují logování chyb pro tyto případy, například . -They work like this: +Fungují následovně: -1. We register at the service and get a piece of JS (or a script URL) from them to insert on pages. -2. That JS script sets a custom `window.onerror` function. -3. When an error occurs, it sends a network request about it to the service. -4. We can log in to the service web interface and see errors. +1. Zaregistrujeme se na službě a dostaneme od ní kousek kódu v JS (nebo URL skriptu), který si vložíme na stránku. +2. Skript v JS nastaví uživatelskou funkci `window.onerror`. +3. Když nastane chyba, skript pošle službě síťový požadavek s informací o chybě. +4. Pak se můžeme přihlásit na webové rozhraní služby a chyby si prohlédnout. -## Summary +## Shrnutí -The `try...catch` construct allows to handle runtime errors. It literally allows to "try" running the code and "catch" errors that may occur in it. +Konstrukt `try...catch` nám umožňuje ošetřovat běhové chyby. Doslova nám umožňuje „pokusit se“ (anglicky „try“) spustit kód a „zachytit“ (anglicky „catch“) chyby, které v něm mohou nastat. -The syntax is: +Syntaxe je: ```js try { - // run this code -} catch (err) { - // if an error happened, then jump here - // err is the error object + // spustí se tento kód +} catch (chyba) { + // pokud nastala chyba, skočí se sem + // v proměnné chyba je chybový objekt } finally { - // do in any case after try/catch + // toto se provede v každém případě po try/catch } ``` -There may be no `catch` section or no `finally`, so shorter constructs `try...catch` and `try...finally` are also valid. +Sekce `catch` nebo `finally` tam nemusí být, takže fungují i kratší konstrukty `try...catch` a `try...finally`. -Error objects have following properties: +Chybové objekty mají následující vlastnosti: -- `message` -- the human-readable error message. -- `name` -- the string with error name (error constructor name). -- `stack` (non-standard, but well-supported) -- the stack at the moment of error creation. +- `message` -- chybová zpráva čitelná člověkem. +- `name` -- řetězec s názvem chyby (název konstruktoru chyby). +- `stack` (nestandardní, ale široce podporovaná) -- zásobník v okamžiku vzniku chyby. -If an error object is not needed, we can omit it by using `catch {` instead of `catch (err) {`. +Pokud chybový objekt nepotřebujeme, můžeme jej vynechat a použít jen `catch {` namísto `catch (chyba) {`. -We can also generate our own errors using the `throw` operator. Technically, the argument of `throw` can be anything, but usually it's an error object inheriting from the built-in `Error` class. More on extending errors in the next chapter. +Můžeme také generovat své vlastní chyby pomocí operátoru `throw`. Technicky může být argumentem `throw` cokoli, ale obvykle to je chybový objekt zděděný z vestavěné třídy `Error`. O rozšiřování chyb se dozvíme více v příští kapitole. -*Rethrowing* is a very important pattern of error handling: a `catch` block usually expects and knows how to handle the particular error type, so it should rethrow errors it doesn't know. +Velmi důležitým vzorcem ošetřování chyb je *opětovné vyvolání*: blok `catch` obvykle očekává a umí ošetřit jen chyby určitého typu, takže chyby, které nezná, by měl opětovně vyvolat. -Even if we don't have `try...catch`, most environments allow us to setup a "global" error handler to catch errors that "fall out". In-browser, that's `window.onerror`. +I když nemáme `try...catch`, většina prostředí nám umožňuje nastavit „globální“ chybový handler, který bude zachytávat chyby, které „vypadnou“. V prohlížeči je to `window.onerror`. diff --git a/1-js/10-error-handling/1-try-catch/try-catch-flow.svg b/1-js/10-error-handling/1-try-catch/try-catch-flow.svg index 2c0d71348..255ef2496 100644 --- a/1-js/10-error-handling/1-try-catch/try-catch-flow.svg +++ b/1-js/10-error-handling/1-try-catch/try-catch-flow.svg @@ -1 +1 @@ -BeginNo ErrorsAn error occured in the codeIgnore catch blockIgnore the rest of tryExecute catch blocktry { }// code... \ No newline at end of file +ZačátekBez chybV kódu nastala chybaIgnoruj blok catchIgnoruj zbytek tryVykonej blok catchtry { }// kód... \ No newline at end of file diff --git a/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md b/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md index 754e68f9a..25a7472bf 100644 --- a/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md +++ b/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md @@ -1,16 +1,16 @@ ```js run untrusted -class FormatError extends SyntaxError { - constructor(message) { - super(message); +class ChybaFormátu extends SyntaxError { + constructor(zpráva) { + super(zpráva); this.name = this.constructor.name; } } -let err = new FormatError("formatting error"); +let chyba = new ChybaFormátu("chyba formátování"); -alert( err.message ); // formatting error -alert( err.name ); // FormatError -alert( err.stack ); // stack +alert( chyba.message ); // chyba formátování +alert( chyba.name ); // ChybaFormátu +alert( chyba.stack ); // zásobník -alert( err instanceof SyntaxError ); // true +alert( chyba instanceof SyntaxError ); // true ``` diff --git a/1-js/10-error-handling/2-custom-errors/1-format-error/task.md b/1-js/10-error-handling/2-custom-errors/1-format-error/task.md index 2c8e910fc..9d2cef0a9 100644 --- a/1-js/10-error-handling/2-custom-errors/1-format-error/task.md +++ b/1-js/10-error-handling/2-custom-errors/1-format-error/task.md @@ -2,21 +2,21 @@ importance: 5 --- -# Inherit from SyntaxError +# Dědění ze třídy SyntaxError -Create a class `FormatError` that inherits from the built-in `SyntaxError` class. +Vytvořte třídu `ChybaFormátu`, která je zděděna ze zabudované třídy `SyntaxError`. -It should support `message`, `name` and `stack` properties. +Měla by podporovat vlastnosti `message`, `name` a `stack`. -Usage example: +Příklad použití: ```js -let err = new FormatError("formatting error"); +let chyba = new ChybaFormátu("chyba formátování"); -alert( err.message ); // formatting error -alert( err.name ); // FormatError -alert( err.stack ); // stack +alert( chyba.message ); // chyba formátování +alert( chyba.name ); // ChybaFormátu +alert( chyba.stack ); // zásobník -alert( err instanceof FormatError ); // true -alert( err instanceof SyntaxError ); // true (because inherits from SyntaxError) +alert( chyba instanceof ChybaFormátu ); // true +alert( chyba instanceof SyntaxError ); // true (protože je zděděna ze SyntaxError) ``` diff --git a/1-js/10-error-handling/2-custom-errors/article.md b/1-js/10-error-handling/2-custom-errors/article.md index d28b07439..916db4c36 100644 --- a/1-js/10-error-handling/2-custom-errors/article.md +++ b/1-js/10-error-handling/2-custom-errors/article.md @@ -1,301 +1,301 @@ -# Custom errors, extending Error +# Vlastní chyby, rozšíření třídy Error -When we develop something, we often need our own error classes to reflect specific things that may go wrong in our tasks. For errors in network operations we may need `HttpError`, for database operations `DbError`, for searching operations `NotFoundError` and so on. +Když něco vyvíjíme, často potřebujeme, aby naše vlastní chybové třídy odrážely specifické záležitosti, které se v našich úlohách mohou pokazit. Pro chyby v síťových operacích můžeme potřebovat třídu `ChybaHttp`, pro databázové operace `ChybaDb`, pro operace hledání `ChybaNenalezeno` a tak dále. -Our errors should support basic error properties like `message`, `name` and, preferably, `stack`. But they also may have other properties of their own, e.g. `HttpError` objects may have a `statusCode` property with a value like `404` or `403` or `500`. +Naše chyby by měly podporovat základní vlastnosti chyb jako `message`, `name` a pokud možno `stack`. Mohou však mít i jiné, své vlastní vlastnosti, např. objekty třídy `ChybaHttp` mohou mít vlastnost `stavovýKód` s hodnotami jako `404` nebo `403` nebo `500`. -JavaScript allows to use `throw` with any argument, so technically our custom error classes don't need to inherit from `Error`. But if we inherit, then it becomes possible to use `obj instanceof Error` to identify error objects. So it's better to inherit from it. +JavaScript nám umožňuje používat `throw` s libovolným argumentem, takže technicky naše vlastní chybové třídy nemusejí dědit ze třídy `Error`. Pokud z ní však dědíme, bude možné k identifikaci chybových objektů používat `obj instanceof Error`. Je tedy lepší z ní dědit. -As the application grows, our own errors naturally form a hierarchy. For instance, `HttpTimeoutError` may inherit from `HttpError`, and so on. +Když aplikace poroste, naše vlastní chyby budou tvořit přirozenou hierarchii. Například `ChybaHttpTimeout` může dědit z `ChybaHttp` a tak dále. -## Extending Error +## Rozšiřování třídy Error -As an example, let's consider a function `readUser(json)` that should read JSON with user data. +Jako příklad uvažujme funkci `načtiUživatele(json)`, která by měla načíst JSON s uživatelskými daty. -Here's an example of how a valid `json` may look: +Zde je příklad, jak může vypadat platný `json`: ```js -let json = `{ "name": "John", "age": 30 }`; +let json = `{ "jméno": "Jan", "věk": 30 }`; ``` -Internally, we'll use `JSON.parse`. If it receives malformed `json`, then it throws `SyntaxError`. But even if `json` is syntactically correct, that doesn't mean that it's a valid user, right? It may miss the necessary data. For instance, it may not have `name` and `age` properties that are essential for our users. +Uvnitř použijeme `JSON.parse`. Jestliže obdrží poškozený `json`, vyvolá `SyntaxError`. Ale i když je `json` syntakticky správně, neznamená to, že obsahuje platného uživatele, že? Mohou v něm chybět nezbytná data. Například nemusí obsahovat vlastnosti `jméno` a `věk`, které jsou pro naše uživatele nezbytné. -Our function `readUser(json)` will not only read JSON, but check ("validate") the data. If there are no required fields, or the format is wrong, then that's an error. And that's not a `SyntaxError`, because the data is syntactically correct, but another kind of error. We'll call it `ValidationError` and create a class for it. An error of that kind should also carry the information about the offending field. +Naše funkce `načtiUživatele(json)` tedy nebude jenom načítat JSON, ale také ověřovat („validovat“) data. Pokud v nich nebudou požadovaná pole nebo formát nebude správný, nastane chyba. A nebude to `SyntaxError`, protože data jsou syntakticky správně, ale chyba jiného druhu. Nazveme ji `ChybaValidace` a vytvoříme pro ni třídu. Chyba tohoto druhu by měla obsahovat také informaci o vadném poli. -Our `ValidationError` class should inherit from the `Error` class. +Naše třída `ChybaValidace` by měla být zděděna ze třídy `Error`. -The `Error` class is built-in, but here's its approximate code so we can understand what we're extending: +Třída `Error` je vestavěná, ale uvedeme její přibližný kód, abychom porozuměli tomu, co rozšiřujeme: ```js -// The "pseudocode" for the built-in Error class defined by JavaScript itself +// „Pseudokód“ pro vestavěnou třídu Error definovanou samotným JavaScriptem class Error { - constructor(message) { - this.message = message; - this.name = "Error"; // (different names for different built-in error classes) - this.stack = ; // non-standard, but most environments support it + constructor(zpráva) { + this.message = zpráva; + this.name = "Error"; // (různé názvy pro různé vestavěné chybové třídy) + this.stack = ; // nestandardní, ale většina prostředí jej podporuje } } ``` -Now let's inherit `ValidationError` from it and try it in action: +Nyní z ní zděďme třídu `ChybaValidace` a vyzkoušejme ji v akci: ```js run *!* -class ValidationError extends Error { +class ChybaValidace extends Error { */!* - constructor(message) { - super(message); // (1) - this.name = "ValidationError"; // (2) + constructor(zpráva) { + super(zpráva); // (1) + this.name = "ChybaValidace"; // (2) } } function test() { - throw new ValidationError("Whoops!"); + throw new ChybaValidace("Ouha!"); } try { test(); } catch(err) { - alert(err.message); // Whoops! - alert(err.name); // ValidationError - alert(err.stack); // a list of nested calls with line numbers for each + alert(err.message); // Ouha! + alert(err.name); // ChybaValidace + alert(err.stack); // seznam vnořených volání s číslem řádku u každého } ``` -Please note: in the line `(1)` we call the parent constructor. JavaScript requires us to call `super` in the child constructor, so that's obligatory. The parent constructor sets the `message` property. +Prosíme všimněte si: na řádku `(1)` zavoláme rodičovský konstruktor. JavaScript vyžaduje, abychom v konstruktoru dítěte volali `super`, takže to je povinné. Rodičovský konstruktor nastaví vlastnost `message`. -The parent constructor also sets the `name` property to `"Error"`, so in the line `(2)` we reset it to the right value. +Rodičovský konstruktor také nastaví vlastnost `name` na `"Error"`, takže ji na řádku `(2)` přenastavíme na správnou hodnotu. -Let's try to use it in `readUser(json)`: +Použijme chybu v metodě `načtiUživatele(json)`: ```js run -class ValidationError extends Error { - constructor(message) { - super(message); - this.name = "ValidationError"; +class ChybaValidace extends Error { + constructor(zpráva) { + super(zpráva); + this.name = "ChybaValidace"; } } -// Usage -function readUser(json) { - let user = JSON.parse(json); +// Použití +function načtiUživatele(json) { + let uživatel = JSON.parse(json); - if (!user.age) { - throw new ValidationError("No field: age"); + if (!uživatel.věk) { + throw new ChybaValidace("Chybí pole: věk"); } - if (!user.name) { - throw new ValidationError("No field: name"); + if (!uživatel.name) { + throw new ChybaValidace("Chybí pole: jméno"); } - return user; + return uživatel; } -// Working example with try..catch +// Příklad fungování s try..catch try { - let user = readUser('{ "age": 25 }'); -} catch (err) { - if (err instanceof ValidationError) { + let uživatel = načtiUživatele('{ "věk": 25 }'); +} catch (chyba) { + if (chyba instanceof ChybaValidace) { *!* - alert("Invalid data: " + err.message); // Invalid data: No field: name + alert("Vadná data: " + chyba.message); // Vadná data: Chybí pole: jméno */!* - } else if (err instanceof SyntaxError) { // (*) - alert("JSON Syntax Error: " + err.message); + } else if (chyba instanceof SyntaxError) { // (*) + alert("Syntaktická chyba JSONu: " + chyba.message); } else { - throw err; // unknown error, rethrow it (**) + throw chyba; // neznámá chyba, vyvoláme ji znovu (**) } } ``` -The `try..catch` block in the code above handles both our `ValidationError` and the built-in `SyntaxError` from `JSON.parse`. +V uvedeném kódu blok `try..catch` ošetřuje jak naši chybu `ChybaValidace`, tak vestavěnou chybu `SyntaxError` z `JSON.parse`. -Please take a look at how we use `instanceof` to check for the specific error type in the line `(*)`. +Prosíme podívejte se, jak na řádku `(*)` používáme `instanceof` k ověřování specifického typu chyby. -We could also look at `err.name`, like this: +Můžeme se podívat i do `chyba.name`, například: ```js // ... -// instead of (err instanceof SyntaxError) -} else if (err.name == "SyntaxError") { // (*) +// namísto (chyba instanceof SyntaxError) +} else if (chyba.name == "SyntaxError") { // (*) // ... ``` -The `instanceof` version is much better, because in the future we are going to extend `ValidationError`, make subtypes of it, like `PropertyRequiredError`. And `instanceof` check will continue to work for new inheriting classes. So that's future-proof. +Verze s `instanceof` je však mnohem lepší, protože v budoucnu se chystáme třídu `ChybaValidace` rozšiřovat, vytvářet její podtypy, např. `ChybaPožadovanéVlastnosti`. A ověření pomocí `instanceof` bude fungovat i pro nově zděděné třídy. Je tedy dopředně kompatibilní. -Also it's important that if `catch` meets an unknown error, then it rethrows it in the line `(**)`. The `catch` block only knows how to handle validation and syntax errors, other kinds (caused by a typo in the code or other unknown reasons) should fall through. +Je také důležité, že pokud `catch` zachytí neznámou chybu, na řádku `(**)` ji opětovně vyvolá. Blok `catch` umí ošetřit jen validační a syntaktické chyby, ostatní druhy chyb (způsobené překlepem v kódu nebo jinými neznámými příčinami) by měly vypadnout výš. -## Further inheritance +## Budoucí dědičnost -The `ValidationError` class is very generic. Many things may go wrong. The property may be absent or it may be in a wrong format (like a string value for `age` instead of a number). Let's make a more concrete class `PropertyRequiredError`, exactly for absent properties. It will carry additional information about the property that's missing. +Třída `ChybaValidace` je velmi obecná. Pokazit se může spousta věcí. Vlastnost může chybět nebo může být v nesprávném formátu (například řetězcová hodnota místo čísla u vlastnosti `věk`). Vytvořme tedy konkrétnější třídu `ChybaPožadovanéVlastnosti`, která bude sloužit výhradně pro případy chybějících vlastností. Bude obsahovat další informace o vlastnosti, která chybí. ```js run -class ValidationError extends Error { - constructor(message) { - super(message); - this.name = "ValidationError"; +class ChybaValidace extends Error { + constructor(zpráva) { + super(zpráva); + this.name = "ChybaValidace"; } } *!* -class PropertyRequiredError extends ValidationError { - constructor(property) { - super("No property: " + property); - this.name = "PropertyRequiredError"; - this.property = property; +class ChybaPožadovanéVlastnosti extends ChybaValidace { + constructor(vlastnost) { + super("Chybí vlastnost: " + vlastnost); + this.name = "ChybaPožadovanéVlastnosti"; + this.vlastnost = vlastnost; } } */!* -// Usage -function readUser(json) { - let user = JSON.parse(json); +// Použití +function načtiUživatele(json) { + let uživatel = JSON.parse(json); - if (!user.age) { - throw new PropertyRequiredError("age"); + if (!uživatel.věk) { + throw new ChybaPožadovanéVlastnosti("věk"); } - if (!user.name) { - throw new PropertyRequiredError("name"); + if (!uživatel.jméno) { + throw new ChybaPožadovanéVlastnosti("jméno"); } - return user; + return uživatel; } -// Working example with try..catch +// Příklad fungování s try..catch try { - let user = readUser('{ "age": 25 }'); -} catch (err) { - if (err instanceof ValidationError) { + let uživatel = načtiUživatele('{ "věk": 25 }'); +} catch (chyba) { + if (chyba instanceof ChybaValidace) { *!* - alert("Invalid data: " + err.message); // Invalid data: No property: name - alert(err.name); // PropertyRequiredError - alert(err.property); // name + alert("Vadná data: " + chyba.message); // Vadná data: Chybí vlastnost: jméno + alert(chyba.name); // ChybaPožadovanéVlastnosti + alert(chyba.vlastnost); // jméno */!* - } else if (err instanceof SyntaxError) { - alert("JSON Syntax Error: " + err.message); + } else if (chyba instanceof SyntaxError) { + alert("Syntaktická chyba JSONu: " + chyba.message); } else { - throw err; // unknown error, rethrow it + throw chyba; // neznámá chyba, vyvoláme ji znovu } } ``` -The new class `PropertyRequiredError` is easy to use: we only need to pass the property name: `new PropertyRequiredError(property)`. The human-readable `message` is generated by the constructor. +Používání nové třídy `ChybaPožadovanéVlastnosti` je snadné: postačí předat název vlastnosti: `new ChybaPožadovanéVlastnosti(vlastnost)`. Konstruktor vygeneruje člověkem čitelnou zprávu `message`. -Please note that `this.name` in `PropertyRequiredError` constructor is again assigned manually. That may become a bit tedious -- to assign `this.name = ` in every custom error class. We can avoid it by making our own "basic error" class that assigns `this.name = this.constructor.name`. And then inherit all our custom errors from it. +Prosíme všimněte si, že `this.name` v konstruktoru `ChybaPožadovanéVlastnosti` se opět přiřazuje ručně. To může být poněkud úmorné -- přiřazovat `this.name = ` v každé vlastní chybové třídě. Můžeme se tomu vyhnout, když si vytvoříme vlastní „základní chybovou“ třídu, která bude přiřazovat `this.name = this.constructor.name`, a pak budeme všechny naše chyby dědit z ní. -Let's call it `MyError`. +Nazvěme ji `MojeChyba`. -Here's the code with `MyError` and other custom error classes, simplified: +Zde je kód s třídou `MojeChyba` a dalšími vlastními chybovými třídami, zjednodušeně: ```js run -class MyError extends Error { - constructor(message) { - super(message); +class MojeChyba extends Error { + constructor(zpráva) { + super(zpráva); *!* this.name = this.constructor.name; */!* } } -class ValidationError extends MyError { } +class ChybaValidace extends MojeChyba { } -class PropertyRequiredError extends ValidationError { - constructor(property) { - super("No property: " + property); - this.property = property; +class ChybaPožadovanéVlastnosti extends ChybaValidace { + constructor(vlastnost) { + super("Chybí vlastnost: " + vlastnost); + this.vlastnost = vlastnost; } } -// name is correct -alert( new PropertyRequiredError("field").name ); // PropertyRequiredError +// název je správně +alert( new ChybaPožadovanéVlastnosti("pole").name ); // ChybaPožadovanéVlastnosti ``` -Now custom errors are much shorter, especially `ValidationError`, as we got rid of the `"this.name = ..."` line in the constructor. +Nyní jsou naše chyby, konkrétně `ChybaValidace`, mnohem kratší, jelikož jsme se zbavili řádku `"this.name = ..."` v konstruktoru. -## Wrapping exceptions +## Obalování výjimek -The purpose of the function `readUser` in the code above is "to read the user data". There may occur different kinds of errors in the process. Right now we have `SyntaxError` and `ValidationError`, but in the future `readUser` function may grow and probably generate other kinds of errors. +Účelem funkce `načtiUživatele` v uvedeném kódu je „načíst uživatelská data“. Při tomto procesu mohou nastat chyby různých druhů. Momentálně máme `SyntaxError` a `ChybaValidace`, ale v budoucnu se funkce `načtiUživatele` může rozrůst a pravděpodobně bude generovat chyby dalších druhů. -The code which calls `readUser` should handle these errors. Right now it uses multiple `if`s in the `catch` block, that check the class and handle known errors and rethrow the unknown ones. +Tyto chyby by měl ošetřovat kód, který funkci `načtiUživatele` volá. Momentálně používá v bloku `catch` několik příkazů `if`, které prozkoumají třídu, ošetří známé chyby a opětovně vyvolají neznámé. -The scheme is like this: +Schéma je následující: ```js try { ... - readUser() // the potential error source + načtiUživatele() // potenciální zdroj chyb ... -} catch (err) { - if (err instanceof ValidationError) { - // handle validation errors - } else if (err instanceof SyntaxError) { - // handle syntax errors +} catch (chyba) { + if (chyba instanceof ChybaValidace) { + // ošetření validačních chyb + } else if (chyba instanceof SyntaxError) { + // ošetření syntaktických chyb } else { - throw err; // unknown error, rethrow it + throw chyba; // neznámá chyba, vyvoláme ji znovu } } ``` -In the code above we can see two types of errors, but there can be more. +V uvedeném kódu vidíme dva typy chyb, ale může jich tam být víc. -If the `readUser` function generates several kinds of errors, then we should ask ourselves: do we really want to check for all error types one-by-one every time? +Jestliže funkce `načtiUživatele` generuje chyby několika druhů, měli bychom se zeptat sami sebe: opravdu chceme pokaždé ověřovat všechny typy chyb jeden po druhém? -Often the answer is "No": we'd like to be "one level above all that". We just want to know if there was a "data reading error" -- why exactly it happened is often irrelevant (the error message describes it). Or, even better, we'd like to have a way to get the error details, but only if we need to. +Odpověď často zní „ne“: chtěli bychom být „o úroveň výš nad tím vším“. Chceme vědět jen to, zda to byla „chyba načítání dat“ -- proč přesně se stala, je často nepodstatné (popisuje to chybová zpráva). Nebo ještě lepší by bylo, kdybychom měli způsob, jak získat podrobnosti o chybě, ale jen když je budeme potřebovat. -The technique that we describe here is called "wrapping exceptions". +Technika, kterou tady popisujeme, se nazývá „obalování (wrapping) výjimek“. -1. We'll make a new class `ReadError` to represent a generic "data reading" error. -2. The function `readUser` will catch data reading errors that occur inside it, such as `ValidationError` and `SyntaxError`, and generate a `ReadError` instead. -3. The `ReadError` object will keep the reference to the original error in its `cause` property. +1. Vytvoříme novou třídu `ChybaČtení`, která bude představovat obecnou chybu „čtení dat“. +2. Funkce `načtiUživatele` bude zachytávat chyby načítání dat, které nastanou uvnitř ní, např. `ChybaValidace` a `SyntaxError`, a místo nich generovat chybu `ChybaČtení`. +3. Objekt `ChybaČtení` si ve své vlastnosti `příčina` bude udržovat odkaz na původní chybu. -Then the code that calls `readUser` will only have to check for `ReadError`, not for every kind of data reading errors. And if it needs more details of an error, it can check its `cause` property. +Pak kód, který volá funkci `načtiUživatele`, bude muset ověřovat jen chybu `ChybaČtení`, ne každý druh chyby načítání dat. A pokud bude potřebovat podrobnosti o chybě, může se podívat na vlastnost `příčina`. -Here's the code that defines `ReadError` and demonstrates its use in `readUser` and `try..catch`: +Zde je kód, který definuje `ChybaČtení` a demonstruje její použití ve funkci `načtiUživatele` a `try..catch`: ```js run -class ReadError extends Error { - constructor(message, cause) { - super(message); - this.cause = cause; - this.name = 'ReadError'; +class ChybaČtení extends Error { + constructor(zpráva, příčina) { + super(zpráva); + this.příčina = příčina; + this.name = 'ChybaČtení'; } } -class ValidationError extends Error { /*...*/ } -class PropertyRequiredError extends ValidationError { /* ... */ } +class ChybaValidace extends Error { /*...*/ } +class ChybaPožadovanéVlastnosti extends ChybaValidace { /* ... */ } -function validateUser(user) { - if (!user.age) { - throw new PropertyRequiredError("age"); +function validujUživatele(uživatel) { + if (!uživatel.věk) { + throw new ChybaPožadovanéVlastnosti("věk"); } - if (!user.name) { - throw new PropertyRequiredError("name"); + if (!uživatel.jméno) { + throw new ChybaPožadovanéVlastnosti("jméno"); } } -function readUser(json) { - let user; +function načtiUživatele(json) { + let uživatel; try { - user = JSON.parse(json); - } catch (err) { + uživatel = JSON.parse(json); + } catch (chyba) { *!* - if (err instanceof SyntaxError) { - throw new ReadError("Syntax Error", err); + if (chyba instanceof SyntaxError) { + throw new ChybaČtení("Syntaktická chyba", chyba); } else { - throw err; + throw chyba; } */!* } try { - validateUser(user); - } catch (err) { + validujUživatele(uživatel); + } catch (chyba) { *!* - if (err instanceof ValidationError) { - throw new ReadError("Validation Error", err); + if (chyba instanceof ChybaValidace) { + throw new ChybaČtení("Chyba validace", chyba); } else { - throw err; + throw chyba; } */!* } @@ -303,13 +303,13 @@ function readUser(json) { } try { - readUser('{bad json}'); + načtiUživatele('{špatný json}'); } catch (e) { - if (e instanceof ReadError) { + if (e instanceof ChybaČtení) { *!* alert(e); - // Original error: SyntaxError: Unexpected token b in JSON at position 1 - alert("Original error: " + e.cause); + // Původní chyba: SyntaxError: Unexpected token š in JSON at position 1 + alert("Původní chyba: " + e.příčina); */!* } else { throw e; @@ -317,14 +317,14 @@ try { } ``` -In the code above, `readUser` works exactly as described -- catches syntax and validation errors and throws `ReadError` errors instead (unknown errors are rethrown as usual). +V uvedeném kódu `načtiUživatele` funguje přesně tak, jak jsme popsali -- zachytává syntaktické a validační chyby a místo nich vyvolává chyby `ChybaČtení` (neznámé chyby se vyvolávají znovu jako obvykle). -So the outer code checks `instanceof ReadError` and that's it. No need to list all possible error types. +Vnější kód si tedy ověří `instanceof ChybaČtení` a to je vše. Není třeba vyjmenovávat všechny možné typy chyb. -The approach is called "wrapping exceptions", because we take "low level" exceptions and "wrap" them into `ReadError` that is more abstract. It is widely used in object-oriented programming. +Tento přístup se nazývá „obalování (wrapping) výjimek“, protože přejímáme výjimky „nižší úrovně“ a „obalujeme“ (anglicky „wrap“) je do výjimky `ChybaČtení`, která je abstraktnější. V objektově orientovaném programování se zeširoka používá. -## Summary +## Shrnutí -- We can inherit from `Error` and other built-in error classes normally. We just need to take care of the `name` property and don't forget to call `super`. -- We can use `instanceof` to check for particular errors. It also works with inheritance. But sometimes we have an error object coming from a 3rd-party library and there's no easy way to get its class. Then `name` property can be used for such checks. -- Wrapping exceptions is a widespread technique: a function handles low-level exceptions and creates higher-level errors instead of various low-level ones. Low-level exceptions sometimes become properties of that object like `err.cause` in the examples above, but that's not strictly required. +- Ze třídy `Error` a jiných vestavěných tříd můžeme dědit běžným způsobem. Jen se musíme postarat o vlastnost `name` a nesmíme zapomenout volat `super`. +- K ověření chyb určitého druhu můžeme použít `instanceof`. Ten funguje i s dědičností. Někdy však máme chybový objekt pocházející z knihovny třetí strany a neexistuje žádný snadný způsob, jak získat jeho třídu. Pak můžeme pro taková ověření použít vlastnost `name`. +- Široce používaná technika je obalování výjimek: funkce ošetří výjimky nižší úrovně a namísto různých chyb nižší úrovně vyvolá chybu vyšší úrovně. Výjimky nižší úrovně se někdy stávají jejími vlastnostmi, například `chyba.příčina` v uvedených příkladech, ale to není striktně vyžadováno. \ No newline at end of file diff --git a/1-js/10-error-handling/index.md b/1-js/10-error-handling/index.md index face61c6e..aaf0679a3 100644 --- a/1-js/10-error-handling/index.md +++ b/1-js/10-error-handling/index.md @@ -1 +1 @@ -# Error handling +# Ošetřování chyb diff --git a/1-js/11-async/01-callbacks/article.md b/1-js/11-async/01-callbacks/article.md index 57115a909..1cd65e4cd 100644 --- a/1-js/11-async/01-callbacks/article.md +++ b/1-js/11-async/01-callbacks/article.md @@ -1,150 +1,150 @@ -# Introduction: callbacks +# Úvod: callbacky -```warn header="We use browser methods in examples here" -To demonstrate the use of callbacks, promises and other abstract concepts, we'll be using some browser methods: specifically, loading scripts and performing simple document manipulations. +```warn header="Ve zdejších příkladech používáme metody prohlížeče" +Abychom demonstrovali použití callbacků, příslibů a jiných abstraktních konceptů, budeme používat některé metody prohlížeče: jmenovitě načítání skriptů a provádění jednoduchých manipulací s dokumentem. -If you're not familiar with these methods, and their usage in the examples is confusing, you may want to read a few chapters from the [next part](/document) of the tutorial. +Jestliže tyto metody neznáte a jejich používání v příkladech je pro vás matoucí, možná si budete chtít přečíst několik kapitol z [další části](/document) tutoriálu. -Although, we'll try to make things clear anyway. There won't be anything really complex browser-wise. +Snažíme se však, aby všechno bylo jasné. Z prohlížeče tady nebude nic příliš složitého. ``` -Many functions are provided by JavaScript host environments that allow you to schedule *asynchronous* actions. In other words, actions that we initiate now, but they finish later. +Hostitelská prostředí JavaScriptu poskytují mnoho funkcí, které nám umožňují naplánovat *asynchronní* akce. Jinými slovy akce, které spustíme nyní, ale dokončí se až později. -For instance, one such function is the `setTimeout` function. +Například jedna taková funkce je `setTimeout`. -There are other real-world examples of asynchronous actions, e.g. loading scripts and modules (we'll cover them in later chapters). +Ze skutečného světa existují i jiné příklady asynchronních akcí, např. načítání skriptů a modulů (vysvětlíme je v dalších kapitolách). -Take a look at the function `loadScript(src)`, that loads a script with the given `src`: +Podívejme se na funkci `načtiSkript(zdroj)`, která načte skript ze zadaného zdroje `zdroj`: ```js -function loadScript(src) { - // creates a ``` -### Module-level scope +### Rozsah platnosti na úrovni modulu -Each module has its own top-level scope. In other words, top-level variables and functions from a module are not seen in other scripts. +Každý modul má na nejvyšší úrovni svůj vlastní rozsah platnosti. Jinými slovy, proměnné a funkce na nejvyšší úrovni modulu nejsou vidět v jiných skriptech. -In the example below, two scripts are imported, and `hello.js` tries to use `user` variable declared in `user.js`. It fails, because it's a separate module (you'll see the error in the console): +V následujícím příkladu jsou importovány dva skripty a `hello.js` se pokusí použít proměnnou `uživatel`, deklarovanou v `user.js`. Selže to, protože to je oddělený modul (chybu uvidíte v konzoli): [codetabs src="https://github.com/scopes" height="140" current="index.html"] -Modules should `export` what they want to be accessible from outside and `import` what they need. +Moduly by měly exportovat direktivou `export` to, co chtějí zpřístupnit zvenčí, a importovat direktivou `import` to, co potřebují. -- `user.js` should export the `user` variable. -- `hello.js` should import it from `user.js` module. +- `user.js` by měl exportovat proměnnou `uživatel`. +- `hello.js` by ji měl importovat z modulu `user.js`. -In other words, with modules we use import/export instead of relying on global variables. +Jinými slovy, s moduly používáme import a export místo závislosti na globálních proměnných. -This is the correct variant: +Toto je správná varianta: [codetabs src="https://github.com/scopes-working" height="140" current="hello.js"] -In the browser, if we talk about HTML pages, independent top-level scope also exists for each ` ``` ```smart -In the browser, we can make a variable window-level global by explicitly assigning it to a `window` property, e.g. `window.user = "John"`. +V prohlížeči můžeme učinit proměnnou globální na úrovni okna tak, že ji výslovně přiřadíme do vlastnosti objektu `window`, např. `window.uživatel = "Jan"`. -Then all scripts will see it, both with `type="module"` and without it. +Pak ji uvidí všechny skripty, s `type="module"` i bez něj. -That said, making such global variables is frowned upon. Please try to avoid them. +Přesto je však vytváření takových globálních proměnných nehezké. Prosíme, snažte se tomu vyhnout. ``` -### A module code is evaluated only the first time when imported +### Modulový kód je vyhodnocen jen poprvé, když je importován -If the same module is imported into multiple other modules, its code is executed only once, upon the first import. Then its exports are given to all further importers. +Je-li tentýž modul importován do několika jiných modulů, jeho kód se spustí pouze jednou, při prvním importu. Pak jsou jeho exporty předány všem budoucím importérům. -The one-time evaluation has important consequences, that we should be aware of. +Jednorázové vyhodnocení má důležité důsledky, kterých bychom si měli být vědomi. -Let's see a couple of examples. +Podívejme se na několik příkladů. -First, if executing a module code brings side-effects, like showing a message, then importing it multiple times will trigger it only once -- the first time: +Především jestliže spuštění kódu modulu způsobí vedlejší efekty, např. zobrazení zprávy, pak se při vícenásobném importu spustí pouze jednou -- poprvé: ```js // 📁 alert.js -alert("Module is evaluated!"); +alert("Modul je vyhodnocen!"); ``` ```js -// Import the same module from different files +// Importujeme stejný modul v různých souborech // 📁 1.js -import `./alert.js`; // Module is evaluated! +import `./alert.js`; // Modul je vyhodnocen! // 📁 2.js -import `./alert.js`; // (shows nothing) +import `./alert.js`; // (nezobrazí nic) ``` -The second import shows nothing, because the module has already been evaluated. +Druhý import nic nezobrazí, protože modul již byl vyhodnocen. -There's a rule: top-level module code should be used for initialization, creation of module-specific internal data structures. If we need to make something callable multiple times - we should export it as a function, like we did with `sayHi` above. +Existuje pravidlo, že kód na nejvyšší úrovni modulu by měl být použit pro inicializaci, vytvoření vnitřních datových struktur specifických pro modul. Jestliže potřebujeme umožnit něco volat vícekrát, měli bychom to exportovat jako funkci, tak jak jsme to udělali s výše uvedenou funkcí `řekniAhoj`. -Now, let's consider a deeper example. +Nyní uvažujme hlubší příklad. -Let's say, a module exports an object: +Řekněme, že modul exportuje objekt: ```js // 📁 admin.js export let admin = { - name: "John" + jméno: "Jan" }; ``` -If this module is imported from multiple files, the module is only evaluated the first time, `admin` object is created, and then passed to all further importers. +Je-li tento modul importován z více souborů, je vyhodnocen pouze poprvé, vytvoří se objekt `admin` a ten je pak předán všem dalším importérům. -All importers get exactly the one and only `admin` object: +Všichni importéři dostanou přesně jeden a tentýž objekt `admin`: ```js // 📁 1.js import {admin} from './admin.js'; -admin.name = "Pete"; +admin.jméno = "Petr"; // 📁 2.js import {admin} from './admin.js'; -alert(admin.name); // Pete +alert(admin.jméno); // Petr *!* -// Both 1.js and 2.js reference the same admin object -// Changes made in 1.js are visible in 2.js +// Jak 1.js, tak 2.js se odkazují na tentýž objekt admin +// Změny učiněné v 1.js jsou viditelné ve 2.js */!* ``` -As you can see, when `1.js` changes the `name` property in the imported `admin`, then `2.js` can see the new `admin.name`. +Jak vidíte, když `1.js` v importovaném objektu `admin` změní vlastnost `jméno`, pak `2.js` uvidí nové `admin.jméno`. -That's exactly because the module is executed only once. Exports are generated, and then they are shared between importers, so if something changes the `admin` object, other importers will see that. +To je právě proto, že modul je spuštěn pouze jednou. Vygenerují se exporty a ty jsou pak sdíleny mezi importéry, takže jestliže něco změní objekt `admin`, ostatní importéři to uvidí. -**Such behavior is actually very convenient, because it allows us to *configure* modules.** +**Takové chování je ve skutečnosti velmi užitečné, protože nám umožňuje *konfigurovat* moduly.** -In other words, a module can provide a generic functionality that needs a setup. E.g. authentication needs credentials. Then it can export a configuration object expecting the outer code to assign to it. +Jinými slovy, modul může poskytovat obecnou funkcionalitu, která potřebuje nějaké nastavení. Například autentifikace potřebuje osobní údaje. Pak modul může exportovat konfigurační objekt a očekávat, že do něj vnější kód něco vloží. -Here's the classical pattern: -1. A module exports some means of configuration, e.g. a configuration object. -2. On the first import we initialize it, write to its properties. The top-level application script may do that. -3. Further imports use the module. +Zde je klasický vzor: +1. Modul exportuje konfiguraci nějakého druhu, např. konfigurační objekt. +2. Při prvním importu jej inicializujeme, zapíšeme do jeho vlastností. To může udělat skript na nejvyšší úrovni aplikace. +3. Další importy budou tento modul využívat. -For instance, the `admin.js` module may provide certain functionality (e.g. authentication), but expect the credentials to come into the `config` object from outside: +Například modul `admin.js` může poskytovat určitou funkcionalitu (např. autentifikaci), ale očekává, že osobní údaje přijdou do objektu `konfigurace` zvenčí: ```js // 📁 admin.js -export let config = { }; +export let konfigurace = { }; -export function sayHi() { - alert(`Ready to serve, ${config.user}!`); +export function řekniAhoj() { + alert(`Jsem připraven posloužit, ${konfigurace.uživatel}!`); } ``` -Here, `admin.js` exports the `config` object (initially empty, but may have default properties too). +Zde modul `admin.js` exportuje objekt `konfigurace` (na začátku je prázdný, ale může mít i nějaké standardní vlastnosti). -Then in `init.js`, the first script of our app, we import `config` from it and set `config.user`: +Pak z něj v `init.js`, prvním skriptu naší aplikace, objekt `konfigurace` importujeme a nastavíme `konfigurace.uživatel`: ```js // 📁 init.js -import {config} from './admin.js'; -config.user = "Pete"; +import {konfigurace} from './admin.js'; +konfigurace.uživatel = "Petr"; ``` -...Now the module `admin.js` is configured. +...Nyní je modul `admin.js` nakonfigurován. -Further importers can call it, and it correctly shows the current user: +Další importéři jej mohou volat a modul správně zobrazí aktuálního uživatele: ```js -// 📁 another.js -import {sayHi} from './admin.js'; +// 📁 jiný.js +import {řekniAhoj} from './admin.js'; -sayHi(); // Ready to serve, *!*Pete*/!*! +řekniAhoj(); // Jsem připraven posloužit, *!*Petr*/!*! ``` ### import.meta -The object `import.meta` contains the information about the current module. +Informace o aktuálním modulu obsahuje objekt `import.meta`. -Its content depends on the environment. In the browser, it contains the URL of the script, or a current webpage URL if inside HTML: +Jeho obsah závisí na prostředí. V prohlížeči obsahuje URL skriptu nebo URL aktuální webové stránky, je-li uvnitř HTML: ```html run height=0 ``` -### In a module, "this" is undefined +### V modulu není definováno „this“ -That's kind of a minor feature, but for completeness we should mention it. +Není to významná vlastnost, ale pro úplnost bychom ji měli uvést. -In a module, top-level `this` is undefined. +V modulu je `this` na nejvyšší úrovni nedefinované. -Compare it to non-module scripts, where `this` is a global object: +Porovnejme si to s nemodulovými skripty, v nichž je `this` globální objekt: ```html run height=0 ``` -## Browser-specific features +## Vlastnosti specifické pro prohlížeče -There are also several browser-specific differences of scripts with `type="module"` compared to regular ones. +Mezi skripty s `type="module"` a běžnými skripty existuje také několik rozdílů, které jsou specifické pro prohlížeče. -You may want to skip this section for now if you're reading for the first time, or if you don't use JavaScript in a browser. +Jestliže tento článek čtete poprvé nebo jestliže nepoužíváte JavaScript v prohlížeči, můžete tuto podkapitolu prozatím přeskočit. -### Module scripts are deferred +### Modulové skripty jsou deferované -Module scripts are *always* deferred, same effect as `defer` attribute (described in the chapter [](info:script-async-defer)), for both external and inline scripts. +Modulové skripty jsou *vždy* deferované. Je to stejný efekt jako u atributu `defer` (popsaného v kapitole [](info:script-async-defer)), a to pro externí i vložené skripty. -In other words: -- downloading external module scripts ` -Compare to regular script below: +Porovnejme si to s běžným skriptem: - + ``` -Please note: the second script actually runs before the first! So we'll see `undefined` first, and then `object`. +Prosíme všimněte si, že druhý skript se ve skutečnosti spustí před prvním! Nejprve tedy uvidíme `undefined`, až pak `object`. -That's because modules are deferred, so we wait for the document to be processed. The regular script runs immediately, so we see its output first. +Je to proto, že moduly jsou deferované, takže čekají, až se zpracuje celý dokument. Běžný skript se spustí okamžitě, proto jeho výstup uvidíme jako první. -When using modules, we should be aware that the HTML page shows up as it loads, and JavaScript modules run after that, so the user may see the page before the JavaScript application is ready. Some functionality may not work yet. We should put "loading indicators", or otherwise ensure that the visitor won't be confused by that. +Při používání modulů bychom si měli být vědomi toho, že HTML stránka se zobrazuje průběžně, když se načítá, ale JavaScriptové moduly se spustí až potom. Uživatel tedy může vidět stránku ještě předtím, než je JavaScriptová aplikace připravena. Některá funkcionalita tedy ještě nemusí fungovat. Měli bychom tedy na stránku umístit „ukazatele načítání“ nebo nějak jinak zajistit, aby to návštěvníka nezmátlo. -### Async works on inline scripts +### Na vložených skriptech funguje async -For non-module scripts, the `async` attribute only works on external scripts. Async scripts run immediately when ready, independently of other scripts or the HTML document. +Pro nemodulové skripty funguje atribut `async` pouze na externích skriptech. Asynchronní skripty se spustí okamžitě, když jsou připraveny, nezávisle na ostatních skriptech nebo HTML dokumentu. -For module scripts, it works on inline scripts as well. +Pro modulové skripty funguje i na vložených skriptech. -For example, the inline script below has `async`, so it doesn't wait for anything. +Například následující vložený skript má `async`, takže nebude na nic čekat. -It performs the import (fetches `./analytics.js`) and runs when ready, even if the HTML document is not finished yet, or if other scripts are still pending. +Provede import (stáhne si `./analytics.js`) a spustí se, jakmile bude připraven, i když HTML dokument ještě nebude dokončen nebo jiné skripty budou stále čekat na vyřízení. -That's good for functionality that doesn't depend on anything, like counters, ads, document-level event listeners. +To je dobré pro funkcionalitu, která na ničem nezávisí, např. čítače, reklamy, posluchače událostí na dokumentové úrovni. ```html - - + + ``` -### External scripts +### Externí skripty -External scripts that have `type="module"` are different in two aspects: +Externí skripty, které mají `type="module"`, se liší ve dvou aspektech: -1. External scripts with the same `src` run only once: +1. Externí skripty se stejným `src` se spustí pouze jednou: ```html - - - + + + ``` -2. External scripts that are fetched from another origin (e.g. another site) require [CORS](mdn:Web/HTTP/CORS) headers, as described in the chapter . In other words, if a module script is fetched from another origin, the remote server must supply a header `Access-Control-Allow-Origin` allowing the fetch. +2. Externí skripty, které jsou staženy z jiného zdroje (např. z jiné stránky), vyžadují hlavičku [CORS](mdn:Web/HTTP/CORS), jak je popsáno v kapitole . Jinými slovy, je-li modulový skript stažen z jiného zdroje, vzdálený server musí poskytnout hlavičku `Access-Control-Allow-Origin`, která stažení umožní. ```html - - - + + + ``` - That ensures better security by default. + To standardně zajišťuje větší bezpečnost. -### No "bare" modules allowed +### „Holé“ moduly nejsou povoleny -In the browser, `import` must get either a relative or absolute URL. Modules without any path are called "bare" modules. Such modules are not allowed in `import`. +V prohlížeči musí `import` obdržet relativní nebo absolutní URL. Moduly bez cesty se nazývají „holé“ moduly. Takové moduly nejsou v `import` povoleny. -For instance, this `import` is invalid: +Například tento `import` je chybný: ```js -import {sayHi} from 'sayHi'; // Error, "bare" module -// the module must have a path, e.g. './sayHi.js' or wherever the module is +import {řekniAhoj} from 'řekniAhoj'; // Chyba, „holý“ modul +// modul musí obsahovat cestu, např. './řekniAhoj.js' nebo jinou, kde tento modul je ``` -Certain environments, like Node.js or bundle tools allow bare modules, without any path, as they have their own ways for finding modules and hooks to fine-tune them. But browsers do not support bare modules yet. +Určitá prostředí, např. Node.js nebo spojovací nástroje, holé moduly bez uvedené cesty dovolují, protože mají své vlastní způsoby nalezení modulů a páky, jak je vyladit. Prohlížeče však holé moduly zatím nepodporují. -### Compatibility, "nomodule" +### Kompatibilita, „nomodule“ -Old browsers do not understand `type="module"`. Scripts of an unknown type are just ignored. For them, it's possible to provide a fallback using the `nomodule` attribute: +Staré prohlížeče nerozumějí `type="module"`. Skripty neznámého typu prostě ignorují. Je možné jim poskytnout nouzové řešení pomocí atributu `nomodule`: ```html run ``` -## Build tools +## Sestavovací nástroje -In real-life, browser modules are rarely used in their "raw" form. Usually, we bundle them together with a special tool such as [Webpack](https://webpack.js.org/) and deploy to the production server. +V reálném životě se prohlížečové moduly jen zřídka používají ve své „surové“ podobě. Obvykle je spojujeme dohromady (anglicky „bundle“) pomocí speciálního nástroje zvaného *bundler*, např. [Webpack](https://webpack.js.org/), a nahráváme na produkční server. -One of the benefits of using bundlers -- they give more control over how modules are resolved, allowing bare modules and much more, like CSS/HTML modules. +Jednou z výhod používání bundlerů je, že nám poskytují více kontroly nad tím, jak jsou moduly vyhodnocovány, umožňují holé moduly a mnoho dalších, např. CSS/HTML moduly. -Build tools do the following: +Sestavovací nástroje provádějí následující: -1. Take a "main" module, the one intended to be put in ` ``` -That said, native modules are also usable. So we won't be using Webpack here: you can configure it later. +I přesto jsou ovšem použitelné i nativní moduly. Zde tedy Webpack používat nebudeme: můžete si jej nakonfigurovat později. -## Summary +## Shrnutí -To summarize, the core concepts are: +Abychom to shrnuli, základní koncepty jsou: -1. A module is a file. To make `import/export` work, browsers need ` diff --git a/1-js/13-modules/01-modules-intro/say.view/say.js b/1-js/13-modules/01-modules-intro/say.view/say.js index 198a3be6d..b80003776 100644 --- a/1-js/13-modules/01-modules-intro/say.view/say.js +++ b/1-js/13-modules/01-modules-intro/say.view/say.js @@ -1,3 +1,3 @@ -export function sayHi(user) { - return `Hello, ${user}!`; +export function řekniAhoj(uživatel) { + return `Ahoj, ${uživatel}!`; } diff --git a/1-js/13-modules/01-modules-intro/scopes-working.view/hello.js b/1-js/13-modules/01-modules-intro/scopes-working.view/hello.js index 6c087ea81..d8ca02d1d 100644 --- a/1-js/13-modules/01-modules-intro/scopes-working.view/hello.js +++ b/1-js/13-modules/01-modules-intro/scopes-working.view/hello.js @@ -1,3 +1,3 @@ -import {user} from './user.js'; +import {uživatel} from './user.js'; -document.body.innerHTML = user; // John +document.body.innerHTML = uživatel; // Jan diff --git a/1-js/13-modules/01-modules-intro/scopes-working.view/user.js b/1-js/13-modules/01-modules-intro/scopes-working.view/user.js index d289329c6..ef37f5ca3 100644 --- a/1-js/13-modules/01-modules-intro/scopes-working.view/user.js +++ b/1-js/13-modules/01-modules-intro/scopes-working.view/user.js @@ -1 +1 @@ -export let user = "John"; +export let uživatel = "Jan"; diff --git a/1-js/13-modules/01-modules-intro/scopes.view/hello.js b/1-js/13-modules/01-modules-intro/scopes.view/hello.js index 714aafa1f..feee28491 100644 --- a/1-js/13-modules/01-modules-intro/scopes.view/hello.js +++ b/1-js/13-modules/01-modules-intro/scopes.view/hello.js @@ -1 +1 @@ -alert(user); // no such variable (each module has independent variables) +alert(uživatel); // taková proměnná neexistuje (každý modul má nezávislé proměnné) diff --git a/1-js/13-modules/01-modules-intro/scopes.view/user.js b/1-js/13-modules/01-modules-intro/scopes.view/user.js index 12ec850d9..406901cc0 100644 --- a/1-js/13-modules/01-modules-intro/scopes.view/user.js +++ b/1-js/13-modules/01-modules-intro/scopes.view/user.js @@ -1 +1 @@ -let user = "John"; +let uživatel = "Jan"; diff --git a/1-js/13-modules/02-import-export/article.md b/1-js/13-modules/02-import-export/article.md index 1b5649c69..90f964dbd 100644 --- a/1-js/13-modules/02-import-export/article.md +++ b/1-js/13-modules/02-import-export/article.md @@ -1,454 +1,454 @@ -# Export and Import +# Export a import -Export and import directives have several syntax variants. +Direktivy pro export a import mají několik syntaktických variant. -In the previous article we saw a simple use, now let's explore more examples. +V předchozím článku jsme viděli jednoduché použití, nyní prozkoumejme další příklady. -## Export before declarations +## Export před deklaracemi -We can label any declaration as exported by placing `export` before it, be it a variable, function or a class. +Kteroukoli deklaraci můžeme označit jako exportovanou tím, že před ní uvedeme `export`, ať už je to proměnná, funkce nebo třída. -For instance, here all exports are valid: +Například zde jsou všechny exporty platné: ```js -// export an array -*!*export*/!* let months = ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; +// export pole +*!*export*/!* let měsíce = ['Led', 'Úno', 'Bře', 'Dub', 'Srp', 'Zář', 'Říj', 'Lis', 'Pro']; -// export a constant -*!*export*/!* const MODULES_BECAME_STANDARD_YEAR = 2015; +// export konstanty +*!*export*/!* const ROK_VSTUPU_MODULŮ_DO_STANDARDU = 2015; -// export a class -*!*export*/!* class User { - constructor(name) { - this.name = name; +// export třídy +*!*export*/!* class Uživatel { + constructor(jméno) { + this.jméno = jméno; } } ``` -````smart header="No semicolons after export class/function" -Please note that `export` before a class or a function does not make it a [function expression](info:function-expressions). It's still a function declaration, albeit exported. +````smart header="Za exportovanou třídou nebo funkcí není středník" +Prosíme všimněte si, že `export` před třídou nebo funkcí z ní nedělá [funkční výraz](info:function-expressions). Je to stále deklarace funkce, byť exportovaná. -Most JavaScript style guides don't recommend semicolons after function and class declarations. +Většina stylových průvodců JavaScriptu nedoporučuje středníky za deklaracemi funkcí a tříd. -That's why there's no need for a semicolon at the end of `export class` and `export function`: +Z tohoto důvodu není na konci `export class` a `export function` nutný středník: ```js -export function sayHi(user) { - alert(`Hello, ${user}!`); -} *!* // no ; at the end */!* +export function řekniAhoj(uživatel) { + alert(`Ahoj, ${uživatel}!`); +} *!* // na konci není ; */!* ``` ```` -## Export apart from declarations +## Export mimo deklarace -Also, we can put `export` separately. +Můžeme uvést `export` i odděleně. -Here we first declare, and then export: +Zde nejprve deklarujeme a pak exportujeme: -```js -// 📁 say.js -function sayHi(user) { - alert(`Hello, ${user}!`); +```js +// 📁 řekni.js +function řekniAhoj(uživatel) { + alert(`Ahoj, ${uživatel}!`); } -function sayBye(user) { - alert(`Bye, ${user}!`); +function řekniNashle(uživatel) { + alert(`Nashle, ${uživatel}!`); } *!* -export {sayHi, sayBye}; // a list of exported variables +export {řekniAhoj, řekniNashle}; // seznam exportovaných proměnných */!* ``` -...Or, technically we could put `export` above functions as well. +...Nebo technicky můžeme umístit `export` i nad funkce. ## Import * -Usually, we put a list of what to import in curly braces `import {...}`, like this: +Obvykle uvádíme seznam toho, co se má importovat, ve složených závorkách `import {...}`, například: ```js // 📁 main.js *!* -import {sayHi, sayBye} from './say.js'; +import {řekniAhoj, řekniNashle} from './řekni.js'; */!* -sayHi('John'); // Hello, John! -sayBye('John'); // Bye, John! +řekniAhoj('Jan'); // Ahoj, Jan! +řekniNashle('Jan'); // Nashle, Jan! ``` -But if there's a lot to import, we can import everything as an object using `import * as `, for instance: +Pokud je toho však hodně, můžeme importovat všechno jako objekt použitím `import * as `, například: ```js // 📁 main.js *!* -import * as say from './say.js'; +import * as řekni from './řekni.js'; */!* -say.sayHi('John'); -say.sayBye('John'); +řekni.řekniAhoj('Jan'); +řekni.řekniNashle('Jan'); ``` -At first sight, "import everything" seems such a cool thing, short to write, why should we ever explicitly list what we need to import? +Na první pohled vypadá „import všeho“ jako bezvadná věc, krátce se zapisuje, proč bychom tedy vůbec někdy měli výslovně uvádět seznam toho, co potřebujeme importovat? -Well, there are few reasons. +Je k tomu ovšem několik důvodů. -1. Explicitly listing what to import gives shorter names: `sayHi()` instead of `say.sayHi()`. -2. Explicit list of imports gives better overview of the code structure: what is used and where. It makes code support and refactoring easier. +1. Výslovné uvedení toho, co se má importovat, nám umožňuje psát kratší názvy: `řekniAhoj()` místo `řekni.řekniAhoj()`. +2. Výslovný seznam importů nám dává lepší přehled o struktuře kódu: vidíme, co a kde je použito. Usnadňuje podporu a refaktorizaci kódu. -```smart header="Don't be afraid to import too much" -Modern build tools, such as [webpack](https://webpack.js.org/) and others, bundle modules together and optimize them to speedup loading. They also remove unused imports. +```smart header="Nebojte se, že importujete příliš mnoho" +Moderní sestavovací nástroje, např. [webpack](https://webpack.js.org/) a jiné, spojují moduly dohromady a optimalizují je, aby urychlily načítání. Rovněž odstraňují nepoužité importy. -For instance, if you `import * as library` from a huge code library, and then use only few methods, then unused ones [will not be included](https://github.com/webpack/webpack/tree/main/examples/harmony-unused#examplejs) into the optimized bundle. +Jestliže například importujete `import * as knihovna` z obrovské knihovny kódu a pak použijete jen několik metod, nepoužité metody [nebudou zahrnuty](https://github.com/webpack/webpack/tree/main/examples/harmony-unused#examplejs) do optimalizovaného svazku. ``` -## Import "as" +## Import „as“ -We can also use `as` to import under different names. +Můžeme také importovat pod odlišnými názvy, a to pomocí `as`. -For instance, let's import `sayHi` into the local variable `hi` for brevity, and import `sayBye` as `bye`: +Například importujme `řekniAhoj` pro stručnost do lokální proměnné `ahoj` a importujme `řekniNashle` jako `nashle`: ```js // 📁 main.js *!* -import {sayHi as hi, sayBye as bye} from './say.js'; +import {řekniAhoj as ahoj, řekniNashle as nashle} from './řekni.js'; */!* -hi('John'); // Hello, John! -bye('John'); // Bye, John! +ahoj('Jan'); // Ahoj, Jan! +nashle('Jan'); // Nashle, Jan! ``` -## Export "as" +## Export „as“ -The similar syntax exists for `export`. +Podobná syntaxe existuje i pro `export`. -Let's export functions as `hi` and `bye`: +Exportujme funkce pod názvy `ahoj` a `nashle`: ```js -// 📁 say.js +// 📁 řekni.js ... -export {sayHi as hi, sayBye as bye}; +export {řekniAhoj as ahoj, řekniNashle as nashle}; ``` -Now `hi` and `bye` are official names for outsiders, to be used in imports: +Nyní jsou `ahoj` a `nashle` oficiální názvy pro vnější kód, které budou použity v importech: ```js // 📁 main.js -import * as say from './say.js'; +import * as řekni from './řekni.js'; -say.*!*hi*/!*('John'); // Hello, John! -say.*!*bye*/!*('John'); // Bye, John! +řekni.*!*ahoj*/!*('Jan'); // Ahoj, Jan! +řekni.*!*nashle*/!*('Jan'); // Nashle, Jan! ``` ## Export default -In practice, there are mainly two kinds of modules. +V praxi se používají převážně dva druhy modulů. -1. Modules that contain a library, pack of functions, like `say.js` above. -2. Modules that declare a single entity, e.g. a module `user.js` exports only `class User`. +1. Moduly, které obsahují knihovnu, balíček funkcí, podobně jako `řekni.js` výše. +2. Moduly, které deklarují jedinou entitu, např. modul `uživatel.js` exportuje pouze `class Uživatel`. -Mostly, the second approach is preferred, so that every "thing" resides in its own module. +Většinou se dává přednost druhému uvedenému přístupu, takže každá „věc“ sídlí ve svém vlastním modulu. -Naturally, that requires a lot of files, as everything wants its own module, but that's not a problem at all. Actually, code navigation becomes easier if files are well-named and structured into folders. +Přirozeně to vyžaduje spoustu souborů, jelikož všechno chce svůj vlastní modul, ale to vůbec není problém. Ve skutečnosti je navigace v kódu snadnější, jsou-li soubory dobře pojmenovány a strukturovány ve složkách. -Modules provide a special `export default` ("the default export") syntax to make the "one thing per module" way look better. +Moduly poskytují speciální syntaxi `export default` („výchozí export“), aby přístup „jedna věc v jednom modulu“ vypadal lépe. -Put `export default` before the entity to export: +Umístěte `export default` před entitu, která se má exportovat: ```js -// 📁 user.js -export *!*default*/!* class User { // just add "default" - constructor(name) { - this.name = name; +// 📁 uživatel.js +export *!*default*/!* class Uživatel { // jen přidáme „default“ + constructor(jméno) { + this.jméno = jméno; } } ``` -There may be only one `export default` per file. +V jednom souboru může být pouze jeden `export default`. -...And then import it without curly braces: +...A pak jej importujte bez složených závorek: ```js // 📁 main.js -import *!*User*/!* from './user.js'; // not {User}, just User +import *!*Uživatel*/!* from './uživatel.js'; // ne {Uživatel}, jen Uživatel -new User('John'); +new Uživatel('Jan'); ``` -Imports without curly braces look nicer. A common mistake when starting to use modules is to forget curly braces at all. So, remember, `import` needs curly braces for named exports and doesn't need them for the default one. +Importy bez složených závorek vypadají lépe. Obvyklá chyba v začátcích používání modulů je zapomínat uvádět složené závorky úplně. Proto si pamatujte, že `import` potřebuje složené závorky pro pojmenované exporty a nepotřebuje je pro výchozí. -| Named export | Default export | +| Pojmenovaný export | Výchozí export | |--------------|----------------| -| `export class User {...}` | `export default class User {...}` | -| `import {User} from ...` | `import User from ...`| +| `export class Uživatel {...}` | `export default class Uživatel {...}` | +| `import {Uživatel} from ...` | `import Uživatel from ...`| -Technically, we may have both default and named exports in a single module, but in practice people usually don't mix them. A module has either named exports or the default one. +Technicky můžeme mít v jednom modulu současně výchozí i pojmenované exporty, ale v praxi je lidé obvykle nesměšují. Modul obsahuje buď pojmenované exporty, nebo výchozí export. -As there may be at most one default export per file, the exported entity may have no name. +Protože v jednom souboru může být nanejvýše jeden výchozí export, exportovaná entita nemusí mít název. -For instance, these are all perfectly valid default exports: +Například tohle všechno jsou zcela platné výchozí exporty: ```js -export default class { // no class name +export default class { // žádný název třídy constructor() { ... } } ``` ```js -export default function(user) { // no function name - alert(`Hello, ${user}!`); +export default function(uživatel) { // žádný název funkce + alert(`Ahoj, ${uživatel}!`); } ``` ```js -// export a single value, without making a variable -export default ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; +// exportujeme jedinou hodnotu, aniž bychom vytvořili proměnnou +export default ['Led', 'Úno', 'Bře', 'Dub', 'Srp', 'Zář', 'Říj', 'Lis', 'Pro']; ``` -Not giving a name is fine, because there is only one `export default` per file, so `import` without curly braces knows what to import. +Neuvést název je v pořádku, protože v jednom souboru je jen jeden `export default`, takže `import` bez složených závorek ví, co má importovat. -Without `default`, such an export would give an error: +Bez `default` by takový export ohlásil chybu: ```js -export class { // Error! (non-default export needs a name) +export class { // Chyba! (nevýchozí export vyžaduje název) constructor() {} } ``` -### The "default" name +### „Výchozí“ název -In some situations the `default` keyword is used to reference the default export. +V některých situacích se klíčové slovo `default` používá k odkazu na výchozí export. -For example, to export a function separately from its definition: +Například k exportu funkce odděleně od její definice: ```js -function sayHi(user) { - alert(`Hello, ${user}!`); +function řekniAhoj(uživatel) { + alert(`Ahoj, ${uživatel}!`); } -// same as if we added "export default" before the function -export {sayHi as default}; +// totéž, jako bychom před funkcí uvedli „export default“ +export {řekniAhoj as default}; ``` -Or, another situation, let's say a module `user.js` exports one main "default" thing, and a few named ones (rarely the case, but it happens): +Nebo jiná situace: řekněme, že modul `uživatel.js` exportuje jednu hlavní „výchozí“ věc a několik pojmenovaných (vzácný případ, ale stává se to): ```js -// 📁 user.js -export default class User { - constructor(name) { - this.name = name; +// 📁 uživatel.js +export default class Uživatel { + constructor(jméno) { + this.jméno = jméno; } } -export function sayHi(user) { - alert(`Hello, ${user}!`); +export function řekniAhoj(uživatel) { + alert(`Ahoj, ${uživatel}!`); } ``` -Here's how to import the default export along with a named one: +Tímto způsobem importujeme výchozí export společně s pojmenovaným: ```js // 📁 main.js -import {*!*default as User*/!*, sayHi} from './user.js'; +import {*!*default as Uživatel*/!*, řekniAhoj} from './uživatel.js'; -new User('John'); +new Uživatel('Jan'); ``` -And, finally, if importing everything `*` as an object, then the `default` property is exactly the default export: +A nakonec, jestliže importujeme všechno `*` jako objekt, pak vlastnost `default` je přesně výchozí export: ```js // 📁 main.js -import * as user from './user.js'; +import * as uživatel from './uživatel.js'; -let User = user.default; // the default export -new User('John'); +let Uživatel = uživatel.default; // výchozí export +new Uživatel('Jan'); ``` -### A word against default exports +### Pár slov proti výchozím exportům -Named exports are explicit. They exactly name what they import, so we have that information from them; that's a good thing. +Pojmenované exporty jsou explicitní. To, co exportují, mají přesně pojmenováno, takže od nich tuto informaci dostaneme; to je dobrá věc. -Named exports force us to use exactly the right name to import: +Pojmenované exporty nás nutí při importu používat přesně ten správný název: ```js -import {User} from './user.js'; -// import {MyUser} won't work, the name must be {User} +import {Uživatel} from './uživatel.js'; +// import {MůjUživatel} nefunguje, název musí být {Uživatel} ``` -...While for a default export, we always choose the name when importing: +...Zatímco u výchozího exportu si při importu název vždy volíme: ```js -import User from './user.js'; // works -import MyUser from './user.js'; // works too -// could be import Anything... and it'll still work +import Uživatel from './uživatel.js'; // funguje +import MůjUživatel from './uživatel.js'; // funguje také +// může být import Cokoli... a pořád to bude fungovat ``` -So team members may use different names to import the same thing, and that's not good. +Členové týmu tedy mohou používat různé názvy při importu stejné věci, a to není dobré. -Usually, to avoid that and keep the code consistent, there's a rule that imported variables should correspond to file names, e.g: +Abychom se tomu vyhnuli a udrželi kód konzistentní, obvykle platí pravidlo, že importované proměnné by měly odpovídat názvům souborů, například: ```js -import User from './user.js'; -import LoginForm from './loginForm.js'; -import func from '/path/to/func.js'; +import Uživatel from './uživatel.js'; +import PřihlašovacíFormulář from './přihlašovacíFormulář.js'; +import funkce from '/cesta/do/funkce.js'; ... ``` -Still, some teams consider it a serious drawback of default exports. So they prefer to always use named exports. Even if only a single thing is exported, it's still exported under a name, without `default`. +I tak to ovšem některé týmy považují za vážnou nevýhodu výchozích exportů. Dávají tedy přednost používání výhradně pojmenovaných exportů. I když je exportována pouze jediná věc, je stále exportována pod svým názvem, bez `default`. -That also makes re-export (see below) a little bit easier. +To také trochu usnadňuje reexport (viz dále). -## Re-export +## Reexport -"Re-export" syntax `export ... from ...` allows to import things and immediately export them (possibly under another name), like this: +Syntaxe „reexportu“ `export ... from ...` nám umožňuje importovat věci a okamžitě je exportovat (třeba i pod jiným názvem), například: ```js -export {sayHi} from './say.js'; // re-export sayHi +export {řekniAhoj} from './řekni.js'; // reexport řekniAhoj -export {default as User} from './user.js'; // re-export default +export {default as Uživatel} from './uživatel.js'; // reexport výchozího exportu ``` -Why would that be needed? Let's see a practical use case. +K čemu by to bylo potřeba? Podívejme se na praktický případ použití. -Imagine, we're writing a "package": a folder with a lot of modules, with some of the functionality exported outside (tools like NPM allow us to publish and distribute such packages, but we don't have to use them), and many modules are just "helpers", for internal use in other package modules. +Představme si, že píšeme „balíček“: složku s mnoha moduly, některá funkcionalita z nich bude exportována ven (publikování a distribuci takových balíčků nám umožňují nástroje jako NPM, ale nemusíme je používat) a mnoho modulů je jen „pomocných“ pro vnitřní použití v jiných modulech balíčku. -The file structure could be like this: +Struktura souborů by mohla být takováto: ``` auth/ - index.js - user.js - helpers.js - tests/ + index.js + uživatel.js + pomocné.js + testy/ login.js - providers/ + poskytovatelé/ github.js facebook.js ... ``` -We'd like to expose the package functionality via a single entry point. +Rádi bychom vystavili funkcionalitu celého balíčku v jediném vstupním bodu. -In other words, a person who would like to use our package, should import only from the "main file" `auth/index.js`. +Jinými slovy, člověk, který by chtěl náš balíček používat, by měl importovat jen z „hlavního souboru“ `auth/index.js`. -Like this: +Například takto: ```js import {login, logout} from 'auth/index.js' ``` -The "main file", `auth/index.js` exports all the functionality that we'd like to provide in our package. +„Hlavní soubor“ `auth/index.js` exportuje veškerou funkcionalitu, kterou bychom v našem balíčku chtěli poskytnout. -The idea is that outsiders, other programmers who use our package, should not meddle with its internal structure, search for files inside our package folder. We export only what's necessary in `auth/index.js` and keep the rest hidden from prying eyes. +Myšlenkou je, že lidé zvnějšku, jiní programátoři používající náš balíček, by se neměli zabývat jeho vnitřní strukturou a hledat soubory uvnitř složky s naším balíčkem. V `auth/index.js` exportujeme jen to, co je nutné, a zbytek je před zvědavýma očima ukryt. -As the actual exported functionality is scattered among the package, we can import it into `auth/index.js` and export from it: +Protože naše skutečná exportovaná funkcionalita je roztroušena po celém balíčku, můžeme ji importovat do `auth/index.js` a exportovat z něj: ```js // 📁 auth/index.js -// import login/logout and immediately export them -import {login, logout} from './helpers.js'; -export {login, logout}; +// importujeme přihlas/odhlas a ihned je exportujeme +import {přihlas, odhlas} from './pomocníci.js'; +export {přihlas, odhlas}; -// import default as User and export it -import User from './user.js'; -export {User}; +// importujeme výchozí export jako Uživatel a exportujeme ho +import Uživatel from './uživatel.js'; +export {Uživatel}; ... ``` -Now users of our package can `import {login} from "auth/index.js"`. +Nyní mohou uživatelé našeho balíčku použít `import {přihlas} from "auth/index.js"`. -The syntax `export ... from ...` is just a shorter notation for such import-export: +Syntaxe `export ... from ...` je jen kratší notace takového importu-exportu: ```js // 📁 auth/index.js -// re-export login/logout -export {login, logout} from './helpers.js'; +// reexport přihlas/odhlas +export {přihlas, odhlas} from './pomocníci.js'; -// re-export the default export as User -export {default as User} from './user.js'; +// reexport výchozího exportu jako Uživatel +export {default as Uživatel} from './uživatel.js'; ... ``` -The notable difference of `export ... from` compared to `import/export` is that re-exported modules aren't available in the current file. So inside the above example of `auth/index.js` we can't use re-exported `login/logout` functions. +Významný rozdíl `export ... from` ve srovnání s `import/export` spočívá v tom, že reexportované moduly nejsou v aktuálním souboru dostupné. Uvnitř uvedeného příkladu `auth/index.js` tedy nemůžeme používat reexportované funkce `přihlas/odhlas`. -### Re-exporting the default export +### Reexportování výchozího exportu -The default export needs separate handling when re-exporting. +Výchozí export musí být při reexportu zpracován odděleně. -Let's say we have `user.js` with the `export default class User` and would like to re-export it: +Řekněme, že máme soubor `uživatel.js` obsahující `export default class Uživatel` a chtěli bychom ji reexportovat: ```js -// 📁 user.js -export default class User { +// 📁 uživatel.js +export default class Uživatel { // ... } ``` -We can come across two problems with it: +Můžeme s tím narazit na dva problémy: -1. `export User from './user.js'` won't work. That would lead to a syntax error. +1. `export Uživatel from './uživatel.js'` nefunguje. Povede k syntaktické chybě. - To re-export the default export, we have to write `export {default as User}`, as in the example above. + Abychom reexportovali výchozí export, musíme napsat `export {default as Uživatel}`, jako v uvedeném příkladu. -2. `export * from './user.js'` re-exports only named exports, but ignores the default one. +2. `export * from './uživatel.js'` reexportuje pouze pojmenované exporty, ale ignoruje výchozí. - If we'd like to re-export both named and default exports, then two statements are needed: + Pokud chceme reexportovat jak pojmenované, tak výchozí exporty, potřebujeme dva příkazy: ```js - export * from './user.js'; // to re-export named exports - export {default} from './user.js'; // to re-export the default export + export * from './uživatel.js'; // reexport pojmenovaných exportů + export {default} from './uživatel.js'; // reexport výchozího exportu ``` -Such oddities of re-exporting a default export are one of the reasons why some developers don't like default exports and prefer named ones. +Tyto zvláštnosti reexportu výchozího exportu jsou jedním z důvodů, proč někteří vývojáři nemají rádi výchozí exporty a dávají přednost pojmenovaným. -## Summary +## Shrnutí -Here are all types of `export` that we covered in this and previous articles. +Zde jsou všechny druhy `export`, které jsme uvedli v této a v předchozí kapitole. -You can check yourself by reading them and recalling what they mean: +Můžete vyzkoušet sami sebe, když si je přečtete a pokusíte se vzpomenout si, co znamenají: -- Before declaration of a class/function/..: +- Před deklarací třídy/funkce/..: - `export [default] class/function/variable ...` -- Standalone export: +- Samostatný export: - `export {x [as y], ...}`. -- Re-export: - - `export {x [as y], ...} from "module"` - - `export * from "module"` (doesn't re-export default). - - `export {default [as y]} from "module"` (re-export default). +- Reexport: + - `export {x [as y], ...} from "modul"` + - `export * from "modul"` (nereexportuje výchozí export). + - `export {default [as y]} from "modul"` (reexportuje výchozí export). Import: -- Importing named exports: - - `import {x [as y], ...} from "module"` -- Importing the default export: - - `import x from "module"` - - `import {default as x} from "module"` -- Import all: - - `import * as obj from "module"` -- Import the module (its code runs), but do not assign any of its exports to variables: - - `import "module"` +- Import pojmenovaných exportů: + - `import {x [as y], ...} from "modul"` +- Import výchozího exportu: + - `import x from "modul"` + - `import {default as x} from "modul"` +- Import všeho: + - `import * as obj from "modul"` +- Import modulu (spustí se jeho kód), ale bez přiřazení jeho exportů do proměnných: + - `import "modul"` -We can put `import/export` statements at the top or at the bottom of a script, that doesn't matter. +Příkazy `import/export` můžeme uvést na začátku nebo na konci skriptu, na tom nezáleží. -So, technically this code is fine: +Technicky je tedy tento kód v pořádku: ```js -sayHi(); +řekniAhoj(); // ... -import {sayHi} from './say.js'; // import at the end of the file +import {řekniAhoj} from './řekni.js'; // import na konci souboru ``` -In practice imports are usually at the start of the file, but that's only for more convenience. +V praxi se importy obvykle uvádějí na začátku souboru, ale to je jen pro větší přehlednost. -**Please note that import/export statements don't work if inside `{...}`.** +**Prosíme všimněte si, že příkazy import/export nefungují, jsou-li uvnitř `{...}`.** -A conditional import, like this, won't work: +Podmíněný import, například tento, nefunguje: ```js -if (something) { - import {sayHi} from "./say.js"; // Error: import must be at top level +if (něco) { + import {řekniAhoj} from "./řekni.js"; // Chyba: import musí být na nejvyšší úrovni } ``` -...But what if we really need to import something conditionally? Or at the right time? Like, load a module upon request, when it's really needed? +...Co když však opravdu potřebujeme něco importovat podmíněně? Nebo ve správnou dobu? Například načíst modul na požádání až tehdy, když je opravdu zapotřebí? -We'll see dynamic imports in the next article. +Dynamické importy uvidíme v dalším článku. \ No newline at end of file diff --git a/1-js/13-modules/03-modules-dynamic-imports/article.md b/1-js/13-modules/03-modules-dynamic-imports/article.md index e48144a3e..b13dcfaf8 100644 --- a/1-js/13-modules/03-modules-dynamic-imports/article.md +++ b/1-js/13-modules/03-modules-dynamic-imports/article.md @@ -1,98 +1,98 @@ -# Dynamic imports +# Dynamické importy -Export and import statements that we covered in previous chapters are called "static". The syntax is very simple and strict. +Příkazy exportu a importu, které jsme uvedli v předchozích kapitolách, se nazývají „statické“. Jejich syntaxe je velmi jednoduchá a striktní. -First, we can't dynamically generate any parameters of `import`. +Za prvé, žádné parametry příkazu `import` nemůžeme dynamicky generovat. -The module path must be a primitive string, can't be a function call. This won't work: +Cesta k modulu musí být primitivní řetězec, ne volání funkce. Tohle nebude fungovat: ```js -import ... from *!*getModuleName()*/!*; // Error, only from "string" is allowed +import ... from *!*vraťNázevModulu()*/!*; // Chyba, povoleno je jen from "řetězec" ``` -Second, we can't import conditionally or at run-time: +Za druhé, nemůžeme importovat podmíněně nebo za běhu skriptu: ```js if(...) { - import ...; // Error, not allowed! + import ...; // Chyba, tohle není dovoleno! } { - import ...; // Error, we can't put import in any block + import ...; // Chyba, nemůžeme umístit import do bloku } ``` -That's because `import`/`export` aim to provide a backbone for the code structure. That's a good thing, as code structure can be analyzed, modules can be gathered and bundled into one file by special tools, unused exports can be removed ("tree-shaken"). That's possible only because the structure of imports/exports is simple and fixed. +Je to proto, že záměrem příkazů `import`/`export` je poskytnout páteř struktury kódu. To je dobrá věc, protože strukturu kódu můžeme analyzovat, moduly můžeme speciálními nástroji shromažďovat a spojovat do jednoho souboru, nepoužité exporty můžeme odstraňovat („třesení stromem“). To je možné jen proto, že struktura importů a exportů je jednoduchá a pevná. -But how can we import a module dynamically, on-demand? +Jak ale můžeme importovat modul dynamicky, na požádání? -## The import() expression +## Výraz import() -The `import(module)` expression loads the module and returns a promise that resolves into a module object that contains all its exports. It can be called from any place in the code. +Výraz `import(modul)` načte modul a vrátí příslib, který se splní do objektu modulu obsahujícího všechny jeho exporty. Může být volán z kteréhokoli místa v kódu. -We can use it dynamically in any place of the code, for instance: +Můžeme jej používat dynamicky na kterémkoli místě kódu, například: ```js -let modulePath = prompt("Which module to load?"); +let cestaModulu = prompt("Který modul načíst?"); -import(modulePath) - .then(obj => ) - .catch(err => ) +import(cestaModulu) + .then(obj => ) + .catch(chyba => ) ``` -Or, we could use `let module = await import(modulePath)` if inside an async function. +Nebo můžeme použít `let modul = await import(cestaModulu)`, jsme-li uvnitř asynchronní funkce. -For instance, if we have the following module `say.js`: +Například jestliže máme následující modul `řekni.js`: ```js -// 📁 say.js -export function hi() { - alert(`Hello`); +// 📁 řekni.js +export function ahoj() { + alert(`Ahoj`); } -export function bye() { - alert(`Bye`); +export function nashle() { + alert(`Nashle`); } ``` -...Then dynamic import can be like this: +...Pak dynamický import může vypadat takto: ```js -let {hi, bye} = await import('./say.js'); +let {ahoj, nashle} = await import('./řekni.js'); -hi(); -bye(); +ahoj(); +nashle(); ``` -Or, if `say.js` has the default export: +Nebo jestliže `řekni.js` obsahuje výchozí export: ```js -// 📁 say.js +// 📁 řekni.js export default function() { - alert("Module loaded (export default)!"); + alert("Modul načten (výchozí export)!"); } ``` -...Then, in order to access it, we can use `default` property of the module object: +...Pak můžeme pro přístup k němu použít vlastnost `default` objektu modulu: ```js -let obj = await import('./say.js'); -let say = obj.default; -// or, in one line: let {default: say} = await import('./say.js'); +let obj = await import('./řekni.js'); +let řekni = obj.default; +// nebo na jednom řádku: let {default: řekni} = await import('./řekni.js'); -say(); +řekni(); ``` -Here's the full example: +Zde je celý příklad: [codetabs src="https://github.com/say" current="index.html"] ```smart -Dynamic imports work in regular scripts, they don't require `script type="module"`. +Dynamické importy fungují i v běžných skriptech, nevyžadují `script type="module"`. ``` ```smart -Although `import()` looks like a function call, it's a special syntax that just happens to use parentheses (similar to `super()`). +Ačkoli `import()` vypadá jako volání funkce, je to speciální syntaxe, která prostě jen používá závorky (podobně jako `super()`). -So we can't copy `import` to a variable or use `call/apply` with it. It's not a function. +Nemůžeme tedy kopírovat `import` do proměnné nebo s ním používat `call/apply`. Není to funkce. ``` diff --git a/1-js/13-modules/03-modules-dynamic-imports/say.view/index.html b/1-js/13-modules/03-modules-dynamic-imports/say.view/index.html index 80909cf94..4d13ed7a3 100644 --- a/1-js/13-modules/03-modules-dynamic-imports/say.view/index.html +++ b/1-js/13-modules/03-modules-dynamic-imports/say.view/index.html @@ -1,10 +1,10 @@ - + diff --git a/1-js/13-modules/03-modules-dynamic-imports/say.view/say.js b/1-js/13-modules/03-modules-dynamic-imports/say.view/say.js index cff234b7c..5e3d9a769 100644 --- a/1-js/13-modules/03-modules-dynamic-imports/say.view/say.js +++ b/1-js/13-modules/03-modules-dynamic-imports/say.view/say.js @@ -1,11 +1,11 @@ -export function hi() { - alert(`Hello`); +export function ahoj() { + alert(`Ahoj`); } -export function bye() { - alert(`Bye`); +export function nashle() { + alert(`Nashle`); } export default function() { - alert("Module loaded (export default)!"); + alert("Modul načten (výchozí export)!"); } diff --git a/1-js/13-modules/index.md b/1-js/13-modules/index.md index 78fb060e8..541d7fa96 100644 --- a/1-js/13-modules/index.md +++ b/1-js/13-modules/index.md @@ -1,2 +1,2 @@ -# Modules +# Moduly diff --git a/1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md b/1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md index 9db69cb2f..fc832281f 100644 --- a/1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md +++ b/1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md @@ -1,23 +1,23 @@ ```js run -let user = { - name: "John" +let uživatel = { + jméno: "Jan" }; -function wrap(target) { - return new Proxy(target, { - get(target, prop, receiver) { - if (prop in target) { - return Reflect.get(target, prop, receiver); +function obal(cíl) { + return new Proxy(cíl, { + get(cíl, vlastnost, příjemce) { + if (vlastnost in cíl) { + return Reflect.get(cíl, vlastnost, příjemce); } else { - throw new ReferenceError(`Property doesn't exist: "${prop}"`) + throw new ReferenceError(`Vlastnost neexistuje: "${vlastnost}"`) } } }); } -user = wrap(user); +uživatel = obal(uživatel); -alert(user.name); // John -alert(user.age); // ReferenceError: Property doesn't exist: "age" +alert(uživatel.jméno); // Jan +alert(uživatel.věk); // ReferenceError: Vlastnost neexistuje: "věk" ``` diff --git a/1-js/99-js-misc/01-proxy/01-error-nonexisting/task.md b/1-js/99-js-misc/01-proxy/01-error-nonexisting/task.md index 47985e1a7..83ef2801d 100644 --- a/1-js/99-js-misc/01-proxy/01-error-nonexisting/task.md +++ b/1-js/99-js-misc/01-proxy/01-error-nonexisting/task.md @@ -1,32 +1,32 @@ -# Error on reading non-existent property +# Chyba při načítání neexistující vlastnosti -Usually, an attempt to read a non-existent property returns `undefined`. +Pokus o načtení neexistující vlastnosti zpravidla vrátí `undefined`. -Create a proxy that throws an error for an attempt to read of a non-existent property instead. +Vytvořte proxy, která při pokusu o načtení neexistující vlastnosti místo toho vyvolá chybu. -That can help to detect programming mistakes early. +To nám může pomoci dříve detekovat programátorské chyby. -Write a function `wrap(target)` that takes an object `target` and return a proxy that adds this functionality aspect. +Napište funkci `obal(cíl)`, která vezme objekt `cíl` a vrátí proxy, která přidá tento funkcionální aspekt. -That's how it should work: +Mělo by to fungovat takto: ```js -let user = { - name: "John" +let uživatel = { + jméno: "Jan" }; -function wrap(target) { - return new Proxy(target, { +function obal(cíl) { + return new Proxy(cíl, { *!* - /* your code */ + /* váš kód */ */!* }); } -user = wrap(user); +uživatel = obal(uživatel); -alert(user.name); // John +alert(uživatel.jméno); // Jan *!* -alert(user.age); // ReferenceError: Property doesn't exist: "age" +alert(uživatel.věk); // ReferenceError: Vlastnost neexistuje: "věk" */!* ``` diff --git a/1-js/99-js-misc/01-proxy/02-array-negative/solution.md b/1-js/99-js-misc/01-proxy/02-array-negative/solution.md index 207205501..8e181a5b0 100644 --- a/1-js/99-js-misc/01-proxy/02-array-negative/solution.md +++ b/1-js/99-js-misc/01-proxy/02-array-negative/solution.md @@ -1,19 +1,19 @@ ```js run -let array = [1, 2, 3]; +let pole = [1, 2, 3]; -array = new Proxy(array, { - get(target, prop, receiver) { - if (prop < 0) { - // even if we access it like arr[1] - // prop is a string, so need to convert it to number - prop = +prop + target.length; +pole = new Proxy(pole, { + get(cíl, vlastnost, příjemce) { + if (vlastnost < 0) { + // i když k poli přistupujeme přes pole[1], + // vlastnost je řetězec, takže jej musíme konvertovat na číslo + vlastnost = +vlastnost + cíl.length; } - return Reflect.get(target, prop, receiver); + return Reflect.get(cíl, vlastnost, příjemce); } }); -alert(array[-1]); // 3 -alert(array[-2]); // 2 +alert(pole[-1]); // 3 +alert(pole[-2]); // 2 ``` diff --git a/1-js/99-js-misc/01-proxy/02-array-negative/task.md b/1-js/99-js-misc/01-proxy/02-array-negative/task.md index 9b0b13f58..8551fe022 100644 --- a/1-js/99-js-misc/01-proxy/02-array-negative/task.md +++ b/1-js/99-js-misc/01-proxy/02-array-negative/task.md @@ -1,33 +1,33 @@ -# Accessing array[-1] +# Přístup k poli[-1] -In some programming languages, we can access array elements using negative indexes, counted from the end. +V některých programovacích jazycích můžeme přistupovat k prvkům pole pomocí záporných indexů, které se počítají od konce. -Like this: +Například: ```js -let array = [1, 2, 3]; +let pole = [1, 2, 3]; -array[-1]; // 3, the last element -array[-2]; // 2, one step from the end -array[-3]; // 1, two steps from the end +pole[-1]; // 3, poslední prvek +pole[-2]; // 2, jeden krok od konce +pole[-3]; // 1, dva kroky od konce ``` -In other words, `array[-N]` is the same as `array[array.length - N]`. +Jinými slovy, `pole[-N]` je totéž jako `pole[pole.length - N]`. -Create a proxy to implement that behavior. +Vytvořte proxy, která bude toto chování implementovat. -That's how it should work: +Měla by fungovat takto: ```js -let array = [1, 2, 3]; +let pole = [1, 2, 3]; -array = new Proxy(array, { - /* your code */ +pole = new Proxy(pole, { + /* váš kód */ }); -alert( array[-1] ); // 3 -alert( array[-2] ); // 2 +alert( pole[-1] ); // 3 +alert( pole[-2] ); // 2 -// Other array functionality should be kept "as is" +// Ostatní funkcionalita pole by měla zůstat nezměněná ``` diff --git a/1-js/99-js-misc/01-proxy/03-observable/solution.md b/1-js/99-js-misc/01-proxy/03-observable/solution.md index c0797a856..fde48daf4 100644 --- a/1-js/99-js-misc/01-proxy/03-observable/solution.md +++ b/1-js/99-js-misc/01-proxy/03-observable/solution.md @@ -1,40 +1,40 @@ -The solution consists of two parts: +Řešení se skládá ze dvou částí: -1. Whenever `.observe(handler)` is called, we need to remember the handler somewhere, to be able to call it later. We can store handlers right in the object, using our symbol as the property key. -2. We need a proxy with `set` trap to call handlers in case of any change. +1. Kdykoli je zavoláno `.pozoruj(handler)`, musíme si handler někde pamatovat, abychom jej mohli volat později. Handlery si můžeme ukládat rovnou do objektu a jako klíč vlastnosti použít náš symbol. +2. Potřebujeme proxy s pastí `set`, která v případě jakékoli změny zavolá handlery. ```js run -let handlers = Symbol('handlers'); +let handlery = Symbol('handlery'); -function makeObservable(target) { - // 1. Initialize handlers store - target[handlers] = []; +function učiňPozorovatelným(cíl) { + // 1. Inicializace skladu handlerů + cíl[handlery] = []; - // Store the handler function in array for future calls - target.observe = function(handler) { - this[handlers].push(handler); + // Uložíme funkci handleru do pole pro budoucí volání + cíl.pozoruj = function(handler) { + this[handlery].push(handler); }; - // 2. Create a proxy to handle changes - return new Proxy(target, { - set(target, property, value, receiver) { - let success = Reflect.set(...arguments); // forward the operation to object - if (success) { // if there were no error while setting the property - // call all handlers - target[handlers].forEach(handler => handler(property, value)); + // 2. Vytvoříme proxy pro zpracování změn + return new Proxy(cíl, { + set(cíl, vlastnost, hodnota, příjemce) { + let úspěch = Reflect.set(...arguments); // předáme operaci objektu + if (úspěch) { // pokud při nastavování vlastnosti nedošlo k chybě, + // zavoláme všechny handlery + cíl[handlery].forEach(handler => handler(vlastnost, hodnota)); } - return success; + return úspěch; } }); } -let user = {}; +let uživatel = {}; -user = makeObservable(user); +uživatel = učiňPozorovatelným(uživatel); -user.observe((key, value) => { - alert(`SET ${key}=${value}`); +uživatel.pozoruj((klíč, hodnota) => { + alert(`SET ${klíč}=${hodnota}`); }); -user.name = "John"; +uživatel.jméno = "Jan"; ``` diff --git a/1-js/99-js-misc/01-proxy/03-observable/task.md b/1-js/99-js-misc/01-proxy/03-observable/task.md index 754d9f3bd..c05ca2ce7 100644 --- a/1-js/99-js-misc/01-proxy/03-observable/task.md +++ b/1-js/99-js-misc/01-proxy/03-observable/task.md @@ -1,27 +1,27 @@ -# Observable +# Pozorovatelný objekt -Create a function `makeObservable(target)` that "makes the object observable" by returning a proxy. +Vytvořte funkci `učiňPozorovatelným(cíl)`, která „učiní objekt pozorovatelným“ tím, že vrátí proxy. -Here's how it should work: +Mělo by to fungovat takto: ```js run -function makeObservable(target) { - /* your code */ +function učiňPozorovatelným(cíl) { + /* váš kód */ } -let user = {}; -user = makeObservable(user); +let uživatel = {}; +uživatel = učiňPozorovatelným(uživatel); -user.observe((key, value) => { - alert(`SET ${key}=${value}`); +uživatel.pozoruj((klíč, hodnota) => { + alert(`SET ${klíč}=${hodnota}`); }); -user.name = "John"; // alerts: SET name=John +uživatel.jméno = "Jan"; // oznámí: SET jméno=Jan ``` -In other words, an object returned by `makeObservable` is just like the original one, but also has the method `observe(handler)` that sets `handler` function to be called on any property change. +Jinými slovy, objekt vrácený funkcí `učiňPozorovatelným` je stejný jako původní, ale navíc obsahuje metodu `pozoruj(handler)`, která nastaví funkci `handler` tak, aby byla volána při každé změně vlastnosti. -Whenever a property changes, `handler(key, value)` is called with the name and value of the property. +Kdykoli se změní některá vlastnost, je zavolán `handler(klíč, hodnota)` s jejím názvem a hodnotou. -P.S. In this task, please only take care about writing to a property. Other operations can be implemented in a similar way. +P.S. V této úloze se postarejte jen o zápis do vlastnosti. Ostatní operace mohou být implementovány podobně. diff --git a/1-js/99-js-misc/01-proxy/article.md b/1-js/99-js-misc/01-proxy/article.md index 1f84912e5..a017c08c8 100644 --- a/1-js/99-js-misc/01-proxy/article.md +++ b/1-js/99-js-misc/01-proxy/article.md @@ -1,66 +1,66 @@ -# Proxy and Reflect +# Třídy Proxy a Reflect -A `Proxy` object wraps another object and intercepts operations, like reading/writing properties and others, optionally handling them on its own, or transparently allowing the object to handle them. +Objekt třídy `Proxy` obaluje jiný objekt a zachytává operace na něm, například čtení nebo zápis vlastností a jiné. Volitelně je zpracovává sám o sobě nebo průhledně umožňuje objektu, aby je zpracovával sám. -Proxies are used in many libraries and some browser frameworks. We'll see many practical applications in this article. +Proxy jsou používány v mnoha knihovnách a některých frameworcích prohlížečů. V tomto článku uvidíme mnoho praktických aplikací. ## Proxy -The syntax: +Syntaxe: ```js -let proxy = new Proxy(target, handler) +let proxy = new Proxy(cíl, handler) ``` -- `target` -- is an object to wrap, can be anything, including functions. -- `handler` -- proxy configuration: an object with "traps", methods that intercept operations. - e.g. `get` trap for reading a property of `target`, `set` trap for writing a property into `target`, and so on. +- `cíl` -- je objekt, který má být obalen, může to být cokoli včetně funkcí. +- `handler` -- konfigurace proxy: objekt s „pastmi“, metodami, které zachytávají operace, např. past `get` pro načítání vlastností objektu `cíl`, past `set` pro zápis vlastnosti do objektu `cíl`, a tak dále. -For operations on `proxy`, if there's a corresponding trap in `handler`, then it runs, and the proxy has a chance to handle it, otherwise the operation is performed on `target`. +Jestliže pro operaci prováděnou na `proxy` existuje odpovídající past v objektu `handler`, pak se spustí a proxy dostane šanci operaci zpracovat, v opačném případě je operace provedena na objektu `cíl`. -As a starting example, let's create a proxy without any traps: +Jako počáteční příklad vytvořme proxy bez jakýchkoli pastí: ```js run -let target = {}; -let proxy = new Proxy(target, {}); // empty handler +let cíl = {}; +let proxy = new Proxy(cíl, {}); // prázdný handler -proxy.test = 5; // writing to proxy (1) -alert(target.test); // 5, the property appeared in target! +proxy.test = 5; // zápis do proxy (1) +alert(cíl.test); // 5, vlastnost se objeví v objektu cíl! -alert(proxy.test); // 5, we can read it from proxy too (2) +alert(proxy.test); // 5, můžeme ji z proxy také načíst (2) -for(let key in proxy) alert(key); // test, iteration works (3) +for(let klíč in proxy) alert(klíč); // test, iterace funguje (3) ``` -As there are no traps, all operations on `proxy` are forwarded to `target`. +Protože zde nejsou žádné pasti, všechny operace na `proxy` jsou předány objektu `cíl`. -1. A writing operation `proxy.test=` sets the value on `target`. -2. A reading operation `proxy.test` returns the value from `target`. -3. Iteration over `proxy` returns values from `target`. +1. Operace zápisu `proxy.test=` nastaví hodnotu v objektu `cíl`. +2. Operace čtení `proxy.test` vrátí hodnotu z objektu `cíl`. +3. Iterace nad objektem `proxy` vrací hodnoty z objektu `cíl`. -As we can see, without any traps, `proxy` is a transparent wrapper around `target`. +Jak vidíme, bez pastí je `proxy` průhledným obalem kolem objektu `cíl`. ![](proxy.svg) -`Proxy` is a special "exotic object". It doesn't have own properties. With an empty `handler` it transparently forwards operations to `target`. +`Proxy` je speciální „exotický objekt“, který nemá své vlastní vlastnosti. Je-li objekt `handler` prázdný, průhledně předává operace objektu `cíl`. -To activate more capabilities, let's add traps. +Abychom aktivovali jeho další schopnosti, přidejme pasti. -What can we intercept with them? +Co s nimi můžeme zachytávat? -For most operations on objects, there's a so-called "internal method" in the JavaScript specification that describes how it works at the lowest level. For instance `[[Get]]`, the internal method to read a property, `[[Set]]`, the internal method to write a property, and so on. These methods are only used in the specification, we can't call them directly by name. +Pro většinu operací na objektech je ve specifikaci JavaScriptu tzv. „interní metoda“, která popisuje, jak operace funguje na nejnižší úrovni. Například `[[Get]]`, interní metoda k načtení vlastnosti, `[[Set]]`, interní metoda k zápisu vlastnosti, a tak dále. Tyto metody se používají jen ve specifikaci, volat přímo názvem je nemůžeme. -Proxy traps intercept invocations of these methods. They are listed in the [Proxy specification](https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots) and in the table below. +Pasti proxy zachytávají vyvolávání těchto metod. Jsou vyjmenovány ve [specifikaci Proxy](https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots) a v následující tabulce. -For every internal method, there's a trap in this table: the name of the method that we can add to the `handler` parameter of `new Proxy` to intercept the operation: +Pro každou interní metodu je v této tabulce past: název metody, který můžeme přidat do parametru `handler` při volání `new Proxy`, abychom operaci zachytili: -| Internal Method | Handler Method | Triggers when... | +| Interní metoda | Metoda handleru | Spustí se při... | |-----------------|----------------|-------------| -| `[[Get]]` | `get` | reading a property | -| `[[Set]]` | `set` | writing to a property | -| `[[HasProperty]]` | `has` | `in` operator | -| `[[Delete]]` | `deleteProperty` | `delete` operator | -| `[[Call]]` | `apply` | function call | -| `[[Construct]]` | `construct` | `new` operator | +| `[[Get]]` | `get` | načítání vlastnosti | +| `[[Set]]` | `set` | zápisu do vlastnosti | +| `[[HasProperty]]` | `has` | operátoru `in` | +| `[[Delete]]` | `deleteProperty` | operátoru `delete` | +| `[[Call]]` | `apply` | volání funkce | +| `[[Construct]]` | `construct` | operátoru `new` | | `[[GetPrototypeOf]]` | `getPrototypeOf` | [Object.getPrototypeOf](mdn:/JavaScript/Reference/Global_Objects/Object/getPrototypeOf) | | `[[SetPrototypeOf]]` | `setPrototypeOf` | [Object.setPrototypeOf](mdn:/JavaScript/Reference/Global_Objects/Object/setPrototypeOf) | | `[[IsExtensible]]` | `isExtensible` | [Object.isExtensible](mdn:/JavaScript/Reference/Global_Objects/Object/isExtensible) | @@ -69,144 +69,144 @@ For every internal method, there's a trap in this table: the name of the method | `[[GetOwnProperty]]` | `getOwnPropertyDescriptor` | [Object.getOwnPropertyDescriptor](mdn:/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor), `for..in`, `Object.keys/values/entries` | | `[[OwnPropertyKeys]]` | `ownKeys` | [Object.getOwnPropertyNames](mdn:/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames), [Object.getOwnPropertySymbols](mdn:/JavaScript/Reference/Global_Objects/Object/getOwnPropertySymbols), `for..in`, `Object.keys/values/entries` | -```warn header="Invariants" -JavaScript enforces some invariants -- conditions that must be fulfilled by internal methods and traps. +```warn header="Invarianty" +JavaScript vyžaduje některé invarianty -- podmínky, které musejí interní metody a pasti splňovat. -Most of them are for return values: -- `[[Set]]` must return `true` if the value was written successfully, otherwise `false`. -- `[[Delete]]` must return `true` if the value was deleted successfully, otherwise `false`. -- ...and so on, we'll see more in examples below. +Většina z nich se týká návratových hodnot: +- `[[Set]]` musí vracet `true`, jestliže byla hodnota úspěšně zapsána, jinak `false`. +- `[[Delete]]` musí vracet `true`, jestliže byla hodnota úspěšně smazána, jinak `false`. +- ...a tak dále, další uvidíme v příkladech níže. -There are some other invariants, like: -- `[[GetPrototypeOf]]`, applied to the proxy object must return the same value as `[[GetPrototypeOf]]` applied to the proxy object's target object. In other words, reading prototype of a proxy must always return the prototype of the target object. +Existují i některé další invarianty, například: +- `[[GetPrototypeOf]]` aplikovaná na proxy objekt musí vracet stejnou hodnotu jako `[[GetPrototypeOf]]` aplikovaná na cílový objekt tohoto proxy objektu. Jinými slovy, načítání prototypu proxy musí vždy vrátit prototyp cílového objektu. -Traps can intercept these operations, but they must follow these rules. +Pasti mohou tyto operace zachytávat, ale musejí dodržovat tato pravidla. -Invariants ensure correct and consistent behavior of language features. The full invariants list is in [the specification](https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots). You probably won't violate them if you're not doing something weird. +Invarianty zajišťují korektní a konzistentní chování prvků jazyka. Úplný seznam invariant je obsažen ve [specifikaci](https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots). Pokud nebudete dělat něco podivného, pravděpodobně je neporušíte. ``` -Let's see how that works in practical examples. +Podívejme se na praktických příkladech, jak to funguje. -## Default value with "get" trap +## Výchozí hodnota s pastí „get“ -The most common traps are for reading/writing properties. +Nejběžnější pasti jsou pro čtení a zápis vlastností. -To intercept reading, the `handler` should have a method `get(target, property, receiver)`. +Abychom zachytili čtení, `handler` by měl obsahovat metodu `get(cíl, vlastnost, příjemce)`. -It triggers when a property is read, with following arguments: +Když je vlastnost načítána, tato metoda se spustí s následujícími argumenty: -- `target` -- is the target object, the one passed as the first argument to `new Proxy`, -- `property` -- property name, -- `receiver` -- if the target property is a getter, then `receiver` is the object that's going to be used as `this` in its call. Usually that's the `proxy` object itself (or an object that inherits from it, if we inherit from proxy). Right now we don't need this argument, so it will be explained in more detail later. +- `cíl` -- je cílový objekt, ten, který byl předán do `new Proxy` jako první argument, +- `vlastnost` -- název vlastnosti, +- `příjemce` -- je-li cílová vlastnost getter, pak `příjemce` je objekt, který bude při volání tohoto getteru použit jako `this`. Obvykle je to samotný objekt `proxy` (nebo objekt, který je z něj zděděn, pokud dědíme z proxy). Prozatím tento argument nepotřebujeme, takže ho podrobněji vysvětlíme později. -Let's use `get` to implement default values for an object. +Použijme `get` k implementaci výchozích hodnot objektu. -We'll make a numeric array that returns `0` for nonexistent values. +Vytvořme číselné pole, které bude pro neexistující hodnoty vracet `0`. -Usually when one tries to get a non-existing array item, they get `undefined`, but we'll wrap a regular array into the proxy that traps reading and returns `0` if there's no such property: +Když se pokoušíme načíst neexistující prvek pole, obyčejně získáme `undefined`, ale my obalíme běžné pole do proxy, která bude obsahovat past na načítání a vracet `0`, pokud načítaná vlastnost neexistuje: ```js run -let numbers = [0, 1, 2]; +let čísla = [0, 1, 2]; -numbers = new Proxy(numbers, { - get(target, prop) { - if (prop in target) { - return target[prop]; +čísla = new Proxy(čísla, { + get(cíl, vlastnost) { + if (vlastnost in cíl) { + return cíl[vlastnost]; } else { - return 0; // default value + return 0; // výchozí hodnota } } }); *!* -alert( numbers[1] ); // 1 -alert( numbers[123] ); // 0 (no such item) +alert( čísla[1] ); // 1 +alert( čísla[123] ); // 0 (takový prvek není) */!* ``` -As we can see, it's quite easy to do with a `get` trap. +Jak vidíme, s pastí `get` je něco takového docela snadné. -We can use `Proxy` to implement any logic for "default" values. +Můžeme použít `Proxy` k implementaci jakékoli logiky pro „výchozí“ hodnoty. -Imagine we have a dictionary, with phrases and their translations: +Představme si, že máme slovník s větami a jejich překlady: ```js run -let dictionary = { - 'Hello': 'Hola', - 'Bye': 'Adiós' +let slovník = { + 'Ahoj': 'Hola', + 'Nashle': 'Adiós' }; -alert( dictionary['Hello'] ); // Hola -alert( dictionary['Welcome'] ); // undefined +alert( slovník['Ahoj'] ); // Hola +alert( slovník['Vítejte'] ); // undefined ``` -Right now, if there's no phrase, reading from `dictionary` returns `undefined`. But in practice, leaving a phrase untranslated is usually better than `undefined`. So let's make it return an untranslated phrase in that case instead of `undefined`. +Prozatím načtení věty, kterou `slovník` neobsahuje, vrací `undefined`. V praxi je však obvykle lepší nechat větu nepřeloženou než vrátit `undefined`. Nechme tedy slovník, aby v takovém případě vrátil místo `undefined` nepřeloženou větu. -To achieve that, we'll wrap `dictionary` in a proxy that intercepts reading operations: +Abychom toho dosáhli, obalíme `slovník` do proxy, která zachytává operace načítání: ```js run -let dictionary = { - 'Hello': 'Hola', - 'Bye': 'Adiós' +let slovník = { + 'Ahoj': 'Hola', + 'Nashle': 'Adiós' }; -dictionary = new Proxy(dictionary, { +slovník = new Proxy(slovník, { *!* - get(target, phrase) { // intercept reading a property from dictionary + get(cíl, věta) { // zachytíme načítání vlastnosti ze slovníku */!* - if (phrase in target) { // if we have it in the dictionary - return target[phrase]; // return the translation + if (věta in cíl) { // máme-li ji ve slovníku, + return cíl[věta]; // vrátíme její překlad } else { - // otherwise, return the non-translated phrase - return phrase; + // jinak vrátíme nepřeloženou větu + return věta; } } }); -// Look up arbitrary phrases in the dictionary! -// At worst, they're not translated. -alert( dictionary['Hello'] ); // Hola +// Podívejte se na různé věty ve slovníku! +// Přinejhorším nebudou přeloženy. +alert( slovník['Ahoj'] ); // Hola *!* -alert( dictionary['Welcome to Proxy']); // Welcome to Proxy (no translation) +alert( slovník['Vítejte v Proxy']); // Vítejte v Proxy (bez překladu) */!* ``` ````smart -Please note how the proxy overwrites the variable: +Prosíme všimněte si, jak proxy přepisuje proměnnou: ```js -dictionary = new Proxy(dictionary, ...); +slovník = new Proxy(slovník, ...); ``` -The proxy should totally replace the target object everywhere. No one should ever reference the target object after it got proxied. Otherwise it's easy to mess up. +Proxovaný objekt by měl cílový objekt všude zcela nahradit. Na cílový objekt by se po jeho nahrazení proxovaným objektem neměl nikdo nikde odkazovat. Jinak snadno naděláme nepořádek. ```` -## Validation with "set" trap +## Ověřování pomocí pasti „set“ -Let's say we want an array exclusively for numbers. If a value of another type is added, there should be an error. +Řekněme, že chceme pole výlučně pro čísla. Bude-li přidána hodnota jiného typu, měla by nastat chyba. -The `set` trap triggers when a property is written. +Když se zapisuje do vlastnosti, spustí se past `set`. -`set(target, property, value, receiver)`: +`set(cíl, vlastnost, hodnota, příjemce)`: -- `target` -- is the target object, the one passed as the first argument to `new Proxy`, -- `property` -- property name, -- `value` -- property value, -- `receiver` -- similar to `get` trap, matters only for setter properties. +- `cíl` -- je cílový objekt, ten, který byl předán do `new Proxy` jako první argument, +- `vlastnost` -- název vlastnosti, +- `hodnota` -- hodnota vlastnosti, +- `příjemce` -- podobně jako u pasti `get`, má význam jen pro settery. -The `set` trap should return `true` if setting is successful, and `false` otherwise (triggers `TypeError`). +Past `set` by měla vracet `true`, je-li nastavení úspěšné, a jinak `false` (vyvolá `TypeError`). -Let's use it to validate new values: +Použijme ji k ověřování nových hodnot: ```js run -let numbers = []; +let čísla = []; -numbers = new Proxy(numbers, { // (*) +čísla = new Proxy(čísla, { // (*) *!* - set(target, prop, val) { // to intercept property writing + set(cíl, vlastnost, hodnota) { // zachytává zápis do vlastností */!* - if (typeof val == 'number') { - target[prop] = val; + if (typeof hodnota == 'number') { + cíl[vlastnost] = hodnota; return true; } else { return false; @@ -214,821 +214,819 @@ numbers = new Proxy(numbers, { // (*) } }); -numbers.push(1); // added successfully -numbers.push(2); // added successfully -alert("Length is: " + numbers.length); // 2 +čísla.push(1); // úspěšně přidáno +čísla.push(2); // úspěšně přidáno +alert("Délka pole je: " + čísla.length); // 2 *!* -numbers.push("test"); // TypeError ('set' on proxy returned false) +čísla.push("test"); // TypeError ('set' na proxy vrátila false) */!* -alert("This line is never reached (error in the line above)"); +alert("Na tento řádek se nikdy nedostaneme (chyba na řádku výše)"); ``` -Please note: the built-in functionality of arrays is still working! Values are added by `push`. The `length` property auto-increases when values are added. Our proxy doesn't break anything. +Prosíme všimněte si, že zabudovaná funkcionalita polí stále funguje! Hodnoty se přidávají metodou `push`. Vlastnost `length` se při přidávání hodnot automaticky zvyšuje. Naše proxy nic nepokazila. -We don't have to override value-adding array methods like `push` and `unshift`, and so on, to add checks in there, because internally they use the `[[Set]]` operation that's intercepted by the proxy. +Metody přidávání hodnot do polí jako `push`, `unshift` a podobně nemusíme kvůli přidání ověření přepisovat, protože vnitřně používají operaci `[[Set]]`, kterou proxy zachytává. -So the code is clean and concise. +Kód je tedy čistý a výstižný. -```warn header="Don't forget to return `true`" -As said above, there are invariants to be held. +```warn header="Nezapomínejte vracet `true`" +Jak bylo řečeno výše, existují invarianty, které je třeba dodržovat. -For `set`, it must return `true` for a successful write. +Pro `set` musíme při úspěšném zápisu vracet `true`. -If we forget to do it or return any falsy value, the operation triggers `TypeError`. +Pokud na to zapomeneme nebo vrátíme jakoukoli nepravdivou hodnotu, operace vyvolá `TypeError`. ``` -## Iteration with "ownKeys" and "getOwnPropertyDescriptor" +## Iterace pomocí „ownKeys“ a „getOwnPropertyDescriptor“ -`Object.keys`, `for..in` loop and most other methods that iterate over object properties use `[[OwnPropertyKeys]]` internal method (intercepted by `ownKeys` trap) to get a list of properties. +Metoda `Object.keys`, cyklus `for..in` a většina ostatních metod, které iterují nad vlastnostmi objektu, používají k načtení seznamu vlastností interní metodu `[[OwnPropertyKeys]]` (kterou zachytává past `ownKeys`). -Such methods differ in details: -- `Object.getOwnPropertyNames(obj)` returns non-symbol keys. -- `Object.getOwnPropertySymbols(obj)` returns symbol keys. -- `Object.keys/values()` returns non-symbol keys/values with `enumerable` flag (property flags were explained in the article ). -- `for..in` loops over non-symbol keys with `enumerable` flag, and also prototype keys. +Tyto metody se liší v detailech: +- `Object.getOwnPropertyNames(obj)` vrací nesymbolické klíče. +- `Object.getOwnPropertySymbols(obj)` vrací symbolické klíče. +- `Object.keys/values()` vrací nesymbolické klíče/hodnoty s přepínačem `enumerable` (přepínače vlastností byly vysvětleny v kapitole ). +- `for..in` cykluje nad nesymbolickými klíči s přepínačem `enumerable` a také nad klíči prototypu. -...But all of them start with that list. +...Všechny však začínají se seznamem vlastností vráceným touto metodou. -In the example below we use `ownKeys` trap to make `for..in` loop over `user`, and also `Object.keys` and `Object.values`, to skip properties starting with an underscore `_`: +V následujícím příkladu použijeme past `ownKeys`, abychom cyklus `for..in` nad objektem `uživatel`, stejně jako metody `Object.keys` a `Object.values`, přiměli přeskakovat vlastnosti začínající podtržítkem `_`: ```js run -let user = { - name: "John", - age: 30, - _password: "***" +let uživatel = { + jméno: "Jan", + věk: 30, + _heslo: "***" }; -user = new Proxy(user, { +uživatel = new Proxy(uživatel, { *!* - ownKeys(target) { + ownKeys(cíl) { */!* - return Object.keys(target).filter(key => !key.startsWith('_')); + return Object.keys(cíl).filter(klíč => !klíč.startsWith('_')); } }); -// "ownKeys" filters out _password -for(let key in user) alert(key); // name, then: age +// „ownKeys“ odfiltruje _heslo +for(let klíč in uživatel) alert(klíč); // jméno, pak: věk -// same effect on these methods: -alert( Object.keys(user) ); // name,age -alert( Object.values(user) ); // John,30 +// stejný efekt má na těchto metodách: +alert( Object.keys(uživatel) ); // jméno,věk +alert( Object.values(uživatel) ); // Jan,30 ``` -So far, it works. +Dosud to funguje. -Although, if we return a key that doesn't exist in the object, `Object.keys` won't list it: +Ale jestliže vrátíme klíč, který v tomto objektu neexistuje, `Object.keys` jej nezpracuje: ```js run -let user = { }; +let uživatel = { }; -user = new Proxy(user, { +uživatel = new Proxy(uživatel, { *!* - ownKeys(target) { + ownKeys(cíl) { */!* return ['a', 'b', 'c']; } }); -alert( Object.keys(user) ); // +alert( Object.keys(uživatel) ); // ``` -Why? The reason is simple: `Object.keys` returns only properties with the `enumerable` flag. To check for it, it calls the internal method `[[GetOwnProperty]]` for every property to get [its descriptor](info:property-descriptors). And here, as there's no property, its descriptor is empty, no `enumerable` flag, so it's skipped. +Proč? Důvod je prostý: metoda `Object.keys` vrací jen vlastnosti s přepínačem `enumerable`. Aby si jej ověřila, volá pro každou vlastnost interní metodu `[[GetOwnProperty]]`, aby získala [její deskriptor](info:property-descriptors). A protože zde žádná vlastnost není, její deskriptor je prázdný a neobsahuje přepínač `enumerable`, a tak je vlastnost přeskočena. -For `Object.keys` to return a property, we need it to either exist in the object, with the `enumerable` flag, or we can intercept calls to `[[GetOwnProperty]]` (the trap `getOwnPropertyDescriptor` does it), and return a descriptor with `enumerable: true`. +Aby `Object.keys` vracel vlastnost, musí buď tato vlastnost v objektu existovat s přepínačem `enumerable`, nebo můžeme zachytávat volání metody `[[GetOwnProperty]]` (to dělá past `getOwnPropertyDescriptor`) a vracet deskriptor obsahující `enumerable: true`. -Here's an example of that: +Zde je příklad: ```js run -let user = { }; +let uživatel = { }; -user = new Proxy(user, { - ownKeys(target) { // called once to get a list of properties +uživatel = new Proxy(uživatel, { + ownKeys(cíl) { // volána jednou pro získání seznamu vlastností return ['a', 'b', 'c']; }, - getOwnPropertyDescriptor(target, prop) { // called for every property + getOwnPropertyDescriptor(cíl, vlastnost) { // volána pro každou vlastnost return { enumerable: true, configurable: true - /* ...other flags, probable "value:..." */ + /* ...další přepínače, pravděpodobně "value:..." */ }; } }); -alert( Object.keys(user) ); // a, b, c +alert( Object.keys(uživatel) ); // a, b, c ``` -Let's note once again: we only need to intercept `[[GetOwnProperty]]` if the property is absent in the object. +Poznamenejme to znovu: jestliže vlastnost v objektu chybí, potřebujeme jen zachycovat `[[GetOwnProperty]]`. -## Protected properties with "deleteProperty" and other traps +## Ochrana vlastností pomocí „deleteProperty“ a jiných pastí -There's a widespread convention that properties and methods prefixed by an underscore `_` are internal. They shouldn't be accessed from outside the object. +Existuje široce přijímaná konvence, že vlastnosti a metody začínající podtržítkem `_` jsou interní. Nemělo by se k nim přistupovat zvnějšku objektu. -Technically that's possible though: +Technicky to však možné je: ```js run -let user = { - name: "John", - _password: "secret" +let uživatel = { + jméno: "Jan", + _heslo: "tajné" }; -alert(user._password); // secret +alert(uživatel._heslo); // tajné ``` -Let's use proxies to prevent any access to properties starting with `_`. +Abychom zabránili jakémukoli přístupu k vlastnostem, které začínají `_`, použijme proxy. -We'll need the traps: -- `get` to throw an error when reading such property, -- `set` to throw an error when writing, -- `deleteProperty` to throw an error when deleting, -- `ownKeys` to exclude properties starting with `_` from `for..in` and methods like `Object.keys`. +Potřebujeme tyto pasti: +- `get` k vyvolání chyby při načítání takové vlastnosti, +- `set` k vyvolání chyby při zapisování do ní, +- `deleteProperty` k vyvolání chyby při jejím mazání, +- `ownKeys` k vyloučení vlastností začínajících `_` z cyklu `for..in` a metod jako `Object.keys`. -Here's the code: +Zde je kód: ```js run -let user = { - name: "John", - _password: "***" +let uživatel = { + jméno: "Jan", + _heslo: "***" }; -user = new Proxy(user, { +uživatel = new Proxy(uživatel, { *!* - get(target, prop) { + get(cíl, vlastnost) { */!* - if (prop.startsWith('_')) { - throw new Error("Access denied"); + if (vlastnost.startsWith('_')) { + throw new Error("Přístup zamítnut"); } - let value = target[prop]; - return (typeof value === 'function') ? value.bind(target) : value; // (*) + let hodnota = cíl[vlastnost]; + return (typeof hodnota === 'function') ? hodnota.bind(cíl) : hodnota; // (*) }, *!* - set(target, prop, val) { // to intercept property writing + set(cíl, vlastnost, hodnota) { // k zachycení zápisu do vlastnosti */!* - if (prop.startsWith('_')) { - throw new Error("Access denied"); + if (vlastnost.startsWith('_')) { + throw new Error("Přístup zamítnut"); } else { - target[prop] = val; + cíl[vlastnost] = hodnota; return true; } }, *!* - deleteProperty(target, prop) { // to intercept property deletion + deleteProperty(cíl, vlastnost) { // k zachycení mazání vlastnosti */!* - if (prop.startsWith('_')) { - throw new Error("Access denied"); + if (vlastnost.startsWith('_')) { + throw new Error("Přístup zamítnut"); } else { - delete target[prop]; + delete cíl[vlastnost]; return true; } }, *!* - ownKeys(target) { // to intercept property list + ownKeys(cíl) { // k zachycení seznamu vlastností */!* - return Object.keys(target).filter(key => !key.startsWith('_')); + return Object.keys(cíl).filter(klíč => !klíč.startsWith('_')); } }); -// "get" doesn't allow to read _password +// „get“ neumožňuje načíst _heslo try { - alert(user._password); // Error: Access denied + alert(uživatel._heslo); // Chyba: Přístup zamítnut } catch(e) { alert(e.message); } -// "set" doesn't allow to write _password +// „set“ neumožňuje zapsat do _heslo try { - user._password = "test"; // Error: Access denied + uživatel._heslo = "test"; // Chyba: Přístup zamítnut } catch(e) { alert(e.message); } -// "deleteProperty" doesn't allow to delete _password +// „deleteProperty“ neumožňuje smazat _heslo try { - delete user._password; // Error: Access denied + delete uživatel._heslo; // Chyba: Přístup zamítnut } catch(e) { alert(e.message); } -// "ownKeys" filters out _password -for(let key in user) alert(key); // name +// „ownKeys“ odfiltruje _heslo +for(let klíč in uživatel) alert(klíč); // jméno ``` -Please note the important detail in the `get` trap, in the line `(*)`: +Prosíme všimněte si důležitého detailu v pasti `get` na řádku `(*)`: ```js -get(target, prop) { +get(cíl, vlastnost) { // ... - let value = target[prop]; + let hodnota = cíl[vlastnost]; *!* - return (typeof value === 'function') ? value.bind(target) : value; // (*) + return (typeof hodnota === 'function') ? hodnota.bind(cíl) : hodnota; // (*) */!* } ``` -Why do we need a function to call `value.bind(target)`? +Proč potřebujeme, aby funkce volala `hodnota.bind(cíl)`? -The reason is that object methods, such as `user.checkPassword()`, must be able to access `_password`: +Důvodem je, že objektové metody, např. `uživatel.ověřHeslo()`, musejí být schopny k `_heslo` přistupovat: ```js -user = { +uživatel = { // ... - checkPassword(value) { - // object method must be able to read _password - return value === this._password; + ověřHeslo(hodnota) { + // objektová metoda musí být schopna _heslo číst + return hodnota === this._heslo; } } ``` +Volání `uživatel.ověřHeslo()` získá jako `this` proxovaný objekt `uživatel` (objekt před tečkou se stane `this`), takže když se pokusí o přístup k `this._heslo`, aktivuje se past `get` (ta se spustí při načítání jakékoli vlastnosti) a vyvolá se chyba. -A call to `user.checkPassword()` gets proxied `user` as `this` (the object before dot becomes `this`), so when it tries to access `this._password`, the `get` trap activates (it triggers on any property read) and throws an error. +Proto na řádku `(*)` navážeme kontext objektových metod na původní objekt, `cíl`. Pak jejich následná volání budou jako `this` používat `cíl` bez jakýchkoli pastí. -So we bind the context of object methods to the original object, `target`, in the line `(*)`. Then their future calls will use `target` as `this`, without any traps. +Toto řešení zpravidla funguje, ale není ideální, protože nějaká metoda může předat neproxovaný objekt někam jinam a pak nastane zmatek: kde je původní objekt a kde proxovaný? -That solution usually works, but isn't ideal, as a method may pass the unproxied object somewhere else, and then we'll get messed up: where's the original object, and where's the proxied one? +Kromě toho objekt může být proxován několikrát (vícenásobné proxy mohou k objektu přidávat různé „úpravy“), a jestliže do metody předáme neobalený objekt, důsledky mohou být nečekané. -Besides, an object may be proxied multiple times (multiple proxies may add different "tweaks" to the object), and if we pass an unwrapped object to a method, there may be unexpected consequences. +Taková proxy by tedy neměla být používána všude. -So, such a proxy shouldn't be used everywhere. +```smart header="Soukromé vlastnosti třídy" +Moderní JavaScriptové motory nativně podporují ve třídách soukromé vlastnosti, začínající znakem `#`. Jsou popsány v článku . Žádné proxy nejsou zapotřebí. -```smart header="Private properties of a class" -Modern JavaScript engines natively support private properties in classes, prefixed with `#`. They are described in the article . No proxies required. - -Such properties have their own issues though. In particular, they are not inherited. +Takové vlastnosti však mají své vlastní problémy. Například nejsou děděny. ``` -## "In range" with "has" trap +## „in“ pro rozsah s pastí „has“ -Let's see more examples. +Podívejme se na další příklady. -We have a range object: +Máme objekt rozsahu: ```js -let range = { - start: 1, - end: 10 +let rozsah = { + začátek: 1, + konec: 10 }; ``` -We'd like to use the `in` operator to check that a number is in `range`. +K ověření, zda číslo leží v rozsahu `rozsah`, bychom rádi používali operátor `in`. -The `has` trap intercepts `in` calls. +Volání `in` zachytává past `has`. -`has(target, property)` +`has(cíl, vlastnost)` -- `target` -- is the target object, passed as the first argument to `new Proxy`, -- `property` -- property name +- `cíl` -- je cílový objekt, předaný jako první argument do `new Proxy`, +- `vlastnost` -- název vlastnosti. -Here's the demo: +Zde je demo: ```js run -let range = { - start: 1, - end: 10 +let rozsah = { + začátek: 1, + konec: 10 }; -range = new Proxy(range, { +rozsah = new Proxy(rozsah, { *!* - has(target, prop) { + has(cíl, vlastnost) { */!* - return prop >= target.start && prop <= target.end; + return vlastnost >= cíl.začátek && vlastnost <= cíl.konec; } }); *!* -alert(5 in range); // true -alert(50 in range); // false +alert(5 in rozsah); // true +alert(50 in rozsah); // false */!* ``` -Nice syntactic sugar, isn't it? And very simple to implement. +Pěkný syntaktický cukr, že? A implementuje se velmi jednoduše. -## Wrapping functions: "apply" [#proxy-apply] +## Obalování funkcí: „apply“ [#proxy-apply] -We can wrap a proxy around a function as well. +Do proxy můžeme obalit i funkci. -The `apply(target, thisArg, args)` trap handles calling a proxy as function: +Past `apply(cíl, thisArg, args)` zpracovává volání proxy jako funkce: -- `target` is the target object (function is an object in JavaScript), -- `thisArg` is the value of `this`. -- `args` is a list of arguments. +- `cíl` je cílový objekt (funkce je v JavaScriptu objekt), +- `thisArg` je hodnota `this`, +- `args` je seznam argumentů. -For example, let's recall `delay(f, ms)` decorator, that we did in the article . +Vzpomeňme si například na dekorátor `zpozdi(f, ms)`, který jsme vytvořili v článku . -In that article we did it without proxies. A call to `delay(f, ms)` returned a function that forwards all calls to `f` after `ms` milliseconds. +V onom článku jsme to udělali bez proxy. Volání `zpozdi(f, ms)` vrátilo funkci, která funkci `f` předává všechna volání za `ms` milisekund. -Here's the previous, function-based implementation: +Zde je předchozí implementace založená na funkcích: ```js run -function delay(f, ms) { - // return a wrapper that passes the call to f after the timeout +function zpozdi(f, ms) { + // vrátí obal, který po uplynutí zadaného času předá volání funkci f return function() { // (*) setTimeout(() => f.apply(this, arguments), ms); }; } -function sayHi(user) { - alert(`Hello, ${user}!`); +function řekniAhoj(uživatel) { + alert(`Ahoj, ${uživatel}!`); } -// after this wrapping, calls to sayHi will be delayed for 3 seconds -sayHi = delay(sayHi, 3000); +// po tomto obalení budou volání řekniAhoj pozdržena o 3 sekundy +řekniAhoj = zpozdi(řekniAhoj, 3000); -sayHi("John"); // Hello, John! (after 3 seconds) +řekniAhoj("Jan"); // Ahoj, Jan! (po 3 sekundách) ``` -As we've seen already, that mostly works. The wrapper function `(*)` performs the call after the timeout. +Jak jsme již viděli, většinou to funguje. Obalová funkce `(*)` provede volání po stanoveném čase. -But a wrapper function does not forward property read/write operations or anything else. After the wrapping, the access is lost to properties of the original functions, such as `name`, `length` and others: +Avšak obalová funkce nepředává dál operace čtení a zápisu do vlastností nebo cokoli jiného. Po obalení ztratíme přístup k vlastnostem původní funkce, např. `name`, `length` a jiným: ```js run -function delay(f, ms) { +function zpozdi(f, ms) { return function() { setTimeout(() => f.apply(this, arguments), ms); }; } -function sayHi(user) { - alert(`Hello, ${user}!`); +function řekniAhoj(uživatel) { + alert(`Ahoj, ${uživatel}!`); } *!* -alert(sayHi.length); // 1 (function length is the arguments count in its declaration) +alert(řekniAhoj.length); // 1 (length=délka, délka funkce je počet argumentů v její deklaraci) */!* -sayHi = delay(sayHi, 3000); +řekniAhoj = zpozdi(řekniAhoj, 3000); *!* -alert(sayHi.length); // 0 (in the wrapper declaration, there are zero arguments) +alert(řekniAhoj.length); // 0 (v deklaraci obalu je 0 argumentů) */!* ``` -`Proxy` is much more powerful, as it forwards everything to the target object. +`Proxy` je mnohem silnější, jelikož cílovému objektu předává všechno. -Let's use `Proxy` instead of a wrapping function: +Použijme `Proxy` místo obalové funkce: ```js run -function delay(f, ms) { +function zpozdi(f, ms) { return new Proxy(f, { - apply(target, thisArg, args) { - setTimeout(() => target.apply(thisArg, args), ms); + apply(cíl, thisArg, args) { + setTimeout(() => cíl.apply(thisArg, args), ms); } }); } -function sayHi(user) { - alert(`Hello, ${user}!`); +function řekniAhoj(uživatel) { + alert(`Ahoj, ${uživatel}!`); } -sayHi = delay(sayHi, 3000); +řekniAhoj = zpozdi(řekniAhoj, 3000); *!* -alert(sayHi.length); // 1 (*) proxy forwards "get length" operation to the target +alert(řekniAhoj.length); // 1 (*) proxy předá cíli operaci „get length“ */!* -sayHi("John"); // Hello, John! (after 3 seconds) +řekniAhoj("Jan"); // Ahoj, Jan! (po 3 sekundách) ``` -The result is the same, but now not only calls, but all operations on the proxy are forwarded to the original function. So `sayHi.length` is returned correctly after the wrapping in the line `(*)`. +Výsledek je stejný, ale nyní se původní funkci předávají nejen volání, ale všechny operace na proxy. Po obalení se tedy `řekniAhoj.length` na řádku `(*)` vrátí správně. -We've got a "richer" wrapper. +Získali jsme „bohatší“ obal. -Other traps exist: the full list is in the beginning of this article. Their usage pattern is similar to the above. +Existují i jiné pasti: jejich úplný seznam je uveden na začátku tohoto článku. Jejich vzorec použití je podobný uvedenému. ## Reflect -`Reflect` is a built-in object that simplifies creation of `Proxy`. +`Reflect` je vestavěný objekt, který zjednodušuje vytváření `Proxy`. -It was said previously that internal methods, such as `[[Get]]`, `[[Set]]` and others are specification-only, they can't be called directly. +Již jsme uvedli, že interní metody, např. `[[Get]]`, `[[Set]]` a jiné, jsou jen specifikační a nemůžeme je volat přímo. -The `Reflect` object makes that somewhat possible. Its methods are minimal wrappers around the internal methods. +Objekt `Reflect` to částečně umožňuje. Jeho metody jsou minimální obaly okolo interních metod. -Here are examples of operations and `Reflect` calls that do the same: +Zde jsou příklady operací a volání `Reflect`, která udělají totéž: -| Operation | `Reflect` call | Internal method | +| Operace | Volání `Reflect` | Interní metoda | |-----------------|----------------|-------------| -| `obj[prop]` | `Reflect.get(obj, prop)` | `[[Get]]` | -| `obj[prop] = value` | `Reflect.set(obj, prop, value)` | `[[Set]]` | -| `delete obj[prop]` | `Reflect.deleteProperty(obj, prop)` | `[[Delete]]` | -| `new F(value)` | `Reflect.construct(F, value)` | `[[Construct]]` | +| `obj[vlastnost]` | `Reflect.get(obj, vlastnost)` | `[[Get]]` | +| `obj[vlastnost] = hodnota` | `Reflect.set(obj, vlastnost, hodnota)` | `[[Set]]` | +| `delete obj[vlastnost]` | `Reflect.deleteProperty(obj, vlastnost)` | `[[Delete]]` | +| `new F(hodnota)` | `Reflect.construct(F, hodnota)` | `[[Construct]]` | | ... | ... | ... | -For example: +Například: ```js run -let user = {}; +let uživatel = {}; -Reflect.set(user, 'name', 'John'); +Reflect.set(uživatel, 'jméno', 'Jan'); -alert(user.name); // John +alert(uživatel.jméno); // Jan ``` -In particular, `Reflect` allows us to call operators (`new`, `delete`...) as functions (`Reflect.construct`, `Reflect.deleteProperty`, ...). That's an interesting capability, but here another thing is important. +Konkrétně nám `Reflect` umožňuje volat operátory (`new`, `delete`...) jako funkce (`Reflect.construct`, `Reflect.deleteProperty`, ...). To je zajímavá schopnost, ale tady je důležitá jiná věc. -**For every internal method, trappable by `Proxy`, there's a corresponding method in `Reflect`, with the same name and arguments as the `Proxy` trap.** +**Pro každou interní metodu, kterou může zachytit `Proxy`, je v `Reflect` odpovídající metoda se stejným názvem a argumenty jako past v `Proxy`.** -So we can use `Reflect` to forward an operation to the original object. +Můžeme tedy používat `Reflect` k předání operace původnímu objektu. -In this example, both traps `get` and `set` transparently (as if they didn't exist) forward reading/writing operations to the object, showing a message: +V tomto příkladu obě pasti `get` a `set` průhledně (jako by neexistovaly) předají objektu operace čtení nebo zápisu a zobrazí zprávu: ```js run -let user = { - name: "John", +let uživatel = { + jméno: "Jan", }; -user = new Proxy(user, { - get(target, prop, receiver) { - alert(`GET ${prop}`); +uživatel = new Proxy(uživatel, { + get(cíl, vlastnost, příjemce) { + alert(`GET ${vlastnost}`); *!* - return Reflect.get(target, prop, receiver); // (1) + return Reflect.get(cíl, vlastnost, příjemce); // (1) */!* }, - set(target, prop, val, receiver) { - alert(`SET ${prop}=${val}`); + set(cíl, vlastnost, hodnota, příjemce) { + alert(`SET ${vlastnost}=${hodnota}`); *!* - return Reflect.set(target, prop, val, receiver); // (2) + return Reflect.set(cíl, vlastnost, hodnota, příjemce); // (2) */!* } }); -let name = user.name; // shows "GET name" -user.name = "Pete"; // shows "SET name=Pete" +let jméno = uživatel.jméno; // zobrazí "GET jméno" +uživatel.jméno = "Petr"; // zobrazí "SET jméno=Petr" ``` -Here: +Zde: -- `Reflect.get` reads an object property. -- `Reflect.set` writes an object property and returns `true` if successful, `false` otherwise. +- `Reflect.get` načte vlastnost objektu. +- `Reflect.set` zapíše vlastnost objektu a vrátí `true`, je-li úspěšná, jinak `false`. -That is, everything's simple: if a trap wants to forward the call to the object, it's enough to call `Reflect.` with the same arguments. +Všechno je přitom jednoduché: jestliže past chce předat volání objektu, stačí jí volat `Reflect.` se stejnými argumenty. -In most cases we can do the same without `Reflect`, for instance, reading a property `Reflect.get(target, prop, receiver)` can be replaced by `target[prop]`. There are important nuances though. +Ve většině případů můžeme udělat totéž i bez `Reflect`, například načítání vlastnosti pomocí `Reflect.get(cíl, vlastnost, příjemce)` můžeme nahradit za `cíl[vlastnost]`. Jsou tady však důležité drobnosti. -### Proxying a getter +### Proxování getteru -Let's see an example that demonstrates why `Reflect.get` is better. And we'll also see why `get/set` have the third argument `receiver`, that we didn't use before. +Podívejme se na příklad, který demonstruje, proč je `Reflect.get` lepší. A také uvidíme, proč `get/set` mají třetí argument `příjemce`, který jsme zatím nepoužívali. -We have an object `user` with `_name` property and a getter for it. +Máme objekt `uživatel` s vlastností `_jméno` a jejím getterem. -Here's a proxy around it: +Zde je proxy okolo něj: ```js run -let user = { - _name: "Guest", - get name() { - return this._name; +let uživatel = { + _jméno: "Host", + get jméno() { + return this._jméno; } }; *!* -let userProxy = new Proxy(user, { - get(target, prop, receiver) { - return target[prop]; +let uživatelProxy = new Proxy(uživatel, { + get(cíl, vlastnost, příjemce) { + return cíl[vlastnost]; } }); */!* -alert(userProxy.name); // Guest +alert(uživatelProxy.jméno); // Host ``` -The `get` trap is "transparent" here, it returns the original property, and doesn't do anything else. That's enough for our example. +Past `get` je zde „průhledná“, vrací původní vlastnost a nic jiného nedělá. To pro náš příklad stačí. -Everything seems to be all right. But let's make the example a little bit more complex. +Vypadá to, že je všechno v pořádku. Učiňme však tento příklad trochu složitějším. -After inheriting another object `admin` from `user`, we can observe the incorrect behavior: +Po zdědění jiného objektu `admin` z objektu `uživatel` můžeme pozorovat nesprávné chování: ```js run -let user = { - _name: "Guest", - get name() { - return this._name; +let uživatel = { + _jméno: "Host", + get jméno() { + return this._jméno; } }; -let userProxy = new Proxy(user, { - get(target, prop, receiver) { - return target[prop]; // (*) target = user +let uživatelProxy = new Proxy(uživatel, { + get(cíl, vlastnost, příjemce) { + return cíl[vlastnost]; // (*) cíl = uživatel } }); *!* let admin = { - __proto__: userProxy, - _name: "Admin" + __proto__: uživatelProxy, + _jméno: "Admin" }; -// Expected: Admin -alert(admin.name); // outputs: Guest (?!?) +// Očekáváme: Admin +alert(admin.jméno); // vypíše: Host (?!?) */!* ``` -Reading `admin.name` should return `"Admin"`, not `"Guest"`! +Načtení `admin.jméno` by mělo vrátit `"Admin"`, ne `"Host"`! -What's the matter? Maybe we did something wrong with the inheritance? +V čem je problém? Udělali jsme snad něco špatně s dědičností? -But if we remove the proxy, then everything will work as expected. +Pokud však odstraníme proxy, bude všechno fungovat tak, jak očekáváme. -The problem is actually in the proxy, in the line `(*)`. +Problém je ve skutečnosti v proxy na řádku `(*)`. -1. When we read `admin.name`, as `admin` object doesn't have such own property, the search goes to its prototype. -2. The prototype is `userProxy`. -3. When reading `name` property from the proxy, its `get` trap triggers and returns it from the original object as `target[prop]` in the line `(*)`. +1. Když načítáme `admin.jméno`, objekt `admin` takovou vlastnost nemá, a proto hledání přejde k jeho prototypu. +2. Prototypem je `uživatelProxy`. +3. Když načítáme vlastnost `jméno` z proxy, spustí se jeho past `get` a na řádku `(*)` ji vrátí z původního objektu jako `cíl[vlastnost]`. - A call to `target[prop]`, when `prop` is a getter, runs its code in the context `this=target`. So the result is `this._name` from the original object `target`, that is: from `user`. + Volání `cíl[vlastnost]`, když `vlastnost` je getter, spustí kód tohoto getteru v kontextu `this=cíl`. Výsledkem je tedy `this._jméno` z původního objektu `cíl`, což je: z objektu `uživatel`. -To fix such situations, we need `receiver`, the third argument of `get` trap. It keeps the correct `this` to be passed to a getter. In our case that's `admin`. +Abychom takové situace opravili, potřebujeme `příjemce`, třetí argument pasti `get`. Ten udržuje správné `this`, které bude předáno getteru. V našem případě to je `admin`. -How to pass the context for a getter? For a regular function we could use `call/apply`, but that's a getter, it's not "called", just accessed. +Jak předat kontext getteru? Pro běžnou funkci bychom mohli použít `call/apply`, ale tohle je getter, ten se „nevolá“, jenom se k němu přistupuje. -`Reflect.get` can do that. Everything will work right if we use it. +Může to udělat `Reflect.get`. Pokud ji použijeme, bude všechno fungovat správně. -Here's the corrected variant: +Zde je opravená varianta: ```js run -let user = { - _name: "Guest", - get name() { - return this._name; +let uživatel = { + _jméno: "Host", + get jméno() { + return this._jméno; } }; -let userProxy = new Proxy(user, { - get(target, prop, receiver) { // receiver = admin +let uživatelProxy = new Proxy(uživatel, { + get(cíl, vlastnost, příjemce) { // příjemce = admin *!* - return Reflect.get(target, prop, receiver); // (*) + return Reflect.get(cíl, vlastnost, příjemce); // (*) */!* } }); let admin = { - __proto__: userProxy, - _name: "Admin" + __proto__: uživatelProxy, + _jméno: "Admin" }; *!* -alert(admin.name); // Admin +alert(admin.jméno); // Admin */!* ``` -Now `receiver` that keeps a reference to the correct `this` (that is `admin`), is passed to the getter using `Reflect.get` in the line `(*)`. +Nyní je getteru předán `příjemce`, který si udržuje odkaz na správné `this` (což je `admin`), pomocí `Reflect.get` na řádku `(*)`. -We can rewrite the trap even shorter: +Tuto past můžeme ještě zkrátit: ```js -get(target, prop, receiver) { +get(cíl, vlastnost, příjemce) { return Reflect.get(*!*...arguments*/!*); } ``` +Metody `Reflect` jsou pojmenovány přesně stejně jako pasti a přijímají stejné argumenty. Byly tak úmyslně navrženy. -`Reflect` calls are named exactly the same way as traps and accept the same arguments. They were specifically designed this way. - -So, `return Reflect...` provides a safe no-brainer to forward the operation and make sure we don't forget anything related to that. +`return Reflect...` tedy poskytuje bezpečný a srozumitelný způsob, jak předat dál operaci a zajistit, abychom nezapomněli na nic, co se k ní vztahuje. -## Proxy limitations +## Omezení proxy -Proxies provide a unique way to alter or tweak the behavior of the existing objects at the lowest level. Still, it's not perfect. There are limitations. +Proxy poskytují unikátní způsob, jak změnit nebo upravit chování existujících objektů na nejnižší úrovni. Přesto nejsou dokonalé a mají svá omezení. -### Built-in objects: Internal slots +### Zabudované objekty: Interní sloty -Many built-in objects, for example `Map`, `Set`, `Date`, `Promise` and others make use of so-called "internal slots". +Mnoho zabudovaných objektů, např. `Map`, `Set`, `Date`, `Promise` a jiné, využívá tzv. „interní sloty“. -These are like properties, but reserved for internal, specification-only purposes. For instance, `Map` stores items in the internal slot `[[MapData]]`. Built-in methods access them directly, not via `[[Get]]/[[Set]]` internal methods. So `Proxy` can't intercept that. +Podobají se vlastnostem, ale jsou rezervovány pro vnitřní, výhradně specifikační účely. Například `Map` si ukládá prvky do interního slotu `[[MapData]]`. Vestavěné metody k nim přistupují přímo, ne interními metodami `[[Get]]/[[Set]]`. `Proxy` je tedy nemůže zachytit. -Why care? They're internal anyway! +Proč se o to starat? Jsou přece interní! -Well, here's the issue. After a built-in object like that gets proxied, the proxy doesn't have these internal slots, so built-in methods will fail. +Zde je důvod. Když bude podobný vestavěný objekt proxován, proxy objekt nebude tyto interní sloty mít, takže vestavěné metody selžou. -For example: +Například: ```js run -let map = new Map(); +let mapa = new Map(); -let proxy = new Proxy(map, {}); +let proxy = new Proxy(mapa, {}); *!* -proxy.set('test', 1); // Error +proxy.set('test', 1); // Chyba */!* ``` -Internally, a `Map` stores all data in its `[[MapData]]` internal slot. The proxy doesn't have such a slot. The [built-in method `Map.prototype.set`](https://tc39.es/ecma262/#sec-map.prototype.set) method tries to access the internal property `this.[[MapData]]`, but because `this=proxy`, can't find it in `proxy` and just fails. +Vnitřně si `Map` ukládá všechna data do svého interního slotu `[[MapData]]`. Proxy takový slot nemá. [Vestavěná metoda `Map.prototype.set`](https://tc39.es/ecma262/#sec-map.prototype.set) se pokusí přistoupit k interní vlastnosti `this.[[MapData]]`, ale protože `this=proxy`, nenajde ji v `proxy` a prostě selže. -Fortunately, there's a way to fix it: +Naštěstí existuje způsob, jak to opravit: ```js run -let map = new Map(); +let mapa = new Map(); -let proxy = new Proxy(map, { - get(target, prop, receiver) { - let value = Reflect.get(...arguments); +let proxy = new Proxy(mapa, { + get(cíl, vlastnost, příjemce) { + let hodnota = Reflect.get(...arguments); *!* - return typeof value == 'function' ? value.bind(target) : value; + return typeof hodnota == 'function' ? hodnota.bind(cíl) : hodnota; */!* } }); proxy.set('test', 1); -alert(proxy.get('test')); // 1 (works!) +alert(proxy.get('test')); // 1 (funguje!) ``` -Now it works fine, because `get` trap binds function properties, such as `map.set`, to the target object (`map`) itself. +Teď to funguje dobře, protože past `get` naváže funkční vlastnosti, např. `mapa.set`, na samotný cílový objekt (`mapa`). -Unlike the previous example, the value of `this` inside `proxy.set(...)` will be not `proxy`, but the original `map`. So when the internal implementation of `set` tries to access `this.[[MapData]]` internal slot, it succeeds. +Na rozdíl od předchozího příkladu hodnota `this` uvnitř `proxy.set(...)` nebude `proxy`, ale původní `mapa`. Když se tedy vnitřní implementace metody `set` pokusí přistoupit k internímu slotu `this.[[MapData]]`, uspěje. -```smart header="`Array` has no internal slots" -A notable exception: built-in `Array` doesn't use internal slots. That's for historical reasons, as it appeared so long ago. +```smart header="`Array` nemá interní sloty" +Významná výjimka: vestavěné `Array` nepoužívá interní sloty. Je tomu tak z historických důvodů, jelikož se objevilo již před dlouhou dobou. -So there's no such problem when proxying an array. +Při proxování pole tedy takový problém nenastává. ``` -### Private fields +### Soukromá pole -A similar thing happens with private class fields. +Obdobný problém nastává se soukromými třídními poli. -For example, `getName()` method accesses the private `#name` property and breaks after proxying: +Například metoda `vraťJméno()` přistupuje k soukromé vlastnosti `#jméno` a po proxování se rozbije: ```js run -class User { - #name = "Guest"; +class Uživatel { + #jméno = "Host"; - getName() { - return this.#name; + vraťJméno() { + return this.#jméno; } } -let user = new User(); +let uživatel = new Uživatel(); -user = new Proxy(user, {}); +uživatel = new Proxy(uživatel, {}); *!* -alert(user.getName()); // Error +alert(uživatel.vraťJméno()); // Chyba */!* ``` -The reason is that private fields are implemented using internal slots. JavaScript does not use `[[Get]]/[[Set]]` when accessing them. +Důvodem je, že soukromá pole jsou implementována pomocí interních slotů. Při přístupu k nim JavaScript nepoužívá `[[Get]]/[[Set]]`. -In the call `getName()` the value of `this` is the proxied `user`, and it doesn't have the slot with private fields. +Při volání `vraťJméno()` je hodnota `this` proxovaný `uživatel`, který neobsahuje slot se soukromými poli. -Once again, the solution with binding the method makes it work: +Opět to opraví řešení s navázáním metody: ```js run -class User { - #name = "Guest"; +class Uživatel { + #jméno = "Host"; - getName() { - return this.#name; + vraťJméno() { + return this.#jméno; } } -let user = new User(); +let uživatel = new Uživatel(); -user = new Proxy(user, { - get(target, prop, receiver) { - let value = Reflect.get(...arguments); - return typeof value == 'function' ? value.bind(target) : value; +uživatel = new Proxy(uživatel, { + get(cíl, vlastnost, příjemce) { + let hodnota = Reflect.get(...arguments); + return typeof hodnota == 'function' ? hodnota.bind(cíl) : hodnota; } }); -alert(user.getName()); // Guest +alert(uživatel.vraťJméno()); // Host ``` -That said, the solution has drawbacks, as explained previously: it exposes the original object to the method, potentially allowing it to be passed further and breaking other proxied functionality. +Při tom všem však toto řešení má nevýhody, jak bylo vysvětleno dříve: vystaví metodě původní objekt, čímž umožní, aby byl předáván dál a rozbíjel ostatní proxovanou funkcionalitu. -### Proxy != target +### Proxy != cíl -The proxy and the original object are different objects. That's natural, right? +Proxovaný a původní objekt jsou různé objekty. To je přirozené, ne? -So if we use the original object as a key, and then proxy it, then the proxy can't be found: +Když tedy použijeme původní objekt jako klíč a pak jej naproxujeme, proxovaný objekt nebude nalezen: ```js run -let allUsers = new Set(); +let všichniUživatelé = new Set(); -class User { - constructor(name) { - this.name = name; - allUsers.add(this); +class Uživatel { + constructor(jméno) { + this.jméno = jméno; + všichniUživatelé.add(this); } } -let user = new User("John"); +let uživatel = new Uživatel("Jan"); -alert(allUsers.has(user)); // true +alert(všichniUživatelé.has(uživatel)); // true -user = new Proxy(user, {}); +uživatel = new Proxy(uživatel, {}); *!* -alert(allUsers.has(user)); // false +alert(všichniUživatelé.has(uživatel)); // false */!* ``` -As we can see, after proxying we can't find `user` in the set `allUsers`, because the proxy is a different object. +Jak vidíme, po naproxování nenajdeme objekt `uživatel` v množině `všichniUživatelé`, jelikož proxovaný objekt je jiný. -```warn header="Proxies can't intercept a strict equality test `===`" -Proxies can intercept many operators, such as `new` (with `construct`), `in` (with `has`), `delete` (with `deleteProperty`) and so on. +```warn header="Proxy nezachycují test striktní rovnosti `===`" +Proxy mohou zachytit mnoho operátorů, např. `new` (pomocí `construct`), `in` (pomocí `has`), `delete` (pomocí `deleteProperty`) a tak dále. -But there's no way to intercept a strict equality test for objects. An object is strictly equal to itself only, and no other value. +Neexistuje však žádný způsob, jak zachytit test striktní rovnosti objektů. Objekt je striktně roven pouze sám sobě a žádné jiné hodnotě. -So all operations and built-in classes that compare objects for equality will differentiate between the object and the proxy. No transparent replacement here. +Všechny operace a vestavěné třídy, které porovnávají objekty, tedy budou rozlišovat mezi objektem a jeho proxy. Tady neexistuje žádná průhledná náhrada. ``` -## Revocable proxies +## Zrušitelné proxy -A *revocable* proxy is a proxy that can be disabled. +*Zrušitelná* proxy je proxy, která může být zakázána. -Let's say we have a resource, and would like to close access to it any moment. +Řekněme, že máme zdroj a chtěli bychom k němu kdykoli uzavřít přístup. -What we can do is to wrap it into a revocable proxy, without any traps. Such a proxy will forward operations to object, and we can disable it at any moment. +Můžeme to udělat tak, že jej obalíme do zrušitelné proxy bez jakýchkoli pastí. Taková proxy pak bude předávat objektu operace a my ji budeme moci kdykoli zakázat. -The syntax is: +Syntaxe je: ```js -let {proxy, revoke} = Proxy.revocable(target, handler) +let {proxy, revoke} = Proxy.revocable(cíl, handler) ``` -The call returns an object with the `proxy` and `revoke` function to disable it. +Toto volání vrátí objekt s `proxy` a funkci `revoke`, která tuto proxy zakáže. -Here's an example: +Zde je příklad: ```js run -let object = { - data: "Valuable data" +let objekt = { + data: "Cenná data" }; -let {proxy, revoke} = Proxy.revocable(object, {}); +let {proxy, revoke} = Proxy.revocable(objekt, {}); -// pass the proxy somewhere instead of object... -alert(proxy.data); // Valuable data +// předáme někam proxy místo objektu... +alert(proxy.data); // Cenná data -// later in our code +// později v našem kódu revoke(); -// the proxy isn't working any more (revoked) -alert(proxy.data); // Error +// proxy nadále nefunguje (je zakázána) +alert(proxy.data); // Chyba ``` -A call to `revoke()` removes all internal references to the target object from the proxy, so they are no longer connected. +Volání `revoke()` odstraní z proxy veškeré interní odkazy na cílový objekt, takže již nebudou propojeny. -Initially, `revoke` is separate from `proxy`, so that we can pass `proxy` around while leaving `revoke` in the current scope. +Na začátku je `revoke` od `proxy` odděleno, takže můžeme předávat `proxy` dále, zatímco `revoke` zůstane v aktuálním rozsahu platnosti. -We can also bind `revoke` method to proxy by setting `proxy.revoke = revoke`. +Můžeme také metodu `revoke` navázat na proxy nastavením `proxy.revoke = revoke`. -Another option is to create a `WeakMap` that has `proxy` as the key and the corresponding `revoke` as the value, that allows to easily find `revoke` for a proxy: +Další možností je vytvořit `WeakMap`, která obsahuje `proxy` jako klíč a odpovídající metodu `revoke` jako hodnotu, což nám umožní snadno najít `revoke` pro požadovanou proxy: ```js run *!* -let revokes = new WeakMap(); +let zákazy = new WeakMap(); */!* -let object = { - data: "Valuable data" +let objekt = { + data: "Cenná data" }; -let {proxy, revoke} = Proxy.revocable(object, {}); +let {proxy, revoke} = Proxy.revocable(objekt, {}); -revokes.set(proxy, revoke); +zákazy.set(proxy, revoke); -// ..somewhere else in our code.. -revoke = revokes.get(proxy); +// ..někde jinde v našem kódu.. +revoke = zákazy.get(proxy); revoke(); -alert(proxy.data); // Error (revoked) +alert(proxy.data); // Chyba (zakázáno) ``` -We use `WeakMap` instead of `Map` here because it won't block garbage collection. If a proxy object becomes "unreachable" (e.g. no variable references it any more), `WeakMap` allows it to be wiped from memory together with its `revoke` that we won't need any more. +Zde používáme `WeakMap` místo `Map`, protože neblokuje sběr odpadků. Pokud se proxovaný objekt stane „nedosažitelným“ (např. protože na něj už nebude odkazovat žádná proměnná), `WeakMap` umožní, aby byl odstraněn z paměti spolu s jeho metodou `revoke`, která už nadále nebude zapotřebí. -## References +## Odkazy -- Specification: [Proxy](https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots). +- Specifikace: [Proxy](https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots). - MDN: [Proxy](mdn:/JavaScript/Reference/Global_Objects/Proxy). -## Summary +## Shrnutí -`Proxy` is a wrapper around an object, that forwards operations on it to the object, optionally trapping some of them. +`Proxy` je obal okolo objektu, který objektu předává operace na něm prováděné a může některé z nich zachytit. -It can wrap any kind of object, including classes and functions. +Může obalit objekt jakéhokoli druhu včetně tříd a funkcí. -The syntax is: +Syntaxe je: ```js -let proxy = new Proxy(target, { - /* traps */ +let proxy = new Proxy(cíl, { + /* pasti */ }); ``` -...Then we should use `proxy` everywhere instead of `target`. A proxy doesn't have its own properties or methods. It traps an operation if the trap is provided, otherwise forwards it to `target` object. +...Pak můžeme všude používat `proxy` místo objektu `cíl`. Proxy nemá své vlastní vlastnosti nebo metody. Jestliže mu je poskytnuta past, zachytí příslušnou operaci, jinak ji předá objektu `cíl`. -We can trap: -- Reading (`get`), writing (`set`), deleting (`deleteProperty`) a property (even a non-existing one). -- Calling a function (`apply` trap). -- The `new` operator (`construct` trap). -- Many other operations (the full list is at the beginning of the article and in the [docs](mdn:/JavaScript/Reference/Global_Objects/Proxy)). +Můžeme zachytávat: +- Čtení (`get`), zápis (`set`), mazání (`deleteProperty`) vlastnosti (i neexistující). +- Volání funkce (past `apply`). +- Operátor `new` (past `construct`). +- Mnoho dalších operací (jejich úplný seznam je na začátku tohoto článku a v [dokumentaci](mdn:/JavaScript/Reference/Global_Objects/Proxy)). -That allows us to create "virtual" properties and methods, implement default values, observable objects, function decorators and so much more. +To nám umožňuje vytvářet „virtuální“ vlastnosti a metody, implementovat výchozí hodnoty, pozorovatelné objekty, dekorátory funkcí a mnoho dalšího. -We can also wrap an object multiple times in different proxies, decorating it with various aspects of functionality. +Můžeme také obalit objekt vícekrát do různých proxy a dekorovat jej tak různými aspekty funkcionality. -The [Reflect](mdn:/JavaScript/Reference/Global_Objects/Reflect) API is designed to complement [Proxy](mdn:/JavaScript/Reference/Global_Objects/Proxy). For any `Proxy` trap, there's a `Reflect` call with same arguments. We should use those to forward calls to target objects. +API [Reflect](mdn:/JavaScript/Reference/Global_Objects/Reflect) je navrženo k doplnění [Proxy](mdn:/JavaScript/Reference/Global_Objects/Proxy). Pro každou past `Proxy` existuje v `Reflect` odpovídající metoda se stejnými argumenty. K předávání volání cílovým objektům bychom měli používat tyto metody. -Proxies have some limitations: +Proxy mají určitá omezení: -- Built-in objects have "internal slots", access to those can't be proxied. See the workaround above. -- The same holds true for private class fields, as they are internally implemented using slots. So proxied method calls must have the target object as `this` to access them. -- Object equality tests `===` can't be intercepted. -- Performance: benchmarks depend on an engine, but generally accessing a property using a simplest proxy takes a few times longer. In practice that only matters for some "bottleneck" objects though. +- Vestavěné objekty mají „interní sloty“ a přístup k nim nemůže být proxován. Viz výše. +- Totéž platí pro soukromá třídní pole, protože ta jsou vnitřně implementována pomocí slotů. Volání proxovaných metod tedy musí nastavovat cílový objekt jako `this`, aby se k nim dalo přistupovat. +- Nelze zachytávat testy rovnosti objektů `===`. +- Výkon: výsledky benchmarků závisejí na motoru, ale obecně přístup k vlastnosti i přes tu nejjednodušší proxy trvá několikrát déle. V praxi na tom však záleží jen u některých objektů, které tvoří „úzké hrdlo“. diff --git a/1-js/99-js-misc/01-proxy/proxy-inherit-admin.svg b/1-js/99-js-misc/01-proxy/proxy-inherit-admin.svg index 3fba64606..dd874ebff 100644 --- a/1-js/99-js-misc/01-proxy/proxy-inherit-admin.svg +++ b/1-js/99-js-misc/01-proxy/proxy-inherit-admin.svg @@ -1 +1 @@ -_name: "Guest" name: getter_name: "Admin"user (proxied)original useradmin[[Prototype]] \ No newline at end of file +_name: "Guest" name: getter_name: "Admin"uživatel (proxy)původní uživateladmin[[Prototype]] \ No newline at end of file diff --git a/1-js/99-js-misc/01-proxy/proxy-inherit.svg b/1-js/99-js-misc/01-proxy/proxy-inherit.svg index 6c34c0f4e..aba6236dc 100644 --- a/1-js/99-js-misc/01-proxy/proxy-inherit.svg +++ b/1-js/99-js-misc/01-proxy/proxy-inherit.svg @@ -1 +1 @@ -_name: "Guest" name: getteruser (proxied)original user \ No newline at end of file +_name: "Guest" name: getteruživatel (proxy)původní uživatel \ No newline at end of file diff --git a/1-js/99-js-misc/01-proxy/proxy.svg b/1-js/99-js-misc/01-proxy/proxy.svg index 6b2224cfd..e5be89480 100644 --- a/1-js/99-js-misc/01-proxy/proxy.svg +++ b/1-js/99-js-misc/01-proxy/proxy.svg @@ -1 +1 @@ -test: 5proxytargetget proxy.test5 \ No newline at end of file +test: 5proxycílget proxy.test5 \ No newline at end of file diff --git a/1-js/99-js-misc/02-eval/1-eval-calculator/solution.md b/1-js/99-js-misc/02-eval/1-eval-calculator/solution.md index 24d40c9b8..bc2b13830 100644 --- a/1-js/99-js-misc/02-eval/1-eval-calculator/solution.md +++ b/1-js/99-js-misc/02-eval/1-eval-calculator/solution.md @@ -1,11 +1,11 @@ -Let's use `eval` to calculate the maths expression: +K výpočtu matematického výrazu použijme `eval`: ```js demo run -let expr = prompt("Type an arithmetic expression?", '2*3+2'); +let výraz = prompt("Zadejte aritmetický výraz:", '2*3+2'); -alert( eval(expr) ); +alert( eval(výraz) ); ``` -The user can input any text or code though. +Uživatel však může zadat libovolný text nebo kód. -To make things safe, and limit it to arithmetics only, we can check the `expr` using a [regular expression](info:regular-expressions), so that it only may contain digits and operators. +Abychom všechno zabezpečili a omezili se jen na aritmetiku, můžeme zkontrolovat `výraz` pomocí [regulárního výrazu](info:regular-expressions), aby směl obsahovat jen číslice a operátory. diff --git a/1-js/99-js-misc/02-eval/1-eval-calculator/task.md b/1-js/99-js-misc/02-eval/1-eval-calculator/task.md index ece43ec9e..74d2de238 100644 --- a/1-js/99-js-misc/02-eval/1-eval-calculator/task.md +++ b/1-js/99-js-misc/02-eval/1-eval-calculator/task.md @@ -2,10 +2,10 @@ importance: 4 --- -# Eval-calculator +# Kalkulátor -Create a calculator that prompts for an arithmetic expression and returns its result. +Vytvořte kalkulátor, který se zeptá na aritmetický výraz a vrátí jeho výsledek. -There's no need to check the expression for correctness in this task. Just evaluate and return the result. +V této úloze není třeba ověřovat správnost výrazu. Jenom ho vyhodnoťte a vraťte výsledek. [demo] diff --git a/1-js/99-js-misc/02-eval/article.md b/1-js/99-js-misc/02-eval/article.md index 1fdafeeec..86a718b48 100644 --- a/1-js/99-js-misc/02-eval/article.md +++ b/1-js/99-js-misc/02-eval/article.md @@ -1,36 +1,36 @@ -# Eval: run a code string +# Eval: spuštění řetězce kódu -The built-in `eval` function allows to execute a string of code. +Zabudovaná funkce `eval` nám umožňuje spustit řetězec kódu. -The syntax is: +Syntaxe je: ```js -let result = eval(code); +let výsledek = eval(kód); ``` -For example: +Například: ```js run -let code = 'alert("Hello")'; -eval(code); // Hello +let kód = 'alert("Ahoj")'; +eval(kód); // Ahoj ``` -A string of code may be long, contain line breaks, function declarations, variables and so on. +Řetězec kódu může být dlouhý, může obsahovat konce řádku, deklarace funkcí, proměnné a podobně. -The result of `eval` is the result of the last statement. +Výsledkem funkce `eval` je výsledek posledního příkazu. -For example: +Příklad: ```js run -let value = eval('1+1'); -alert(value); // 2 +let hodnota = eval('1+1'); +alert(hodnota); // 2 ``` ```js run -let value = eval('let i = 0; ++i'); -alert(value); // 1 +let hodnota = eval('let i = 0; ++i'); +alert(hodnota); // 1 ``` -The eval'ed code is executed in the current lexical environment, so it can see outer variables: +Vyhodnocovaný kód je spouštěn v aktuálním lexikálním prostředí, takže vidí vnější proměnné: ```js run no-beautify let a = 1; @@ -46,56 +46,56 @@ function f() { f(); ``` -It can change outer variables as well: +Může vnější proměnné také měnit: ```js untrusted refresh run let x = 5; eval("x = 10"); -alert(x); // 10, value modified +alert(x); // 10, hodnota změněna ``` -In strict mode, `eval` has its own lexical environment. So functions and variables, declared inside eval, are not visible outside: +Ve striktním režimu má `eval` své vlastní lexikální prostředí, takže funkce a proměnné deklarované uvnitř `eval` nejsou viditelné venku: ```js untrusted refresh run -// reminder: 'use strict' is enabled in runnable examples by default +// pamatujte: 'use strict' je ve spustitelných příkladech standardně zapnuté eval("let x = 5; function f() {}"); -alert(typeof x); // undefined (no such variable) -// function f is also not visible +alert(typeof x); // undefined (taková proměnná neexistuje) +// funkce f rovněž není viditelná ``` -Without `use strict`, `eval` doesn't have its own lexical environment, so we would see `x` and `f` outside. +Bez `use strict` nemá `eval` své vlastní lexikální prostředí, takže bychom `x` a `f` venku viděli. -## Using "eval" +## Použití „eval“ -In modern programming `eval` is used very sparingly. It's often said that "eval is evil". +V moderním programování se `eval` používá velmi vzácně. Často se říká, že „eval je zlo“ *(anglicky „eval is evil“ -- pozn. překl.)*. -The reason is simple: long, long time ago JavaScript was a much weaker language, many things could only be done with `eval`. But that time passed a decade ago. +Důvod je jednoduchý: před dávnými, dávnými časy býval JavaScript mnohem slabší jazyk a mnoho věcí bylo možné provést jedině pomocí `eval`. Ale tahle doba pominula už před deseti lety. -Right now, there's almost no reason to use `eval`. If someone is using it, there's a good chance they can replace it with a modern language construct or a [JavaScript Module](info:modules). +V současnosti není téměř žádný důvod, proč `eval` používat. Pokud ho někdo používá, je velká šance, že se dá nahradit nějakou moderní jazykovou konstrukcí nebo [JavaScriptovým modulem](info:modules). -Please note that its ability to access outer variables has side-effects. +Prosíme všimněte si, že jeho schopnost přistupovat k vnějším proměnným má vedlejší efekty. -Code minifiers (tools used before JS gets to production, to compress it) rename local variables into shorter ones (like `a`, `b` etc) to make the code smaller. That's usually safe, but not if `eval` is used, as local variables may be accessed from eval'ed code string. So minifiers don't do that renaming for all variables potentially visible from `eval`. That negatively affects code compression ratio. +Minifikátory kódu (nástroje používané před odesláním JS do produkce, aby jej zkomprimovaly) přejmenovávají lokální proměnné na kratší (např. `a`, `b` atd.), aby kód zkrátily. To je obvykle bezpečné, ale při použití `eval` ne, protože vyhodnocovaný řetězec kódu může k lokálním proměnným přistupovat. Minifikátory tedy toto přejmenování neprovádějí u proměnných, které mohou být viditelné z `eval`. To negativně ovlivňuje poměr komprese kódu. -Using outer local variables inside `eval` is also considered a bad programming practice, as it makes maintaining the code more difficult. +Rovněž používání vnějších lokálních proměnných uvnitř `eval` se považuje za špatnou programátorskou praktiku, protože ztěžuje údržbu kódu. -There are two ways how to be totally safe from such problems. +Existují dva způsoby, jak být před takovými problémy zcela v bezpečí. -**If eval'ed code doesn't use outer variables, please call `eval` as `window.eval(...)`:** +**Jestliže vyhodnocovaný kód nepoužívá vnější proměnné, prosíme volejte `eval` jako `window.eval(...)`:** -This way the code is executed in the global scope: +Tímto způsobem bude kód spuštěn v globálním rozsahu platnosti: ```js untrusted refresh run let x = 1; { let x = 5; - window.eval('alert(x)'); // 1 (global variable) + window.eval('alert(x)'); // 1 (globální proměnná) } ``` -**If eval'ed code needs local variables, change `eval` to `new Function` and pass them as arguments:** +**Jestliže vyhodnocovaný kód potřebuje lokální proměnné, změňte `eval` na `new Function` a předejte je jako argumenty:** ```js run let f = new Function('a', 'alert(a)'); @@ -103,12 +103,12 @@ let f = new Function('a', 'alert(a)'); f(5); // 5 ``` -The `new Function` construct is explained in the chapter . It creates a function from a string, also in the global scope. So it can't see local variables. But it's so much clearer to pass them explicitly as arguments, like in the example above. +Konstrukce `new Function` je vysvětlena v kapitole . Vytvoří funkci z řetězce, rovněž v globálním rozsahu platnosti. Funkce tedy neuvidí lokální proměnné. Je však mnohem čistší předat je explicitně jako argumenty, tak jako v uvedeném příkladu. -## Summary +## Shrnutí -A call to `eval(code)` runs the string of code and returns the result of the last statement. -- Rarely used in modern JavaScript, as there's usually no need. -- Can access outer local variables. That's considered bad practice. -- Instead, to `eval` the code in the global scope, use `window.eval(code)`. -- Or, if your code needs some data from the outer scope, use `new Function` and pass it as arguments. +Volání `eval(kód)` spustí řetězec kódu a vrátí výsledek posledního příkazu. +- V moderním JavaScriptu se používá málokdy, jelikož obvykle není zapotřebí. +- Může přistupovat k vnějším lokálním proměnným. To se považuje za špatnou praktiku. +- Místo toho k vyhodnocení kódu v globálním rozsahu platnosti použijte `window.eval(kód)`. +- Nebo, jestliže váš kód potřebuje data z vnějšího rozsahu, použijte `new Function` a předejte je jako argumenty. \ No newline at end of file diff --git a/1-js/99-js-misc/03-currying-partials/article.md b/1-js/99-js-misc/03-currying-partials/article.md index d71ac23f8..4057774f8 100644 --- a/1-js/99-js-misc/03-currying-partials/article.md +++ b/1-js/99-js-misc/03-currying-partials/article.md @@ -5,19 +5,19 @@ libs: # Currying -[Currying](https://en.wikipedia.org/wiki/Currying) is an advanced technique of working with functions. It's used not only in JavaScript, but in other languages as well. +[Currying neboli curryování](https://en.wikipedia.org/wiki/Currying) je pokročilá technika práce s funkcemi. Používá se nejen v JavaScriptu, ale i v jiných jazycích. -Currying is a transformation of functions that translates a function from callable as `f(a, b, c)` into callable as `f(a)(b)(c)`. +Currying je transformace funkce, která přeloží funkci volatelnou způsobem `f(a, b, c)` na volatelnou způsobem `f(a)(b)(c)`. -Currying doesn't call a function. It just transforms it. +Currying nevolá funkci, jen ji transformuje. -Let's see an example first, to better understand what we're talking about, and then practical applications. +Nejprve se podívejme na příklad, abychom lépe porozuměli tomu, o čem se tady mluví, a pak na praktické aplikace. -We'll create a helper function `curry(f)` that performs currying for a two-argument `f`. In other words, `curry(f)` for two-argument `f(a, b)` translates it into a function that runs as `f(a)(b)`: +Vytvořme pomocnou funkci `curry(f)`, která provádí currying dvouargumentové funkce `f`. Jinými slovy, `curry(f)` na dvouargumentové funkci `f(a, b)` ji přeloží na funkci, která se bude spouštět jako `f(a)(b)`: ```js run *!* -function curry(f) { // curry(f) does the currying transform +function curry(f) { // curry(f) provede curryingovou transformaci return function(a) { return function(b) { return f(a, b); @@ -26,104 +26,104 @@ function curry(f) { // curry(f) does the currying transform } */!* -// usage -function sum(a, b) { +// použití +function součet(a, b) { return a + b; } -let curriedSum = curry(sum); +let curryovanýSoučet = curry(součet); -alert( curriedSum(1)(2) ); // 3 +alert( curryovanýSoučet(1)(2) ); // 3 ``` -As you can see, the implementation is straightforward: it's just two wrappers. +Jak vidíte, implementace je přímočará: jsou to pouhé dva wrappery. -- The result of `curry(func)` is a wrapper `function(a)`. -- When it is called like `curriedSum(1)`, the argument is saved in the Lexical Environment, and a new wrapper is returned `function(b)`. -- Then this wrapper is called with `2` as an argument, and it passes the call to the original `sum`. +- Výsledkem `curry(func)` je wrapper `function(a)`. +- Když je zavolán způsobem `curryovanýSoučet(1)`, argument se uloží do lexikálního prostředí a vrátí se nový wrapper `function(b)`. +- Pak je tento wrapper volán s argumentem `2` a předá volání původní funkci `součet`. -More advanced implementations of currying, such as [_.curry](https://lodash.com/docs#curry) from lodash library, return a wrapper that allows a function to be called both normally and partially: +Pokročilejší implementace curryingu, např. [_.curry](https://lodash.com/docs#curry) z knihovny lodash, vrátí wrapper, který umožní, aby funkce mohla být volána jak normálně, tak parciálně: ```js run -function sum(a, b) { +function součet(a, b) { return a + b; } -let curriedSum = _.curry(sum); // using _.curry from lodash library +let curryovanýSoučet = _.curry(součet); // použijeme _.curry z knihovny lodash -alert( curriedSum(1, 2) ); // 3, still callable normally -alert( curriedSum(1)(2) ); // 3, called partially +alert( curryovanýSoučet(1, 2) ); // 3, stále volatelná normálně +alert( curryovanýSoučet(1)(2) ); // 3, voláno parciálně ``` -## Currying? What for? +## Currying? K čemu to je? -To understand the benefits we need a worthy real-life example. +Abychom pochopili výhody, potřebujeme cenný příklad z reálného života. -For instance, we have the logging function `log(date, importance, message)` that formats and outputs the information. In real projects such functions have many useful features like sending logs over the network, here we'll just use `alert`: +Mějme například logovací funkci `log(datum, důležitost, zpráva)`, která naformátuje a vypíše informaci. Ve skutečných projektech mají takové funkce mnoho užitečných možností, např. posílání logů po síti, zde jenom zavoláme `alert`: ```js -function log(date, importance, message) { - alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`); +function log(datum, důležitost, zpráva) { + alert(`[${datum.getHours()}:${datum.getMinutes()}] [${důležitost}] ${zpráva}`); } ``` -Let's curry it! +Zcurryujme ji! ```js log = _.curry(log); ``` -After that `log` works normally: +Pak bude `log` fungovat normálně: ```js -log(new Date(), "DEBUG", "some debug"); // log(a, b, c) +log(new Date(), "DEBUG", "nějaký debug"); // log(a, b, c) ``` -...But also works in the curried form: +...Ale bude fungovat i v curryované formě: ```js -log(new Date())("DEBUG")("some debug"); // log(a)(b)(c) +log(new Date())("DEBUG")("nějaký debug"); // log(a)(b)(c) ``` -Now we can easily make a convenience function for current logs: +Nyní můžeme snadno vytvořit pohodlnou funkci pro aktuální logování: ```js -// logNow will be the partial of log with fixed first argument -let logNow = log(new Date()); +// logNyní bude parciální log s pevným prvním argumentem +let logNyní = log(new Date()); -// use it -logNow("INFO", "message"); // [HH:mm] INFO message +// použijeme ji +logNyní("INFO", "zpráva"); // [HH:mm] INFO zpráva ``` -Now `logNow` is `log` with fixed first argument, in other words "partially applied function" or "partial" for short. +Nyní `logNyní` je `log` s pevným prvním argumentem, jinými slovy „parciálně aplikovaná funkce“ nebo krátce „parciální funkce“. -We can go further and make a convenience function for current debug logs: +Můžeme jít dál a vytvořit pohodlnou funkci pro aktuální logování debugů: ```js -let debugNow = logNow("DEBUG"); +let debugNyní = logNyní("DEBUG"); -debugNow("message"); // [HH:mm] DEBUG message +debugNyní("zpráva"); // [HH:mm] DEBUG zpráva ``` -So: -1. We didn't lose anything after currying: `log` is still callable normally. -2. We can easily generate partial functions such as for today's logs. +Tedy: +1. Po curryingu nic neztratíme: `log` se stále dá volat normálně. +2. Můžeme snadno generovat parciální funkce, např. pro logování s dnešním datem. -## Advanced curry implementation +## Pokročilá implementace curryingu -In case you'd like to get in to the details, here's the "advanced" curry implementation for multi-argument functions that we could use above. +V případě, že byste chtěli zajít do detailů, zde je „pokročilá“ implementace curryingu pro víceargumentové funkce, kterou bychom mohli použít výše. -It's pretty short: +Je opravdu krátká: ```js -function curry(func) { +function curry(funkce) { - return function curried(...args) { - if (args.length >= func.length) { - return func.apply(this, args); + return function curryovaná(...args) { + if (args.length >= funkce.length) { + return funkce.apply(this, args); } else { return function(...args2) { - return curried.apply(this, args.concat(args2)); + return curryovaná.apply(this, args.concat(args2)); } } }; @@ -131,58 +131,58 @@ function curry(func) { } ``` -Usage examples: +Příklady použití: ```js -function sum(a, b, c) { +function součet(a, b, c) { return a + b + c; } -let curriedSum = curry(sum); +let curryovanýSoučet = curry(součet); -alert( curriedSum(1, 2, 3) ); // 6, still callable normally -alert( curriedSum(1)(2,3) ); // 6, currying of 1st arg -alert( curriedSum(1)(2)(3) ); // 6, full currying +alert( curryovanýSoučet(1, 2, 3) ); // 6, stále normálně volatelná +alert( curryovanýSoučet(1)(2,3) ); // 6, currying 1. argumentu +alert( curryovanýSoučet(1)(2)(3) ); // 6, úplný currying ``` -The new `curry` may look complicated, but it's actually easy to understand. +Nová funkce `curry` může vypadat komplikovaně, ale ve skutečnosti je snadné jí porozumět. -The result of `curry(func)` call is the wrapper `curried` that looks like this: +Výsledkem volání `curry(funkce)` je wrapper `curryovaná`, který vypadá takto: ```js -// func is the function to transform -function curried(...args) { - if (args.length >= func.length) { // (1) - return func.apply(this, args); +// funkce je funkce, která se má transformovat +function curryovaná(...args) { + if (args.length >= funkce.length) { // (1) + return funkce.apply(this, args); } else { return function(...args2) { // (2) - return curried.apply(this, args.concat(args2)); + return curryovaná.apply(this, args.concat(args2)); } } }; ``` -When we run it, there are two `if` execution branches: +Když ji spustíme, obsahuje dvě výkonové větve `if`: -1. If passed `args` count is the same or more than the original function has in its definition (`func.length`) , then just pass the call to it using `func.apply`. -2. Otherwise, get a partial: we don't call `func` just yet. Instead, another wrapper is returned, that will re-apply `curried` providing previous arguments together with the new ones. +1. Je-li počet předaných argumentů `args` stejný nebo větší, než v definici původní funkce (`funkce.length`), pak jí jen předáme volání pomocí `funkce.apply`. +2. V opačném případě získáme parciální funkci: ještě funkci `funkce` nebudeme volat. Místo toho se vrátí další wrapper, který znovu aplikuje funkci `curryovaná` a poskytne jí předchozí argumenty společně s novými. -Then, if we call it, again, we'll get either a new partial (if not enough arguments) or, finally, the result. +Když ji pak znovu zavoláme, získáme buď novou parciální funkci (nemáme-li ještě dost argumentů), nebo nakonec výsledek. -```smart header="Fixed-length functions only" -The currying requires the function to have a fixed number of arguments. +```smart header="Jen pro funkce s pevnou délkou" +Currying vyžaduje, aby funkce měla pevný počet argumentů. -A function that uses rest parameters, such as `f(...args)`, can't be curried this way. +Funkci, která používá zbytkové parametry, např. `f(...args)`, nelze tímto způsobem curryovat. ``` -```smart header="A little more than currying" -By definition, currying should convert `sum(a, b, c)` into `sum(a)(b)(c)`. +```smart header="Víc než jen currying" +Podle definice by currying měl převést `součet(a, b, c)` na `součet(a)(b)(c)`. -But most implementations of currying in JavaScript are advanced, as described: they also keep the function callable in the multi-argument variant. +Většina implementací curryingu v JavaScriptu je však pokročilá, jak bylo popsáno: udržují funkci volatelnou i ve víceargumentové variantě. ``` -## Summary +## Shrnutí -*Currying* is a transform that makes `f(a,b,c)` callable as `f(a)(b)(c)`. JavaScript implementations usually both keep the function callable normally and return the partial if the arguments count is not enough. +*Currying* je transformace, která umožní volat `f(a,b,c)` jako `f(a)(b)(c)`. Implementace v JavaScriptu obvykle současně ponechají funkci volatelnou normálně a vrátí parciální funkci, není-li poskytnuto dost argumentů. -Currying allows us to easily get partials. As we've seen in the logging example, after currying the three argument universal function `log(date, importance, message)` gives us partials when called with one argument (like `log(date)`) or two arguments (like `log(date, importance)`). +Currying nám umožní snadno získat parciální funkci. Jak jsme viděli v příkladu s logováním, univerzální tříargumentová funkce `log(datum, důležitost, zpráva)` nám po curryingu vydá parciální funkci, když je volána s jedním argumentem (např. `log(datum)`) nebo se dvěma argumenty (např. `log(datum, důležitost)`). diff --git a/1-js/99-js-misc/04-reference-type/2-check-syntax/solution.md b/1-js/99-js-misc/04-reference-type/2-check-syntax/solution.md index ba5d3bf04..d8e53fc03 100644 --- a/1-js/99-js-misc/04-reference-type/2-check-syntax/solution.md +++ b/1-js/99-js-misc/04-reference-type/2-check-syntax/solution.md @@ -1,37 +1,37 @@ -**Error**! +**Chyba!** -Try it: +Zkuste si to: ```js run -let user = { - name: "John", - go: function() { alert(this.name) } +let uživatel = { + jméno: "Jan", + jdi: function() { alert(this.jméno) } } -(user.go)() // error! +(uživatel.jdi)() // chyba! ``` -The error message in most browsers does not give us much of a clue about what went wrong. +Chybová zpráva ve většině prohlížečů nám nedává mnoho informací o tom, co bylo špatně. -**The error appears because a semicolon is missing after `user = {...}`.** +**Chyba se objevila proto, že za `uživatel = {...}` chybí středník.** -JavaScript does not auto-insert a semicolon before a bracket `(user.go)()`, so it reads the code like: +JavaScript automaticky nevloží středník před závorku `(uživatel.jdi)()`, takže přečte kód jako: ```js no-beautify -let user = { go:... }(user.go)() +let uživatel = { jdi:... }(uživatel.jdi)() ``` -Then we can also see that such a joint expression is syntactically a call of the object `{ go: ... }` as a function with the argument `(user.go)`. And that also happens on the same line with `let user`, so the `user` object has not yet even been defined, hence the error. +Pak také vidíme, že takový spojený výraz je syntakticky voláním objektu `{ jdi: ... }` jako funkce s argumentem `(uživatel.jdi)`. A to se také odehrává na stejném řádku jako `let uživatel`, takže objekt `uživatel` ještě ani nebyl definován, proto nastane chyba. -If we insert the semicolon, all is fine: +Jestliže vložíme středník, bude vše v pořádku: ```js run -let user = { - name: "John", - go: function() { alert(this.name) } +let uživatel = { + jméno: "Jan", + jdi: function() { alert(this.jméno) } }*!*;*/!* -(user.go)() // John +(uživatel.jdi)() // Jan ``` -Please note that parentheses around `(user.go)` do nothing here. Usually they setup the order of operations, but here the dot `.` works first anyway, so there's no effect. Only the semicolon thing matters. +Prosíme všimněte si, že závorky okolo `(uživatel.jdi)` tady nic nedělají. Obvykle nastavují pořadí operací, ale tady jako první zafunguje tečka `.` tak jako tak, takže závorky nemají žádný efekt. Vadí jenom chybějící středník. diff --git a/1-js/99-js-misc/04-reference-type/2-check-syntax/task.md b/1-js/99-js-misc/04-reference-type/2-check-syntax/task.md index f40d68735..927d801a6 100644 --- a/1-js/99-js-misc/04-reference-type/2-check-syntax/task.md +++ b/1-js/99-js-misc/04-reference-type/2-check-syntax/task.md @@ -2,18 +2,18 @@ importance: 2 --- -# Syntax check +# Syntaktická kontrola -What is the result of this code? +Jaký je výsledek tohoto kódu? ```js no-beautify -let user = { - name: "John", - go: function() { alert(this.name) } +let uživatel = { + jméno: "Jan", + jdi: function() { alert(this.jméno) } } -(user.go)() +(uživatel.jdi)() ``` -P.S. There's a pitfall :) +P.S. Je tady chyták :) diff --git a/1-js/99-js-misc/04-reference-type/3-why-this/solution.md b/1-js/99-js-misc/04-reference-type/3-why-this/solution.md index e4ee78748..e8afcb837 100644 --- a/1-js/99-js-misc/04-reference-type/3-why-this/solution.md +++ b/1-js/99-js-misc/04-reference-type/3-why-this/solution.md @@ -1,22 +1,22 @@ -Here's the explanations. +Zde je vysvětlení. -1. That's a regular object method call. +1. Toto je běžné volání metody objektu. -2. The same, parentheses do not change the order of operations here, the dot is first anyway. +2. Totéž, závorky tady nezmění pořadí operací, tečka je i tak první. -3. Here we have a more complex call `(expression)()`. The call works as if it were split into two lines: +3. Zde máme složitější volání `(výraz)()`. Toto volání funguje tak, jako by bylo rozděleno na dva řádky: ```js no-beautify - f = obj.go; // calculate the expression - f(); // call what we have + f = obj.jdi; // vypočítáme výraz + f(); // zavoláme to, co máme ``` - Here `f()` is executed as a function, without `this`. + Zde se `f()` spustí jako funkce bez `this`. -4. The similar thing as `(3)`, to the left of the parentheses `()` we have an expression. +4. Podobně jako `(3)`, nalevo od závorek `()` máme výraz. -To explain the behavior of `(3)` and `(4)` we need to recall that property accessors (dot or square brackets) return a value of the Reference Type. +Abychom vysvětlili chování `(3)` a `(4)`, musíme si vzpomenout, že accessory vlastností (tečka nebo hranaté závorky) vracejí hodnotu referenčního typu. -Any operation on it except a method call (like assignment `=` or `||`) turns it into an ordinary value, which does not carry the information allowing to set `this`. +Jakákoli operace na ní kromě volání metody (např. přiřazení `=`, nebo `||`) ji změní na obyčejnou hodnotu, která neobsahuje informaci umožňující nastavit `this`. diff --git a/1-js/99-js-misc/04-reference-type/3-why-this/task.md b/1-js/99-js-misc/04-reference-type/3-why-this/task.md index e2c073f62..85ffb6dfd 100644 --- a/1-js/99-js-misc/04-reference-type/3-why-this/task.md +++ b/1-js/99-js-misc/04-reference-type/3-why-this/task.md @@ -2,25 +2,25 @@ importance: 3 --- -# Explain the value of "this" +# Vysvětlete hodnotu „this“ -In the code below we intend to call `obj.go()` method 4 times in a row. +V níže uvedeném kódu jsme zamýšleli volat metodu `obj.jdi()` čtyřikrát za sebou. -But calls `(1)` and `(2)` works differently from `(3)` and `(4)`. Why? +Avšak volání `(1)` a `(2)` fungují jinak než `(3)` a `(4)`. Proč? ```js run no-beautify -let obj, method; +let obj, metoda; obj = { - go: function() { alert(this); } + jdi: function() { alert(this); } }; -obj.go(); // (1) [object Object] +obj.jdi(); // (1) [object Object] -(obj.go)(); // (2) [object Object] +(obj.jdi)(); // (2) [object Object] -(method = obj.go)(); // (3) undefined +(metoda = obj.jdi)(); // (3) undefined -(obj.go || obj.stop)(); // (4) undefined +(obj.jdi || obj.stůj)(); // (4) undefined ``` diff --git a/1-js/99-js-misc/04-reference-type/article.md b/1-js/99-js-misc/04-reference-type/article.md index 894db8fc6..bab8dbc40 100644 --- a/1-js/99-js-misc/04-reference-type/article.md +++ b/1-js/99-js-misc/04-reference-type/article.md @@ -1,108 +1,108 @@ -# Reference Type +# Referenční typ -```warn header="In-depth language feature" -This article covers an advanced topic, to understand certain edge-cases better. +```warn header="Hloubková vlastnost jazyka" +Tento článek se zabývá pokročilým tématem, abychom lépe porozuměli určitým okrajovým případům. -It's not important. Many experienced developers live fine without knowing it. Read on if you want to know how things work under the hood. +Není důležité. Mnoho zkušených vývojářů žije šťastně i přesto, že je neznají. Přečtěte si ho, pokud chcete vědět, jak fungují věci „pod kapotou“. ``` -A dynamically evaluated method call can lose `this`. +Dynamicky vyhodnocované volání metody může ztratit `this`. -For instance: +Například: ```js run -let user = { - name: "John", - hi() { alert(this.name); }, - bye() { alert("Bye"); } +let uživatel = { + jméno: "Jan", + ahoj() { alert(this.jméno); }, + nashle() { alert("Nashle"); } }; -user.hi(); // works +uživatel.ahoj(); // funguje -// now let's call user.hi or user.bye depending on the name +// nyní zavolejme uživatel.ahoj nebo uživatel.nashle podle jména *!* -(user.name == "John" ? user.hi : user.bye)(); // Error! +(uživatel.jméno == "Jan" ? uživatel.ahoj : uživatel.nashle)(); // Chyba! */!* ``` -On the last line there is a conditional operator that chooses either `user.hi` or `user.bye`. In this case the result is `user.hi`. +Na posledním řádku je podmíněný operátor, který vybere buď `uživatel.ahoj`, nebo `uživatel.nashle`. V tomto případě je výsledek `uživatel.ahoj`. -Then the method is immediately called with parentheses `()`. But it doesn't work correctly! +Pak je tato metoda okamžitě volána pomocí závorek `()`. Ale nefunguje to správně! -As you can see, the call results in an error, because the value of `"this"` inside the call becomes `undefined`. +Jak vidíte, výsledkem volání je chyba, protože hodnota `"this"` uvnitř volání se stala `undefined`. -This works (object dot method): +Tohle funguje (objekt tečka metoda): ```js -user.hi(); +uživatel.ahoj(); ``` -This doesn't (evaluated method): +Tohle ne (vyhodnocená metoda): ```js -(user.name == "John" ? user.hi : user.bye)(); // Error! +(uživatel.jméno == "Jan" ? uživatel.ahoj : uživatel.nashle)(); // Chyba! ``` -Why? If we want to understand why it happens, let's get under the hood of how `obj.method()` call works. +Proč? Chceme-li porozumět, proč se to děje, podívejme se na zoubek tomu, jak funguje volání `obj.metoda()`. -## Reference type explained +## Vysvětlení referenčního typu -Looking closely, we may notice two operations in `obj.method()` statement: +Když se podíváme pozorněji, můžeme si v příkazu `obj.metoda()` všimnout dvou operací: -1. First, the dot `'.'` retrieves the property `obj.method`. -2. Then parentheses `()` execute it. +1. Nejprve tečka `'.'` získá vlastnost `obj.metoda`. +2. Pak ji závorky `()` spustí. -So, how does the information about `this` get passed from the first part to the second one? +Jak se tedy informace o `this` předá z první části do druhé? -If we put these operations on separate lines, then `this` will be lost for sure: +Umístíme-li tyto operace na samostatné řádky, pak bude `this` zcela jistě ztraceno: ```js run -let user = { - name: "John", - hi() { alert(this.name); } -}; +let uživatel = { + jméno: "Jan", + ahoj() { alert(this.jméno); } +} *!* -// split getting and calling the method in two lines -let hi = user.hi; -hi(); // Error, because this is undefined +// rozdělíme získání a volání metody na dva řádky +let ahoj = uživatel.ahoj; +ahoj(); // Chyba, protože this je undefined */!* ``` -Here `hi = user.hi` puts the function into the variable, and then on the last line it is completely standalone, and so there's no `this`. +Zde `ahoj = uživatel.ahoj` vloží funkci do proměnné a ta je pak na posledním řádku zcela samostatná, takže tam není žádné `this`. -**To make `user.hi()` calls work, JavaScript uses a trick -- the dot `'.'` returns not a function, but a value of the special [Reference Type](https://tc39.github.io/ecma262/#sec-reference-specification-type).** +**Aby volání `uživatel.ahoj()` fungovalo, JavaScript používá trik -- tečka `'.'` nevrací funkci, ale hodnotu speciálního [referenčního typu](https://tc39.github.io/ecma262/#sec-reference-specification-type).** -The Reference Type is a "specification type". We can't explicitly use it, but it is used internally by the language. +Referenční typ je „specifikační typ“. Nemůžeme jej explicitně používat, ale je používán interně jazykem. -The value of Reference Type is a three-value combination `(base, name, strict)`, where: +Hodnotou referenčního typu je tříhodnotová kombinace `(base, name, strict)`, kde: -- `base` is the object. -- `name` is the property name. -- `strict` is true if `use strict` is in effect. +- `base` (základ) je objekt. +- `name` (název) je název vlastnosti. +- `strict` je true, pokud je použito `use strict`. -The result of a property access `user.hi` is not a function, but a value of Reference Type. For `user.hi` in strict mode it is: +Výsledkem přístupu k vlastnosti `uživatel.ahoj` není funkce, ale hodnota referenčního typu. Pro `uživatel.ahoj` ve striktním režimu to je: ```js -// Reference Type value -(user, "hi", true) +// hodnota referenčního typu +(uživatel, "ahoj", true) ``` -When parentheses `()` are called on the Reference Type, they receive the full information about the object and its method, and can set the right `this` (`user` in this case). +Když se na referenčním typu zavolají závorky `()`, obdrží úplnou informaci o objektu a jeho metodě a mohou tedy nastavit správné `this` (v tomto případě `uživatel`). -Reference type is a special "intermediary" internal type, with the purpose to pass information from dot `.` to calling parentheses `()`. +Referenční typ je speciální „prostřednický“ interní typ, jehož účelem je předat informaci z tečky `.` volajícím závorkám `()`. -Any other operation like assignment `hi = user.hi` discards the reference type as a whole, takes the value of `user.hi` (a function) and passes it on. So any further operation "loses" `this`. +Jakákoli jiná operace, např. přiřazení `ahoj = uživatel.ahoj`, celý referenční typ zahodí, vezme hodnotu `uživatel.ahoj` (funkci) a předá ji dál. Jakákoli další operace tedy „ztratí“ `this`. -So, as the result, the value of `this` is only passed the right way if the function is called directly using a dot `obj.method()` or square brackets `obj['method']()` syntax (they do the same here). There are various ways to solve this problem such as [func.bind()](/bind#solution-2-bind). +Výsledkem tedy je, že hodnota `this` se předá správně jen tehdy, je-li funkce volána přímo syntaxí tečky `obj.metoda()` nebo hranatých závorek `obj['metoda']()` (obojí zde provádí totéž). Existují různé způsoby, jak tento problém vyřešit, např. [funkce.bind()](/bind#solution-2-bind). -## Summary +## Shrnutí -Reference Type is an internal type of the language. +Referenční typ je interní jazykový typ. -Reading a property, such as with dot `.` in `obj.method()` returns not exactly the property value, but a special "reference type" value that stores both the property value and the object it was taken from. +Načtení vlastnosti, např. pomocí tečky `.` v `obj.metoda()`, nevrací přesně hodnotu vlastnosti, ale speciální hodnotu „referenčního typu“, v níž je uložena jak hodnota vlastnosti, tak objekt, z něhož byla vzata. -That's for the subsequent method call `()` to get the object and set `this` to it. +To je proto, aby následné volání metody `()` mohlo získat objekt a nastavit jej jako `this`. -For all other operations, the reference type automatically becomes the property value (a function in our case). +Při všech ostatních operacích se z referenčního typu automaticky stává hodnota vlastnosti (v našem případě funkce). -The whole mechanics is hidden from our eyes. It only matters in subtle cases, such as when a method is obtained dynamically from the object, using an expression. +Celá tato mechanika je před našima očima ukryta. Záleží na ní jen v krajních případech, např. když je metoda dynamicky získána z objektu použitím výrazu. diff --git a/1-js/99-js-misc/05-bigint/article.md b/1-js/99-js-misc/05-bigint/article.md index 2a1cfc843..998bec9f5 100644 --- a/1-js/99-js-misc/05-bigint/article.md +++ b/1-js/99-js-misc/05-bigint/article.md @@ -2,21 +2,21 @@ [recent caniuse="bigint"] -`BigInt` is a special numeric type that provides support for integers of arbitrary length. +`BigInt` je speciální číselný typ, který poskytuje podporu celých čísel libovolné délky. -A bigint is created by appending `n` to the end of an integer literal or by calling the function `BigInt` that creates bigints from strings, numbers etc. +Číslo typu BigInt se vytvoří přidáním písmene `n` na konec celočíselného literálu nebo voláním funkce `BigInt`, která vytváří biginty z řetězců, čísel apod. ```js const bigint = 1234567890123456789012345678901234567890n; -const sameBigint = BigInt("1234567890123456789012345678901234567890"); +const stejnýBigint = BigInt("1234567890123456789012345678901234567890"); -const bigintFromNumber = BigInt(10); // same as 10n +const bigintZČísla = BigInt(10); // totéž jako 10n ``` -## Math operators +## Matematické operátory -`BigInt` can mostly be used like a regular number, for example: +`BigInt` lze většinou používat jako obvyklé číslo, například: ```js run alert(1n + 2n); // 3 @@ -24,44 +24,44 @@ alert(1n + 2n); // 3 alert(5n / 2n); // 2 ``` -Please note: the division `5/2` returns the result rounded towards zero, without the decimal part. All operations on bigints return bigints. +Prosíme všimněte si: dělení `5/2` vrací výsledek zaokrouhlený směrem k nule, bez desetinné části. Všechny operace na bigintech vracejí biginty. -We can't mix bigints and regular numbers: +Nemůžeme směšovat biginty a běžná čísla: ```js run -alert(1n + 2); // Error: Cannot mix BigInt and other types +alert(1n + 2); // Chyba: Nelze míchat dohromady BigInt a jiné typy ``` -We should explicitly convert them if needed: using either `BigInt()` or `Number()`, like this: +Když je potřeba, měli bychom je explicitně konvertovat: použitím buď `BigInt()`, nebo `Number()`, například: ```js run let bigint = 1n; -let number = 2; +let číslo = 2; -// number to bigint -alert(bigint + BigInt(number)); // 3 +// číslo na bigint +alert(bigint + BigInt(číslo)); // 3 -// bigint to number -alert(Number(bigint) + number); // 3 +// bigint na číslo +alert(Number(bigint) + číslo); // 3 ``` -The conversion operations are always silent, never give errors, but if the bigint is too huge and won't fit the number type, then extra bits will be cut off, so we should be careful doing such conversion. +Konverzní operace jsou vždy tiché a nikdy neohlásí chybu, ale je-li bigint příliš velký a nevejde se do číselného typu, budou přebývající bity odříznuty, takže bychom při takové konverzi měli být opatrní. -````smart header="The unary plus is not supported on bigints" -The unary plus operator `+value` is a well-known way to convert `value` to a number. +````smart header="Biginty nepodporují unární plus" +Operátor unárního plusu `+hodnota` je dobře známý způsob, jak převést hodnotu `hodnota` na číslo. -In order to avoid confusion, it's not supported on bigints: +Aby nedocházelo ke zmatkům, biginty jej nepodporují: ```js run let bigint = 1n; -alert( +bigint ); // error +alert( +bigint ); // chyba ``` -So we should use `Number()` to convert a bigint to a number. +Ke konverzi bigintu na číslo bychom tedy měli používat `Number()`. ```` -## Comparisons +## Porovnávání -Comparisons, such as `<`, `>` work with bigints and numbers just fine: +Porovnávání, např. `<`, `>`, fungují s biginty a čísly správně: ```js run alert( 2n > 1n ); // true @@ -69,7 +69,7 @@ alert( 2n > 1n ); // true alert( 2n > 1 ); // true ``` -Please note though, as numbers and bigints belong to different types, they can be equal `==`, but not strictly equal `===`: +Prosíme všimněte si však, že protože čísla a biginty patří k různým typům, mohou si být rovny `==`, ale ne striktně rovny `===`: ```js run alert( 1 == 1n ); // true @@ -77,54 +77,54 @@ alert( 1 == 1n ); // true alert( 1 === 1n ); // false ``` -## Boolean operations +## Booleovské operace -When inside `if` or other boolean operations, bigints behave like numbers. +Když jsme uvnitř `if` nebo jiných booleovských operací, biginty se chovají jako čísla. -For instance, in `if`, bigint `0n` is falsy, other values are truthy: +Například v `if` je bigint `0n` nepravdivý, ostatní hodnoty jsou pravdivé: ```js run if (0n) { - // never executes + // nikdy se nespustí } ``` -Boolean operators, such as `||`, `&&` and others also work with bigints similar to numbers: +Rovněž booleovské operátory, např. `||`, `&&` a jiné, fungují s biginty obdobně jako s čísly: ```js run -alert( 1n || 2 ); // 1 (1n is considered truthy) +alert( 1n || 2 ); // 1 (1n se považuje za pravdivé) -alert( 0n || 2 ); // 2 (0n is considered falsy) +alert( 0n || 2 ); // 2 (0n se považuje za nepravdivé) ``` -## Polyfills +## Polyfilly -Polyfilling bigints is tricky. The reason is that many JavaScript operators, such as `+`, `-` and so on behave differently with bigints compared to regular numbers. +Polyfillování bigintů je problematické. Příčinou je, že mnoho JavaScriptových operátorů, např. `+`, `-` a podobně, se chová na bigintech jinak oproti běžným číslům. -For example, division of bigints always returns a bigint (rounded if necessary). +Například dělení bigintů vrátí vždy bigint (zaokrouhlený, je-li to nutné). -To emulate such behavior, a polyfill would need to analyze the code and replace all such operators with its functions. But doing so is cumbersome and would cost a lot of performance. +Aby polyfill mohl takové chování emulovat, musel by analyzovat kód a nahradit všechny takové operátory svými funkcemi. Provést něco takového je však těžkopádné a značně by to snížilo výkon. -So, there's no well-known good polyfill. +Dosud tedy není dobře znám žádný dobrý polyfill. -Although, the other way around is proposed by the developers of [JSBI](https://github.com/GoogleChromeLabs/jsbi) library. +Jinou cestičku kolem ovšem nabízejí vývojáři knihovny [JSBI](https://github.com/GoogleChromeLabs/jsbi). -This library implements big numbers using its own methods. We can use them instead of native bigints: +Tato knihovna implementuje velká čísla svými vlastními metodami. Můžeme je používat místo nativních bigintů: -| Operation | native `BigInt` | JSBI | +| Operace | Nativní `BigInt` | JSBI | |-----------|-----------------|------| -| Creation from Number | `a = BigInt(789)` | `a = JSBI.BigInt(789)` | -| Addition | `c = a + b` | `c = JSBI.add(a, b)` | -| Subtraction | `c = a - b` | `c = JSBI.subtract(a, b)` | +| Vytvoření z čísla | `a = BigInt(789)` | `a = JSBI.BigInt(789)` | +| Sčítání | `c = a + b` | `c = JSBI.add(a, b)` | +| Odčítání | `c = a - b` | `c = JSBI.subtract(a, b)` | | ... | ... | ... | -...And then use the polyfill (Babel plugin) to convert JSBI calls to native bigints for those browsers that support them. +...A pak použít polyfill (plugin Babel) ke konverzi volání JSBI na nativní biginty pro prohlížeče, které je podporují. -In other words, this approach suggests that we write code in JSBI instead of native bigints. But JSBI works with numbers as with bigints internally, emulates them closely following the specification, so the code will be "bigint-ready". +Jinými slovy, tento přístup nám navrhuje, abychom místo používání nativních bigintů psali kód v JSBI. Avšak JSBI interně pracuje s čísly jako s biginty a emuluje je způsobem blízkým specifikaci, takže kód bude „připraven pro biginty“. -We can use such JSBI code "as is" for engines that don't support bigints and for those that do support - the polyfill will convert the calls to native bigints. +Takový kód s JSBI můžeme používat „tak, jak je“ na enginech, které biginty nepodporují, i na těch, které ano -- polyfill bude konvertovat volání na nativní biginty. -## References +## Odkazy -- [MDN docs on BigInt](mdn:/JavaScript/Reference/Global_Objects/BigInt). -- [Specification](https://tc39.es/ecma262/#sec-bigint-objects). +- [MDN dokumentace BigIntu](mdn:/JavaScript/Reference/Global_Objects/BigInt). +- [Specifikace](https://tc39.es/ecma262/#sec-bigint-objects). \ No newline at end of file diff --git a/1-js/99-js-misc/06-unicode/article.md b/1-js/99-js-misc/06-unicode/article.md index 4f144f824..11f813bc7 100644 --- a/1-js/99-js-misc/06-unicode/article.md +++ b/1-js/99-js-misc/06-unicode/article.md @@ -1,165 +1,166 @@ -# Unicode, String internals +# Unicode, interní reprezentace řetězce -```warn header="Advanced knowledge" -The section goes deeper into string internals. This knowledge will be useful for you if you plan to deal with emoji, rare mathematical or hieroglyphic characters, or other rare symbols. +```warn header="Pokročilá znalost" +Tato kapitola se hlouběji zabývá interní reprezentací řetězců. Tato znalost vám bude užitečná, jestliže plánujete pracovat s emoji, vzácnými matematickými nebo hieroglyfickými znaky nebo jinými vzácnými symboly. ``` -As we already know, JavaScript strings are based on [Unicode](https://en.wikipedia.org/wiki/Unicode): each character is represented by a byte sequence of 1-4 bytes. +Jak už víme, řetězce v JavaScriptu jsou založeny na [Unicode](https://cs.wikipedia.org/wiki/Unicode): každý znak představuje posloupnost 1-4 bytů. -JavaScript allows us to insert a character into a string by specifying its hexadecimal Unicode code with one of these three notations: +JavaScript nám umožňuje vložit znak do řetězce specifikací jeho hexadecimálního kódu v Unicode pomocí jednoho z následujících tří zápisů: - `\xXX` - `XX` must be two hexadecimal digits with a value between `00` and `FF`, then `\xXX` is the character whose Unicode code is `XX`. + `XX` musí být dvě hexadecimální číslice s hodnotou mezi `00` a `FF`, pak `\xXX` je znak, jehož kód v Unicode je `XX`. - Because the `\xXX` notation supports only two hexadecimal digits, it can be used only for the first 256 Unicode characters. + Protože zápis `\xXX` podporuje jen dvě hexadecimální číslice, může být použit jedině pro prvních 256 znaků Unicode. - These first 256 characters include the Latin alphabet, most basic syntax characters, and some others. For example, `"\x7A"` is the same as `"z"` (Unicode `U+007A`). + Těchto prvních 256 znaků obsahuje latinskou abecedu, většinu základních syntaktických znaků a některé další. Například `"\x7A"` je totéž jako `"z"` (Unicode `U+007A`). ```js run alert( "\x7A" ); // z - alert( "\xA9" ); // ©, the copyright symbol + alert( "\xA9" ); // ©, symbol copyrightu ``` - `\uXXXX` - `XXXX` must be exactly 4 hex digits with the value between `0000` and `FFFF`, then `\uXXXX` is the character whose Unicode code is `XXXX`. - Characters with Unicode values greater than `U+FFFF` can also be represented with this notation, but in this case, we will need to use a so called surrogate pair (we will talk about surrogate pairs later in this chapter). + `XXXX` musí být přesně 4 hexadecimální číslice s hodnotou mezi `0000` a `FFFF`, pak `\uXXXX` je znak, jehož kód v Unicode je `XXXX`. + + Tímto zápisem mohou být reprezentovány i znaky, jejichž hodnoty v Unicode jsou větší než `U+FFFF`, ale v takovém případě musíme použít takzvaný náhradní pár (o náhradních párech pohovoříme později v této kapitole). ```js run - alert( "\u00A9" ); // ©, the same as \xA9, using the 4-digit hex notation - alert( "\u044F" ); // я, the Cyrillic alphabet letter - alert( "\u2191" ); // ↑, the arrow up symbol + alert( "\u00A9" ); // ©, totéž jako \xA9 s použitím 4-číslicového hexadecimálního zápisu + alert( "\u044F" ); // я, písmeno z kyrilice (azbuky) + alert( "\u2191" ); // ↑, symbol šipky nahoru ``` - `\u{X…XXXXXX}` - `X…XXXXXX` must be a hexadecimal value of 1 to 6 bytes between `0` and `10FFFF` (the highest code point defined by Unicode). This notation allows us to easily represent all existing Unicode characters. + `X…XXXXXX` musí být hexadecimální hodnota 1 až 6 bytů mezi `0` a `10FFFF` (nejvyšší kódový bod definovaný v Unicode). Tento zápis nám umožňuje snadno reprezentovat všechny existující znaky v Unicode. ```js run - alert( "\u{20331}" ); // 佫, a rare Chinese character (long Unicode) - alert( "\u{1F60D}" ); // 😍, a smiling face symbol (another long Unicode) + alert( "\u{20331}" ); // 佫, vzácný čínský znak (dlouhý Unicode) + alert( "\u{1F60D}" ); // 😍, symbol usmívající se tváře (další dlouhý Unicode) ``` -## Surrogate pairs +## Náhradní páry -All frequently used characters have 2-byte codes (4 hex digits). Letters in most European languages, numbers, and the basic unified CJK ideographic sets (CJK -- from Chinese, Japanese, and Korean writing systems), have a 2-byte representation. +Všechny často používané znaky mají 2-bytové kódy (4 hexadecimální číslice). Písmena ve většině evropských jazyků, číslice a základní sjednocené ideografické sady CJK (CJK -- pro čínské, japonské a korejské písmenné soustavy) mají 2-bytovou reprezentaci. -Initially, JavaScript was based on UTF-16 encoding that only allowed 2 bytes per character. But 2 bytes only allow 65536 combinations and that's not enough for every possible symbol of Unicode. +JavaScript byl původně založen na kódování UTF-16, které umožňovalo jen 2 byty na znak. Avšak 2 byty umožňují jen 65536 kombinací, a to pro každý možný symbol v Unicode nestačí. -So rare symbols that require more than 2 bytes are encoded with a pair of 2-byte characters called "a surrogate pair". +Vzácné symboly, které vyžadují více než 2 byty, jsou tedy zakódovány dvojicí 2-bytových znaků nazývanou „náhradní pár“ '(„surrogate pair“). -As a side effect, the length of such symbols is `2`: +Vedlejším efektem je, že délka takových symbolů je `2`: ```js run -alert( '𝒳'.length ); // 2, MATHEMATICAL SCRIPT CAPITAL X -alert( '😂'.length ); // 2, FACE WITH TEARS OF JOY -alert( '𩷶'.length ); // 2, a rare Chinese character +alert( '𝒳'.length ); // 2, VELKÉ X V MATEMATICKÉM PÍSMU +alert( '😂'.length ); // 2, TVÁŘ SE SLZAMI RADOSTI +alert( '𩷶'.length ); // 2, vzácný čínský znak ``` -That's because surrogate pairs did not exist at the time when JavaScript was created, and thus are not correctly processed by the language! +Je to proto, že v době, kdy byl JavaScript vytvořen, ještě náhradní páry neexistovaly, a proto nejsou jazykem správně zpracovávány! -We actually have a single symbol in each of the strings above, but the `length` property shows a length of `2`. +Ve skutečnosti máme v každém z výše uvedených řetězců jediný symbol, ale vlastnost `length` ukazuje délku `2`. -Getting a symbol can also be tricky, because most language features treat surrogate pairs as two characters. +Také načtení symbolu může být matoucí, jelikož většina prvků jazyka zachází s náhradními páry jako se dvěma znaky. -For example, here we can see two odd characters in the output: +Například zde vidíme na výstupu dva podivné znaky: ```js run -alert( '𝒳'[0] ); // shows strange symbols... -alert( '𝒳'[1] ); // ...pieces of the surrogate pair +alert( '𝒳'[0] ); // zobrazuje zvláštní symboly... +alert( '𝒳'[1] ); // ...části náhradního páru ``` -Pieces of a surrogate pair have no meaning without each other. So the alerts in the example above actually display garbage. +Části náhradního páru nemají jedna bez druhé žádný význam. V uvedeném příkladu se tedy ve skutečnosti zobrazí nesmysly. -Technically, surrogate pairs are also detectable by their codes: if a character has the code in the interval of `0xd800..0xdbff`, then it is the first part of the surrogate pair. The next character (second part) must have the code in interval `0xdc00..0xdfff`. These intervals are reserved exclusively for surrogate pairs by the standard. +Technicky lze náhradní páry detekovat podle jejich kódu: jestliže znak má kód v intervalu `0xd800..0xdbff`, pak je to první část náhradního páru. Další znak (druhá část) musí mít kód v intervalu `0xdc00..0xdfff`. Tyto intervaly jsou ve standardu exkluzívně rezervovány pro náhradní páry. -So the methods [String.fromCodePoint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint) and [str.codePointAt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt) were added in JavaScript to deal with surrogate pairs. +Proto byly do JavaScriptu přidány metody [String.fromCodePoint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint) a [str.codePointAt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt), které si dokáží s náhradními páry poradit. -They are essentially the same as [String.fromCharCode](mdn:js/String/fromCharCode) and [str.charCodeAt](mdn:js/String/charCodeAt), but they treat surrogate pairs correctly. +Jsou v zásadě stejné jako [String.fromCharCode](mdn:js/String/fromCharCode) a [řetězec.charCodeAt](mdn:js/String/charCodeAt), ale s náhradními páry zacházejí správně. -One can see the difference here: +Zde vidíme rozdíl: ```js run -// charCodeAt is not surrogate-pair aware, so it gives codes for the 1st part of 𝒳: +// charCodeAt nezná náhradní páry, takže vydá kód pro 1. část 𝒳: alert( '𝒳'.charCodeAt(0).toString(16) ); // d835 -// codePointAt is surrogate-pair aware -alert( '𝒳'.codePointAt(0).toString(16) ); // 1d4b3, reads both parts of the surrogate pair +// codePointAt zná náhradní páry +alert( '𝒳'.codePointAt(0).toString(16) ); // 1d4b3, přečte obě části náhradního páru ``` -That said, if we take from position 1 (and that's rather incorrect here), then they both return only the 2nd part of the pair: +Při tom všem, načítáme-li od pozice 1 (a to je zde dosti nekorektní), pak obě vrátí jen 2. část páru: ```js run alert( '𝒳'.charCodeAt(1).toString(16) ); // dcb3 alert( '𝒳'.codePointAt(1).toString(16) ); // dcb3 -// meaningless 2nd half of the pair +// nesmyslná 2. část páru ``` -You will find more ways to deal with surrogate pairs later in the chapter . There are probably special libraries for that too, but nothing famous enough to suggest here. +Další způsoby, jak si s náhradními páry poradit, naleznete v kapitole . Pravděpodobně pro to existují i speciální knihovny, ale žádná není dostatečně známá na to, abychom ji tady doporučili. -````warn header="Takeaway: splitting strings at an arbitrary point is dangerous" -We can't just split a string at an arbitrary position, e.g. take `str.slice(0, 4)` and expect it to be a valid string, e.g.: +````warn header="Zásadní zjištění: dělení řetězců na libovolném místě je nebezpečné" +Nemůžeme jen tak rozdělit řetězec na libovolné pozici, např. volat `řetězec.slice(0, 6)` a očekávat, že to bude platný řetězec, např.: ```js run -alert( 'hi 😂'.slice(0, 4) ); // hi [?] +alert( 'ahoj 😂'.slice(0, 6) ); // ahoj [?] ``` -Here we can see a garbage character (first half of the smile surrogate pair) in the output. +Zde vidíme na výstupu nesmyslný znak (první polovinu náhradního páru úsměvu). -Just be aware of it if you intend to reliably work with surrogate pairs. May not be a big problem, but at least you should understand what happens. +Mějte to na paměti, jestliže zamýšlíte zodpovědně pracovat s náhradními páry. Nemusí to být velký problém, ale aspoň byste měli chápat, co se děje. ```` -## Diacritical marks and normalization +## Diakritická znaménka a normalizace -In many languages, there are symbols that are composed of the base character with a mark above/under it. +V mnoha jazycích jsou symboly, které se skládají ze základního znaku a znaménka nad/pod ním. -For instance, the letter `a` can be the base character for these characters: `àáâäãåā`. +Například písmeno `a` může být základním znakem pro tyto znaky: `àáâäãåā`. -Most common "composite" characters have their own code in the Unicode table. But not all of them, because there are too many possible combinations. +Většina běžných „složených“ znaků má v tabulce Unicode svůj vlastní kód. Ne však všechny, protože možných kombinací je příliš mnoho. -To support arbitrary compositions, the Unicode standard allows us to use several Unicode characters: the base character followed by one or many "mark" characters that "decorate" it. +Aby standard Unicode podporoval libovolné složeniny, umožňuje nám použít několik znaků Unicode: základní znak následovaný jedním nebo více znaky „znamének“, které jej „ozdobí“. -For instance, if we have `S` followed by the special "dot above" character (code `\u0307`), it is shown as Ṡ. +Například máme-li `S` následované speciálním znakem „tečka nahoře“ (kód `\u0307`), zobrazí se jako Ṡ. ```js run alert( 'S\u0307' ); // Ṡ ``` -If we need an additional mark above the letter (or below it) -- no problem, just add the necessary mark character. +Potřebujeme-li další znaménko nad písmenem (nebo pod ním) -- žádný problém, jednoduše přidáme potřebný znak znaménka. -For instance, if we append a character "dot below" (code `\u0323`), then we'll have "S with dots above and below": `Ṩ`. +Například připojíme-li znak „tečka dole“ (kód `\u0323`), budeme mít „S s tečkami nahoře a dole“: `Ṩ`. -For example: +Příklad: ```js run alert( 'S\u0307\u0323' ); // Ṩ ``` -This provides great flexibility, but also an interesting problem: two characters may visually look the same, but be represented with different Unicode compositions. +To nám poskytuje velkou flexibilitu, ale také zajímavý problém: dva znaky mohou vizuálně vypadat stejně, ale být reprezentovány různými složeninami z Unicode. -For instance: +Příklad: ```js run -let s1 = 'S\u0307\u0323'; // Ṩ, S + dot above + dot below -let s2 = 'S\u0323\u0307'; // Ṩ, S + dot below + dot above +let s1 = 'S\u0307\u0323'; // Ṩ, S + tečka nahoře + tečka dole +let s2 = 'S\u0323\u0307'; // Ṩ, S + tečka dole + tečka nahoře alert( `s1: ${s1}, s2: ${s2}` ); -alert( s1 == s2 ); // false though the characters look identical (?!) +alert( s1 == s2 ); // false, třebaže znaky vypadají stejně (?!) ``` -To solve this, there exists a "Unicode normalization" algorithm that brings each string to the single "normal" form. +K tomu, abychom to vyřešili, existuje algoritmus „normalizace Unicode“, který převádí každý řetězec do jednoduché „normální“ formy. -It is implemented by [str.normalize()](mdn:js/String/normalize). +Je implementován metodou [řetězec.normalize()](mdn:js/String/normalize). ```js run alert( "S\u0307\u0323".normalize() == "S\u0323\u0307".normalize() ); // true ``` -It's funny that in our situation `normalize()` actually brings together a sequence of 3 characters to one: `\u1e68` (S with two dots). +Je humorné, že v naší situaci `normalize()` ve skutečnosti spojí posloupnost 3 znaků do jednoho: `\u1e68` (S se dvěma tečkami). ```js run alert( "S\u0307\u0323".normalize().length ); // 1 @@ -167,6 +168,6 @@ alert( "S\u0307\u0323".normalize().length ); // 1 alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true ``` -In reality, this is not always the case. The reason is that the symbol `Ṩ` is "common enough", so Unicode creators included it in the main table and gave it the code. +V realitě však tomu tak není vždy. Důvod je, že symbol `Ṩ` je „dostatečně běžný“, takže jej tvůrci Unicode zahrnuli do hlavní tabulky a přiřadili mu kód. -If you want to learn more about normalization rules and variants -- they are described in the appendix of the Unicode standard: [Unicode Normalization Forms](https://www.unicode.org/reports/tr15/), but for most practical purposes the information from this section is enough. +Pokud se chcete o pravidlech normalizace a variantách dozvědět víc -- jsou popsány v příloze standardu Unicode: [Normalizační formy Unicode](https://www.unicode.org/reports/tr15/), ale pro většinu praktických účelů je informace z tohoto článku dostačující. diff --git a/1-js/99-js-misc/index.md b/1-js/99-js-misc/index.md index 79cd72fe7..07f5a5686 100644 --- a/1-js/99-js-misc/index.md +++ b/1-js/99-js-misc/index.md @@ -1,2 +1,2 @@ -# Miscellaneous +# Různé diff --git a/1-js/index.md b/1-js/index.md index c313cb85c..42079a365 100644 --- a/1-js/index.md +++ b/1-js/index.md @@ -1,6 +1,6 @@ -# The JavaScript language +# Jazyk JavaScript -Here we learn JavaScript, starting from scratch and go on to advanced concepts like OOP. +Zde se naučíme JavaScript. Začneme od píky a postupně přejdeme k pokročilým konceptům, například OOP. -We concentrate on the language itself here, with the minimum of environment-specific notes. +Budeme se soustředit na samotný jazyk a uvedeme jen minimum poznámek specifických pro určité prostředí. diff --git a/2-ui/1-document/05-basic-dom-node-properties/article.md b/2-ui/1-document/05-basic-dom-node-properties/article.md index 99dde5bcd..aed342b20 100644 --- a/2-ui/1-document/05-basic-dom-node-properties/article.md +++ b/2-ui/1-document/05-basic-dom-node-properties/article.md @@ -28,7 +28,7 @@ The classes are: - [Document](https://dom.spec.whatwg.org/#interface-document), for historical reasons often inherited by `HTMLDocument` (though the latest spec doesn't dictate it) -- is a document as a whole. - The `document` global object belongs exactly to this class. It serves as an entry point to the DOM. + The `document` global object belongs exactly to this class. It servers as an entry point to the DOM. - [CharacterData](https://dom.spec.whatwg.org/#interface-characterdata) -- an "abstract" class, inherited by: - [Text](https://dom.spec.whatwg.org/#interface-text) -- the class corresponding to a text inside elements, e.g. `Hello` in `

Hello

`. diff --git a/2-ui/2-events/02-bubbling-and-capturing/event-order-bubbling.svg b/2-ui/2-events/02-bubbling-and-capturing/event-order-bubbling.svg index 2ea88f081..ae0c4dc67 100644 --- a/2-ui/2-events/02-bubbling-and-capturing/event-order-bubbling.svg +++ b/2-ui/2-events/02-bubbling-and-capturing/event-order-bubbling.svg @@ -1 +1 @@ -123Most deeply nested element \ No newline at end of file +123Nejhlouběji vnořený prvek \ No newline at end of file diff --git a/2-ui/99-ui-misc/02-selection-range/selection-direction-backward.svg b/2-ui/99-ui-misc/02-selection-range/selection-direction-backward.svg index 85615d38f..1ea2c6adc 100644 --- a/2-ui/99-ui-misc/02-selection-range/selection-direction-backward.svg +++ b/2-ui/99-ui-misc/02-selection-range/selection-direction-backward.svg @@ -1 +1 @@ -focusanchormouse move direction \ No newline at end of file +zaměřeníkotvamouse move direction \ No newline at end of file diff --git a/2-ui/99-ui-misc/02-selection-range/selection-direction-forward.svg b/2-ui/99-ui-misc/02-selection-range/selection-direction-forward.svg index 511b00a26..ee7bd92c3 100644 --- a/2-ui/99-ui-misc/02-selection-range/selection-direction-forward.svg +++ b/2-ui/99-ui-misc/02-selection-range/selection-direction-forward.svg @@ -1 +1 @@ -anchorfocusmouse move direction \ No newline at end of file +kotvazaměřenímouse move direction \ No newline at end of file diff --git a/2-ui/99-ui-misc/02-selection-range/selection-firefox.svg b/2-ui/99-ui-misc/02-selection-range/selection-firefox.svg index aa7ff1eb7..0b795bfd1 100644 --- a/2-ui/99-ui-misc/02-selection-range/selection-firefox.svg +++ b/2-ui/99-ui-misc/02-selection-range/selection-firefox.svg @@ -1 +1 @@ -selection \ No newline at end of file +výběr \ No newline at end of file diff --git a/2-ui/99-ui-misc/03-event-loop/eventLoop-full.svg b/2-ui/99-ui-misc/03-event-loop/eventLoop-full.svg index 593cbab9b..7360c2f8e 100644 --- a/2-ui/99-ui-misc/03-event-loop/eventLoop-full.svg +++ b/2-ui/99-ui-misc/03-event-loop/eventLoop-full.svg @@ -1 +1 @@ -...mousemoveevent looprendermicrotasksrendermicrotasksscriptsetTimeout \ No newline at end of file +...mousemoveudálost cyklusrenderovánímikroúlohyrenderovánímikroúlohyskriptsetTimeout \ No newline at end of file diff --git a/2-ui/99-ui-misc/03-event-loop/eventLoop.svg b/2-ui/99-ui-misc/03-event-loop/eventLoop.svg index 6dc459ef8..9a736a035 100644 --- a/2-ui/99-ui-misc/03-event-loop/eventLoop.svg +++ b/2-ui/99-ui-misc/03-event-loop/eventLoop.svg @@ -1 +1 @@ -...mousemovescriptevent loopmacrotask queuesetTimeout \ No newline at end of file +...mousemoveskriptudálost cyklusmakroúloha frontasetTimeout \ No newline at end of file diff --git a/5-network/05-fetch-crossorigin/cors-gmail-messages.svg b/5-network/05-fetch-crossorigin/cors-gmail-messages.svg index c24aac140..5412e7ac0 100644 --- a/5-network/05-fetch-crossorigin/cors-gmail-messages.svg +++ b/5-network/05-fetch-crossorigin/cors-gmail-messages.svg @@ -1 +1 @@ -evil.comgot the cookie? okay!gmail.comGET /messagescookie: user=John{"messages": [...]} \ No newline at end of file +evil.commáme cookie? ok!gmail.comGET /messagescookie: user=John{"messages": [...]} \ No newline at end of file diff --git a/5-network/05-fetch-crossorigin/xhr-another-domain.svg b/5-network/05-fetch-crossorigin/xhr-another-domain.svg index 2ed70febd..da7ce30bc 100644 --- a/5-network/05-fetch-crossorigin/xhr-another-domain.svg +++ b/5-network/05-fetch-crossorigin/xhr-another-domain.svg @@ -1 +1 @@ -JavaScriptBrowserServerOrigin: https://javascript.infoHTTP-requestfetch()HTTP-responseAccess-Control-Allow-Origin: * (or https://javascript.info)if the header allows, then success,otherwise fail \ No newline at end of file +JavaScriptProhlížečServerOrigin: https://javascript.infoHTTP požadavekfetch()HTTP odpověďAccess-Control-Allow-Origin: * (or https://javascript.info)pokud to hlavička umožní, pak úspěch,jinak chyba \ No newline at end of file diff --git a/5-network/05-fetch-crossorigin/xhr-preflight.svg b/5-network/05-fetch-crossorigin/xhr-preflight.svg index 049572cee..6935a70fa 100644 --- a/5-network/05-fetch-crossorigin/xhr-preflight.svg +++ b/5-network/05-fetch-crossorigin/xhr-preflight.svg @@ -1 +1 @@ -JavaScriptBrowserServerfetch()OPTIONSOrigin Access-Control-Request-Method Access-Control-Request-Headers200 OKAccess-Control-Allow-OriginMain HTTP-responseotherwise errorif allowed: success,OriginMain HTTP-requestpreflightif allowed1234 Access-Control-Allow-Origin Access-Control-Allow-Methods Access-Control-Allow-Headers Access-Control-Max-Age \ No newline at end of file +JavaScriptProhlížečServerfetch()OPTIONSOrigin Access-Control-Request-Method Access-Control-Request-Headers200 OKAccess-Control-Allow-OriginHlavní HTTP odpověďjinak chybaje-li povoleno, úspěch,OriginHlavní HTTP požadavekpředletje-li povoleno1234 Access-Control-Allow-Origin Access-Control-Allow-Methods Access-Control-Allow-Headers Access-Control-Max-Age \ No newline at end of file diff --git a/5-network/10-long-polling/long-polling.svg b/5-network/10-long-polling/long-polling.svg index 045ef371f..9f354c689 100644 --- a/5-network/10-long-polling/long-polling.svg +++ b/5-network/10-long-polling/long-polling.svg @@ -1 +1 @@ -BrowserServerrequestconnection hangsconnection breaks end of requestdatarequestconnection hangsrequestdataconnection breaks end of request \ No newline at end of file +ProhlížečServerpožadavekspojení visíspojení přerušeno konec požadavkudatapožadavekspojení visípožadavekdataspojení přerušeno konec požadavku \ No newline at end of file diff --git a/5-network/11-websocket/websocket-handshake.svg b/5-network/11-websocket/websocket-handshake.svg index 96c2cd3ef..a2605291f 100644 --- a/5-network/11-websocket/websocket-handshake.svg +++ b/5-network/11-websocket/websocket-handshake.svg @@ -1 +1 @@ -BrowserServerHTTP-request"Hey, server, let's talk WebSocket?"HTTP-response "Okay!"WebSocket protocol \ No newline at end of file +ProhlížečServerHTTP požadavek„Servere, popovídáme si na WebSocketu?“HTTP odpověď Dobře!Protokol WebSocket \ No newline at end of file diff --git a/6-data-storage/01-cookie/cookie-xsrf.svg b/6-data-storage/01-cookie/cookie-xsrf.svg index 961a8078f..85f7989fa 100644 --- a/6-data-storage/01-cookie/cookie-xsrf.svg +++ b/6-data-storage/01-cookie/cookie-xsrf.svg @@ -1 +1 @@ -<form action="https://bank.com/pay"> .... </form>evil.comgot the cookie? okay!bank.comPOST /paycookie: user=John \ No newline at end of file +<form action="https://bank.com/pay"> .... </form>evil.commáme cookie? ok!bank.comPOST /paycookie: user=John \ No newline at end of file diff --git a/9-regular-expressions/03-regexp-unicode/article.md b/9-regular-expressions/03-regexp-unicode/article.md index 1be163aff..712b6ecd0 100644 --- a/9-regular-expressions/03-regexp-unicode/article.md +++ b/9-regular-expressions/03-regexp-unicode/article.md @@ -142,7 +142,7 @@ Let's use it to look for prices in the format "currency, followed by a digit": ```js run let regexp = /\p{Sc}\d/gu; -let str = `Prices: $2, €1, ¥9`; +let str = `Prices: $2, €1, ¥9`; alert( str.match(regexp) ); // $2,€1,¥9 ``` diff --git a/images.yml b/images.yml index 16d6c177b..0bb422960 100644 --- a/images.yml +++ b/images.yml @@ -174,10 +174,6 @@ object-user-empty.svg: position: "center" user: uživatel -garbage-collection-5.svg: - unreachables: - text: nedosažitelný - array-shift.svg: clear: text: vymazat @@ -192,7 +188,7 @@ array-pop.svg: position: "center" decorator-makecaching-wrapper.svg: - wrapper: 'wrapper' + wrapper: 'obal' around the function: 'kolem funkce' xhr-another-domain.svg: @@ -280,9 +276,10 @@ promise-handler-variants.svg: promiseQueue.svg: '"code finished"': '"konec kódu"' - handler enqueued: 'handler ve frontě' + handler enqueued: 'handler vložen do fronty' queued handler runs: 'spouští se handler z fronty' script execution finished: 'výkon skriptu ukončen' + 'promise.then(handler)': 'příslib.then(handler)' eventLoop-full.svg: script: 'skript' @@ -378,12 +375,12 @@ object-prototype-empty.svg: 'prototype object': 'prototypový objekt' rabbit-prototype-constructor.svg: - 'default "prototype"': 'defaultně "prototype"' + 'default "prototype"': 'standardně "prototype"' 'Rabbit': 'Králík' 'rabbit': 'králík' function-prototype-constructor.svg: - 'default "prototype"': 'defaultní "prototype"' + 'default "prototype"': 'standardní "prototype"' 'Rabbit': 'Králík' rabbit-animal-independent-animal.svg: @@ -452,13 +449,6 @@ proto-animal-rabbit.svg: 'eats: true': 'žere: true' 'jumps: true': 'skáče: true' -proto-constructor-animal-rabbit.svg: - 'Rabbit': 'Králík' - 'animal': 'zvíře' - 'eats: true': 'žere: true' - 'rabbit': 'králík' - 'name: "White Rabbit"': 'jméno: "Bílý králík"' - native-prototypes-classes.svg: 'other object methods': 'jiné metody objektů' 'other array methods': 'jiné metody polí' @@ -478,7 +468,7 @@ proto-animal-rabbit-chain.svg: 'walk: function': 'jdi: function' 'rabbit': 'králík' 'jumps: true': 'skáče: true' - 'longEar': 'dlouhouchý' + 'longEar': 'ušatý' 'earLength': 'délkaUcha' proto-animal-rabbit-walk-2.svg: @@ -506,7 +496,7 @@ this-super-loop.svg: 'rabbit': 'králík' 'animal': 'zvíře' 'eat': 'žer' - 'longEar': 'dlouhouchý' + 'longEar': 'ušatý' 'let rabbit = {': 'let králík = {' ' __proto__: animal': ' __proto__: zvíře' ' __proto__: rabbit': ' __proto__: králík' @@ -529,7 +519,21 @@ variable-change.svg: '"Hello!"': '"Ahoj!"' '"World!"': '"světe!"' 'message': 'zpráva' - + +variable-copy-value.svg: + '"Hello!"': '"Ahoj!"' + 'message': 'zpráva' + 'phrase': 'věta' + +variable-contains-reference.svg: + 'user': 'uživatel' + 'name': 'jméno' + +variable-copy-reference.svg: + 'user': 'uživatel' + 'name': 'jméno' + 'admin': 'správce' + rabbit-extends-object.svg: 'class Rabbit': 'class Králík' 'class Rabbit extends Object': 'class Králík extends Object' @@ -592,15 +596,97 @@ object-user-isadmin.svg: user: uživatel name: jméno age: věk - isAdmin: jeAdmin + isAdmin: jeSprávce object-user-delete.svg: user: uživatel name: jméno - isAdmin: jeAdmin + isAdmin: jeSprávce object-user-props.svg: user: uživatel name: jméno age: věk - likes birds: má rád ptáky \ No newline at end of file + likes birds: má rád ptáky + +memory-user-john.svg: + '': '' + user: uživatel + 'name: "John"': 'jméno: "Jan"' + +memory-user-john-lost.svg: + '': '' + 'user: null': 'uživatel: null' + 'name: "John"': 'jméno: "Jan"' + +memory-user-john-admin.svg: + '': '' + user: uživatel + admin: správce + 'name: "John"': 'jméno: "Jan"' + +family.svg: + '': '' + family: rodina + father: otec + mother: matka + 'name: "John"': 'jméno: "Jan"' + wife: manželka + husband: manžel + 'name: "Ann"': 'jméno: "Anna"' + +family-delete-refs.svg: + '': '' + family: rodina + father: otec + mother: matka + 'name: "John"': 'jméno: "Jan"' + wife: manželka + husband: manžel + 'name: "Ann"': 'jméno: "Anna"' + +family-no-father.svg: + '': '' + family: rodina + mother: matka + 'name: "John"': 'jméno: "Jan"' + wife: manželka + 'name: "Ann"': 'jméno: "Anna"' + +family-no-father-2.svg: + '': '' + family: rodina + mother: matka + 'name: "Ann"': 'jméno: "Anna"' + +family-no-family.svg: + '': '' + 'family: null': 'rodina: null' + father: otec + mother: matka + 'name: "John"': 'jméno: "Jan"' + wife: manželka + husband: manžel + 'name: "Ann"': 'jméno: "Anna"' + +garbage-collection-1.svg: + '': '' + +garbage-collection-2.svg: + '': '' + +garbage-collection-3.svg: + '': '' + +garbage-collection-4.svg: + '': '' + +garbage-collection-5.svg: + '': '' + unreachables: nedosažitelné + +promise-then-chain.svg: + 'resolve(1)': 'splň(1)' + +promise-then-many.svg: + 'resolve(1)': 'splň(1)'