From 0a245cf1d36255bde5128e1eb8c81425dc811076 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Wed, 3 Aug 2022 21:55:55 +0200 Subject: [PATCH 01/55] =?UTF-8?q?=C4=8Desky=20od=201.3.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../1-style-errors/solution.md | 46 +- .../02-coding-style/1-style-errors/task.md | 18 +- .../02-coding-style/article.md | 276 ++--- .../02-coding-style/code-style.svg | 2 +- 1-js/03-code-quality/03-comments/article.md | 160 +-- 1-js/03-code-quality/04-ninja-code/article.md | 237 ++--- .../3-pow-test-wrong/solution.md | 46 +- .../05-testing-mocha/3-pow-test-wrong/task.md | 20 +- .../05-testing-mocha/article.md | 358 +++---- .../beforeafter.view/index.html | 16 +- .../05-testing-mocha/index.html | 20 +- .../05-testing-mocha/pow-1.view/index.html | 20 +- .../05-testing-mocha/pow-2.view/index.html | 20 +- .../05-testing-mocha/pow-3.view/index.html | 24 +- .../05-testing-mocha/pow-4.view/index.html | 24 +- .../05-testing-mocha/pow-full.view/index.html | 24 +- .../05-testing-mocha/pow-min.view/index.html | 22 +- .../05-testing-mocha/pow-nan.view/index.html | 26 +- 1-js/03-code-quality/index.md | 4 +- .../01-object/2-hello-object/solution.md | 10 +- .../01-object/2-hello-object/task.md | 15 +- .../01-object/3-is-empty/_js.view/solution.js | 6 +- .../01-object/3-is-empty/_js.view/test.js | 12 +- .../01-object/3-is-empty/solution.md | 2 +- .../01-object/3-is-empty/task.md | 14 +- .../01-object/5-sum-object/solution.md | 16 +- .../01-object/5-sum-object/task.md | 16 +- .../8-multiply-numeric/_js.view/solution.js | 8 +- .../8-multiply-numeric/_js.view/source.js | 14 +- .../8-multiply-numeric/_js.view/test.js | 22 +- .../01-object/8-multiply-numeric/task.md | 28 +- 1-js/04-object-basics/01-object/article.md | 452 ++++----- .../01-object/object-user-delete.svg | 2 +- .../01-object/object-user-empty.svg | 2 +- .../01-object/object-user-isadmin.svg | 2 +- .../01-object/object-user-props.svg | 2 +- .../01-object/object-user.svg | 2 +- 1-js/04-object-basics/01-object/object.svg | 2 +- .../02-object-copy/article.md | 230 ++--- .../03-garbage-collection/article.md | 186 ++-- .../garbage-collection-5.svg | 2 +- .../4-object-property-this/solution.md | 42 +- .../4-object-property-this/task.md | 14 +- .../7-calculator/_js.view/solution.js | 8 +- .../7-calculator/_js.view/test.js | 21 +- .../7-calculator/solution.md | 14 +- .../04-object-methods/7-calculator/task.md | 20 +- .../8-chain-calls/_js.view/solution.js | 17 +- .../8-chain-calls/_js.view/test.js | 30 +- .../8-chain-calls/solution.md | 36 +- .../04-object-methods/8-chain-calls/task.md | 40 +- .../04-object-methods/article.md | 248 ++--- .../1-two-functions-one-object/solution.md | 6 +- .../1-two-functions-one-object/task.md | 6 +- .../_js.view/solution.js | 8 +- .../2-calculator-constructor/_js.view/test.js | 22 +- .../2-calculator-constructor/solution.md | 16 +- .../2-calculator-constructor/task.md | 20 +- .../3-accumulator/_js.view/solution.js | 10 +- .../3-accumulator/_js.view/test.js | 24 +- .../3-accumulator/solution.md | 16 +- .../06-constructor-new/3-accumulator/task.md | 22 +- .../06-constructor-new/article.md | 214 ++-- .../07-optional-chaining/article.md | 204 ++-- 1-js/04-object-basics/08-symbol/article.md | 228 ++--- .../09-object-toprimitive/article.md | 268 ++--- 1-js/04-object-basics/index.md | 2 +- .../1-string-new-property/solution.md | 22 +- .../1-string-new-property/task.md | 8 +- .../01-primitives-methods/article.md | 116 +-- .../02-number/1-sum-interface/solution.md | 8 +- .../02-number/1-sum-interface/task.md | 6 +- .../02-number/2-why-rounded-down/solution.md | 18 +- .../02-number/2-why-rounded-down/task.md | 10 +- .../_js.view/solution.js | 12 +- .../3-repeat-until-number/_js.view/test.js | 26 +- .../3-repeat-until-number/solution.md | 20 +- .../02-number/3-repeat-until-number/task.md | 8 +- .../4-endless-loop-error/solution.md | 10 +- .../02-number/4-endless-loop-error/task.md | 4 +- .../02-number/8-random-min-max/solution.md | 10 +- .../02-number/8-random-min-max/task.md | 8 +- .../9-random-int-min-max/solution.md | 38 +- .../02-number/9-random-int-min-max/task.md | 10 +- 1-js/05-data-types/02-number/article.md | 360 +++---- .../03-string/1-ucfirst/_js.view/solution.js | 6 +- .../03-string/1-ucfirst/_js.view/test.js | 10 +- .../03-string/1-ucfirst/solution.md | 24 +- .../05-data-types/03-string/1-ucfirst/task.md | 6 +- .../2-check-spam/_js.view/solution.js | 6 +- .../03-string/2-check-spam/_js.view/test.js | 14 +- .../03-string/2-check-spam/solution.md | 14 +- .../03-string/2-check-spam/task.md | 12 +- .../03-string/3-truncate/_js.view/solution.js | 6 +- .../03-string/3-truncate/_js.view/test.js | 14 +- .../03-string/3-truncate/solution.md | 10 +- .../03-string/3-truncate/task.md | 12 +- .../4-extract-currency/_js.view/solution.js | 4 +- .../4-extract-currency/_js.view/test.js | 6 +- .../03-string/4-extract-currency/task.md | 10 +- 1-js/05-data-types/03-string/article.md | 614 ++++++------ .../04-array/1-item-value/solution.md | 12 +- .../04-array/1-item-value/task.md | 16 +- .../10-maximal-subarray/_js.view/solution.js | 16 +- .../10-maximal-subarray/_js.view/test.js | 38 +- .../04-array/10-maximal-subarray/solution.md | 92 +- .../04-array/10-maximal-subarray/task.md | 28 +- .../04-array/2-create-array/solution.md | 10 +- .../04-array/2-create-array/task.md | 22 +- .../04-array/3-call-array-this/solution.md | 12 +- .../04-array/3-call-array-this/task.md | 10 +- .../04-array/5-array-input-sum/solution.md | 24 +- .../04-array/5-array-input-sum/task.md | 12 +- 1-js/05-data-types/04-array/array-pop.svg | 2 +- 1-js/05-data-types/04-array/array-shift.svg | 2 +- 1-js/05-data-types/04-array/article.md | 442 ++++---- .../1-camelcase/_js.view/solution.js | 12 +- .../1-camelcase/_js.view/test.js | 18 +- .../05-array-methods/1-camelcase/task.md | 16 +- .../10-average-age/solution.md | 14 +- .../05-array-methods/10-average-age/task.md | 18 +- .../11-array-unique/_js.view/solution.js | 12 +- .../11-array-unique/_js.view/test.js | 18 +- .../11-array-unique/solution.md | 40 +- .../05-array-methods/11-array-unique/task.md | 18 +- .../12-reduce-object/_js.view/solution.js | 6 +- .../12-reduce-object/_js.view/test.js | 26 +- .../05-array-methods/12-reduce-object/task.md | 34 +- .../2-filter-range/_js.view/solution.js | 6 +- .../2-filter-range/_js.view/test.js | 18 +- .../2-filter-range/solution.md | 14 +- .../05-array-methods/2-filter-range/task.md | 16 +- .../_js.view/solution.js | 12 +- .../3-filter-range-in-place/_js.view/test.js | 14 +- .../3-filter-range-in-place/solution.md | 18 +- .../3-filter-range-in-place/task.md | 14 +- .../05-array-methods/4-sort-back/solution.md | 6 +- .../05-array-methods/4-sort-back/task.md | 8 +- .../5-copy-sort-array/solution.md | 14 +- .../5-copy-sort-array/task.md | 14 +- .../6-array-get-names/solution.md | 12 +- .../6-array-get-names/task.md | 18 +- .../_js.view/solution.js | 14 +- .../6-calculator-extendable/_js.view/test.js | 26 +- .../6-calculator-extendable/solution.md | 4 +- .../6-calculator-extendable/task.md | 37 +- .../7-map-objects/solution.md | 48 +- .../05-array-methods/7-map-objects/task.md | 32 +- .../8-sort-objects/solution.md | 22 +- .../05-array-methods/8-sort-objects/task.md | 24 +- .../05-array-methods/9-shuffle/solution.md | 98 +- .../05-array-methods/9-shuffle/task.md | 22 +- .../05-data-types/05-array-methods/article.md | 748 +++++++------- 1-js/05-data-types/06-iterable/article.md | 278 +++--- .../01-array-unique-map/_js.view/solution.js | 4 +- .../01-array-unique-map/_js.view/test.js | 18 +- .../07-map-set/01-array-unique-map/task.md | 22 +- .../02-filter-anagrams/_js.view/solution.js | 12 +- .../02-filter-anagrams/_js.view/test.js | 26 +- .../07-map-set/02-filter-anagrams/solution.md | 70 +- .../07-map-set/02-filter-anagrams/task.md | 23 +- .../07-map-set/03-iterable-keys/solution.md | 14 +- .../07-map-set/03-iterable-keys/task.md | 18 +- 1-js/05-data-types/07-map-set/article.md | 353 ++++--- .../01-recipients-read/solution.md | 52 +- .../01-recipients-read/task.md | 20 +- .../02-recipients-when-read/solution.md | 16 +- .../02-recipients-when-read/task.md | 18 +- .../08-weakmap-weakset/article.md | 260 ++--- .../01-sum-salaries/_js.view/solution.js | 10 +- .../01-sum-salaries/_js.view/test.js | 18 +- .../01-sum-salaries/solution.md | 32 +- .../01-sum-salaries/task.md | 20 +- .../02-count-properties/_js.view/solution.js | 2 +- .../02-count-properties/_js.view/test.js | 14 +- .../02-count-properties/task.md | 16 +- .../09-keys-values-entries/article.md | 106 +- .../1-destruct-user/solution.md | 14 +- .../1-destruct-user/task.md | 32 +- .../6-max-salary/_js.view/solution.js | 16 +- .../6-max-salary/_js.view/test.js | 18 +- .../6-max-salary/task.md | 20 +- .../10-destructuring-assignment/article.md | 554 +++++----- .../11-date/1-new-date/solution.md | 12 +- 1-js/05-data-types/11-date/1-new-date/task.md | 6 +- .../2-get-week-day/_js.view/solution.js | 6 +- .../11-date/2-get-week-day/_js.view/test.js | 30 +- .../11-date/2-get-week-day/solution.md | 14 +- .../11-date/2-get-week-day/task.md | 10 +- .../11-date/3-weekday/_js.view/solution.js | 10 +- .../11-date/3-weekday/_js.view/test.js | 30 +- 1-js/05-data-types/11-date/3-weekday/task.md | 8 +- .../4-get-date-ago/_js.view/solution.js | 8 +- .../11-date/4-get-date-ago/_js.view/test.js | 28 +- .../11-date/4-get-date-ago/solution.md | 28 +- .../11-date/4-get-date-ago/task.md | 18 +- .../5-last-day-of-month/_js.view/solution.js | 6 +- .../5-last-day-of-month/_js.view/test.js | 14 +- .../11-date/5-last-day-of-month/solution.md | 16 +- .../11-date/5-last-day-of-month/task.md | 12 +- .../11-date/6-get-seconds-today/solution.md | 24 +- .../11-date/6-get-seconds-today/task.md | 10 +- .../7-get-seconds-to-tomorrow/solution.md | 42 +- .../11-date/7-get-seconds-to-tomorrow/task.md | 10 +- .../_js.view/solution.js | 27 +- .../8-format-date-relative/_js.view/test.js | 18 +- .../8-format-date-relative/solution.md | 99 +- .../11-date/8-format-date-relative/task.md | 24 +- 1-js/05-data-types/11-date/article.md | 421 ++++---- .../12-json/1-serialize-object/solution.md | 8 +- .../12-json/1-serialize-object/task.md | 10 +- .../2-serialize-event-circular/solution.md | 28 +- .../2-serialize-event-circular/task.md | 38 +- 1-js/05-data-types/12-json/article.md | 491 +++++---- 1-js/05-data-types/index.md | 4 +- .../01-recursion/01-sum-to/solution.md | 32 +- .../01-recursion/01-sum-to/task.md | 34 +- .../01-recursion/02-factorial/solution.md | 18 +- .../01-recursion/02-factorial/task.md | 14 +- .../03-fibonacci-numbers/solution.md | 62 +- .../01-recursion/03-fibonacci-numbers/task.md | 17 +- .../04-output-single-linked-list/solution.md | 86 +- .../04-output-single-linked-list/task.md | 28 +- .../solution.md | 78 +- .../task.md | 6 +- .../01-recursion/article.md | 508 +++++----- .../01-recursion/recursion-pow.svg | 2 +- .../02-rest-parameters-spread/article.md | 273 +++-- .../1-closure-latest-changes/solution.md | 6 +- .../1-closure-latest-changes/task.md | 18 +- .../10-make-army/_js.view/solution.js | 12 +- .../10-make-army/_js.view/source.js | 20 +- .../03-closure/10-make-army/_js.view/test.js | 14 +- .../03-closure/10-make-army/solution.md | 91 +- .../03-closure/10-make-army/task.md | 35 +- .../2-closure-variable-access/solution.md | 8 +- .../2-closure-variable-access/task.md | 24 +- .../3-counter-independent/solution.md | 6 +- .../03-closure/3-counter-independent/task.md | 24 +- .../4-counter-object-independent/solution.md | 26 +- .../4-counter-object-independent/task.md | 26 +- .../03-closure/5-function-in-if/solution.md | 4 +- .../03-closure/5-function-in-if/task.md | 14 +- .../03-closure/6-closure-sum/solution.md | 12 +- .../03-closure/6-closure-sum/task.md | 12 +- .../03-closure/7-let-scope/solution.md | 30 +- .../03-closure/7-let-scope/task.md | 10 +- .../_js.view/solution.js | 6 +- .../_js.view/source.js | 10 +- .../_js.view/test.js | 22 +- .../8-filter-through-function/solution.md | 18 +- .../8-filter-through-function/task.md | 26 +- .../9-sort-by-field/_js.view/solution.js | 4 +- .../9-sort-by-field/_js.view/source.js | 4 +- .../9-sort-by-field/_js.view/test.js | 52 +- .../03-closure/9-sort-by-field/solution.md | 1 - .../03-closure/9-sort-by-field/task.md | 32 +- .../03-closure/article.md | 353 ++++--- .../lexenv-nested-makecounter-2.svg | 2 +- .../lexenv-nested-makecounter-6.svg | 2 +- .../lexical-environment-global-2.svg | 2 +- .../lexical-environment-global-3.svg | 2 +- 1-js/06-advanced-functions/04-var/article.md | 220 ++-- .../05-global-object/article.md | 78 +- .../2-counter-inc-dec/_js.view/solution.js | 14 +- .../2-counter-inc-dec/_js.view/source.js | 20 +- .../2-counter-inc-dec/_js.view/test.js | 38 +- .../2-counter-inc-dec/solution.md | 2 +- .../2-counter-inc-dec/task.md | 14 +- .../5-sum-many-brackets/_js.view/solution.js | 8 +- .../5-sum-many-brackets/_js.view/source.js | 14 +- .../5-sum-many-brackets/_js.view/test.js | 18 +- .../5-sum-many-brackets/solution.md | 44 +- .../5-sum-many-brackets/task.md | 16 +- .../06-function-object/article.md | 308 +++--- .../07-new-function/article.md | 106 +- .../1-output-numbers-100ms/solution.md | 60 +- .../1-output-numbers-100ms/task.md | 10 +- .../4-settimeout-result/solution.md | 6 +- .../4-settimeout-result/task.md | 16 +- .../08-settimeout-setinterval/article.md | 274 ++--- .../01-spy-decorator/_js.view/solution.js | 12 +- .../01-spy-decorator/_js.view/source.js | 4 +- .../01-spy-decorator/_js.view/test.js | 42 +- .../01-spy-decorator/solution.md | 2 +- .../01-spy-decorator/task.md | 24 +- .../02-delay/_js.view/solution.js | 2 +- .../02-delay/_js.view/test.js | 46 +- .../02-delay/solution.md | 22 +- .../09-call-apply-decorators/02-delay/task.md | 20 +- .../03-debounce/_js.view/solution.js | 4 +- .../03-debounce/_js.view/test.js | 30 +- .../03-debounce/debounce.view/index.html | 10 +- .../03-debounce/solution.md | 6 +- .../03-debounce/task.md | 36 +- .../04-throttle/_js.view/solution.js | 34 +- .../04-throttle/_js.view/test.js | 59 +- .../04-throttle/solution.md | 36 +- .../04-throttle/task.md | 55 +- .../09-call-apply-decorators/article.md | 376 +++---- .../decorator-makecaching-wrapper.svg | 2 +- .../2-write-to-object-after-bind/solution.md | 10 +- .../2-write-to-object-after-bind/task.md | 8 +- .../10-bind/3-second-bind/solution.md | 12 +- .../10-bind/3-second-bind/task.md | 10 +- .../solution.md | 4 +- .../4-function-property-after-bind/task.md | 16 +- .../10-bind/5-question-use-bind/solution.md | 38 +- .../10-bind/5-question-use-bind/task.md | 30 +- .../10-bind/6-ask-partial/solution.md | 12 +- .../10-bind/6-ask-partial/task.md | 28 +- 1-js/06-advanced-functions/10-bind/article.md | 292 +++--- .../12-arrow-functions/article.md | 122 +-- 1-js/06-advanced-functions/index.md | 2 +- .../01-property-descriptors/article.md | 270 ++--- .../02-property-accessors/article.md | 211 ++-- 1-js/07-object-properties/index.md | 4 +- .../1-property-after-delete/solution.md | 6 +- .../1-property-after-delete/task.md | 28 +- .../2-search-algorithm/solution.md | 36 +- .../2-search-algorithm/task.md | 28 +- .../3-proto-and-this/solution.md | 8 +- .../3-proto-and-this/task.md | 18 +- .../4-hamster-proto/solution.md | 80 +- .../4-hamster-proto/task.md | 32 +- .../01-prototype-inheritance/article.md | 318 +++--- .../object-prototype-empty.svg | 2 +- .../proto-animal-rabbit-chain.svg | 2 +- .../proto-animal-rabbit-walk-2.svg | 2 +- .../proto-animal-rabbit-walk-3.svg | 2 +- .../proto-animal-rabbit-walk.svg | 2 +- .../proto-animal-rabbit.svg | 2 +- .../rabbit-animal-object.svg | 2 +- .../1-changing-prototype/solution.md | 12 +- .../1-changing-prototype/task.md | 72 +- .../4-new-object-same-constructor/solution.md | 50 +- .../4-new-object-same-constructor/task.md | 8 +- .../02-function-prototype/article.md | 154 +-- .../function-prototype-constructor.svg | 2 +- .../proto-constructor-animal-rabbit.svg | 2 +- .../rabbit-prototype-constructor.svg | 2 +- .../1-defer-to-prototype/solution.md | 6 +- .../1-defer-to-prototype/task.md | 10 +- .../2-defer-to-prototype-extended/solution.md | 32 +- .../2-defer-to-prototype-extended/task.md | 10 +- .../03-native-prototypes/article.md | 146 +-- .../function-prototype-constructor.svg | 2 +- .../native-prototypes-classes.svg | 2 +- .../proto-constructor-animal-rabbit.svg | 1 + .../rabbit-prototype-constructor.svg | 2 +- .../2-dictionary-tostring/solution.md | 28 +- .../2-dictionary-tostring/task.md | 28 +- .../3-compare-calls/solution.md | 22 +- .../3-compare-calls/task.md | 24 +- .../04-prototype-methods/article.md | 199 ++-- 1-js/08-prototypes/index.md | 2 +- .../1-rewrite-to-class/_js.view/solution.js | 42 +- .../1-rewrite-to-class/_js.view/source.js | 40 +- .../01-class/1-rewrite-to-class/task.md | 6 +- 1-js/09-classes/01-class/article.md | 390 ++++---- 1-js/09-classes/01-class/class-user.svg | 2 +- .../1-class-constructor-error/solution.md | 22 +- .../1-class-constructor-error/task.md | 24 +- .../solution.view/clock.js | 38 +- .../solution.view/extended-clock.js | 14 +- .../source.view/clock.js | 38 +- .../2-clock-class-extended/task.md | 10 +- .../animal-rabbit-extends.svg | 2 +- .../02-class-inheritance/article.md | 604 +++++------ .../class-inheritance-rabbit-animal-2.svg | 2 +- .../class-inheritance-rabbit-animal.svg | 2 +- .../rabbit-animal-independent-animal.svg | 2 +- .../rabbit-animal-independent-rabbit.svg | 2 +- .../super-homeobject-wrong.svg | 2 +- .../02-class-inheritance/this-super-loop.svg | 2 +- .../rabbit-extends-object.svg | 2 +- .../3-class-extend-object/solution.md | 74 +- .../3-class-extend-object/task.md | 34 +- .../animal-rabbit-static.svg | 2 +- .../03-static-properties-methods/article.md | 224 ++--- .../article.md | 304 +++--- 1-js/09-classes/05-extend-natives/article.md | 78 +- .../object-date-inheritance.svg | 2 +- .../1-strange-instanceof/solution.md | 8 +- .../1-strange-instanceof/task.md | 4 +- 1-js/09-classes/06-instanceof/article.md | 188 ++-- 1-js/09-classes/06-instanceof/instanceof.svg | 2 +- 1-js/09-classes/07-mixins/article.md | 204 ++-- 1-js/09-classes/07-mixins/head.html | 47 +- .../07-mixins/mixin-inheritance.svg | 2 +- 1-js/09-classes/index.md | 2 +- .../1-finally-or-code-after/solution.md | 34 +- .../1-finally-or-code-after/task.md | 28 +- 1-js/10-error-handling/1-try-catch/article.md | 543 +++++----- .../1-try-catch/try-catch-flow.svg | 2 +- .../1-format-error/solution.md | 16 +- .../2-custom-errors/1-format-error/task.md | 20 +- .../2-custom-errors/article.md | 312 +++--- 1-js/10-error-handling/index.md | 2 +- 1-js/11-async/01-callbacks/article.md | 270 ++--- .../01-re-resolve/solution.md | 4 +- .../02-promise-basics/01-re-resolve/task.md | 8 +- .../02-delay-promise/solution.md | 6 +- .../02-delay-promise/task.md | 12 +- .../solution.view/index.html | 14 +- .../03-animate-circle-promise/task.md | 12 +- 1-js/11-async/02-promise-basics/article.md | 349 +++---- 1-js/11-async/02-promise-basics/head.html | 12 +- .../02-promise-basics/promise-reject-1.svg | 2 +- .../02-promise-basics/promise-resolve-1.svg | 2 +- .../promise-resolve-reject.svg | 2 +- .../01-then-vs-catch/solution.md | 14 +- .../01-then-vs-catch/task.md | 10 +- 1-js/11-async/03-promise-chaining/article.md | 350 +++---- 1-js/11-async/03-promise-chaining/head.html | 12 +- 1-js/11-async/03-promise-chaining/one.js | 2 +- .../promise-handler-variants.svg | 2 +- 1-js/11-async/03-promise-chaining/three.js | 2 +- 1-js/11-async/03-promise-chaining/two.js | 2 +- .../01-error-async/solution.md | 8 +- .../01-error-async/task.md | 6 +- .../04-promise-error-handling/article.md | 176 ++-- .../04-promise-error-handling/head.html | 14 +- 1-js/11-async/05-promise-api/article.md | 240 ++--- 1-js/11-async/05-promise-api/head.html | 4 +- 1-js/11-async/06-promisify/article.md | 124 +-- 1-js/11-async/07-microtask-queue/article.md | 102 +- .../07-microtask-queue/promiseQueue.svg | 2 +- .../01-rewrite-async/solution.md | 32 +- .../08-async-await/01-rewrite-async/task.md | 18 +- .../02-rewrite-async-2/solution.md | 52 +- .../08-async-await/02-rewrite-async-2/task.md | 52 +- .../03-async-from-regular/solution.md | 10 +- .../03-async-from-regular/task.md | 14 +- 1-js/11-async/08-async-await/article.md | 216 ++-- 1-js/11-async/index.md | 2 +- .../_js.view/solution.js | 8 +- .../_js.view/test.js | 12 +- .../01-pseudo-random-generator/solution.md | 36 +- .../01-pseudo-random-generator/task.md | 30 +- .../1-generators/article.md | 382 +++---- .../1-generators/genYield2-2.svg | 2 +- .../1-generators/genYield2.svg | 2 +- .../2-async-iterators-generators/article.md | 346 +++---- 1-js/12-generators-iterators/index.md | 2 +- 1-js/13-modules/01-modules-intro/article.md | 362 +++---- .../01-modules-intro/say.view/index.html | 4 +- .../01-modules-intro/say.view/say.js | 4 +- .../scopes-working.view/hello.js | 4 +- .../scopes-working.view/user.js | 2 +- .../01-modules-intro/scopes.view/hello.js | 2 +- .../01-modules-intro/scopes.view/user.js | 2 +- 1-js/13-modules/02-import-export/article.md | 410 ++++---- .../03-modules-dynamic-imports/article.md | 80 +- .../say.view/index.html | 12 +- .../say.view/say.js | 10 +- 1-js/13-modules/index.md | 2 +- .../01-proxy/01-error-nonexisting/solution.md | 22 +- .../01-proxy/01-error-nonexisting/task.md | 28 +- .../01-proxy/02-array-negative/solution.md | 20 +- .../01-proxy/02-array-negative/task.md | 32 +- .../01-proxy/03-observable/solution.md | 46 +- .../99-js-misc/01-proxy/03-observable/task.md | 26 +- 1-js/99-js-misc/01-proxy/article.md | 944 +++++++++--------- .../01-proxy/proxy-inherit-admin.svg | 2 +- 1-js/99-js-misc/01-proxy/proxy-inherit.svg | 2 +- 1-js/99-js-misc/01-proxy/proxy.svg | 2 +- .../02-eval/1-eval-calculator/solution.md | 10 +- .../02-eval/1-eval-calculator/task.md | 6 +- 1-js/99-js-misc/02-eval/article.md | 82 +- .../03-currying-partials/article.md | 150 +-- .../2-check-syntax/solution.md | 34 +- .../04-reference-type/2-check-syntax/task.md | 14 +- .../04-reference-type/3-why-this/solution.md | 20 +- .../04-reference-type/3-why-this/task.md | 18 +- 1-js/99-js-misc/04-reference-type/article.md | 108 +- 1-js/99-js-misc/05-bigint/article.md | 96 +- 1-js/99-js-misc/index.md | 2 +- 1-js/index.md | 6 +- 479 files changed, 13400 insertions(+), 13389 deletions(-) create mode 100644 1-js/08-prototypes/03-native-prototypes/proto-constructor-animal-rabbit.svg diff --git a/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md b/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md index 4facc8b29..2e6870983 100644 --- a/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md +++ b/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md @@ -1,48 +1,48 @@ -You could note the following: +Měli byste si všimnout následujícího: ```js no-beautify -function pow(x,n) // <- no space between arguments -{ // <- figure bracket on a separate line - let result=1; // <- no spaces before or after = - for(let i=0;i -Now let's discuss the rules and reasons for them in detail. +Nyní si tato pravidla a jejich důvody probereme podrobně. -```warn header="There are no \"you must\" rules" -Nothing is set in stone here. These are style preferences, not religious dogmas. +```warn header="Toto nejsou žádná povinná pravidla" +Nic tady není zasazeno do kamene. Toto jsou stylové preference, ne náboženská dogmata. ``` -### Curly Braces +### Složené závorky -In most JavaScript projects curly braces are written in "Egyptian" style with the opening brace on the same line as the corresponding keyword -- not on a new line. There should also be a space before the opening bracket, like this: +Ve většině JavaScriptových projektů se složené závorky píší „egyptským“ stylem, kdy je levá závorka na stejném řádku jako odpovídající klíčové slovo -- ne na novém řádku. Před levou závorkou by také měla být mezera, jako zde: ```js -if (condition) { - // do this - // ...and that - // ...and that +if (podmínka) { + // dělej tohle + // ...a tohle + // ...a tohle } ``` -A single-line construct, such as `if (condition) doSomething()`, is an important edge case. Should we use braces at all? +Důležitým krajním případem je jednořádková konstrukce, například `if (podmínka) dělejNěco()`. Měli bychom vůbec použít závorky? -Here are the annotated variants so you can judge their readability for yourself: +Uvádíme jednotlivé varianty s komentářem, takže můžete sami posoudit jejich čitelnost: -1. 😠 Beginners sometimes do that. Bad! Curly braces are not needed: +1. 😠 Začátečníci někdy píší takto. Špatně! Složené závorky nejsou zapotřebí: ```js - if (n < 0) *!*{*/!*alert(`Power ${n} is not supported`);*!*}*/!* + if (n < 0) *!*{*/!*alert(`${n}-tá mocnina není podporována`);*!*}*/!* ``` -2. 😠 Split to a separate line without braces. Never do that, easy to make an error when adding new lines: +2. 😠 Umístění na samostatný řádek bez složených závorek. Tohle nikdy nedělejte, jelikož snadno uděláte chybu, když budete přidávat další řádky: ```js if (n < 0) - alert(`Power ${n} is not supported`); + alert(`${n}-tá mocnina není podporována`); ``` -3. 😏 One line without braces - acceptable, if it's short: +3. 😏 Jeden řádek bez složených závorek - to je přijatelné, pokud je krátký: ```js - if (n < 0) alert(`Power ${n} is not supported`); + if (n < 0) alert(`${n}-tá mocnina není podporována`); ``` -4. 😃 The best variant: +4. 😃 Nejlepší varianta: ```js if (n < 0) { - alert(`Power ${n} is not supported`); + alert(`${n}-tá mocnina není podporována`); } ``` -For a very brief code, one line is allowed, e.g. `if (cond) return null`. But a code block (the last variant) is usually more readable. +Pro velmi krátký kód je dovolen jeden řádek, např. `if (podmínka) return null`. Ale kódový blok (poslední uvedená varianta) bývá obvykle čitelnější. -### Line Length +### Délka řádku -No one likes to read a long horizontal line of code. It's best practice to split them. +Nikdo není rád, když musí číst dlouhý vodorovný řádek kódu. Lepší přístup je rozdělit jej. -For example: +Například: ```js -// backtick quotes ` allow to split the string into multiple lines -let str = ` - ECMA International's TC39 is a group of JavaScript developers, - implementers, academics, and more, collaborating with the community - to maintain and evolve the definition of JavaScript. +// zpětné uvozovky ` umožňují rozdělit řádek na více řádků +let řetězec = ` + TC39 v ECMA International je skupina JavaScriptových vývojářů, + implementátorů, akademiků a dalších, kteří spolupracují s komunitou, + aby udržovali a rozvíjeli definici JavaScriptu. `; ``` -And, for `if` statements: +A pro příkazy `if`: ```js if ( id === 123 && - moonPhase === 'Waning Gibbous' && - zodiacSign === 'Libra' + měsíčníFáze === 'Ubývání' && + znameníZvěrokruhu === 'Váhy' ) { - letTheSorceryBegin(); + začniKouzlo(); } ``` -The maximum line length should be agreed upon at the team-level. It's usually 80 or 120 characters. +Na maximální délce řádku by se měl dohodnout celý tým. Obvykle bývá 80 nebo 120 znaků. -### Indents +### Odsazení -There are two types of indents: +Existují dva druhy odsazení: -- **Horizontal indents: 2 or 4 spaces.** +- **Vodorovné odsazení: 2 nebo 4 mezery.** - A horizontal indentation is made using either 2 or 4 spaces or the horizontal tab symbol (key `key:Tab`). Which one to choose is an old holy war. Spaces are more common nowadays. + Vodorovné odsazení se dělá pomocí 2 nebo 4 mezer nebo pomocí vodorovného symbolu tabulátoru (klávesa `key:Tab`). O tom, které zvolit, se už dlouho vedou svaté války. V dnešní době se více používají mezery. - One advantage of spaces over tabs is that spaces allow more flexible configurations of indents than the tab symbol. + Výhodou mezer oproti tabulátorům je, že mezery umožňují konfigurovat odsazení flexibilněji než symbol tabulátoru. - For instance, we can align the parameters with the opening bracket, like this: + Můžeme například zarovnat parametry k levé závorce takto: ```js no-beautify - show(parameters, - aligned, // 5 spaces padding at the left - one, - after, - another + zobraz(parametry, + zarovnané, // vlevo je odsazení 7 mezer + jeden, + za, + druhým ) { // ... } ``` -- **Vertical indents: empty lines for splitting code into logical blocks.** +- **Svislé odsazení: prázdné řádky pro rozdělení kódu do logických bloků.** - Even a single function can often be divided into logical blocks. In the example below, the initialization of variables, the main loop and returning the result are split vertically: + I jediná funkce může být často rozdělena do logických bloků. V níže uvedeném příkladu jsou svisle odděleny inicializace proměnných, hlavní smyčka a vrácení výsledku: ```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; } ``` - Insert an extra newline where it helps to make the code more readable. There should not be more than nine lines of code without a vertical indentation. + Vkládejte prázdný nový řádek všude, kde pomáhá učinit kód čitelnějším. V kódu by nemělo být více než devět řádků za sebou bez svislého odsazení. -### Semicolons +### Středníky -A semicolon should be present after each statement, even if it could possibly be skipped. +Středník by měl být uveden za každým příkazem, i kdyby mohl být vynechán. -There are languages where a semicolon is truly optional and it is rarely used. In JavaScript, though, there are cases where a line break is not interpreted as a semicolon, leaving the code vulnerable to errors. See more about that in the chapter . +Existují jazyky, v nichž je středník zcela dobrovolný a používá se jen zřídka. V JavaScriptu však existují případy, kdy se zlom řádku neinterpretuje jako středník, čímž se kód stává náchylnějším k chybám. Více o tom se píše v kapitole . -If you're an experienced JavaScript programmer, you may choose a no-semicolon code style like [StandardJS](https://standardjs.com/). Otherwise, it's best to use semicolons to avoid possible pitfalls. The majority of developers put semicolons. +Jste-li zkušený programátor v JavaScriptu, můžete se rozhodnout pro bezstředníkový kódovací styl, např. [StandardJS](https://standardjs.com/). Jinak je však lepší středníky používat, abyste se vyhnuli možným úskalím. Většina vývojářů středníky uvádí. -### Nesting Levels +### Úrovně vnoření -Try to avoid nesting code too many levels deep. +Snažte se vyhnout příliš mnoha úrovním vnoření. -For example, in the loop, it's sometimes a good idea to use the [`continue`](info:while-for#continue) directive to avoid extra nesting. +Například v cyklu je někdy dobrý nápad použít direktivu [`continue`](info:while-for#continue), abychom se vyhnuli dalšímu vnoření. -For example, instead of adding a nested `if` conditional like this: +Například místo použití vnořené podmínky `if` tímto způsobem: ```js for (let i = 0; i < 10; i++) { - if (cond) { - ... // <- one more nesting level + if (podmínka) { + ... // <- o jednu úroveň vnoření víc } } ``` -We can write: +můžeme napsat: ```js for (let i = 0; i < 10; i++) { - if (!cond) *!*continue*/!*; - ... // <- no extra nesting level + if (!podmínka) *!*continue*/!*; + ... // <- žádná další úroveň vnoření } ``` -A similar thing can be done with `if/else` and `return`. +Podobně můžeme postupovat s `if/else` a `return`. -For example, two constructs below are identical. +Například dvě níže uvedené konstrukce jsou identické. -Option 1: +Možnost 1: ```js -function pow(x, n) { +function mocnina(x, n) { if (n < 0) { - alert("Negative 'n' not supported"); + alert("Záporné 'n' není podporováno"); } else { - let result = 1; + let výsledek = 1; for (let i = 0; i < n; i++) { - result *= x; + výsledek *= x; } - return result; + return výsledek; } } ``` -Option 2: +Možnost 2: ```js -function pow(x, n) { +function mocnina(x, n) { if (n < 0) { - alert("Negative 'n' not supported"); + alert("Záporné 'n' není podporováno"); return; } - let result = 1; + let výsledek = 1; for (let i = 0; i < n; i++) { - result *= x; + výsledek *= x; } - return result; + return výsledek; } ``` -The second one is more readable because the "special case" of `n < 0` is handled early on. Once the check is done we can move on to the "main" code flow without the need for additional nesting. +Druhá konstrukce je čitelnější, protože „zvláštní případ“ `n < 0` je ošetřen hned na začátku. Když je kontrola provedena, můžeme se přesunout k „hlavnímu“ toku kódu, aniž bychom potřebovali další vnoření. -## Function Placement +## Umístění funkcí -If you are writing several "helper" functions and the code that uses them, there are three ways to organize the functions. +Jestliže píšeme několik „pomocných“ funkcí a kód, který je používá, máme tři možnosti, jak funkce organizovat. -1. Declare the functions *above* the code that uses them: +1. Deklarovat funkce *před* kódem, který je používá: ```js - // *!*function declarations*/!* - function createElement() { + // *!*deklarace funkcí*/!* + function vytvořPrvek() { ... } - function setHandler(elem) { + function nastavHandler(prvek) { ... } - function walkAround() { + function choďKolem() { ... } - // *!*the code which uses them*/!* - let elem = createElement(); - setHandler(elem); - walkAround(); + // *!*kód, který je používá*/!* + let prvek = vytvořPrvek(); + nastavHandler(prvek); + choďKolem(); ``` -2. Code first, then functions +2. Nejprve kód, pak funkce: ```js - // *!*the code which uses the functions*/!* - let elem = createElement(); - setHandler(elem); - walkAround(); + // *!*kód, který používá funkce*/!* + let prvek = vytvořPrvek(); + nastavHandler(prvek); + choďKolem(); - // --- *!*helper functions*/!* --- - function createElement() { + // --- *!*pomocné funkce*/!* --- + function vytvořPrvek() { ... } - function setHandler(elem) { + function nastavHandler(prvek) { ... } - function walkAround() { + function choďKolem() { ... } ``` -3. Mixed: a function is declared where it's first used. +3. Směs: funkce je deklarována tam, kde je poprvé použita. -Most of time, the second variant is preferred. +Ve většině případů se dává přednost druhé variantě. -That's because when reading code, we first want to know *what it does*. If the code goes first, then it becomes clear from the start. Then, maybe we won't need to read the functions at all, especially if their names are descriptive of what they actually do. +Je to proto, že při čtení kódu chceme nejdříve vědět, *co kód dělá*. Pokud je kód uveden jako první, bude to zřejmé od začátku. Pak možná nebudeme muset funkce vůbec číst, zvláště pokud je z jejich názvů dostatečně jasné, co dělají. -## Style Guides +## Styloví průvodci -A style guide contains general rules about "how to write" code, e.g. which quotes to use, how many spaces to indent, the maximal line length, etc. A lot of minor things. +Stylový průvodce obsahuje obecná pravidla o tom, „jak psát“ kód, tj. které uvozovky používat, o kolik mezer odsazovat, maximální délku řádku atd. Mnoho vedlejších věcí. -When all members of a team use the same style guide, the code looks uniform, regardless of which team member wrote it. +Když všichni členové týmu používají stejného stylového průvodce, bude kód vypadat jednotně bez ohledu na to, který člen týmu ho napsal. -Of course, a team can always write their own style guide, but usually there's no need to. There are many existing guides to choose from. +Samozřejmě si tým vždy může napsat svého vlastního stylového průvodce, ale obvykle to není zapotřebí. Existuje mnoho průvodců, z nichž si lze vybrat. -Some popular choices: +Některé oblíbené možnosti: -- [Google JavaScript Style Guide](https://google.github.io/styleguide/jsguide.html) -- [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript) +- [JavaScriptový stylový průvodce Google](https://google.github.io/styleguide/jsguide.html) +- [JavaScriptový stylový průvodce Airbnb](https://github.com/airbnb/javascript) - [Idiomatic.JS](https://github.com/rwaldron/idiomatic.js) - [StandardJS](https://standardjs.com/) -- (plus many more) +- (a mnoho dalších) -If you're a novice developer, start with the cheat sheet at the beginning of this chapter. Then you can browse other style guides to pick up more ideas and decide which one you like best. +Pokud jste začínající vývojář, začněte podle příkladu na začátku této kapitoly. Pak si můžete projít jiné stylové průvodce, abyste získali další nápady a rozhodli se, který se vám líbí nejvíc. -## Automated Linters +## Automatické lintery -Linters are tools that can automatically check the style of your code and make improving suggestions. +Lintery jsou nástroje, které umějí automaticky zkontrolovat styl vašeho kódu a navrhnout zlepšení. -The great thing about them is that style-checking can also find some bugs, like typos in variable or function names. Because of this feature, using a linter is recommended even if you don't want to stick to one particular "code style". +Výborné na nich je, že tato kontrola stylu umí najít i některé chyby, například překlepy v názvech proměnných nebo funkcí. Pro tuto jejich vlastnost se používání linteru doporučuje, i když se nechcete vázat k jednomu konkrétnímu „kódovacímu stylu“. -Here are some well-known linting tools: +Zde jsou některé dobře známé lintery: -- [JSLint](https://www.jslint.com/) -- one of the first linters. -- [JSHint](https://jshint.com/) -- more settings than JSLint. -- [ESLint](https://eslint.org/) -- probably the newest one. +- [JSLint](https://www.jslint.com/) -- jeden z prvních linterů. +- [JSHint](https://www.jshint.com/) -- více nastavení než JSLint. +- [ESLint](https://eslint.org/) -- pravděpodobně nejnovější. -All of them can do the job. The author uses [ESLint](https://eslint.org/). +Všechny tuto práci odvedou. Autor používá [ESLint](http://eslint.org/). -Most linters are integrated with many popular editors: just enable the plugin in the editor and configure the style. +Většina linterů je integrována s mnoha oblíbenými editory: jednoduše povolte plugin v editoru a nakonfigurujte styl. -For instance, for ESLint you should do the following: +Například pro ESLint byste měli udělat následující: -1. Install [Node.js](https://nodejs.org/). -2. Install ESLint with the command `npm install -g eslint` (npm is a JavaScript package installer). -3. Create a config file named `.eslintrc` in the root of your JavaScript project (in the folder that contains all your files). -4. Install/enable the plugin for your editor that integrates with ESLint. The majority of editors have one. +1. Nainstalujte [Node.js](https://nodejs.org/). +2. Nainstalujte ESLint příkazem `npm install -g eslint` (npm je instalátor JavaScriptových balíků). +3. Vytvořte konfigurační soubor s názvem `.eslintrc` v kořenové složce vašeho JavaScriptového projektu (ve složce, která obsahuje všechny vaše soubory). +4. Nainstalujte/povolte ve svém editoru plugin, který jej spojí s ESLintem. Většina editorů jej má. -Here's an example of an `.eslintrc` file: +Uvádíme příklad souboru `.eslintrc`: ```js { @@ -333,16 +333,16 @@ Here's an example of an `.eslintrc` file: } ``` -Here the directive `"extends"` denotes that the configuration is based on the "eslint:recommended" set of settings. After that, we specify our own. +Zde direktiva `"extends"` oznamuje, že konfigurace je založena na sadě nastavení „eslint:recommended“. Poté si specifikujeme vlastní. -It is also possible to download style rule sets from the web and extend them instead. See for more details about installation. +Je také možné si místo toho stáhnout sady stylových pravidel z webu a pak je rozšířit. Pro podrobnosti ohledně instalace viz . -Also certain IDEs have built-in linting, which is convenient but not as customizable as ESLint. +Také některá IDE obsahují zabudovaný linting, který je vyhovující, ale ne tak nastavitelný jako ESLint. -## Summary +## Shrnutí -All syntax rules described in this chapter (and in the style guides referenced) aim to increase the readability of your code. All of them are debatable. +Všechna syntaktická pravidla uvedená v této kapitole (a v odkazovaných stylových průvodcích) směřují ke zvýšení čitelnosti vašeho kódu. Všechna jsou diskutovatelná. -When we think about writing "better" code, the questions we should ask ourselves are: "What makes the code more readable and easier to understand?" and "What can help us avoid errors?" These are the main things to keep in mind when choosing and debating code styles. +Když uvažujeme o psaní „lepšího“ kódu, měli bychom si klást otázky „Co učiní kód čitelnějším a snadnějším k porozumění?“ a „Co nám pomůže vyvarovat se chyb?“. To je to hlavní, co bychom měli mít na paměti, když si vybíráme styly kódování a diskutujeme o nich. -Reading popular style guides will allow you to keep up to date with the latest ideas about code style trends and best practices. +Čtení oblíbených stylových průvodců nám umožní držet krok s nejnovějšími idejemi o trendech kódovacích stylů a nejlepších praktikách. diff --git a/1-js/03-code-quality/02-coding-style/code-style.svg b/1-js/03-code-quality/02-coding-style/code-style.svg index 739d9f1ed..4a5acdb09 100644 --- a/1-js/03-code-quality/02-coding-style/code-style.svg +++ b/1-js/03-code-quality/02-coding-style/code-style.svg @@ -1 +1 @@ -2No space between the function name and parentheses between the parentheses and the parameterIndentation 2 spacesA space after for/if/while…} else { without a line breakSpaces around a nested callAn empty line between logical blocksLines are not very longA semicolon ; is mandatorySpaces around operatorsCurly brace { on the same line, after a spaceA space between argumentsA space between parameters \ No newline at end of file +2Bez mezer mezi názvem funkcí a závorkou mezi závorkou a parametremOdsazení 2 mezeryMezera za for/if/while…} else { bez konce řádkuMezery kolem vnořeného voláníPrázdný řádek mezi logickými blokyŘádky nejsou příliš dlouhéStředník ; je povinnýMezery kolem operátorůSložená závorka { na stejném řádku za mezerouMezera mezi argumentyMezera mezi parametry \ No newline at end of file diff --git a/1-js/03-code-quality/03-comments/article.md b/1-js/03-code-quality/03-comments/article.md index af3a06c80..069e158a6 100644 --- a/1-js/03-code-quality/03-comments/article.md +++ b/1-js/03-code-quality/03-comments/article.md @@ -1,40 +1,40 @@ -# Comments +# Komentáře -As we know from the chapter , comments can be single-line: starting with `//` and multiline: `/* ... */`. +Jak víme z kapitoly , komentáře mohou být jednořádkové, které začínají `//`, a víceřádkové `/* ... */`. -We normally use them to describe how and why the code works. +Obvykle je používáme k popisu, jak a proč kód funguje. -At first sight, commenting might be obvious, but novices in programming often use them wrongly. +Na první pohled může být komentování samozřejmé, ale začínající programátoři je často používají nesprávně. -## Bad comments +## Špatné komentáře -Novices tend to use comments to explain "what is going on in the code". Like this: +Začátečníci tíhnou k psaní komentářů, které vysvětlují, „co se v kódu děje“. Například: ```js -// This code will do this thing (...) and that thing (...) -// ...and who knows what else... -very; -complex; -code; +// Tento kód dělá toto (...) a toto (...) +// ...a kdo ví, co jiného... +velmi; +složitý; +kód; ``` -But in good code, the amount of such "explanatory" comments should be minimal. Seriously, the code should be easy to understand without them. +V dobrém kódu by však množství takových „vysvětlujících“ komentářů mělo být minimální. Opravdu by kód měl být srozumitelný i bez nich. -There's a great rule about that: "if the code is so unclear that it requires a comment, then maybe it should be rewritten instead". +Platí jedno zlaté pravidlo: „Je-li kód natolik nejasný, že vyžaduje komentář, možná by místo toho měl být přepsán.“ -### Recipe: factor out functions +### Recept: extrahujte funkce -Sometimes it's beneficial to replace a code piece with a function, like here: +Někdy se vyplatí nahradit kus kódu funkcí, například: ```js -function showPrimes(n) { - nextPrime: +function zobrazPrvočísla(n) { + dalšíPrvočíslo: for (let i = 2; i < n; i++) { *!* - // check if i is a prime number + // ověří, zda i je prvočíslo for (let j = 2; j < i; j++) { - if (i % j == 0) continue nextPrime; + if (i % j == 0) continue dalšíPrvočíslo; } */!* @@ -43,20 +43,20 @@ function showPrimes(n) { } ``` -The better variant, with a factored out function `isPrime`: +Lepší varianta s vyjmutou funkcí `jePrvočíslo`: ```js -function showPrimes(n) { +function zobrazPrvočísla(n) { for (let i = 2; i < n; i++) { - *!*if (!isPrime(i)) continue;*/!* + *!*if (!jePrvočíslo(i)) continue;*/!* alert(i); } } -function isPrime(n) { +function jePrvočíslo(n) { for (let i = 2; i < n; i++) { if (n % i == 0) return false; } @@ -65,116 +65,116 @@ function isPrime(n) { } ``` -Now we can understand the code easily. The function itself becomes the comment. Such code is called *self-descriptive*. +Nyní kódu snadno porozumíme. Funkce sama o sobě se stává komentářem. Takový kód se nazývá *sebepopisující*. -### Recipe: create functions +### Recept: vytvářejte funkce -And if we have a long "code sheet" like this: +A máme-li dlouhý „kus kódu“, jako třeba: ```js -// here we add whiskey +// zde přidáme whisky for(let i = 0; i < 10; i++) { - let drop = getWhiskey(); - smell(drop); - add(drop, glass); + let kapka = vezmiWhisky(); + přičichni(kapka); + přidej(kapka, sklenice); } -// here we add juice +// zde přidáme džus for(let t = 0; t < 3; t++) { - let tomato = getTomato(); - examine(tomato); - let juice = press(tomato); - add(juice, glass); + let rajče = vezmiRajče(); + prozkoumej(rajče); + let džus = rozmačkej(rajče); + přidej(džus, sklenice); } // ... ``` -Then it might be a better variant to refactor it into functions like: +pak může být lepší varianta jej přepsat do funkcí takto: ```js -addWhiskey(glass); -addJuice(glass); +přidejWhisky(sklenice); +přidejDžus(sklenice); -function addWhiskey(container) { +function přidejWhisky(nádoba) { for(let i = 0; i < 10; i++) { - let drop = getWhiskey(); + let kapka = vezmiWhisky(); //... } } -function addJuice(container) { +function přidejDžus(nádoba) { for(let t = 0; t < 3; t++) { - let tomato = getTomato(); + let rajče = vezmiRajče(); //... } } ``` -Once again, functions themselves tell what's going on. There's nothing to comment. And also the code structure is better when split. It's clear what every function does, what it takes and what it returns. +Opět funkce samy o sobě říkají, co se děje. Není tady co komentovat. I struktura kódu je lepší, když je kód rozdělený. Je jasné, co která funkce provádí, co přijímá a co vrací. -In reality, we can't totally avoid "explanatory" comments. There are complex algorithms. And there are smart "tweaks" for purposes of optimization. But generally we should try to keep the code simple and self-descriptive. +V realitě se nemůžeme „vysvětlujícím“ komentářům úplně vyhnout. Existují složité algoritmy a existují chytrá „vylepšení“ pro účely optimalizace. Obecně bychom se však měli snažit udržet kód jednoduchý a sebepopisující. -## Good comments +## Dobré komentáře -So, explanatory comments are usually bad. Which comments are good? +Vysvětlující komentáře jsou tedy obecně špatné. Jaké komentáře jsou dobré? -Describe the architecture -: Provide a high-level overview of components, how they interact, what's the control flow in various situations... In short -- the bird's eye view of the code. There's a special language [UML](http://wikipedia.org/wiki/Unified_Modeling_Language) to build high-level architecture diagrams explaining the code. Definitely worth studying. +Popis architektury +: Poskytují vysokoúrovňový pohled na komponenty, jak spolu interagují, jaký je řídicí tok v různých situacích... Stručně řečeno -- pohled na kód z ptačí perspektivy. Existuje i speciální jazyk [UML](http://wikipedia.org/wiki/Unified_Modeling_Language) určený k tvorbě diagramů na vysoké úrovni architektury, které popisují kód. Rozhodně má smysl si jej prostudovat. -Document function parameters and usage -: There's a special syntax [JSDoc](http://en.wikipedia.org/wiki/JSDoc) to document a function: usage, parameters, returned value. +Dokumentace parametrů a použití funkcí +: Existuje speciální syntaxe [JSDoc](http://en.wikipedia.org/wiki/JSDoc) pro dokumentaci funkcí: použití, parametry, návratová hodnota. -For instance: +Například: ```js /** - * Returns x raised to the n-th power. + * Vrátí x umocněné na n-tou. * - * @param {number} x The number to raise. - * @param {number} n The power, must be a natural number. - * @return {number} x raised to the n-th power. + * @param {number} x Číslo, které se má umocnit. + * @param {number} n Exponent, musí být přirozené číslo. + * @return {number} x umocněné na n-tou. */ -function pow(x, n) { +function mocnina(x, n) { ... } ``` -Such comments allow us to understand the purpose of the function and use it the right way without looking in its code. +Takové komentáře nám umožňují porozumět účelu funkce a používat ji správně, aniž bychom se dívali na její kód. -By the way, many editors like [WebStorm](https://www.jetbrains.com/webstorm/) can understand them as well and use them to provide autocomplete and some automatic code-checking. +Mimochodem i mnoho editorů, například [WebStorm](https://www.jetbrains.com/webstorm/), jim dokáže porozumět a používá je k automatickému doplňování a určité automatické kontrole kódu. -Also, there are tools like [JSDoc 3](https://github.com/jsdoc/jsdoc) that can generate HTML-documentation from the comments. You can read more information about JSDoc at . +Existují i nástroje jako [JSDoc 3](https://github.com/jsdoc/jsdoc), které umějí z těchto komentářů vygenerovat dokumentaci v HTML. Více informací o JSDoc si můžete přečíst na . -Why is the task solved this way? -: What's written is important. But what's *not* written may be even more important to understand what's going on. Why is the task solved exactly this way? The code gives no answer. +Proč se tato úloha řeší zrovna takhle? +: To, co je psáno, je důležité. Ale to, co *není* psáno, může být ještě důležitější k pochopení toho, o co jde. Proč je tato úloha řešena právě tímto způsobem? Kód nám odpověď nedává. - If there are many ways to solve the task, why this one? Especially when it's not the most obvious one. + Existuje-li mnoho způsobů, jak tuto úlohu řešit, proč zrovna tento? Zvláště pokud to není zrovna ten nejzřejmější. - Without such comments the following situation is possible: - 1. You (or your colleague) open the code written some time ago, and see that it's "suboptimal". - 2. You think: "How stupid I was then, and how much smarter I'm now", and rewrite using the "more obvious and correct" variant. - 3. ...The urge to rewrite was good. But in the process you see that the "more obvious" solution is actually lacking. You even dimly remember why, because you already tried it long ago. You revert to the correct variant, but the time was wasted. + Bez takových komentářů může nastat následující situace: + 1. Vy (nebo váš kolega) otevřete kód, napsaný před nějakou dobou, a vidíte, že je „suboptimální“. + 2. Pomyslíte si: „To jsem byl tehdy ale hloupý, teď jsem o hodně chytřejší“, a přepíšete ho na „jasnější a korektnější“ variantu. + 3. ...Potřeba přepsat kód byla dobrá. Ale po spuštění uvidíte, že „jasnější“ řešení je ve skutečnosti horší. Matně si vzpomenete proč, jelikož jste je už před dlouhou dobou zkoušeli. Vrátíte kód na korektní variantu, ale byla to ztráta času. - Comments that explain the solution are very important. They help to continue development the right way. + Komentáře, které vysvětlují řešení, jsou velmi důležité, protože nám pomáhají vyvíjet správnou cestou. -Any subtle features of the code? Where they are used? -: If the code has anything subtle and counter-intuitive, it's definitely worth commenting. +Jsou v kódu nějaké finty? Proč jsou použity? +: Obsahuje-li kód cokoli promyšleného a neintuitivního, má rozhodně smysl jej komentovat. -## Summary +## Shrnutí -An important sign of a good developer is comments: their presence and even their absence. +Komentáře jsou důležitým znakem dobrého vývojáře: jejich přítomnost, ale i jejich absence. -Good comments allow us to maintain the code well, come back to it after a delay and use it more effectively. +Dobré komentáře nám umožňují kód dobře udržovat, později se k němu vracet a efektivněji jej využívat. -**Comment this:** +**Komentujte toto:** -- Overall architecture, high-level view. -- Function usage. -- Important solutions, especially when not immediately obvious. +- Celkovou architekturu, pohled z vysoké úrovně. +- Používání funkcí. +- Důležitá řešení, zvláště pokud nejsou jasná na první pohled. -**Avoid comments:** +**Zdržte se komentářů:** -- That tell "how code works" and "what it does". -- Put them in only if it's impossible to make the code so simple and self-descriptive that it doesn't require them. +- Které vysvětlují „jak kód funguje“ a „co dělá“. +- Vkládejte je jen tehdy, když není možné udržet kód natolik jednoduchý a sebepopisující, že je nevyžaduje. -Comments are also used for auto-documenting tools like JSDoc3: they read them and generate HTML-docs (or docs in another format). +Komentáře se také používají pro nástroje automatické dokumentace jako JSDoc3, které je načtou a vygenerují z nich dokumentaci v HTML (nebo v jakémkoli jiném formátu). 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 96fdf4143..8b4e82b49 100644 --- a/1-js/03-code-quality/04-ninja-code/article.md +++ b/1-js/03-code-quality/04-ninja-code/article.md @@ -1,240 +1,241 @@ -# Ninja code +# Ninjův kód -```quote author="Confucius (Analects)" -Learning without thought is labor lost; thought without learning is perilous. +```quote author="Konfucius (Hovory)" +Učení bez myšlení je zbytečná práce; myšlení bez učení je nebezpečné. ``` -Programmer ninjas of the past used these tricks to sharpen the mind of code maintainers. +Tyto triky používali programátorští ninjové v minulosti, aby zostřili mysl údržbářů kódu. -Code review gurus look for them in test tasks. +Zasvěcení recenzenti kódu je hledají v testovacích úlohách. -Novice developers sometimes use them even better than programmer ninjas. +Začínající vývojáři je někdy používají ještě lépe než programátorští ninjové. -Read them carefully and find out who you are -- a ninja, a novice, or maybe a code reviewer? +Pozorně si je přečtěte a zjistěte, kdo jste -- ninja, začátečník, nebo snad recenzent kódu? -```warn header="Irony detected" -Many try to follow ninja paths. Few succeed. +```warn header="Detekována ironie" +Mnozí lidé se snaží následovat cesty ninjů. Jen málokteří uspějí. ``` -## Brevity is the soul of wit +## Stručnost je duší důvtipu -Make the code as short as possible. Show how smart you are. +Snažte se napsat kód co nejkratší. Ukažte všem, jak jste chytří. -Let subtle language features guide you. +Nechte se vést jemnými prvky jazyka. -For instance, take a look at this ternary operator `'?'`: +Podívejte se například na tento ternární operátor `'?'`: ```js -// taken from a well-known javascript library +// převzato z dobře známé JavaScriptové knihovny i = i ? i < 0 ? Math.max(0, len + i) : i : 0; ``` -Cool, right? If you write like that, a developer who comes across this line and tries to understand what is the value of `i` is going to have a merry time. Then come to you, seeking for an answer. +Hezké, ne? Budete-li takhle psát, zažije vývojář, který narazí na tento řádek a bude se snažit porozumět, jaká je hodnota `i`, veselé chvíle. Pak přijde za vámi a bude žádat odpověď. -Tell them that shorter is always better. Initiate them into the paths of ninja. +Řekněte mu, že co je kratší, to je vždy lepší. Zasvěťte ho do cest ninjů. -## One-letter variables +## Jednopísmenné proměnné -```quote author="Laozi (Tao Te Ching)" -The Dao hides in wordlessness. Only the Dao is well begun and well -completed. +```quote author="Laozi (Tao te ťing)" +Dao spočívá v bezeslovnosti. Jedině Dao správně začíná a správně končí. ``` -Another way to code shorter is to use single-letter variable names everywhere. Like `a`, `b` or `c`. +Další způsob, jak zkrátit kód, je všude používat jednopísmenné názvy proměnných, např. `a`, `b` nebo `c`. -A short variable disappears in the code like a real ninja in the forest. No one will be able to find it using "search" of the editor. And even if someone does, they won't be able to "decipher" what the name `a` or `b` means. +Krátká proměnná se v kódu ztratí jako opravdový ninja v lese. Nikdo ji nebude moci najít pomocí funkce hledání v editoru. A i kdyby ano, nedokáže „rozšifrovat“, co názvy `a` nebo `b` znamenají. -...But there's an exception. A real ninja will never use `i` as the counter in a `"for"` loop. Anywhere, but not here. Look around, there are many more exotic letters. For instance, `x` or `y`. +...Je tady však jedna výjimka. Opravdový ninja nikdy nepoužije `i` jako čítač v cyklu `„for“`. Všude, jen ne tam. Jen se rozhlédněte kolem, existuje spousta exotičtějších písmen, např. `x` nebo `y`. -An exotic variable as a loop counter is especially cool if the loop body takes 1-2 pages (make it longer if you can). Then if someone looks deep inside the loop, they won't be able to quickly figure out that the variable named `x` is the loop counter. +Exotická proměnná jako čítač v cyklu je obzvláště půvabná, jestliže tělo cyklu zabírá 1-2 stránky (můžete-li, napište je co nejdelší). Když se potom někdo podívá hlouběji do cyklu, nebude schopen rychle přijít na to, že proměnná `x` je čítač cyklu. -## Use abbreviations +## Používejte zkratky -If the team rules forbid the use of one-letter and vague names -- shorten them, make abbreviations. +Jestliže týmová pravidla zakazují používat jednopísmenné a vágní názvy, zkracujte je. Vytvářejte zkratky. -Like this: +Třeba takto: -- `list` -> `lst`. -- `userAgent` -> `ua`. -- `browser` -> `brsr`. -- ...etc +- `seznam` -> `szn`. +- `uživatelskýAgent` -> `ua`. +- `prohlížeč` -> `prhl`. +- ...atd. -Only the one with truly good intuition will be able to understand such names. Try to shorten everything. Only a worthy person should be able to uphold the development of your code. +Jedině osoba s opravdu dobrou intuicí pak bude schopna takové názvy pochopit. Snažte se zkrátit všechno. Jen úctyhodný člověk pak bude moci podpořit vývoj vašeho kódu. -## Soar high. Be abstract. +## Stoupejte vzhůru. Buďte abstraktní. -```quote author="Laozi (Tao Te Ching)" -The great square is cornerless
-The great vessel is last complete,
-The great note is rarified sound,
-The great image has no form. +```quote author="Laozi (Tao te ťing) (překlad Václav Cílek)" +velký čtverec nemá rohy
+velkou nádobu neuděláš hned
+velký tón není slyšet
+velká podoba je bez tvaru
``` -While choosing a name try to use the most abstract word. Like `obj`, `data`, `value`, `item`, `elem` and so on. +Když volíte název, snažte se použít co nejabstraktnější slovo. Třeba `obj`, `data`, `hodnota`, `prvek`, `element` a podobně. -- **The ideal name for a variable is `data`.** Use it everywhere you can. Indeed, every variable holds *data*, right? +- **Ideální název proměnné je `data`.** Používejte jej všude, kde můžete. Každá proměnná přece obsahuje nějaká *data*, ne? - ...But what to do if `data` is already taken? Try `value`, it's also universal. After all, a variable eventually gets a *value*. + ...Ale co když je název `data` už zabrán? Zkuste `hodnota`, to je také univerzální. Koneckonců každá proměnná nakonec bude mít nějakou *hodnotu*. -- **Name a variable by its type: `str`, `num`...** +- **Pojmenujte proměnnou podle jejího typu: `řetězec`, `číslo`...** - Give them a try. A young initiate may wonder -- are such names really useful for a ninja? Indeed, they are! + Zkuste to. Mladý učedník se může divit -- jsou takové názvy pro ninju opravdu užitečné? Ale ano, jsou! - Sure, the variable name still means something. It says what's inside the variable: a string, a number or something else. But when an outsider tries to understand the code, they'll be surprised to see that there's actually no information at all! And will ultimately fail to alter your well-thought code. + Jistě, takový název proměnné stále něco znamená. Říká, co proměnná obsahuje: řetězec, číslo nebo něco jiného. Když se však outsider pokusí porozumět kódu, bude překvapen, že vidí, že název neobsahuje vlastně vůbec žádnou informaci! A nakonec se mu nepodaří váš skvěle promyšlený kód změnit. - The value type is easy to find out by debugging. But what's the meaning of the variable? Which string/number does it store? + Datový typ proměnné lze snadno odhalit při ladění. Ale jaký je význam proměnné? Jaký řetězec nebo číslo je v ní uloženo? - There's just no way to figure out without a good meditation! + Není způsob, jak to odhalit bez dobré meditace! -- **...But what if there are no more such names?** Just add a number: `data1, item2, elem5`... +- **...Ale co když žádné další takové názvy už nezbývají?** Stačí přidat číslo: `data1, prvek2, element5`... -## Attention test +## Zkouška pozornosti -Only a truly attentive programmer should be able to understand your code. But how to check that? +Vašemu kódu by měl porozumět jen skutečně pozorný programátor. Ale jak to zajistit? -**One of the ways -- use similar variable names, like `date` and `data`.** +**Jeden způsob -- používejte podobné názvy proměnných, např. `datum` a `data`.** -Mix them where you can. +Směšujte je všude, kde je to možné. -A quick read of such code becomes impossible. And when there's a typo... Ummm... We're stuck for long, time to drink tea. +Takový kód je pak nemožné rychle přečíst. A když je někde překlep... Hmmm... Nadlouho nás to zdrží, uděláme si přestávku na čaj. -## Smart synonyms +## Chytrá synonyma -```quote author="Laozi (Tao Te Ching)" -The Tao that can be told is not the eternal Tao. The name that can be named is not the eternal name. +```quote author="Laozi (Tao te ťing) (překlad Václav Cílek)" +Tao, které se dá popsat slovy, není stálé Tao
+jméno, které se dá jmenovat, není věčné jméno ``` -Using *similar* names for *same* things makes life more interesting and shows your creativity to the public. +Používání *podobných* názvů pro *stejné* věci činí život zajímavějším a ukáže publiku vaši kreativitu. -For instance, consider function prefixes. If a function shows a message on the screen -- start it with `display…`, like `displayMessage`. And then if another function shows on the screen something else, like a user name, start it with `show…` (like `showName`). +Zvažte například prefixy funkcí. Jestliže funkce zobrazuje zprávu na obrazovce, začněte její název `zobraz…`, např. `zobrazZprávu`. Pokud pak jiná funkce zobrazí na obrazovce něco jiného, třeba uživatelské jméno, začněte její název `vypiš…` (např. `vypišJméno`). -Insinuate that there's a subtle difference between such functions, while there is none. +To naznačuje, že mezi těmito funkcemi je nějaký drobný rozdíl, přestože ve skutečnosti žádný není. -Make a pact with fellow ninjas of the team: if John starts "showing" functions with `display...` in his code, then Peter could use `render..`, and Ann -- `paint...`. Note how much more interesting and diverse the code became. +Dohodněte se s kolegy ninji z týmu: bude-li Honza pojmenovávat „zobrazovací“ funkce ve svém kódu `zobraz...`, pak Petr by mohl používat `vypiš...` a Anna `vykresli...`. Všimněte si, nakolik se kód stane zajímavějším a rozmanitějším. -...And now the hat trick! +...A nyní přijde ten pravý trik! -For two functions with important differences -- use the same prefix! +Pro dvě funkce, mezi nimiž je důležitý rozdíl, použijte stejný prefix! -For instance, the function `printPage(page)` will use a printer. And the function `printText(text)` will put the text on-screen. Let an unfamiliar reader think well over similarly named function `printMessage`: "Where does it put the message? To a printer or on the screen?". To make it really shine, `printMessage(message)` should output it in the new window! +Například funkce `tiskniStránku(stránka)` bude tisknout na tiskárnu. Ale funkce `tiskniText(text)` vypíše text na obrazovku. Nechte neznalého čtenáře, aby se zamyslel nad podobně pojmenovanou funkcí `tiskniZprávu`: „Kam tu zprávu vlastně vytiskne? Na tiskárnu, nebo na obrazovku?“ Aby to bylo opravdu úchvatné, `tiskniZprávu(zpráva)` by měla zobrazit zprávu v novém okně! -## Reuse names +## Používejte opakovaně stejné názvy -```quote author="Laozi (Tao Te Ching)" -Once the whole is divided, the parts
-need names.
-There are already enough names.
-One must know when to stop. +```quote author="Laozi (Tao te ťing) (překlad Václav Cílek)" +když rozdělujeme jednotu,
+objevují se jména
+pohromě se vyhneme,
+jen když víme, kdy přestat
``` -Add a new variable only when absolutely necessary. +Přidejte novou proměnnou jen tehdy, když je to absolutně nezbytné. -Instead, reuse existing names. Just write new values into them. +Jinak místo toho opakovaně používejte již existující názvy. Jen do nich zapisujte nové hodnoty. -In a function try to use only variables passed as parameters. +Ve funkci se snažte používat jedině proměnné, které byly předány jako parametry. -That would make it really hard to identify what's exactly in the variable *now*. And also where it comes from. The purpose is to develop the intuition and memory of a person reading the code. A person with weak intuition would have to analyze the code line-by-line and track the changes through every code branch. +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. -**An advanced variant of the approach is to covertly (!) replace the value with something alike in the middle of a loop or a function.** +**Pokročilá varianta tohoto přístupu je utajeně (!) nahradit hodnotu něčím podobným uvnitř cyklu nebo funkce.** -For instance: +Například: ```js -function ninjaFunction(elem) { - // 20 lines of code working with elem +function ninjovaFunkce(elem) { + // 20 řádků kódu pracujícího s elem elem = clone(elem); - // 20 more lines, now working with the clone of the elem! + // 20 dalších řádků kódu, které nyní pracují s klonem proměnné elem! } ``` -A fellow programmer who wants to work with `elem` in the second half of the function will be surprised... Only during the debugging, after examining the code they will find out that they're working with a clone! +Kolega, který bude chtít pracovat s proměnnou `elem` ve druhé polovině funkce, bude překvapen... Teprve při ladění po prozkoumání kódu přijde na to, že pracuje s klonem! -Seen in code regularly. Deadly effective even against an experienced ninja. +Toto je v kódu často vidět. Je to hrozivě efektivní i proti zkušenému ninjovi. -## Underscores for fun -Put underscores `_` and `__` before variable names. Like `_name` or `__value`. It would be great if only you knew their meaning. Or, better, add them just for fun, without particular meaning at all. Or different meanings in different places. +## Legrace s podtržítky -You kill two rabbits with one shot. First, the code becomes longer and less readable, and the second, a fellow developer may spend a long time trying to figure out what the underscores mean. +Umisťujte před názvy proměnných podtržítka `_` a `__`. Například `_jméno` nebo `__hodnota`. Bude to legrace, když budete jejich význam znát jenom vy. Nebo ještě lépe: přidávejte je jen pro legraci, aniž by měla nějaký konkrétní význam. Nebo ať mají na různých místech různé významy. -A smart ninja puts underscores at one spot of code and evades them at other places. That makes the code even more fragile and increases the probability of future errors. +Zabijete dvě mouchy jednou ranou. Za prvé, kód se prodlouží a stane se méně čitelným, a za druhé, kolega vývojář může strávit dlouhou dobu zjišťováním, co vlastně ta podtržítka znamenají. -## Show your love +Elegantní ninja na jednom místě kódu podtržítka vkládá a na jiných se jim vyhýbá. Díky tomu je kód ještě zranitelnější a zvyšuje se pravděpodobnost budoucích chyb. -Let everyone see how magnificent your entities are! Names like `superElement`, `megaFrame` and `niceItem` will definitely enlighten a reader. -Indeed, from one hand, something is written: `super..`, `mega..`, `nice..` But from the other hand -- that brings no details. A reader may decide to look for a hidden meaning and meditate for an hour or two of their paid working time. +## Ukažte svou lásku +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í. -## Overlap outer variables +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. + + +## Překrývejte vnější proměnné ```quote author="Guan Yin Zi" -When in the light, can't see anything in the darkness.
-When in the darkness, can see everything in the light. +Kdo je na světle, nevidí nic, co je ve tmě.
+Kdo je ve tmě, vidí všechno, co je na světle. ``` -Use same names for variables inside and outside a function. As simple. No efforts to invent new names. +Používejte stejné názvy pro proměnné vně a uvnitř funkce. Je to jednoduché. Není třeba úsilí k vymýšlení nových názvů. ```js -let *!*user*/!* = authenticateUser(); +let *!*uživatel*/!* = autentikujUživatele(); -function render() { - let *!*user*/!* = anotherValue(); +function renderuj() { + let *!*uživatel*/!* = jináHodnota(); ... - ...many lines... + ...mnoho řádků... ... - ... // <-- a programmer wants to work with user here and... + ... // <-- programátor zde chce pracovat s uživatelem a... ... } ``` -A programmer who jumps inside the `render` will probably fail to notice that there's a local `user` shadowing the outer one. +Programátor, který skočí dovnitř funkce `renderuj`, si pravděpodobně nevšimne, že v ní je lokální proměnná `uživatel`, která zastiňuje tu vnější. -Then they'll try to work with `user` assuming that it's the external variable, the result of `authenticateUser()`... The trap is sprung! Hello, debugger... +Pak se pokusí pracovat s proměnnou `uživatel` předpokládaje, že je to externí proměnná, která je výsledkem volání `autentikujUživatele()`... A past sklapne! Nazdar, debuggere... -## Side-effects everywhere! +## Všude vedlejší efekty! -There are functions that look like they don't change anything. Like `isReady()`, `checkPermission()`, `findTags()`... They are assumed to carry out calculations, find and return the data, without changing anything outside of them. In other words, without "side-effects". +Existují funkce, které vypadají, jako by nic neměnily. Například `jePřipraven()`, `ověřOprávnění()`, `najdiZnačky()`... Předpokládá se, že provedou výpočty a najdou a vrátí data, aniž by měnily cokoli mimo ně. Jinými slovy, bez „vedlejších efektů“. -**A really beautiful trick is to add a "useful" action to them, besides the main task.** +**Opravdu krásný trik je přidat do nich kromě hlavního úkolu ještě nějakou „užitečnou“ akci navíc.** -An expression of dazed surprise on the face of your colleague when they see a function named `is..`, `check..` or `find...` changing something -- will definitely broaden your boundaries of reason. +Pohled na překvapenou tvář vašeho kolegy, který zjistí, že funkce pojmenovaná `je..`, `ověř..` nebo `najdi..` něco mění, zaručeně posune hranice vašeho rozumu. -**Another way to surprise is to return a non-standard result.** +**Další cestou, jak překvapit, je vrátit nestandardní výsledek.** -Show your original thinking! Let the call of `checkPermission` return not `true/false`, but a complex object with the results of the check. +Předveďte své originální myšlení! Nechte funkci `ověřOprávnění` vrátit nikoli `true/false`, ale složitý objekt s výsledky ověření. -Those developers who try to write `if (checkPermission(..))`, will wonder why it doesn't work. Tell them: "Read the docs!". And give this article. +Vývojáři, kteří se pokusí napsat `if (ověřOprávnění(..))`, se budou divit, proč to nefunguje. Řekněte jim: „Přečtěte si dokumentaci!“ A dejte jim odkaz na tento článek. -## Powerful functions! +## Silné funkce! -```quote author="Laozi (Tao Te Ching)" -The great Tao flows everywhere,
-both to the left and to the right. +```quote author="Laozi (Tao te ťing) (překlad Václav Cílek)" +Velké Tao se rozlévá, kam chce ``` -Don't limit the function by what's written in its name. Be broader. +Neomezujte funkci na to, co je uvedeno v jejím názvu. Rozšiřte se. -For instance, a function `validateEmail(email)` could (besides checking the email for correctness) show an error message and ask to re-enter the email. +Například funkce `zkontrolujEmail(email)` by mohla (kromě kontroly, zda email je správně) zobrazit chybovou zprávu a požádat uživatele, aby email zadal znovu. -Additional actions should not be obvious from the function name. A true ninja coder will make them not obvious from the code as well. +Přidané akce by neměly být zřejmé z názvu funkce. Opravdový ninja je učiní nezřejmými dokonce i z kódu. -**Joining several actions into one protects your code from reuse.** +**Spojení několika akcí do jedné ochrání váš kód před opakovaným použitím.** -Imagine, another developer wants only to check the email, and not output any message. Your function `validateEmail(email)` that does both will not suit them. So they won't break your meditation by asking anything about it. +Představte si, že jiný vývojář bude chtít jen zkontrolovat email a nevypisovat žádnou zprávu. Vaše funkce `zkontrolujEmail(email)`, která dělá obojí, mu pak nebude vyhovovat. Nepřekazí tedy vaši meditaci tím, že se na ni bude ptát. -## Summary +## Shrnutí -All "pieces of advice" above are from the real code... Sometimes, written by experienced developers. Maybe even more experienced than you are ;) +Všechny výše uvedené „rady“ pocházejí ze skutečného kódu... Někdy byl dokonce napsán zkušenými vývojáři. Možná ještě zkušenějšími, než vy ;) -- Follow some of them, and your code will become full of surprises. -- Follow many of them, and your code will become truly yours, no one would want to change it. -- Follow all, and your code will become a valuable lesson for young developers looking for enlightenment. +- Když budete dodržovat některé z nich, bude váš kód plný překvapení. +- Když budete dodržovat mnohé z nich, bude váš kód opravdu jen váš a nikdo ho nebude chtít měnit. +- Když budete dodržovat všechny, bude váš kód cennou lekcí pro mladé vývojáře toužící po osvícení. \ No newline at end of file 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 79f190370..8d2035969 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](http://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](http://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ě 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 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](http://mochajs.org/) -- the core framework: it provides common testing functions including `describe` and `it` and the main function that runs tests. -- [Chai](http://chaijs.com) -- the library with many assertions. It allows to use a lot of different assertions, for now we need only `assert.equal`. -- [Sinon](http://sinonjs.org/) -- a library to spy over functions, emulate built-in functions and more, we'll need it much later. +- [Mocha](http://mochajs.org/) -- jádro rámce: poskytuje běžné testovací funkce včetně `describe` a `it` a hlavní funkci, která spouští testy. +- [Chai](http://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](http://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="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/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..8dea8a8b6 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í klíčovaných kolekcí různých dat 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 booleanovou: ```js -user.isAdmin = true; +uživatel.jeAdmin = 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á“ nebo „závěsná“ *(v angličtině „trailing“ nebo „hanging“, nevím o standardním českém názvu -- pozn. překl.)*. 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 +// vrátit +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. To se nazývá *vypočítávané vlastnosti*. -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ž bývá 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`: +Například vydáme 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, + jeAdmin: 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, jeAdmin + // 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)"` *(v angličtině `"for (let prop in obj)"` -- pozn. překl.)*. -### 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ž procházíme objekt v cyklu, 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 k navržení seznamu možností pro uživatele. 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í něco jako „typ Array“ nebo „typ Date“, ale formálně to nejsou samostatné typy, nýbrž patří do jednoduchého datového 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..cf779a10a 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énojeAdminuž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..8adf3d08e 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ěkjeAdminuž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 7fe8a26a6..c241863ab 100644 --- a/1-js/04-object-basics/02-object-copy/article.md +++ b/1-js/04-object-basics/02-object-copy/article.md @@ -1,260 +1,260 @@ -# 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`, engine JavaScriptu se podívá, 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 admin = 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 admin = uživatel; *!* -admin.name = 'Pete'; // changed by the "admin" reference +admin.jméno = 'Petr'; // změna pomocí odkazu „admin“ */!* -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 (`admin`) 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ž představují 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. -## 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, [src1, src2, src3...]) +Object.assign(cíl, [zdroj1, zdroj2, zdroj3...]) ``` -- The first argument `dest` is a target object. -- Further arguments `src1, ..., srcN` (can be as many as needed) are source objects. -- It copies the properties of all source objects `src1, ..., srcN` into the target `dest`. In other words, properties of all arguments starting from the second are copied into the first object. -- The call returns `dest`. +- První argument `cíl` je cílový objekt. +- Další argumenty `zdroj1, ..., zdrojN` (může jich být tolik, kolik potřebujeme) jsou zdrojové objekty. +- Metoda zkopíruje vlastnosti všech zdrojových objektů `zdroj1, ..., zdrojN` do cíle `cíl`. Jinými slovy, do cílového objektu se zkopírují vlastnosti všech argumentů počínaje druhým. +- Volání vrátí `cíl`. -For instance, we can use it to merge several objects into one: +Například ji můžeme použít ke sloučení několika objektů do jednoho: ```js -let user = { name: "John" }; +let uživatel = { jméno: "Jan" }; -let permissions1 = { canView: true }; -let permissions2 = { canEdit: true }; +let práva1 = { můžeProhlížet: true }; +let práva2 = { můžeEditovat: true }; *!* -// copies all properties from permissions1 and permissions2 into user -Object.assign(user, permissions1, permissions2); +// zkopíruje všechny vlastnosti z objektů práva1 a práva2 do objektu uživatel +Object.assign(uživatel, práva1, práva2); */!* -// now user = { name: "John", canView: true, canEdit: true } +// nyní uživatel = { jméno: "Jan", můžeProhlížet: true, 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 replace `for..in` loop for simple cloning: +Můžeme také využít `Object.assign` k nahrazení cyklu `for..in` jednoduchým klonováním: ```js -let user = { - name: "John", - age: 30 +let uživatel = { + jméno: "Jan", + věk: 30 }; *!* -let clone = Object.assign({}, user); +let klon = Object.assign({}, uživatel); */!* ``` -It copies all properties of `user` into the empty object and returns it. +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++; // change a property from one place -alert(clone.sizes.width); // 51, get the result from the other one +// uživatel a klon sdílejí tytéž míry +uživatel.míry.šířka++; // změníme vlastnost na jednom místě +alert(klon.míry.šířka); // 51, vidí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". +Abychom to opravili a učinily 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é“ nebo „hluboké“. -We can use recursion to implement it. 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). +Můžeme to implementovat pomocí rekurze. Nebo, abychom znovu nevynalézali kolo, použít existující implementaci, např. [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) z JavaScriptové knihovny [lodash](https://lodash.com). -````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 řádek `(*)` ohlásí chybu, 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` způsobí 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 opravdu 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 . ```` -## 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) této hodnoty. Zkopírování této hodnoty nebo její předání jako argument funkce 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, 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 pro „hloubkové klonování“, např. [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). 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 50ada6713..33b0f8e05 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,214 @@ # Garbage collection -Memory management in JavaScript is performed automatically and invisibly to us. We create primitives, objects, functions... All that takes memory. +*(Pozn. překladatele: výraz „garbage collection“ znamená česky „sbírání odpadu“, ale v programování se většinou ponechává anglický název.)* -What happens when something is not needed any more? How does the JavaScript engine discover it and clean it up? +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ěť. -## Reachability +Co se stane, když něco už není potřeba? Jak to JavaScriptový engine odhalí a vyčistí? -The main concept of memory management in JavaScript is *reachability*. +## Dosažitelnost -Simply put, "reachable" values are those that are accessible or usable somehow. They are guaranteed to be stored in memory. +Hlavním konceptem správy paměti v JavaScriptu je *dosažitelnost*. -1. There's a base set of inherently reachable values, that cannot be deleted for obvious reasons. +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. - For instance: +1. Existuje základní sada zaručeně dosažitelných hodnot, které nelze smazat z pochopitelných důvodů. - - 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) + Například: - These values are called *roots*. + - 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í) -2. Any other value is considered reachable if it's reachable from a root by a reference or by a chain of references. + Tyto hodnoty se nazývají *kořenové hodnoty* nebo *kořeny*. - 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. +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ů. -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. + 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. -## A simple example +V JavaScriptovém enginu v pozadí probíhá proces, který se nazývá [garbage collector](https://cs.wikipedia.org/wiki/Garbage_collection) *(česky se mu někdy říká „sběrač odpadků“ -- pozn. překl.)*. Monitoruje všechny objekty a odstraňuje ty, které se staly nedosažitelnými. -Here's the simplest example: +## Jednoduchý příklad + +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. Garbage collector 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 na objekt `uživatel` do objektu `admin`: ```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 admin = 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é `admin`, a tedy musí zůstat v paměti. Jestliže přepíšeme i `admin`, 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í garbage collection: ![](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ý 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 garbage collection se nazývá „mark-and-sweep“ *(česky „označ a zameť“ -- pozn. překl.)*. -The following "garbage collection" steps are regularly performed: +Pravidelně se provádějí následující kroky „garbage collection“: -- 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. +- Garbage collector 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í garbage collector typu „mark-and-sweep“. -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 rozlévání velkého kbelíku s barvou, která teče od kořenů 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 typickém kódu má mnoho objektů jen krátký život: objeví se, odvedou 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 se tedy snaží rozdělit 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 menší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ů garbage collection. Rád bych je zde popsal, ale musím se toho vzdát, jelikož různé enginy implementují různá vylepšení a techniky. Co je ještě důležitější, během vývoje enginů se vše neustále mění, takže studovat je hlouběji „napřed“, 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í enginy implementují pokročilé algoritmy garbage collection. -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 pokryty 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](http://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](http://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](http://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ě, abyste se naučili o sbírání odpadků víc, měli byste se připravit tak, že se naučíte něco o interních záležitostech V8 obecně a přečtete si blog [Vjačeslava Jegorova](http://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/garbage-collection-5.svg b/1-js/04-object-basics/03-garbage-collection/garbage-collection-5.svg index 2d85432bc..1682a438d 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 +<global>nedosažitelný \ 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..4bd272ce7 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,44 +1,44 @@ -**Answer: an error.** +**Odpověď: chyba.** -Try it: +Zkuste to: ```js run -function makeUser() { +function vytvořUživatele() { return { - name: "John", + jméno: "Jan", ref: this }; } -let user = makeUser(); +let uživatel = vytvořUživatele(); -alert( user.ref.name ); // Error: Cannot read property 'name' of undefined +alert( uživatel.ref.jméno ); // Error: Cannot read property 'jméno' of 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 momentu 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 `ref: 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 ); // Error: Cannot read property 'jméno' of 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.ref.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() { return this; @@ -47,9 +47,9 @@ function makeUser() { }; } -let user = makeUser(); +let uživatel = vytvořUživatele(); -alert( user.ref().name ); // John +alert( uživatel.ref().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.ref()` 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..f897b11ec 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 jejímu `ref`? Proč? ```js -function makeUser() { +function vytvořUživatele() { return { - name: "John", + jméno: "Jan", ref: this }; } -let user = makeUser(); +let uživatel = vytvořUživatele(); -alert( user.ref.name ); // What's the result? +alert( uživatel.ref.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 a2a19c620..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 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, 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 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..91b323b9b 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. +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í" +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 vztahující se k 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ř. `admin = 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 níže: ```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 admin = uživatel; +uživatel = null; // přepíšeme, aby to bylo zřejmé *!* -admin.sayHi(); // TypeError: Cannot read property 'name' of null +admin.ř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 admin = { jméno: "Admin" }; -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; +admin.f = řekniAhoj; */!* -// these calls have different this -// "this" inside the function is the object "before the dot" -user.f(); // John (this == user) +// tato volání mají různá this +// „this“ uvnitř funkce je objekt „před tečkou“ +uživatel.f(); // Jan (this == uživatel) admin.f(); // Admin (this == admin) -admin['f'](); // Admin (dot or square brackets access the method – doesn't matter) +admin['f'](); // Admin (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 `admin`. -````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 funkci znovu použít 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. Šipkové funkce hlouběji prozkoumáme později v kapitole . -## 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 různými 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. +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 d80113acc..2c46522ab 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 60e7c373e..5c2d74530 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()` asks for two values using `prompt` and remembers them in object properties. -- `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. +- `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..b0c6f283c 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ý tento konstruktor vytvoří, 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í argumentem konstruktoru `počátečníHodnota`. +- Metoda `načti()` by se měla pomocí `prompt` zeptat na nové číslo a přičíst je do 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 f3e9c3ec0..65483224f 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 běžné 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.jeAdmin = 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.jeAdmin); // 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` a přidá do něj 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á do něj vlastnosti + this.jméno = jméno; + this.jeAdmin = 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", + jeAdmin: 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 lépe č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.jeAdmin = 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 opakovaně volat, protože není nikde uložen. Jen se vytvoří a zavolá. 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, speciální vlastností `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`, rovná se 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 stále 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 tady 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`, if it has no arguments: +````smart header="Vypuštění závorek" +Mimochodem, za `new` můžeme vypustit závorky, jestliže nemá žádné argumenty: ```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 pojmenovávat je s velkým prvním písmenem. +- 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í vyplně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..f4ce0761f 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 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 vyžadováno 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.name : 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.name ); // 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.name` 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ódování 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ý, ohlásí se programátorská chyba a my ji opravíme. Kdybychom však přehnaně používali `?.`, mohly by se chyby v kódu neohlásit i tehdy, když to není vhodné, a jejich 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ě pozastaví („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 za pozastaveným `?.` vpravo 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 výkon 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á konstrukce, 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 `admin` a někteří ne: ```js run -let userAdmin = { +let uživatelAdmin = { admin() { - alert("I am admin"); + alert("Jsem admin"); } }; -let userGuest = {}; +let uživatelHost = {}; *!* -userAdmin.admin?.(); // I am admin +uživatelAdmin.admin?.(); // Jsem admin */!* *!* -userGuest.admin?.(); // nothing happens (no such method) +uživatelHost.admin?.(); // 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živatelAdmin.admin`) k získání vlastnosti `admin`, 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 `admin` existuje, pak se spustí (tak tomu je pro `uživatelAdmin`). 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 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..8527e3875 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. +Symboly jsou zaručeně 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 náhodně 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 + name: "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] = "Jeho 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 = "Jeho 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í (nebo 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 zavolá kontrolu globálního registru, 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 do objektu přidat vlastnost, 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.*`. Někdy je můžeme použít, 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 acc4e78b4..f025016a5 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 úspěchy č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ývá žádné počítání 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 s nimi 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 +## Hinty -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 „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. `"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 hint `"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 hint `"default"`. ```js - // binary plus uses the "default" hint - let total = obj1 + obj2; + // binární plus používá hint "default" + let celkem = obj1 + obj2; - // obj == number uses the "default" hint - if (user == 1) { ... }; + // obj == číslo používá hint "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í hint `"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 jedinou 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 hinty. 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](hint)` -- 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 hint `"string"`: + - pokusí se zavolat `obj.toString()` nebo `obj.valueOf()`, první z nich, která existuje. +3. V opačném případě, je-li hint `"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" + // sem přijde kód, který převede tento objekt na primitiv + // musí vrátit primitivní hodnotu + // hint = 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 hinty 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; + return hint == "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); // hint: string -> {jméno: "Jan"} +alert(+uživatel); // hint: number -> 1000 +alert(uživatel + 500); // hint: 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, then `valueOf` (so `toString` has the priority for string conversions). -- For other hints: `valueOf`, and if it doesn't exist, then `toString` (so `valueOf` has the priority for maths). +- Pro hint `"string"`: volá se metoda `toString`, a jestliže neexistuje, pak `valueOf` (při konverzi na řetězec má tedy přednost `toString`). +- Pro jiné hinty: `valueOf`, a jestliže neexistuje, pak `toString` (při 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ých časů. Nejsou to symboly (symboly tak dávno ještě neexistovaly), ale „obvyklé“ metody pojmenované řetězcem. 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 (tak, jako by taková metoda neexistovala). -By default, a plain object has following `toString` and `valueOf` methods: +Standardně 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. +Standardní `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 hint="string" toString() { - return `{name: "${this.name}"}`; + return `{jméno: "${this.jméno}"}`; }, - // for hint="number" or "default" + // pro hint="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 jediné místo „pro všechno“, aby obsloužilo všechny konverze na primitivy. 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. +Není-li přítomna `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 hint `"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ých dobách 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 bude ohlášena 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, mnoho operátorů a funkcí provádí typovou konverzi, 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 the 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ž s radostí 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 +## Shrnutí -The object-to-primitive conversion is called automatically by many built-in functions and operators that expect a primitive as a value. +Konverze objektu na primitiv je volána automaticky mnoha vestavěnými funkcemi a operátory, které očekávají primitiv jako hodnotu. -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"`) +Dělí se na 3 druhy (hinty): +- `"string"` (pro `alert` a jiné operace, které vyžadují řetězec) +- `"number"` (pro matematické výpočty) +- `"default"` (pro operátory, obvykle ji objekty implementují stejným způsobem jako `"number"`) -The specification describes explicitly which operator uses which hint. +Specifikace výslovně popisuje, který operátor používá který hint. -The conversion algorithm is: +Algoritmus konverze je: -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. +1. Zavolá `obj[Symbol.toPrimitive](hint)`, jestliže tato metoda existuje. +2. V opačném případě, je-li hint `"string"`: + - pokusí se zavolat `obj.toString()` nebo `obj.valueOf()`, první z nich, která existuje. +3. V opačném případě, je-li hint `"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). -All these methods must return a primitive to work (if defined). - -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 „zachytávací“ metodu pro konverzi na řetězec, která by měla vracet „člověkem č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..6bdfd1952 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 str = "Ahoj"; str.test = 5; // (*) alert(str.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 `str`, vytvoří se „wrapper“. +2. Ve striktním režimu zápis do něj znamená chybu. +3. Jinak bude operace s touto vlastností provedena, objekt získá vlastnost `test`, ale poté „wrapper“ zmizí, takže na posledním řádku nemá `str` 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..487e5ac50 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 str = "Ahoj"; str.test = 5; alert(str.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..7e1a1e4f1 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é můžeme takto volat. Brzy 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. +- Je schopen ukládat více hodnot jako své vlastnosti. +- 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. +Mnoho objektů je již vestavěných, 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í interní mašinérii. -## A primitive as an object +## Primitiv jako objekt -Here's the paradox faced by the creator of JavaScript: +Tvůrce JavaScriptu čelil 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 nejlehčí. -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ý „wrapper“ *(česky se mu někdy říká „obal“ -- pozn. překl.)*, který poskytne tuto přídavnou funkcionalitu 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é wrappery“ 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 [str.toUpperCase()](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase), která vrací řetězec `str` velkými písmeny. -Here's how it works: +Funguje následovně: ```js run -let str = "Hello"; +let str = "Ahoj"; -alert( str.toUpperCase() ); // HELLO +alert( str.toUpperCase() ); // AHOJ ``` -Simple, right? Here's what actually happens in `str.toUpperCase()`: +Jednoduché, že? Ve skutečnosti se ve `str.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 `str` 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 `str`. -So primitives can provide methods, but they still remain lightweight. +Primitivy tedy mohou poskytovat metody, ale samy zůstávají lehké. -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ý engine tento proces vysoce 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 číslo má své vlastní metody, například [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) zaokrouhluje číslo na 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 „wrappery“ 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 silně **nedoporučované**. Věci začnou bláznit 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). +Na druhou stranu 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 num = 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` jsou výjimky. Nemají odpovídající „wrappery“ 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é enginy jsou dobře vyladěny, aby je interně 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 a17a4671a..f9579e0db 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áta přesnosti může číslo zvýšit i snížit. V tomto konkrétním případě se číslo stane o něco menším, 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ětš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 dělené mocninami `2` 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..0de988e60 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í „obvyklé čí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..2a6561582 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 ptá 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 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 stiskem „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..01ced8f22 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,6 +1,6 @@ -# 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) { @@ -11,28 +11,28 @@ function randomInteger(min, max) { 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 mnohokrát za sebou spustíte výše uvedený příklad, snadno uvidíte, že `2` se objevuje nejčastěji. -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 přidat požadované pravděpodobnosti krajních hodnot: ```js run *!* function randomInteger(min, max) { - // now rand is from (min-0.5) to (max+0.5) + // nyní rand je od (min-0.5) do (max+0.5) let rand = min - 0.5 + Math.random() * (max - min + 1); return Math.round(rand); } @@ -41,12 +41,12 @@ function randomInteger(min, max) { 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) + // zde rand je od min do (max+1) let rand = min + Math.random() * (max + 1 - min); return Math.floor(rand); } @@ -55,12 +55,12 @@ function randomInteger(min, max) { 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..a6bf38216 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ž možnými hodnotami budou 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 3fec8848f..32f5658e2 100644 --- a/1-js/05-data-types/02-number/article.md +++ b/1-js/05-data-types/02-number/article.md @@ -1,148 +1,147 @@ -# Numbers +# Čísla -In modern JavaScript, there are two types of numbers: +V moderním JavaScriptu jsou 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á většinou používáme 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 few special areas, we devote them 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 nebo být menší než -253, 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 +## Více způsobů, 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ěco velmi malého. 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 ``` -### 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éž, na velikosti písmen nezáleží) ``` -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 kódová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` je tehdy, 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 goes the method. - -Also could write `(123456).toString(36)`. +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í přijde na řadu metoda. +Můžeme napsat i `(123456).toString(36)`. ``` -## Rounding +## Zaokrouhlování -One of the most used operations when working with numbers is rounding. +Jedna z nejčastěji používaných operací při práci s čísly je zaokrouhlování. -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`, the middle case: `3.5` rounds up to `4` too. +: Zaokrouhluje na nejbližší celé číslo: `3.1` se zaokrouhlí na `3`, `3.6` se zaokrouhlí na `4`, prostřední případ `3.5` se také zaokrouhlí na `4`. -`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` | |---|---------|--------|---------|---------| @@ -152,300 +151,301 @@ 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 je 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 čá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 obrovské, 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 +alert( 1e500 ); // Infinity (nekonečno) ``` -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á. -What is `0.1`? It is one divided by ten `1/10`, one-tenth. In 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 `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, 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 čárkou má vždy 2 číslice. To se obzvláště hodí, když máme elektronický obchod a potřebujeme zobrazit `$0.30`. V jiným případech můžeme použít unární plus, abychom jej 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, multiply/divide approach reduces the error, but doesn't remove it totally. +Přístup 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 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 nimi 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 ``` - 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 běž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("str") ); // 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 běž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="Compare 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="Srovnání s `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 true, because internally the number has a sign bit that may be different even if all other bits are zeroes. +1. Funguje s `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 pravda, protože interně má číslo 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`. -This way of comparison is 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)). +Tento způsob porovnávání 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ívá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. Až 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í symbol 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(str, soustava)`" +Funkce `parseInt()` má volitelný druhý parametr. Ten specifikuje základ číselné soustavy, takže `parseInt` může také načítat řetězce hexadecimálních čísel, binárních čísel 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ší funkce a konstanty včetně trigonometrický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(str, základ)` parsuje řetězec `str` 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 běžné testování čísel: -- `isNaN(value)` converts its argument to a number and then tests it for being `NaN` -- `isFinite(value)` converts its argument to a number and returns `true` if it's a regular number, not `NaN/Infinity/-Infinity` +- `isNaN(hodnota)` převede svůj argument na číslo a pak testuje, zda je `NaN` +- `isFinite(hodnota)` převede svůj argument na číslo a vrátí `true`, pokud je to skutečné číslo a ne `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, viz 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 f7a332d0d..e0d5f0c03 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,27 +1,27 @@ -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. -There are two variants here: +Jsou zde dvě varianty řešení: -1. Use `str.charAt(0)`, as it always returns a string (maybe empty). -2. Add a test for an empty string. +1. Použít `řetězec.charAt(0)`, jelikož ta vždy vrátí řetězec (možná prázdný). +2. Přidat kontrolu na prázdný řetězec. -Here's the 2nd variant: +Zde je druhá varianta: ```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..0a776ad0a 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 o něco kratší řetězec, 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 6382029f4..ab5f0ffe4 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..769654b70 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 značka 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 b3535866d..174d15635 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -1,653 +1,653 @@ -# 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 oddělený 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ávisí 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 apostrofů, uvozovek nebo gravisů (obrácených čárek): ```js -let single = 'single-quoted'; -let double = "double-quoted"; +let apostrofy = 'apostrofy'; +let uvozovky = "uvozovky"; -let backticks = `backticks`; +let gravisy = `gravisy`; ``` -Single and double quotes are essentially the same. Backticks, however, allow us to embed any expression into the string, by wrapping it in `${…}`: +Apostrofy a uvozovky jsou v zásadě stejné. Gravisy 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í gravisů 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 apostrofy nebo 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ů vytváření jazyka, kdy potřeba víceřádkových řetězců nebyla brána v úvahu. 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 is called "tagged templates". This feature makes it easier to implement custom templating, but is rarely used in practice. You can read more about it in the [manual](mdn:/JavaScript/Reference/Template_literals#Tagged_templates). +Zpětné uvozovky nám také umožňují specifikovat „šablonovou funkci“ před levou čárkou. Syntaxe je funkce`řetězec`. Funkce `funkce` je volána automaticky, obdrží řetězec a vnořené výrazy a může je zpracovat. To se nazývá „značkované vlastnosti“ *(anglicky „tagged templates“ -- pozn. překl.)*. Tato vlastnost nám umožňuje snadněji implementovat vlastní šablony, ale v praxi se používá jen málokdy. Více se o ní můžete dočíst v [manuálu](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 apostrofů nebo 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 +alert(seznamHostů); // víceřádkový seznam hostů ``` -For example, these two lines are equal, just written differently: +Například tyto dva řádky jsou stejné, jen jinak 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 gravisů +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. -Here's the full list: +Následuje jejich úplný seznam: -| 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 -- kept for compatibility, not used nowadays. | -|`\xXX`|Unicode character with the given hexadecimal Unicode `XX`, e.g. `'\x7A'` is the same as `'z'`.| -|`\uXXXX`|A Unicode symbol with the hex code `XXXX` in UTF-16 encoding, for instance `\u00A9` -- is a Unicode for the copyright symbol `©`. It must be exactly 4 hex digits. | -|`\u{X…XXXXXX}` (1 to 6 hex characters)|A Unicode symbol with the given UTF-32 encoding. Some rare characters are encoded with two Unicode symbols, taking 4 bytes. This way we can insert long codes. | +| 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`.| +|`\'`, `\"`|Apostrof, uvozovky| +|`\\`|Zpětné lomítko| +|`\t`|Tabulátor| +|`\b`, `\f`, `\v`| Backspace, Form Feed, vertikální tabulátor -- ponechány kvůli kompatibilitě, v současnosti se nepoužívají. | +|`\xXX`| Znak Unicode se zadaným hexadecimálním kódem v Unicode `XX`, např. `'\x7A'` je totéž jako `'z'`.| +|`\uXXXX`|Symbol Unicode s hexadecimálním kódem `XXXX` v kódování UTF-16, např. `\u00A9` -- Unicode pro symbol copyrightu `©`. Musí obsahovat přesně 4 hexadecimální číslice. | +|`\u{X…XXXXXX}` (1 až 6 hexadecimálních znaků)|Symbol Unicode se zadaným kódováním UTF-32. Pomocí dvou symbolů Unicode jsou zakódovány některé vzácné znaky, které zaberou 4 bajty. Tímto způsobem můžeme vkládat dlouhé kódy. | -Examples with Unicode: +Příklady s Unicode: ```js run alert( "\u00A9" ); // © -alert( "\u{20331}" ); // 佫, a rare Chinese hieroglyph (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) ``` -All special characters start with a backslash character `\`. It is also called an "escape character". +Všechny speciální znaky začínají znakem zpětného lomítka `\`. Tomu se také říká „únikový *(escape)* znak“. -We might also use it if we wanted to insert a quote into the string. +Můžeme jej také použít, když chceme vložit do řetězce uvozovky nebo apostrof. -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ím apostrofem uvést zpětné lomítko `\'`, jinak by apostrof znamenal 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 uvozovky nebo gravisy: ```js run -alert( `I'm the Walrus!` ); // I'm the Walrus! +alert( `To's přehnal!` ); // To's přehnal! ``` -Note that the backslash `\` serves for the correct reading of the string by JavaScript, then disappears. The in-memory string has no `\`. You can clearly see that in `alert` from the examples above. +Všimněte si, že zpětné lomítko `\` poslouží pro korektní načtení řetězce JavaScriptem a pak zmizí. Řetězec uložený v paměti neobsahuje žádné `\`. Můžete to jasně vidět v `alert` ve výše uvedených příkladech. -But what if we need to show an actual backslash `\` within the string? +Co ale, když potřebujeme zobrazit v řetězci skutečné zpětné lomítko `\`? -That's possible, but we need to double it like `\\`: +Je to možné, ale musíme je zdvojit `\\`: ```js run -alert( `The backslash: \\` ); // The backslash: \ +alert( `Zpětné lomítko: \\` ); // Zpětné lomítko: \ ``` -## 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 `str.length()` místo `str.length`. To nefunguje. -Please note that `str.length` is a numeric property, not a function. There is no need to add parenthesis after it. +Prosíme všimněte si, že `str.length` je číselná vlastnost, ne funkce. Není důvod za ní uvádět závorky. ``` -## Accessing characters +## Přístup ke znakům -To get a character at position `pos`, use square brackets `[pos]` or call the method [str.charAt(pos)](mdn:js/String/charAt). The first character starts from the zero position: +Abyste získali znak na pozici `poz`, použijte hranaté závorky `[poz]` nebo zavolejte metodu [str.charAt(pos)](mdn:js/String/charAt). 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.charAt(0) ); // H +// první znak +alert( řetězec[0] ); // A +alert( řetězec.charAt(0) ); // A -// the last character -alert( str[str.length - 1] ); // o +// poslední znak +alert( řetězec[řetězec.length - 1] ); // j ``` -The square brackets are a modern way of getting a character, while `charAt` exists mostly for historical reasons. +Moderním způsobem získání znaku jsou hranaté závorky, zatímco `charAt` existuje převážně z historických důvodů. -The only difference between them is that if no character is found, `[]` returns `undefined`, and `charAt` returns an empty string: +Jediný rozdíl mezi nimi je v tom, že když není znak nalezen, `[]` vrátí `undefined`, ale `charAt` vrátí prázdný řetězec: ```js run -let str = `Hello`; +let řetězec = `Ahoj`; -alert( str[1000] ); // undefined -alert( str.charAt(1000) ); // '' (an empty string) +alert( řetězec[1000] ); // undefined +alert( řetězec.charAt(1000) ); // '' (prázdný řetězec) ``` -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 `ř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/řetězecing/toLowerCase) mění písmena řetězce na malá a metoda [toUpperCase()](mdn:js/řetězecing/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 jestliže chceme jediný znak malým písmenem: ```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/řetězecing/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 nebylo nic nalezeno, 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 začít 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í se bude konat od pozice 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( `Nalezeno na ${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` přináší drobnou nepohodlnost do testu v `if`. 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 `ř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: +Ve skutečnosti bychom tedy měli kontrolovat na `-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! } ``` -#### The bitwise NOT trick +#### Trik s bitovým NOT -One of the old tricks used here is the [bitwise NOT](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_NOT) `~` operator. It converts the number to a 32-bit integer (removes the decimal part if exists) and then reverses all bits in its binary representation. +Jeden z nejstarších zde používaných triků je operátor [bitového NOT](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_NOT) `~`, který převádí číslo na 32-bitové celé číslo (odstraní desetinnou část, pokud nějaká je) a pak převrátí všechny bity v jeho binární reprezentaci. -In practice, that means a simple thing: for 32-bit integers `~n` equals `-(n+1)`. +V praxi to znamená jednoduchou věc: pro 32-bitová celá čísla se `~n` rovná `-(n+1)`. -For instance: +Například: ```js run -alert( ~2 ); // -3, the same as -(2+1) -alert( ~1 ); // -2, the same as -(1+1) -alert( ~0 ); // -1, the same as -(0+1) +alert( ~2 ); // -3, totéž jako -(2+1) +alert( ~1 ); // -2, totéž jako -(1+1) +alert( ~0 ); // -1, totéž jako -(0+1) *!* -alert( ~-1 ); // 0, the same as -(-1+1) +alert( ~-1 ); // 0, totéž jako -(-1+1) */!* ``` -As we can see, `~n` is zero only if `n == -1` (that's for any 32-bit signed integer `n`). +Jak vidíme, `~n` je nulová, jedině když `n == -1` (to platí pro kterékoli 32-bitové celé číslo `n` se znaménkem). -So, the test `if ( ~str.indexOf("...") )` is truthy only if the result of `indexOf` is not `-1`. In other words, when there is a match. +Test `if ( ~řetězec.indexOf("...") )` je tedy pravdivý jedině tehdy, jestliže výsledek `indexOf` není `-1`. Jinými slovy, když je něco nalezeno. -People use it to shorten `indexOf` checks: +Lidé to používají ke zkrácení kontrol výsledku `indexOf`: ```js run -let str = "Widget"; +let řetězec = "Prorokovo"; -if (~str.indexOf("Widget")) { - alert( 'Found it!' ); // works +if (~řetězec.indexOf("Prorokovo")) { + alert( 'Nalezeno!' ); // funguje to } ``` -It is usually not recommended to use language features in a non-obvious way, but this particular trick is widely used in old code, so we should understand it. +Obecně se nedoporučuje používat vlastnosti jazyka neprůhledným způsobem, ale tento konkrétní trik se zhusta používá ve starých kódech, takže bychom mu měli rozumět. -Just remember: `if (~str.indexOf(...))` reads as "if found". +Jen si pamatujte: `if (~řetězec.indexOf(...))` se čte jako „jestliže je nalezeno“. -To be precise though, as big numbers are truncated to 32 bits by `~` operator, there exist other numbers that give `0`, the smallest is `~4294967295=0`. That makes such check correct only if a string is not that long. +Abychom však byli přesní, jelikož operátor `~` zkracuje velká čísla na 32 bitů, existují i jiná čísla, která dávají `0`, nejmenší z nich je `~4294967295=0`. Taková kontrola je tedy správná jen tehdy, není-li řetězec tak dlouhý. -Right now we can see this trick only in the old code, as modern JavaScript provides `.includes` method (see below). +V současnosti vidíme tento trik jen ve starém kódu, jelikož moderní JavaScript poskytuje metodu `.includes` (viz níže). ### 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/řetězecing/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 správná volba, 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 *(„startsWith“ = začíná na, „endsWith“ = končí na, takže `startsWith` vrátí `true`, jestliže řetězec začíná zadaným podřetězcem, a `endsWith` vrátí `true`, jestliže řetězec končí 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 0 ``` - If there is no second argument, then `slice` goes till the end of the string: + Není-li uveden druhý argument, `slice` jde až na konec ř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`. +`řetězec.substring(začátek [, konec])` +: Vrátí část řetězce *mezi* pozicemi `začátek` a `konec`. - This is almost the same as `slice`, but it allows `start` to be greater than `end`. + Je to téměř totéž jako `slice`, ale umožňuje, aby `začátek` byl větší než `konec`. - 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" + // je to 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 ``` -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` | 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` | 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?" +Všechny odvedou svou práci. Formálně má `substr` drobnou nevýhodu: není popsána v jádru specifikace JavaScriptu, ale v Příloze B, která pokrývá pouze prohlížečové vlastnosti, existující zejména z historických důvodů. Neprohlížečová prostředí 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. So, it's enough to remember solely `slice` of these three methods. +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í. Z těchto tří metod si tedy stačí pamatovat `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, let's review the internal representation of strings in JavaScript. +Abychom pochopili, co se tady děje, prohlédneme si vnitřní reprezentaci řetězců v JavaScriptu. -All strings are encoded using [UTF-16](https://en.wikipedia.org/wiki/UTF-16). That is: each character has a corresponding numeric code. There are special methods that allow to get the character for the code and back. +Všechny řetězce jsou zakódovány pomocí [UTF-16](https://cs.wikipedia.org/wiki/UTF-16). To je: každý znak má odpovídající číselný kód. Existují speciální metody, které umožňují získat znak pro zadaný kód a naopak. -`str.codePointAt(pos)` -: Returns the code for the character at position `pos`: +`řetězec.codePointAt(poz)` +: Vrátí kód znaku na pozici `poz`: ```js run - // different case letters have different codes + // písmena různé velikosti mají různé kódy alert( "z".codePointAt(0) ); // 122 alert( "Z".codePointAt(0) ); // 90 ``` -`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 ``` - We can also add Unicode characters by their codes using `\u` followed by the hex code: + Můžeme vytvořit znaky Unicode podle jejich kódů i pomocí `\u`, za nímž následuje hexadecimální kód: ```js run - // 90 is 5a in hexadecimal system + // 90 je 5a v hexadecimální soustavě alert( '\u005a' ); // Z ``` -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 ); +alert( řetězec ); // 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, all modern browsers (IE10- requires the additional library [Intl.js](https://github.com/andyearnshaw/Intl.js/)) support the internationalization standard [ECMA-402](http://www.ecma-international.org/ecma-402/1.0/ECMA-402.pdf). +Naštěstí všechny moderní prohlížeče (IE10- vyžaduje přidání knihovny [Intl.js](https://github.com/andyearnshaw/Intl.js/)) podporují internacionalizační standard [ECMA-402](http://www.ecma-international.org/ecma-402/1.0/ECMA-402.pdf). -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ř. velikost písmen, nebo zda se `"a"` a `"á"` mají brát jako stejné znaky, atd. -## Internals, Unicode +## Vnitřní reprezentace, Unicode -```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 podkapitola zachází hlouběji do vnitřní reprezentace řetězců. Tato znalost vám bude užitečná, jestliže plánujete pracovat s emoji, vzácnými matematickými či hieroglyfickými znaky nebo jinými vzácnými symboly. -You can skip the section if you don't plan to support them. +Jestliže je neplánujete podporovat, můžete tuto podkapitolu přeskočit. ``` -### Surrogate pairs +### Znaky kódované dvěma dvojicemi bajtů -All frequently used characters have 2-byte codes. Letters in most european languages, numbers, and even most hieroglyphs, have a 2-byte representation. +Všechny často používané znaky mají 2-bajtové kódy. Písmena většiny evropských jazyků, číslice a dokonce většina hieroglyfů má 2-bajtovou reprezentaci. -But 2 bytes only allow 65536 combinations and that's not enough for every possible symbol. So rare symbols are encoded with a pair of 2-byte characters called "a surrogate pair". +Avšak 2 bajty umožňují jen 65536 kombinací, a to pro všechny možné symboly nestačí. Vzácné symboly se tedy kódují dvojicí 2-bajtových znaků, která se nazývá „surrogate pair“ *(není mi znám žádný používaný český ekvivalent -- pozn. překl.)*. -The length of such symbols is `2`: +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 hieroglyph +alert( '𝒳'.length ); // 2, VELKÉ X V MATEMATICKÉM SKRIPTU +alert( '😂'.length ); // 2, TVÁŘ SE SLZAMI RADOSTI +alert( '𩷶'.length ); // 2, vzácný čínský znak ``` -Note that surrogate pairs did not exist at the time when JavaScript was created, and thus are not correctly processed by the language! +Všimněte si, že v době, kdy byl JavaScript vytvořen, surrogate pairy ještě neexistovaly, a proto je jazyk nezpracovává korektně! -We actually have a single symbol in each of the strings above, but the `length` shows a length of `2`. +Ve skutečnosti máme v každém z výše uvedených řetězců jediný symbol, ale `length` ukáže délku `2`. -`String.fromCodePoint` and `str.codePointAt` are few rare methods that deal with surrogate pairs right. They recently appeared in the language. Before them, there were only [String.fromCharCode](mdn:js/String/fromCharCode) and [str.charCodeAt](mdn:js/String/charCodeAt). These methods are actually the same as `fromCodePoint/codePointAt`, but don't work with surrogate pairs. +Jedny z mála vzácných metod, které pracují se surrogate pairy správně, jsou `String.fromCodePoint` a `řetězec.codePointAt`. Ty se objevily v jazyce teprve nedávno. Před nimi existovaly jen [String.fromCharCode](mdn:js/string/fromCharCode) a [řetězec.charCodeAt](mdn:js/string/charCodeAt). Tyto metody jsou ve skutečnosti totéž jako `fromCodePoint/codePointAt`, avšak nefungují se surrogate pairy. -Getting a symbol can be tricky, because surrogate pairs are treated as two characters: +Získat symbol může být ošidné, jelikož se surrogate pairy se zachází jako se dvěma znaky: ```js run -alert( '𝒳'[0] ); // strange symbols... -alert( '𝒳'[1] ); // ...pieces of the surrogate pair +alert( '𝒳'[0] ); // podivné symboly... +alert( '𝒳'[1] ); // ...části surrogate pairu ``` -Note that pieces of the surrogate pair have no meaning without each other. So the alerts in the example above actually display garbage. +Všimněte si, že části surrogate pairu nemají jedna bez druhé žádný význam. Funkce `alert` ve výše uvedeném příkladu 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 jsou surrogate pairy detekovatelné i podle svého kódu: má-li znak kód v intervalu `0xd800..0xdbff`, je to první část surrogate pairu. Další znak (druhá část) musí mít kód v intervalu `0xdc00..0xdfff`. Tyto intervaly jsou standardem výslovně vyhrazeny pro surrogate pairy. -In the case above: +Ve výše uvedeném příkladu: ```js run -// charCodeAt is not surrogate-pair aware, so it gives codes for parts +// charCodeAt nezná surrogate pairy, takže vydá kódy pro jejich části -alert( '𝒳'.charCodeAt(0).toString(16) ); // d835, between 0xd800 and 0xdbff -alert( '𝒳'.charCodeAt(1).toString(16) ); // dcb3, between 0xdc00 and 0xdfff +alert( '𝒳'.charCodeAt(0).toString(16) ); // d835, mezi 0xd800 a 0xdbff +alert( '𝒳'.charCodeAt(1).toString(16) ); // dcb3, mezi 0xdc00 a 0xdfff ``` -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 poradit se surrogate pairy, najdete později v kapitole . Existují pro ně pravděpodobně i speciální knihovny, ale žádná není natolik slavná, abych ji tady navrhl. -### 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. +Mnoho jazyků obsahuje symboly, které se skládají ze základního znaku a znaménka nad nebo pod ním. -For instance, the letter `a` can be the base character for: `àáâäãåā`. Most common "composite" character have their own code in the UTF-16 table. But not all of them, because there are too many possible combinations. +Například písmeno `a` může být základním znakem pro: `àáâäãåā`. Většina běžných „složených“ znaků má v tabulce UTF-16 svůj vlastní kód, ale ne všechny, protože možných kombinací je příliš mnoho. -To support arbitrary compositions, UTF-16 allows us to use several Unicode characters: the base character followed by one or many "mark" characters that "decorate" it. +Aby UTF-16 podporovalo libovolnou složeninu, umožňuje nám použít několik znaků Unicode: základní znak následovaný jedním nebo více „znaménky“, která jej „zdobí“. -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 nad písmenem (nebo pod ním) další znaménko -- není to problém, prostě přidejte znak požadovaného 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řidá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 jsou reprezentovány různými složeninami Unicode. -For instance: +Napří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, ačkoli znaky vypadají stejně (?!) ``` -To solve this, there exists a "Unicode normalization" algorithm that brings each string to the single "normal" form. +Abychom to vyřešili, existuje algoritmus „normalizace Unicode“, který vytvoří z každého řetězce jedinou „normální“ formu. -It is implemented by [str.normalize()](mdn:js/String/normalize). +Je implementován ve funkci [ř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 veselé, že v naší situaci `normalize()` ve skutečnosti vytvoří z posloupnosti tří znaků jediný: `\u1e68` (S se dvěma tečkami). ```js run alert( "S\u0307\u0323".normalize().length ); // 1 @@ -655,25 +655,25 @@ alert( "S\u0307\u0323".normalize().length ); // 1 alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true ``` -In reality, this is not always the case. The reason being that the symbol `Ṩ` is "common enough", so UTF-16 creators included it in the main table and gave it the code. +Ve skutečnosti tomu tak vždy není. Důvodem je, že symbol `Ṩ` je „dostatečně běžný“, takže jej tvůrci UTF-16 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](http://www.unicode.org/reports/tr15/), but for most practical purposes the information from this section is enough. +Chcete-li se dozvědět víc o pravidlech a variantách normalizace -- jsou popsány v příloze ke standardu Unicode: [Unicode Normalization Forms](http://www.unicode.org/reports/tr15/), ale pro většinu praktických účelů postačí informace z této podkapitoly. -## Summary +## Shrnutí -- There are 3 types of quotes. Backticks allow a string to span multiple lines and embed expressions `${…}`. -- Strings in JavaScript are encoded using UTF-16. -- We can use special characters like `\n` and insert letters by their Unicode using `\u...`. -- To get a character, use: `[]`. -- 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. Gravisy umožňují rozdělit řetězec na více řádků a vnořit výrazy `${…}`. +- Řetězce v JavaScriptu jsou kódovány pomocí UTF-16. +- Můžeme používat speciální znaky jako `\n` a vkládat písmena podle jejich kódu Unicode pomocí `\u...`. +- Chceme-li získat znak, použijeme `[]`. +- 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, které bude vysvětleno v samostatné části tutoriálu . \ No newline at end of file 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..bc22147e6 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četPod(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..be9e2ed1e 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četPod", function() { + it("maximální podsoučet [1, 2, 3] se rovná 6", function() { + assert.equal(vraťMaxSoučetPod([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četPod([-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četPod([-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četPod([-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četPod([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četPod([]), 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četPod([-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četPod([-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četPod([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 befd80296..16272645d 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četPod(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četPod([-1, 2, 3, -9]) ); // 5 +alert( vraťMaxSoučetPod([-1, 2, 3, -9, 11]) ); // 11 +alert( vraťMaxSoučetPod([-2, -1, 1, 2]) ); // 3 +alert( vraťMaxSoučetPod([1, 2, 3]) ); // 6 +alert( vraťMaxSoučetPod([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 a 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četPod(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četPod([-1, 2, 3, -9]) ); // 5 +alert( vraťMaxSoučetPod([-1, 2, 3, -9, 11]) ); // 11 +alert( vraťMaxSoučetPod([-2, -1, 1, 2]) ); // 3 +alert( vraťMaxSoučetPod([100, -9, 2, -3, 5]) ); // 100 +alert( vraťMaxSoučetPod([1, 2, 3]) ); // 6 +alert( vraťMaxSoučetPod([-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 detail 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 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..04d7ced29 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četPod(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četPod([-1, *!*2, 3*/!*, -9]) == 5 (součet zvýrazněných prvků) +vraťMaxSoučetPod([*!*2, -1, 2, 3*/!*, -9]) == 6 +vraťMaxSoučetPod([-1, 2, 3, -9, *!*11*/!*]) == 11 +vraťMaxSoučetPod([-2, -1, *!*1, 2*/!*]) == 3 +vraťMaxSoučetPod([*!*100*/!*, -9, 2, -3, 5]) == 100 +vraťMaxSoučetPod([*!*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četPod([-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 16d14071f..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 by "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..36db3743b 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. +- Zeptá se uživatele na hodnoty pomocí `prompt` a uloží 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 4bcab0bc9..222ca1bfa 100644 --- a/1-js/05-data-types/04-array/article.md +++ b/1-js/05-data-types/04-array/article.md @@ -1,95 +1,95 @@ -# 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="Koncová čá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 „koncové *(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" @@ -125,325 +125,325 @@ 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. -## 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. 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) *(z anglického „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. `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 +## Interní 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 interní reprezentace. Engine 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 v 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 engine 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 enginech 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 vyčistí 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ů se zachovají. 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 jsou 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 v úzkých hrdlech. 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*. +Je-li `new Array` voláno 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 střelit do nohy: ```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, pokud opravdu dobře neví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: +Pole mohou obsahovat prvky, které jsou také pole. To můžeme využít pro vícerozměrná pole, například pro ukládání matic: ```js run -let matrix = [ +let matice = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]; -alert( matrix[1][1] ); // 5, the central element +alert( matice[1][1] ); // 5, prostřední prvek ``` ## 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řidává něco do řetězce, 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 nezná žádné zvláštní zacházení s poli, 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 převeden 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 nebo, 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 neznají žá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ůžeme 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..a73eda419 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) { +function camelizace(str) { return str - .split('-') // splits 'my-long-word' into array ['my', 'long', 'word'] + .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..ca41ec884 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(str)`, 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..258caedd0 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 str of pole) { + if (!výsledek.includes(str)) { + výsledek.push(str); } } - 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..b29f90904 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 str of pole) { + if (!výsledek.includes(str)) { + výsledek.push(str); } } - 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(str)` interně prochází pole `výsledek` a porovná každý jeho prvek se `str`, 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á `str`, 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é enginy 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..857950989 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 s unikátními 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..5b94b6541 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ě(arr, 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..10f166445 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á `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..462f7fec6 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(str) { let split = str.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..7e7dd7899 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(str)`, 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..c4b87c52a 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á `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 `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 namapovat 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..65964664a 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` 1000000krá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 enginu JS): ```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 jednotlivých JavaScriptových enginů 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 enginy 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] + // k dosažení tohoto použijeme syntaxi „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 104093785..4965b2df4 100644 --- a/1-js/05-data-types/05-array-methods/article.md +++ b/1-js/05-data-types/05-array-methods/article.md @@ -1,462 +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 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. +- `arr.push(...prvky)` -- přidává prvky na konec, +- `arr.pop()` -- vybírá prvek z konce, +- `arr.shift()` -- vybírá prvek ze začátku, +- `arr.unshift(...items)` -- 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 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 prázdné 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í. K tomu musíme nastavit `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 +// 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 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 předpokládá pozice 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 pro další transformace, které by neměly 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 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 vypíše podrobnosti o pozicích 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. +Výsledek funkce (pokud funkce nějaký vrátí) 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: `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 exact index, then `arr.includes` is preferred. +Chceme-li si jen ověřit, zda `prvek` je obsažen v poli, a nepotřebujeme jeho přesný 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 [arr.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( arr.indexOf('Apple') ); // 0 (first Apple) -alert( arr.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 zaznamenatelný 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 `includes` byla do JavaScriptu přidána mnohem později a interně používá novější algoritmus porovnávání. ```` -### find and findIndex/findLastIndex +### find a findIndex/findLastIndex -Imagine we have an array of objects. How do we find an object with the 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, na jednom po 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 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 is a common thing, so the `find` method is very useful. +V reálném životě jsou pole objektů běžnou věcí, 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í se hodnota `-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 jich 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 používá se často. -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"`. +Doslova všechny prvky 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 what's happening. The `arr` can be 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. +Pojďme teď stranou a zamysleme se nad tím, co se děje. `pole` může být pole čehokoli, ž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í porovnat své prvky. 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ý [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 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) { @@ -465,91 +463,91 @@ 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 pro úhlednější řazení: ```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 `str.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í `pole` po převrácení. -### 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 [str.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 space: +V níže uvedeném příkladu jsme oddělovali čá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"; @@ -558,128 +556,128 @@ alert( str.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. +Volání [pole.join(spojka)](mdn:js/Array/join) provádí opak metody `split`. Vytvoří řetězec z prvků `pole`, které budou spojeny řetězcem `spojka` mezi nimi. -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 str = pole.join(';'); // spojíme pole do řetězce pomocí ; -alert( str ); // Bilbo;Gandalf;Nazgul +alert( str ); // 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 v závislosti 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á na všech prvcích pole za sebou a „přenáší“ svůj výsledek 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 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 tomu 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 tomu další prvek, a tak dále... -The calculation flow: +Tok 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 @@ -687,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. - -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. +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ě. -## Summary +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 druhá varianta se používá častěji, jelikož pro většinu lidí je trochu srozumitelnější. -A cheat sheet of array methods: +## Shrnutí -- 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. +Přehled metod polí: -- To search among elements: - - `indexOf/lastIndexOf(item, pos)` -- look for `item` starting from position `pos`, 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 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ýkoli prvek z `prvky` pole, pak se vezmou jeho prvky. -- To iterate over elements: - - `forEach(func)` -- calls `func` for every element, does not return anything. +- 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 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 procházení prvků: + - `forEach(funkce)` -- volá `funkce` pro každý prvek, nic nevrací. -- Additionally: - - `Array.isArray(value)` checks `value` for being an array, if so returns `true`, otherwise `false`. +- 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. -Please note that methods `sort`, `reverse` and `splice` modify the array itself. +- Ostatní: + - `Array.isArray(hodnota)` ověří, zda `hodnota` je pole. Pokud ano, vrátí `true`, jinak vrátí `false`. -These methods are the most used ones, they cover 99% of use cases. But there are few others: +Prosíme všimněte si, že metody `sort`, `reverse` a `splice` modifikují samotné pole. -- [arr.some(fn)](mdn:js/Array/some)/[arr.every(fn)](mdn:js/Array/every) check the array. +Tyto metody jsou nejpoužívanější a v 99% případů dostačují. Existuje však i několik dalších: - The function `fn` is called on each element of the array similar to `map`. If any/all results are `true`, returns `true`, otherwise `false`. +- [pole.some(fn)](mdn:js/Array/some)/[pole.every(fn)](mdn:js/Array/every) prověří pole. - 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. + 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`. - We can use `every` to compare arrays: + Tyto metody se chovají trochu 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 viz [manuál](mdn:js/Array). -From the 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 ce9074cc7..e3dfa7c2b 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 rozběhnout. ## 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 interval = { + 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 interval) ... čí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 `interval` 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 `interval` s komentáři: ```js run -let range = { - from: 1, - to: 5 +let interval = { + 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 +interval[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 interval) { + 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 `interval` nemá metodu `next()`. +- Místo toho se voláním `interval[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ý `interval`, abychom kód zjednodušili. -Like this: +Třeba takto: ```js run -let range = { - from: 1, - to: 5, +let interval = { + 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 interval) { + 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í `interval[Symbol.iterator]()` vrátí samotný objekt `interval`: ten obsahuje potřebnou metodu `next()` a pamatuje si aktuální krok iterace v `this.current`. 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" +Nekonečné iterátory jsou rovněž možné. Například `interval` se stane nekonečným pro `interval.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 pomocí `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 `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 surrogate pairy! ```js run let str = '𝒳😂'; -for (let char of str) { - alert( char ); // 𝒳, and then 😂 +for (let znak of str) { + 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 str = "Ahoj"; -// does the same as -// for (let char of str) alert(char); +// provádí totéž jako +// for (let znak of str) alert(znak); *!* let iterator = str[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. +Tohle potřebujeme jen vzácně, ale dává nám to 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 polím podobné objekty [#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. +- *Polím podobné objekty* 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 be not array-like. And vice versa an array-like may be not 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 `interval` 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 `interval` 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 -// 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 interval z výše uvedeného příkladu +let pole = Array.from(interval); +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 pro `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. +Volitelný 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 -// assuming that range is taken from the example above +// předpokládáme interval 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(interval, čí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 = '𝒳😂'; -// splits str into array of characters -let chars = Array.from(str); +// rozdělí str na pole znaků +let znaky = Array.from(str); -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 `str.split` tato metoda využívá iterovatelnou povahu řetězce, a proto, stejně jako `for..of`, funguje korektně se surrogate pairy. -Technically here it does the same as: +Technicky zde provádí totéž jako: ```js run let str = '𝒳😂'; -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 str) { + 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 surrogate pairy: ```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 surrogate pairy +alert( řetězec.slice(1, 3) ); // nesmysly (dvě části z různých surrogate pairů) ``` -## 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 nazvanou `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á surrogate pairy. -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í *polím podobné*. 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..940545a92 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 s unikátními 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..b6aa84482 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. 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 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 formu 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 něj 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..bd138c35c 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á písmena ve stejných počtech, 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..16773d280 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ě používat metody polí, 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 bd6cad562..23872d025 100644 --- a/1-js/05-data-types/07-map-set/article.md +++ b/1-js/05-data-types/07-map-set/article.md @@ -1,332 +1,331 @@ +# 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í klíčovaných kolekcí. +- 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 +[Mapa](mdn:js/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](mdn:js/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()` -- vytvoří mapu. +- `mapa.set(klíč, hodnota)` -- uloží hodnotu pod klíčem. +- `mapa.get(klíč)` -- vrátí hodnotu podle klíče, jestliže `klíč` v mapě neexistuje, vrátí `undefined`. +- `mapa.has(klíč)` -- vrátí `true`, jestliže `klíč` existuje, jinak `false`. +- `mapa.delete(klíč)` -- odstraní hodnotu pod zadaným klíčem. +- `mapa.clear()` -- odstraní z mapy všechny hodnoty. +- `mapa.size` -- vrátí aktuální počet prvků. -- `new Map()` -- creates the map. -- `map.set(key, value)` -- stores the value by the key. -- `map.get(key)` -- returns the value by the key, `undefined` if `key` doesn't exist in map. -- `map.has(key)` -- returns `true` if the `key` exists, `false` otherwise. -- `map.delete(key)` -- removes the value by the key. -- `map.clear()` -- removes everything from the map. -- `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', 'str1'); // řetězcový klíč +mapa.set(1, 'num1'); // čí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) ); // 'num1' +alert( mapa.get('1') ); // 'str1' -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. Je povolen jakýkoli typ klíče. -```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`, zachází s mapou jako s planým JavaScriptovým objektem, takže pro něj 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ř. výše 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 to zhruba totéž 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') +mapa.set('1', 'str1') .set(1, 'num1') .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()` -- returns an iterable for keys, -- `map.values()` -- returns an iterable for values, -- `map.entries()` -- returns an iterable for entries `[key, value]`, it's used by default in `for..of`. +- `mapa.keys()` -- vrátí iterovatelný objekt klíčů, +- `mapa.values()` -- vrátí iterovatelný objekt hodnot, +- `mapa.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í při inicializaci předat pole (nebo jiný iterovatelný objekt) dvojic klíč/hodnota, například: ```js run -// array of [key, value] pairs -let map = new Map([ +// pole dvojic [klíč, hodnota] +let mapa = new Map([ ['1', 'str1'], [1, 'num1'], [true, 'bool1'] ]); -alert( map.get('1') ); // str1 +alert( mapa.get('1') ); // str1 ``` -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)](mdn:js/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)](mdn:js/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` is a special type collection - "set of values" (without keys), where each value may occur only once. +Množina `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)` -- creates the set, and if an `iterable` object is provided (usually an array), copies values from it into the set. -- `set.add(value)` -- adds a value, returns the set itself. -- `set.delete(value)` -- removes the value, returns `true` if `value` existed at the moment of the call, otherwise `false`. -- `set.has(value)` -- returns `true` if the value exists in the set, otherwise `false`. -- `set.clear()` -- removes everything from the set. -- `set.size` -- is the elements count. +- `new Set(iterovatelnýObjekt)` -- vytvoří množinu, a je-li poskytnut `iterovatelnýObjekt` (obvykle pole), zkopíruje do ní hodnoty z tohoto objektu. +- `množina.add(hodnota)` -- přidá hodnotu, vrátí samotnou množinu. +- `množina.delete(hodnota)` -- odstraní hodnotu, vrátí `true`, jestliže `hodnota` v okamžiku volání existovala, jinak `false`. +- `množina.has(hodnota)` -- vrátí `true`, jestliže hodnota v množině existuje, jinak `false`. +- `množina.clear()` -- odstraní z množiny všechny hodnoty. +- `množina.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 neprovedou. 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](mdn:js/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í [arr.find](mdn:js/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 legračního. Callbacková 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 may help to replace `Map` with `Set` in certain cases with ease, and vice versa. +To slouží ke kompatibilitě s `Map`, v níž callback 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: +Rovněž jsou podporovány stejné metody, jaké má `Map` pro iterovatelné objekty: -- `set.keys()` -- returns an iterable object for values, -- `set.values()` -- same as `set.keys()`, for compatibility with `Map`, -- `set.entries()` -- returns an iterable object for entries `[value, value]`, exists for compatibility with `Map`. +- `množina.keys()` -- vrátí iterovatelný objekt s hodnotami, +- `množina.values()` -- totéž jako `množina.keys()`, kvůli kompatibilitě s `Map`, +- `množina.entries()` -- vrátí iterovatelný objekt s dvojicemi `[hodnota, hodnota]`, existuje kvůli kompatibilitě s `Map`. -## Summary +## Shrnutí -`Map` -- is a collection of keyed values. +`Map` -- je kolekce hodnot s klíči. -Methods and properties: +Metody a vlastnosti: -- `new Map([iterable])` -- creates the map, with optional `iterable` (e.g. array) of `[key,value]` pairs for initialization. -- `map.set(key, value)` -- stores the value by the key, returns the map itself. -- `map.get(key)` -- returns the value by the key, `undefined` if `key` doesn't exist in map. -- `map.has(key)` -- returns `true` if the `key` exists, `false` otherwise. -- `map.delete(key)` -- removes the value by the key, returns `true` if `key` existed at the moment of the call, otherwise `false`. -- `map.clear()` -- removes everything from the map. -- `map.size` -- returns the current element count. +- `new Map([iterovatelnýObjekt])` -- vytvoří mapu, nepovinný objekt `iterovatelnýObjekt` (např. pole) obsahuje dvojice `[klíč,hodnota]` pro inicializaci. +- `mapa.set(klíč, hodnota)` -- uloží hodnotu pod klíčem, vrátí samotnou mapu. +- `mapa.get(klíč)` -- vrátí hodnotu podle klíče, jestliže `klíč` v mapě neexistuje, vrátí `undefined`. +- `mapa.has(klíč)` -- vrátí `true`, jestliže `klíč` existuje, jinak `false`. +- `mapa.delete(klíč)` -- odstraní hodnotu pod zadaným klíčem, vrátí `true`, jestliže `klíč` v okamžiku volání existoval, jinak `false`. +- `mapa.clear()` -- odstraní z mapy všechny hodnoty. +- `mapa.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é včetně objektů. +- Další příhodné metody, vlastnost `size`. -`Set` -- is a collection of unique values. +`Set` -- je kolekce unikátních hodnot. -Methods and properties: +Metody a vlastnosti: -- `new Set([iterable])` -- creates the set, with optional `iterable` (e.g. array) of values for initialization. -- `set.add(value)` -- adds a value (does nothing if `value` exists), returns the set itself. -- `set.delete(value)` -- removes the value, returns `true` if `value` existed at the moment of the call, otherwise `false`. -- `set.has(value)` -- returns `true` if the value exists in the set, otherwise `false`. -- `set.clear()` -- removes everything from the set. -- `set.size` -- is the elements count. +- `new Set(iterovatelnýObjekt)` -- vytvoří množinu, nepovinný objekt `iterovatelnýObjekt` (např. pole) obsahuje hodnoty pro inicializaci. +- `množina.add(hodnota)` -- přidá hodnotu (pokud `hodnota` již existuje, neudělá nic), vrátí samotnou množinu. +- `množina.delete(hodnota)` -- odstraní hodnotu, vrátí `true`, jestliže `hodnota` v okamžiku volání existovala, jinak `false`. +- `množina.has(hodnota)` -- vrátí `true`, jestliže hodnota v množině existuje, jinak `false`. +- `množina.clear()` -- odstraní z množiny všechny hodnoty. +- `množina.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 podle jeho 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..d54db7298 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 se uvidíme", 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é nejsou 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. Protože 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..fd43af70c 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 se uvidíme", 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..cec811065 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 garbage collectorem. -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 8d5a86981..9af77b74b 100644 --- a/1-js/05-data-types/08-weakmap-weakset/article.md +++ b/1-js/05-data-types/08-weakmap-weakset/article.md @@ -1,213 +1,213 @@ -# 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 , engine 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 garbage collectorem +// 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 garbage collectorem. -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` is fundamentally different in this aspect. It doesn't prevent garbage-collection of key objects. +`WeakMap` („slabá mapa“) se v tomto ohledu zásadně liší. Nebrání odstraňování svých klíčových objektů garbage collectorem. -Let's see what it means on examples. +Na příkladech se podívejme, co to znamená. ## WeakMap -The first difference between `Map` and `WeakMap` is that keys must be objects, not primitive values: +Prvním rozdílem mezi `Map` a `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.get(key)` -- `weakMap.set(key, value)` -- `weakMap.delete(key)` -- `weakMap.has(key)` +- `slabáMapa.get(klíč)` +- `slabáMapa.set(klíč, hodnota)` +- `slabáMapa.delete(klíč)` +- `slabáMapa.has(klíč)` -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` ve výše uvedeném kódu), má být automaticky odstraněn garbage collectorem. 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 JavaScriptový engine. 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ž dojde k dalšímu mazání. Technicky tedy není znám momentální počet prvků `WeakMap`. Engine 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 tento objekt použijeme jako klíč. Když bude objekt odklizen garbage collectorem, 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 garbage collectorem), 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 +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ý ji používá: ```js // 📁 main.js -let john = { name: "John" }; +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 `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 +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í nemusíme čistit `mapaPočetNávštěv`. 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í: cache -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 cache. Můžeme si ukládat do paměti (tato paměť se nazývá „cache“) výsledky funkce, abychom je mohli znovu použít při jejích dalších voláních 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(); -// calculate and remember the result -function process(obj) { +// vypočítá a zapamatuje si výsledek +function proces(obj) { if (!cache.has(obj)) { - let result = /* calculations of the result for */ obj; + let výsledek = /* výpočet výsledku pro */ obj; - cache.set(obj, result); + cache.set(obj, výsledek); } return cache.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 */}; +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 cache 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(cache.size); // 1 (Ouha! Objekt je stále v cache 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 `cache`. Nevýhodou je, že když už objekt nebudeme potřebovat, musíme `cache` 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ž nahradíme `Map` za `WeakMap`, tento problém zmizí. Výsledek v cache bude z paměti odstraněn automaticky poté, co bude objekt odklizen garbage collectorem. ```js run // 📁 cache.js @@ -215,77 +215,77 @@ If we replace `Map` with `WeakMap`, then this problem disappears. The cached res let cache = new WeakMap(); */!* -// calculate and remember the result -function process(obj) { +// vypočítá a zapamatuje si výsledek +function proces(obj) { if (!cache.has(obj)) { - let result = /* calculate the result for */ obj; + let výsledek = /* výpočet výsledku pro */ obj; - cache.set(obj, result); + cache.set(obj, výsledek); } return cache.get(obj); } // 📁 main.js -let obj = {/* some object */}; +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 cache.size, protože to je WeakMap, +// ale je nebo zanedlouho bude 0 +// Když bude obj odklizen, budou odstraněna i data z cache ``` ## WeakSet -`WeakSet` behaves similarly: +`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`, `has` and `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`, `has` a `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. +Přestože je „slabá“, může sloužit i jako dodatečné úložiště. 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 momentální 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` 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` 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` is `Set`-like collection that stores only objects and removes them once they become inaccessible by other means. +`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 garbage collectorem. -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..79c334fc4 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` s určitým počtem 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..26ac2bf76 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` -Plain objects also support similar methods, but the syntax is a bit different. +Plané objekty rovněž podporují podobné metody, 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 | „skutečné“ 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 procházení hodnot 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ány: 1, + pomeranče: 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..a344d76cc 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 41e36db2c..c12b0aa3b 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 podle klíčů. +- Pole nám umožňují shromáždit datové prvky do seřazeného seznamu. -Although, when we pass those to a function, it may need not be an object/array as a whole. It may need individual pieces. +Když je však předáváme funkci, funkce nemusí potřebovat objekt nebo pole jako celek. Může potřebovat jen jednotlivé části. -*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 great 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ů, defaultní 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 the 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 better understand it. +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. But the array itself is not modified. +````smart header="„Destrukturace“ neznamená „destrukce“" +Nazývá se to „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 pomocí čárky navíc: ```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 is also skipped (as there are no variables for them). +Ve výše 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 interně 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 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 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 s výměnou 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 prostě 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 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 +### Defaultní hodnoty -If the array is shorter than the list of variables at the left, there'll 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á „defaultní“ hodnota, můžeme ji uvést pomocí `=`: ```js run *!* -// default values -let [name = "Guest", surname = "Anonymous"] = ["Julius"]; +// defaultní 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 defaultní hodnota) ``` -Default values can be more complex expressions or even function calls. They are evaluated only if the value is not provided. +Defaultními hodnotami mohou být další složité výrazy nebo dokonce volání funkcí. Vyhodnocují se jen tehdy, není-li hodnota poskytnuta. -For instance, here we use the `prompt` function for two defaults: +Například zde použijeme pro dvě defaultní 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.title`, `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é stejného názvu. -For potentially missing properties we can set default values using `"="`, like this: +Pro vlastnosti, které mohou chybět, můžeme nastavit defaultní 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 defaultní hodnoty být libovolné výrazy nebo dokonce volání funkcí. Budou vyhodnoceny, jestliže hodnota nebude poskytnuta. -In the code below `prompt` asks for `width`, but not for `title`: +V níže uvedené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 vydal 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 dě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 toku hlavního 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 contain 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 zahloubené čá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íže uvedené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 defaultní 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` that 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` z defaultní 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, items 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 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ž většina parametrů má být defaultních. -Like this? +Takhle? ```js -// undefined where default values are fine -showMenu("My Menu", undefined, undefined, ["Item1", "Item2"]) +// undefined tam, kde se má použít defaultní 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 defaultní 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é = defaultníHodnota ... }) ``` -Then, for an object of parameters, there will be a variable `varName` for property `incomingProperty`, with `defaultValue` by default. +Pak budeme mít vlastnost `vstupujícíVlastnost` objektu parametrů uloženou v proměnné `názevProměnné`, jejíž defaultní hodnota bude `defaultní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 defaultní, měli bychom uvést prázdný objekt: ```js -showMenu({}); // ok, all values are default +zobrazMenu({}); // ok, všechny hodnoty jsou defaultní -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 `{}` defaultní 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 defaultně `{}`, 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 okamžité mapování objektu nebo pole do mnoha proměnných. +- Úplná syntaxe pro objekt: ```js - let {prop : varName = default, ...rest} = object + let {vlastnost : názevProměnné = defaultní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 `defaultníHodnota`. - Object properties that have no mapping are copied to the `rest` object. + Objektové vlastnosti, které nejsou mapovány, se zkopírují do objektu `zbytek`. -- The full array syntax: +- Úplná syntaxe pro pole: ```js - let [item1 = default, item2, ...rest] = array + let [prvek1 = defaultníHodnota, prvek2, ...zbytek] = pole ``` - The first item goes to `item1`; the second goes into `item2`, all the rest makes the array `rest`. + První prvek přijde do proměnné `prvek1`, druhý do `prvek2`, všechny ostatní prvky se stanou polem `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..6a305afc6 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) atd., 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..fc80059ef 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..2629f9e48 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, 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..8044f9a01 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 jednočíslicový 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..83a1db577 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 jednočíslicový 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, např. 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..fe04be34b 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, např. 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 2266c0779..1e666b39e 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 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í doby vytvoření nebo modifikace, 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 automaticky rozparsován. 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 11: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 součástí 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` musí 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 silně 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 tak dále 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, `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 enginů 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íže uvedený 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 podle 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 garbage collector. -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 kvůli pohodlí 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 -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. +První myšlenka může být spustit je mnohokrát za sebou a změřit rozdíl časů. V našem případě jsou tyto funkce velmi jednoduché, takže to musíme udělat alespoň 100000krá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 když tam není typová konverze, je pro enginy 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 něco 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ší benchmarking 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é enginy začínají aplikovat pokročilejší 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 mikrobenchmarkingu buďte opatrní" +Moderní JavaScriptové enginy 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ž benchmarkujeme něco velmi malého, např. práci operátoru nebo vestavěnou funkci. Pokud tedy chcete skutečně porozumět výkonu, pak si prosíme prostudujte, jak funguje JavaScriptový engine. 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 +## Parsování data z řetězce -The method [Date.parse(str)](mdn:js/Date/parse) can read a date from a string. +Metoda [Date.parse(str)](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(str)` parsuje řetězec v zadané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 „jen datum“ nebo „jen č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 rozsah. To je dobré pro přičítání/odečítání dnů/měsíců/hodin. +- Data od sebe lze 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. +- Aktuální časové razítko 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č má 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 to není v `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..32b0a445f 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 na JSON a zpět -Turn the `user` into JSON and then read it back into another variable. +Převeďte objekt `uživatel` na JSON 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..d081bb9b0 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.self = mítink; -alert( JSON.stringify(meetup, function replacer(key, value) { - return (key != "" && value == meetup) ? undefined : value; +alert( JSON.stringify(mítink, function replacer(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..e4e2028e4 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 `replacer`, 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.self = mítink; */!* -alert( JSON.stringify(meetup, function replacer(key, value) { - /* your code */ +alert( JSON.stringify(mítink, function replacer(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 503745356..fa552db3b 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 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 bolestivé. 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 psá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 JSON 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 JSONem zakódovaný objekt 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 používají uvozovky. V JSON nejsou apostrofy ani gravisy. Z `'Jan'` se tedy stane `"Jan"`. +- Názvy vlastností objektů jsou rovněž v 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` přeskakuje. -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 není to, co chceme, 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: replacer -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[, replacer, 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)`. +: 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 vyfiltrovat 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 tyto vlastnosti. -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 `úč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 `replacer` použít funkci místo pole. -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íže uvedený 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 replacer(klíč, hodnota) { + alert(`${klíč}: ${hodnota}`); + return (klíč == 'obsazenoČím') ? undefined : hodnota; })); -/* key:value pairs that come to replacer: +/* dvojice klíč:hodnota, které vstoupily do replaceru: : [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 `replacer` obdrží každou dvojici klíč/hodnota včetně vnořených objektů a prvků pole. Aplikuje se rekurzívně. Hodnota `this` uvnitř funkce `replacer` 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 „wrapperového objektu“: `{"": mítink}`. Jinými slovy, první dvojice `(klíč, hodnota)` má prázdný klíč a hodnotou je celý cílový objekt. To je důvod, proč 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. +Myšlenkou je poskytnout funkci `replacer` 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, replacer, 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 pěkný výstup. -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 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 takovéhoto 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 JSON 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, [reviver]); ``` -str -: JSON-string to parse. +řetězec +: Řetězec JSON, který se má dekódovat. reviver -: Optional function(key,value) that will be called for each `(key, value)` pair and can transform the value. +: 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 jen 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 JSON (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 apostrofech (musí být v uvozovkách) + *!*'jeAdmin'*/!*: false // chyba: klíč v apostrofech (musí být v uvozovká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 JSON jej učiní neplatným. -There's another format named [JSON5](http://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](http://json5.org/), který umožňuje klíče bez uvozovek, komentáře apod. To je však samostatná knihovna a není 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 parsovacího algoritmu. -## Using reviver +## Použití reviveru -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 reviveru, 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 str = '{"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(str, 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 JSON a [JSON.parse](mdn:js/JSON/parse) pro načítání z JSON. +- Obě metody podporují transformační funkce pro elegantní 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 3a281ef3f..97e618962 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 také vyžaduje zdroje, takže je to pomalejší. -P.P.S. Some engines support the "tail call" optimization: if a recursive call is the very last one in the function (like in `sumTo` above), 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, so counting `sumTo(100000)` becomes possible. 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é enginy podporují optimalizaci „koncového volání“: je-li rekurzívní volání ve funkci úplně poslední (jako ve výše uvedené `sečtiDo`), pak se nemusí obnovovat provádění vnější funkce, takže si engine nemusí pamatovat její prováděcí kontext. To odstraní paměťovou zátěž, takže bude možné provést výpočet `sečtiDo(100000)`. Pokud však engine JavaScriptu nepodporuje optimalizaci koncového volání (a většina enginů 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..8bee93235 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 `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..3484f1674 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 engine, 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é dvojí 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á `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..d4c45778e 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 tmp = seznam; while (tmp) { - alert(tmp.value); - tmp = tmp.next; + alert(tmp.hodnota); + tmp = tmp.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 `tmp`. 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. +Na druhou stranu role `tmp` je výhradně procházení seznamu, podobně jako `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. +Na druhou stranu je rekurzívní varianta 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..f369501c7 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 také „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 tmp = seznam; while (tmp) { - arr.push(tmp.value); - tmp = tmp.next; + pole.push(tmp.hodnota); + tmp = tmp.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 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 b7992f162..02fafa532 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 samu: ```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) = +mocnina(x, n) = \ - else = x * pow(x, n - 1) + 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í. To se nazývá *základ* rekurze, jelikož okamžitě vydá zřejmý výsledek: `mocnina(x, 1)` se rovná `x`. +2. Jinak můžeme reprezentovat `mocnina(x, n)` jako `x * mocnina(x, n - 1)`. V matematice můžeme zapsat xn = x * xn-1. +To 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 `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 enginem JavaScriptu. Můžeme se spolehnout, že to bude aspoň 10000, některé enginy umožňují víc, ale 100000 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í tok řízení právě teď, aktuální proměnné, hodnotu `this` (zde ji nepoužíváme) a některé další interní 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ů*. +- Je spuštěno vnořené volání. +- Až toto volání skončí, starý prováděcí kontext se vyjme ze zásobníku a vnější funkce se obnoví od místa, kde byla zastavena. -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`, tok ří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 tok 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)`: +Zde je 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ž si udržuje 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 po vnořeném volání“. ``` -### 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 pracovat 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ů pro všechny nižší hodnoty `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 smyčky. Variantu se smyčkou lze obvykle napsat efektivněji.** -...But sometimes the rewrite is non-trivial, especially when 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í stát za tu 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 podporu. Optimalizace nejsou nutné všude, většinou potřebujeme dobrý kód, proto používáme rekurzi. -## Recursive traversals +## Rekurzívní traversaly -Another great application of the recursion is a recursive traversal. +Další skvělé využití rekurze je rekurzívní traversal. -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í, které 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. 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í vlastnosti, 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 `arr.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. +Právě jsme ji viděli ve výše uvedeném příkladu struktury firmy. -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 `arr.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, které nevyžadují masové přečíslování, jsou ty, které pracují s koncem pole: `pole.push/pop`. Pole tedy může být poměrně pomalé pro velké fronty, když musíme 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 *null*, jestliže tento prvek je poslední. -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 list = { hodnota: 1 }; +list.další = { hodnota: 2 }; +list.další.další = { hodnota: 3 }; +list.další.další.další = { hodnota: 4 }; +list.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řipojit 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 zprostředka, 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. + Když funkce volá sebe sama, nazývá se to *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í: mají 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 procházení skrz ně 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 c63fe70cd..4dc3a3a6f 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 podporuje volitelný 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. +Kvůli „přebytečným“ argumentům nenastane chyba, ale do výsledku se samozřejmě budou počítat jen první dva. -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". +Zbytek parametrů 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 zbytek parametrů 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" +Zbytkové parametry shromažďují 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 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. +Za starých časů 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ém kódu. -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, vezme jej 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 ručně vyjmenovat prvky pole v kódu `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 bylo by to ošklivé. -*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`, „roztáhne“ iterovatelný objekt `pole` 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 k předvedení 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 interně 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]`. +Takže pro řetězec `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 poli podobných objektech 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 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í volitelný 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 v objektu `arguments` ve starém stylu: 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..62310d030 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 jsou právě teď. 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..44be5407e 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` použí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..c064beb24 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ř funkce `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`, a jiné scénáře, kde 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..c0857833c 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 kódu níže načte `jméno` z místa svého vzniku skrz odkaz 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 z výše uvedeného řetězce. 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..425c23628 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íže uvedená 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..52fb2d5f2 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 s 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..eae0f8885 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 podivný 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 výkon vstoupí do kódového bloku (nebo 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. +Výše 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 + // engine 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..71abe5ea6 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. +Máme vestavěnou metodu `pole.filter(f)` pro pole, 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 jim (inkluzívně). +- `vPoli([...])` -- v zadaném poli. -The usage must be like this: +Použití musí být takovéto: -- `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..a3b5792c2 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 velmi funkcionálně orientovaný jazyk. Dává nám velké množství svobody. Funkci můžeme vytvořit kdykoli, předat ji jako argument jiné funkci a později ji volat ze zcela odlišné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 poté, co je funkce vytvořena, vnější proměnné změní? Dostanou se do funkce jejich nové hodnoty nebo staré? -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 parametr 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 3 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 je i o `const`. +- Staré `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 kus kódu, který odvede svou vlastní práci, s proměnnými, které budou patřit pouze jemu: ```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 poté, co `if` skončí, `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 konstrukce `for` je v tomto speciální: proměnná, která je deklarována uvnitř ní, 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. +Co je ještě zajímavější, vnořenou funkci můžeme vrátit: buď jako vlastnost nového objektu, nebo jako samotný výsledek. Pak ji můžeme použít někde jinde. Ať to bude kdekoli, stále bude mít přístup k vnějším proměnným. -Below, `makeCounter` creates the "counter" function that returns the next number on each invocation: +Níže `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. +Ačkoli jsou jednoduché, mírně upravené varianty tohoto kódu 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 automatické 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 celkovou 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 ve výše uvedeném obrázku znamená záznam prostředí (skladiště proměnných) a šipka znamená odkaz vně. Globální lexikální prostředí nemá žádný odkaz vně, proto šipka ukazuje na `null`. -As the code starts executing and goes on, the Lexical Environment changes. +Když se kód začne vykonávat a pokračuje, lexikální prostředí se 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 výkonu 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í interní stav, který znamená, že engine ví o proměnné, ale ta nemůže být odkazována, 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 její hodnota 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ěci fungují. 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. +Enginy JavaScriptu jej také mohou optimalizovat, vyřazovat nepoužívané proměnné, aby ušetřily paměť, a provádět jiné interní 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 deklarace funkce je 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í, funkce z deklarace se okamžitě stane funkcí připravenou k použití (na rozdíl od proměnné v `let`, která je až do deklarace 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 (výkon 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 výkonu 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 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ě žádná proměnná `věta` není, takže postupuje 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 toto spuštění 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í žádná magie: 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 později volán `čítač()`, vytvoří se pro toto volání nové lexikální prostředí a 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://en.wikipedia.org/wiki/Closure_(computer_programming)) 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á: automaticky si pamatují, kde byly vytvořeny, pomocí skryté vlastnosti `[[Environment]]`, 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 -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í 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ěj nejsou žádné odkazy. Stejně jako jiné 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 dostupná, pak tato funkce má vlastnost `[[Environment]]`, která se odkazuje na lexikální prostředí. -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 dokončení funkce, takže zůstane naživu. -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íže uvedeném kódu 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, existuje, jen dokud existuje 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íže uvedeném kódu je poté, co je vnořená funkce odstraněna, její uzavírající lexikální prostředí (a tedy i `hodnota`) vyčiště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 je funkce naživu, 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é enginy 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 ladicí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 engine 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 s Chrome/Edge/Operou, 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 debuggeru, 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 1579afb62..c05ee6c7b 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 je užitečná, 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. +Interně je však `var` velmi odlišná potvůrka, která pochází z prastarý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. +Na druhou stranu je důležité porozumět rozdílům, když převádíte staré skripty z `var` na `let`, 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 +```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 v dávných časech JavaScriptu bloky 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 +## Proměnné deklarované „var“ můžeme deklarovat až za jejich použitím -`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é `var` jsou definovány od začátku funkce bez ohledu na to, kde se tato definice nachází (předpokládáme, ž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í lidé někdy říkají „stoupání“ *(anglicky „hoisting“ nebo „raising“ -- pozn. překl.)*, 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. +Ve výše 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 ve chvíli `(*)` 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 na ně dostane provádění. */!* } -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 se na ně odkazovat kdekoli. Ale proměnné jsou nedefinované až do přiřazení. -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 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, nazvali „okamžitě volané funkční výrazy“, zkráceně IIFE *(z anglického „immediately-invoked function expressions“ - pozn. překl.)*. -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ž engine JavaScriptu narazí v hlavním kódu na `„function“`, chápe to jako začátek deklarace funkce. Avšak deklarace funkce musí mít svůj 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() { +// syntaktická chyba kvůli závorkám níže +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 výše uvedených případech deklarujeme funkční výraz a okamžitě jej zavoláme. Znovu opakujeme: 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`: +Existují dva hlavní rozdíly `var` ve srovnání s `let/const`: -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é `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 zahrnuto `let`, a to je nyní hlavním způsobem (spolu s `const`) deklarace proměnných. 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..2b936bf59 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 bylo do jazyka přidáno `globalThis` jako standardizovaný název globálního objektu, který by měla podporovat všechna prostředí. Je podporováno ve všech významných prohlížečích. -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še prostředí je prohlížeč. Pokud váš skript má běžet v jiných prostředích, je lepší místo toho 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 hlavním 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í [moduly JavaScriptu](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 jej 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, kdy 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í podpory moderních vlastností 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 opravdu starých prohlížečích): ```js run if (!window.Promise) { - alert("Your browser is really old!"); + alert("Máte opravdu starý 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 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 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. +- Abychom učinili kód připravený na budoucnost 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..b8132adf3 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č.set = 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..8308f1517 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í používá `počet` v lokální proměnné, ale přidané metody jsou vepsány přímo do `čítač`. Sdílejí stejné vnější lexikální prostředí a mohou také přistupovat k aktuální 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..ba4b6b59e 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. +Pro úplný příklad použití viz kód 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..47c1a5564 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 součet(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..63c1a6420 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 součet(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 +součet(1)(2) == 3; // 1 + 2 +součet(1)(2)(3) == 6; // 1 + 2 + 3 +součet(5)(-1)(2) == 6 +součet(6)(-1)(-2)(-3) == 0 +součet(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..36b6c852b 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("součet", function(){ - it("sum(1)(2) == 3", function(){ - assert.equal(3, sum(1)(2)); + it("součet(1)(2) == 3", function(){ + assert.equal(3, součet(1)(2)); }); - it("sum(5)(-1)(2) == 6", function(){ - assert.equal(6, sum(5)(-1)(2)); + it("součet(5)(-1)(2) == 6", function(){ + assert.equal(6, součet(5)(-1)(2)); }); - it("sum(6)(-1)(-2)(-3) == 0", function(){ - assert.equal(0, sum(6)(-1)(-2)(-3)); + it("součet(6)(-1)(-2)(-3) == 0", function(){ + assert.equal(0, součet(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("součet(0)(1)(2)(3)(4)(5) == 15", function(){ + assert.equal(15, součet(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..e1021eaac 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 `součet` 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 součet(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( součet(1)(2) ); // 3 +alert( součet(5)(-1)(2) ); // 6 +alert( součet(6)(-1)(-2)(-3) ); // 0 +alert( součet(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 `součet` 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 při každém následném volání `f` 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 `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 `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..2229d3af4 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 `součet`, 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 +součet(1)(2) == 3; // 1 + 2 +součet(1)(2)(3) == 6; // 1 + 2 + 3 +součet(5)(-1)(2) == 6 +součet(6)(-1)(-2)(-3) == 0 +součet(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..15aedaf64 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 atd. -## 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“ („jméno“): ```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 defaultní 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 vlastní název neposkytne, pak je v 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 však žádná magie. Existují případy, kdy není 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 ); // +// engine 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“ („délka“), 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ů, 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í 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 `length`. Tato myšlenka je 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 ji 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 mohou někdy 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 taková věc 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, zkráceně NFE *(z anglického „Named Function Expression“ -- pozn. překl.)*, 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 operace přiřazení. -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: +Na názvu `funkce` jsou 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 interně sama na sebe. +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íže uvedená funkce `řekniAhoj` volá sama sebe s parametrem `"Host"`, není-li poskytnuto `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 změnit ve vnějším kódu. 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 ve chvíli 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. +Volitelný 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" +Zde 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 toku 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, viz [dokumentaci](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..0072fc60c 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 str = ... dynamické získání kódu ze serveru ... -let func = new Function(str); -func(); +let funkce = new Function(str); +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 k dynamickému kompilování funkce 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`, do její vlastnosti `[[Environment]]` se nenastaví 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 v průběhu spuštění. 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, že předtím, než je JavaScript zveřejněn k produkci, je zkomprimován použitím *minifikátoru* -- speciálního programu, který zkrátí kód tím, že odstraní komentáře, přebytečné mezery a -- co je důležité, přejmenuje lokální proměnné 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, je-li toto již 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í každou zmínku o ní. 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. Explicitní předávání parametrů je architektonicky mnohem lepší metoda 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..959e92609 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) { + alert(aktuální); + if (aktuální < konec) { setTimeout(go, 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..c67964047 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 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/4-settimeout-result/task.md b/1-js/06-advanced-functions/08-settimeout-setinterval/4-settimeout-result/task.md index 667c8ffa6..1b5a75cdf 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íže uvedené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 fa1d98cb9..2e1d3bbaa 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í“. -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 ji neustále v tomto intervalu opakovat. -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), defaultně 0. `arg1`, `arg2`... -: Arguments for the function (not supported in IE9-) +: Argumenty této funkce (není podporováno v IE9-). -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: +Tohle tedy bude fungovat také: ```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 funkci `setTimeout` se předá *výsledek jejího volání*. V našem případě je výsledek `řekniAhoj` `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í 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íže uvedené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://www.w3.org/TR/html5/webappapis.html#timers) of HTML5 standard. +Pro prohlížeče jsou časovače popsány v [sekci časovačů](https://www.w3.org/TR/html5/webappapis.html#timers) standardu HTML5. ## 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 bude funkce spuštěna nejenom jednou, ale pravidelně vždy po zadaném časovém 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 interní časovač „tiká“ dál, zatímco je zobrazeno `alert/confirm/prompt`. -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 `(*)`. +Výše uvedený `setTimeout` načasuje další volání na konci aktuálního `(*)`. -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 odlišně v závislosti na výsledcích aktuálního. -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`, „zkonzumuje“ čá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ě engine 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 pauzy. -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="Garbage collection 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í funkci, aby byla odstraněna garbage collectorem, přestože 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. +Je tady 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ě spouštěný 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 po 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 [HTML5 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. [Standard HTML5](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íže uvedené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 skutečný čas od předchozího v poli `časy`. 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 z 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...`. Do hry vstupuje povinná prodleva aspoň 4 ms mezi voláními. -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í z prastarých časů a mnoho skriptů na něm závisí, 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ž poté, co bude dokončen aktuální skript“. +- 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..f33ba3168 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,12 @@ -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 wrapper(...argumenty) { + // použijeme ...argumenty místo arguments, abychom do wrapper.volání uložili „skutečné“ pole + wrapper.volání.push(argumenty); + return funkce.apply(this, argumenty); } - wrapper.calls = []; + wrapper.volání = []; return wrapper; } 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..8bf5726db 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 = spy(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 kalk = { + sečti: sinon.spy((a, b) => a + b) }; - calc.wrappedSum = spy(calc.sum); + kalk.obalenéSečti = spy(kalk.sečti); - assert.equal(calc.wrappedSum(1, 2), 3); - assert(calc.sum.calledWith(1, 2)); - assert(calc.sum.calledOn(calc)); + assert.equal(kalk.obalenéSečti(1, 2), 3); + assert(kalk.sečti.calledWith(1, 2)); + assert(kalk.sečti.calledOn(kalk)); }); }); 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..e74af70ad 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. +Wrapper, který vrátí `špión(f)`, by měl uložit všechny argumenty a pak pomocí `f.apply` forwardovat 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..13ee3c0ce 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 wrapper, 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 unit-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..20ebfe912 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 čekej(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..6d1604abe 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("čekej", 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 = čekej(f, 1000); f1000("test"); - this.clock.tick(2000); - assert(f.calledOnce, 'calledOnce check fails'); + this.hodiny.tick(2000); + assert(f.calledOnce, 'test calledOnce selhal'); }); - 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 spy = uživatel.řekniAhoj; + uživatel.řekniAhoj = čekej(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(spy.calledOnce, 'test calledOnce selhal'); }); }); 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..db66051f6 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 čekej(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 = čekej(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 wrapperu. -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: +Stále můžeme předávat pravé `this` pomocí dočasné proměnné, ale to je trochu pracnější: ```js -function delay(f, ms) { +function čekej(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 dočasné 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..7f2442ff7 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 +# Čekací dekorátor -Create a decorator `delay(f, ms)` that delays each call of `f` by `ms` milliseconds. +Vytvořte dekorátor `čekej(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í wrapperů +let f1000 = čekej(f, 1000); +let f1500 = čekej(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, `čekej(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`. +Ve výše 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..e5936fb80 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) { +function debounce(funkce, ms) { let timeout; return function() { clearTimeout(timeout); - timeout = setTimeout(() => func.apply(this, arguments), ms); + timeout = 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..8232ce0ea 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,39 +1,39 @@ describe('debounce', 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); debounced('test'); - assert(f.notCalled, 'not called immediately'); - this.clock.tick(1000); - assert(f.calledOnceWith('test'), 'called after 1000ms'); + 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); debounced('a'); - setTimeout(() => debounced('b'), 200); // ignored (too early) - setTimeout(() => debounced('c'), 500); // runs (1000 ms passed) - this.clock.tick(1000); + setTimeout(() => debounced('b'), 200); // ignorováno (příliš brzy) + setTimeout(() => debounced('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); @@ -42,7 +42,7 @@ describe('debounce', function () { obj.f = debounce(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..a8d33244a 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: +Debouncovaná funkce debounce(handler, 1000) je volána na tomto vstupu:

- + 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..f823568ba 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. +Je to právě `finally`, co nám zde úklid zajistí. 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..d96d0c46a 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ž na ní záleží. 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 a928da289..1f068f4fe 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`: +Konstrukce `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: řízení dosáhne konce `try`, přeskočí blok `catch` a pokračuje dál. +3. Pokud nastane chyba, výkon bloku `try` se ukončí a řízení 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("Engine 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ý engine 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 engine tomuto 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ž engine již opustil konstrukci `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 +## Vazba „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 JSON. -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. +Tímto způsobem, je-li s daty něco špatně, návštěvník se o tom 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 tok řízení 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. +Ve výše 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 open-source 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. Nevíme-li, jak jej 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íže uvedené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ší konstrukcí `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íže uvedený 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( "Externí 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 `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`. +Konstrukce `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?')) ŠPATNÝ_KÓD(); +} catch (chyba) { alert( 'catch' ); } finally { alert( 'finally' ); } ``` -The code has two ways of execution: +Tento kód má dvě možné cesty průběhu: -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čnete něco dělat a chcete 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íže uvedené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 skvělé 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` ve výše 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íže uvedeném příkladu je `return` uvnitř `try`. V tom případě se `finally` spustí právě předtím, než se řízení 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. +Užitečná je i konstrukce `try...finally` bez klauzule `catch`. Používáme ji, 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. +Ve výše uvedeném kódu chyba vzniklá uvnitř `try` vždy vypadne, protože zde není `catch`. Ale `finally` zafunguje ještě předtím, než tok řízení 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 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 nebývá obnovit výkon 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 nebo . -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. Zaregistrujete se na službě a dostanete od ní kousek kódu v JS (nebo URL skriptu), který si vložíte 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. +Konstrukce `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ší konstrukce `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 použitím `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 bývá 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 chybu 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 918289319..bfb2874f0 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é věci, 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 přirozeně tvořit 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. +Interně 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 zde je 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 untrusted *!* -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 potomka 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`. +Ve výše 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") { // (*) +// mí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 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 dál. -## 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` sloužící výhradně pro případy absence vlastnosti. Bude obsahovat další informace o vlastnosti, která schází. ```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 +## Wrapová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` ve výše uvedeném kódu je „načíst uživatelská data“. V 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. +Ve výše 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. +Často zní odpověď „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ě lépe, bychom rádi 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á „wrapování 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). +Ve výše uvedeném kódu `načtiUživatele` funguje přesně tak, jak je popsáno -- 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á „wrapování (obalování) 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 běžně dědit. 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 wrapování výjimek: funkce ošetří výjimky nižší úrovně a namísto různých chyb nižší úrovně vyvolá chybu vyšší úrovně. Jejími vlastnostmi se někdy stávají výjimky nižší úrovně, například `chyba.příčina` ve výše 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..d6fd46542 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 vás mate, 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 opravdu 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é vám umožňují naplánovat *asynchronní* akce. Jinými slovy akce, které spustíte 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(src)`, která načte skript ze zadaného zdroje `src`: ```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íže uvedené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="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 zvnějšku, 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/export místo závislosti na globálních proměnných. -This is the correct variant: +Toto je správná varianta: [codetabs src="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 tím, že ji výslovně přiřadíme do vlastnosti `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ři tom všem 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 více 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 z různých souborů // 📁 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: 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. Potřebujeme-li umožnit volat něco vícekrát, měli bychom to exportovat jako funkci, tak jak jsme to udělali s výše uvedeným `ř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 generickou funkcionalitu, která potřebuje nastavení. Například autentifikace potřebuje osobní údaje. Pak může exportovat konfigurační objekt a očekávat, že do něj vnější kód něco přiřadí. -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 nějaký druh konfigurace, 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` zvnějšku: ```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é defaultní vlastnosti). -Then in `init.js`, the first script of our app, we import `config` from it and set `config.user`: +Pak v `init.js`, prvním skriptu naší aplikace, z něj 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. +Objekt `import.meta` obsahuje informaci o aktuálním modulu. -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 je „this“ nedefinováno -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)), pro externí i inline 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: 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 tam umístit „indikátory načítání“ nebo jinak zajistit, aby to návštěvníka nezmátlo. -### Async works on inline scripts +### Na inline 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 inline skriptech. -For example, the inline script below has `async`, so it doesn't wait for anything. +Například níže uvedený inline 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, listenery 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í header [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 header `Access-Control-Allow-Origin`, který stažení umožní. ```html - - - + + + ``` - That ensures better security by default. + To 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í mít cestu, např. './řekniAhoj.js' nebo 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, umožňují holé moduly bez jakékoli cesty, 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. +Při tom všem jsou však použitelné i nativní moduly. Nebudeme tedy zde používat Webpack: 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 8af1b3b10..3f1321048 100644 --- a/1-js/13-modules/02-import-export/article.md +++ b/1-js/13-modules/02-import-export/article.md @@ -1,465 +1,465 @@ -# 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`: +To je důvod, proč na konci `export class` a `export function` není středník potřeba: ```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}!`); +// 📁 ř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 explicitně uvádět seznam toho, co potřebujeme importovat? -Well, there are few reasons. +Je k tomu ovšem několik důvodů. -1. Modern build tools ([webpack](https://webpack.js.org/) and others) bundle modules together and optimize them to speedup loading and remove unused stuff. +1. Moderní sestavovací nástroje ([Webpack](https://webpack.js.org/) a jiné) spojují moduly dohromady a optimalizují je, aby urychlily načítání a odstranily nepoužité části. - Let's say, we added a 3rd-party library `say.js` to our project with many functions: + Řekněme, že jsme do našeho projektu přidali knihovnu třetí strany `řekni.js` s mnoha funkcemi: ```js - // 📁 say.js - export function sayHi() { ... } - export function sayBye() { ... } - export function becomeSilent() { ... } + // 📁 řekni.js + export function řekniAhoj() { ... } + export function řekniNashle() { ... } + export function buďZticha() { ... } ``` - Now if we only use one of `say.js` functions in our project: + Pokud nyní v našem projektu využijeme jen jednu z funkcí `řekni.js`: ```js // 📁 main.js - import {sayHi} from './say.js'; + import {řekniAhoj} from './řekni.js'; ``` - ...Then the optimizer will see that and remove the other functions from the bundled code, thus making the build smaller. That is called "tree-shaking". + ...Pak to optimalizátor uvidí a odstraní ze spojeného kódu ostatní funkce, čímž sestavený kód zkrátí. To se nazývá „třesení stromem“. -2. Explicitly listing what to import gives shorter names: `sayHi()` instead of `say.sayHi()`. -3. Explicit list of imports gives better overview of the code structure: what is used and where. It makes code support and refactoring easier. +2. Explicitní uvedení toho, co se má importovat, nám umožňuje psát kratší názvy: `řekniAhoj()` místo `řekni.řekniAhoj()`. +3. Explicitní seznam importů nám dává lepší přehled struktury kódu: co a kde je použito. Usnadňuje podporu a refaktorizaci kódu. -## Import "as" +## Import „as“ -We can also use `as` to import under different names. +S použitím `as` můžeme také importovat pod odlišnými názvy. -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` („defaultní 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 defaultní. -| Named export | Default export | +| Pojmenovaný export | Defaultní 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ě defaultní i pojmenované exporty, ale v praxi je lidé obvykle nesměšují. Modul obsahuje buď pojmenované exporty, nebo defaultní 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 defaultní 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é defaultní 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! (nedefaultní export vyžaduje název) constructor() {} } ``` -### The "default" name +### „Defaultní“ 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 defaultní 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í „defaultní“ 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 defaultní 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ě defaultní 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; // defaultní export +new Uživatel('Jan'); ``` -### A word against default exports +### Pár slov proti defaultní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í. Přesně pojmenovávají, co importují, takže od nich tuto informaci máme; 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 při defaultním 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: +Obvykle, abychom se tomu vyhnuli a udrželi kód konzistentní, 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 defaultní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 níže). -## 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 defaultní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 (takové balíčky nám umožňují publikovat a distribuovat nástroje jako NPM, ale nemusíme je používat) a mnoho modulů jsou jen „pomocníci“ 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/ + uživatel.js + pomocníci.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 ukrýváme před slídivýma očima. -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'; +// importujeme login/logout a ihned je exportujeme +import {login, logout} from './pomocníci.js'; export {login, logout}; -// import default as User and export it -import User from './user.js'; -export {User}; +// importujeme default 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 {login} 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 login/logout +export {login, logout} from './pomocníci.js'; -// re-export the default export as User -export {default as User} from './user.js'; +// reexport defaultní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 `login/logout`. -### Re-exporting the default export +### Reexportování defaultního exportu -The default export needs separate handling when re-exporting. +Defaultní 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 defaultní export, musíme napsat `export {default as Uživatel}`, jako ve výše 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 defaultní. - If we'd like to re-export both named and default exports, then two statements are needed: + Pokud chceme reexportovat jak pojmenované, tak defaultní 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 defaultní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 defaultního exportu jsou jedním z důvodů, proč někteří vývojáři nemají rádi defaultní 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 defaultní export). + - `export {default [as y]} from "modul"` (reexportuje defaultní 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 defaultní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 žádný jeho export se nepřiřadí do proměnné): + - `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í, 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..08e9b2b59 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ů/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 vyhodnotí 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` má defaultní export: ```js -// 📁 say.js +// 📁 řekni.js export default function() { - alert("Module loaded (export default)!"); + alert("Modul načten (defaultní export)!"); } ``` -...Then, in order to access it, we can use `default` property of the module object: +...Pak, abychom k němu přistoupili, můžeme 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="say" current="index.html"] ```smart -Dynamic imports work in regular scripts, they don't require `script type="module"`. +Dynamické importy fungují 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..78b68b695 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..ca920d700 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 (defaultní 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..9bb1d3dae 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 wrap(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 = wrap(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..063c20f70 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 brzy 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 `wrap(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 wrap(cíl) { + return new Proxy(cíl, { *!* - /* your code */ + /* váš kód */ */!* }); } -user = wrap(user); +uživatel = wrap(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..de636724f 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ů, počítaných 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 tak, „jak je“ ``` 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..2fcd62304 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 názvem a hodnotou oné vlastnosti. -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..810af6a53 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 +# 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 `Proxy` zapouzdřuje jiný objekt a zachytává operace na něm, například čtení/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 zapouzdřen, 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“. 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 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, přímo názvem je volat 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íže uvedené 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 existuje 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 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 +## Defaultní hodnota s pastí „get“ -The most common traps are for reading/writing properties. +Nejběžnější pasti jsou pro čtení/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: +Ta se spustí, když je vlastnost načítána, 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 jeho volání použit jako `this`. Obvykle je to samotný objekt `proxy` (nebo objekt, který je z něj zděděn, dědíme-li 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 defaultní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 zapouzdříme běžné pole do proxy, která bude obsahovat past na načítání a vracet `0`, pokud taková 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; // defaultní 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 to docela snadné. -We can use `Proxy` to implement any logic for "default" values. +Můžeme použít `Proxy` k implementaci jakékoli logiky pro „defaultní“ 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`. +Momentálně načtení věty, kterou `slovník` neobsahuje, vrací `undefined`. V praxi je však obvykle lepší nechat větu nepřeloženou než `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, zapouzdří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. +Proxy by měl cílový objekt všude zcela nahradit. Nikdo by se nikde neměl odkazovat na cílový objekt poté, co je nahrazen proxy objektem. 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. +Past `set` se spustí, když se zapisuje do vlastnosti. -`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 `false` jinak (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: zabudovaná funkcionalita polí stále funguje! Hodnoty se přidávají metodou `push`. Vlastnost `length` se automaticky zvyšuje, když jsou hodnoty přidávány. 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. +Nemusíme přepisovat metody přidávání hodnot do polí jako `push`, `unshift` a tak dále, abychom tam přidali ověření, protože ty interně 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í s tímto seznamem. -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íže uvedené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ý: `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ý, neobsahuje přepínač `enumerable`, a tak je přeskočen. -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 `_`. +Použijme proxy, abychom zabránili jakémukoli přístupu k vlastnostem, které začínají `_`. -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í, +- `defineProperty` 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 budoucí 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 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 nezapouzdřený 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é enginy 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. Konkrétně 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`. +Rádi bychom používali operátor `in` k ověření, zda číslo leží v rozsahu `rozsah`. -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] +## Wrapovací funkce: „apply“ [#proxy-apply] -We can wrap a proxy around a function as well. +Do proxy můžeme zapouzdřit 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 `čekej(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í `čekej(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 čekej(f, ms) { + // vrátí wrapper, který po uplynutí č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 wrapování budou volání řekniAhoj pozdržena o 3 sekundy +řekniAhoj = čekej(ř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. Wrapperová 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 wrapperová funkce nepředává dál operace čtení/zápisu do vlastností nebo cokoli jiného. Po wrapování ztratíme přístup k vlastnostem původní funkce, např. `name`, `length` a jiným: ```js run -function delay(f, ms) { +function čekej(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 = čekej(řekniAhoj, 3000); *!* -alert(sayHi.length); // 0 (in the wrapper declaration, there are zero arguments) +alert(řekniAhoj.length); // 0 (v deklaraci wrapperu 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 wrapovací funkce: ```js run -function delay(f, ms) { +function čekej(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 = čekej(ř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 wrapování se tedy `řekniAhoj.length` na řádku `(*)` vrátí správně. -We've got a "richer" wrapper. +Získali jsme „bohatší“ wrapper. -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 vzor použití je podobný tomu uvedenému výše. ## 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í wrappery 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í/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. +Přitom je všechno jednoduché: jestliže past chce předat objektu volání, 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 můžeme 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*/!*); } ``` +Volání `Reflect` jsou pojmenována přesně stejně jako pasti a přijímají stejné argumenty. Byla tak úmyslně navržena. -`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 ovšem nejsou dokonalé. 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 interní, 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. +Interně 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 interní 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á žádné 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ž dávno. -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á věc 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? +Proxy 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, proxy nebude nalezena: ```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ž proxy je jiný objekt. -```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 v libovolném okamžiku uzavřít přístup k němu. -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. +To, co můžeme udělat, je zapouzdřit jej 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 funkcí `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 proxy někam 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 garbage collection. Pokud se proxy 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 wrapper 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 zapouzdřovat 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 defaultní vlastnosti, 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é zapouzdřit 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 odpovídající volání `Reflect` se stejnými argumenty. Měli bychom je používat k předávání volání cílovým objektům. -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 interně 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: benchmarky závisejí na enginu, 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ů v „úzkém hrdle“. 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 6861837a9..7a069168e 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/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í. From bd308e3df2a86a50f923351eef5ad0f3d300a9b0 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Mon, 22 Aug 2022 18:57:30 +0200 Subject: [PATCH 02/55] Update article.md --- 1-js/02-first-steps/07-type-conversions/article.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 2cabd01b2..b8cf5b179 100644 --- a/1-js/02-first-steps/07-type-conversions/article.md +++ b/1-js/02-first-steps/07-type-conversions/article.md @@ -70,7 +70,7 @@ Pravidla pro konverzi na číslo: |`undefined`|`NaN`| |`null`|`0`| |true a false | `1` a `0` | -| `řetězec` | Odstraní se bílé znaky (mezery, tabulátory, konce řádku) ze začátku a konce. Je-li výsledný řetězec prázdný, výsledkem je `0`. Jinak se číslo „přečte“ z řetězce. Při chybě je vydáno `NaN`. | +| `řetězec` | Odstraní se bílé znaky (mezery, tabulátory `\t`, konce řádku `\n` atd.) ze začátku a konce. Je-li výsledný řetězec prázdný, výsledkem je `0`. Jinak se číslo „přečte“ z řetězce. Při chybě je vydáno `NaN`. | Příklady: @@ -130,7 +130,7 @@ Konverze se řídí těmito pravidly: |`undefined`|`NaN`| |`null`|`0`| |true / false | `1 / 0` | -| `řetězec` | Načte se „doslovně“, bílé znaky na obou stranách se ignorují. Z prázdného řetězce se stane `0`. Při chybě je vydáno `NaN`. | +| `řetězec` | Načte se „doslovně“, bílé znaky (mezery, tabulátory `\t`, konce řádku `\n` atd.) na obou stranách se ignorují. Z prázdného řetězce se stane `0`. Při chybě je vydáno `NaN`. | **`Konverze na boolean`** -- Nastává při logických operacích. Můžeme ji provést pomocí `Boolean(hodnota)`. @@ -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 From 834292bf4b37b45e4d080fc896539e751c5681b1 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Tue, 23 Aug 2022 22:08:13 +0200 Subject: [PATCH 03/55] 1.4.1 --- .../2-check-standard/ifelse_task2.svg | 2 +- .../9-check-login/ifelse_task.svg | 2 +- .../chrome-sources-breakpoint.svg | 2 +- .../chrome-sources-debugger-pause.svg | 2 +- .../chrome-sources-debugger-trace-1.svg | 2 +- 1-js/04-object-basics/01-object/article.md | 28 +++++++++---------- .../01-object/object-user-delete.svg | 2 +- .../01-object/object-user-isadmin.svg | 2 +- images.yml | 4 +-- 9 files changed, 23 insertions(+), 23 deletions(-) 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/04-object-basics/01-object/article.md b/1-js/04-object-basics/01-object/article.md index 8dea8a8b6..841dd000e 100644 --- a/1-js/04-object-basics/01-object/article.md +++ b/1-js/04-object-basics/01-object/article.md @@ -3,7 +3,7 @@ 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). -Naproti tomu objekty se používají k uložení klíčovaných kolekcí různých dat 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. +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. 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. @@ -54,10 +54,10 @@ alert( uživatel.jméno ); // Jan alert( uživatel.věk ); // 30 ``` -Hodnota může být libovolného typu. Přidejme booleanovou: +Hodnota může být libovolného typu. Přidejme hodnotu typu boolean: ```js -uživatel.jeAdmin = true; +uživatel.jeSprávce = true; ``` ![user object 2](object-user-isadmin.svg) @@ -90,7 +90,7 @@ let uživatel = { věk: 30*!*,*/!* } ``` -Tato čárka se nazývá „vlečná“ nebo „závěsná“ *(v angličtině „trailing“ nebo „hanging“, nevím o standardním českém názvu -- pozn. překl.)*. Díky ní je jednodušší přidávat, odebírat nebo přesunovat vlastnosti, protože všechny řádky budou vypadat podobně. +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ě. ## Hranaté závorky @@ -113,7 +113,7 @@ let uživatel = {}; // nastavit uživatel["má rád ptáky"] = true; -// vrátit +// načíst alert(uživatel["má rád ptáky"]); // true // smazat @@ -161,7 +161,7 @@ alert( uživatel.klíč ) // undefined ### Vypočítávané vlastnosti -Když vytváříme objekt, můžeme použít hranaté závorky v objektovém literálu. To se nazývá *vypočítávané vlastnosti*. +Když vytváříme objekt, můžeme použít hranaté závorky v objektovém literálu. Takové vlastnosti se nazývají *vypočítávané*. Například: @@ -323,7 +323,7 @@ alert( "věk" in uživatel ); // true, uživatel.věk existuje alert( "blabla" in uživatel ); // false, uživatel.blabla neexistuje ``` -Prosíme všimněte si, že na levé straně `in` musí být *název vlastnosti*, což bývá obvykle řetězec v uvozovkách. +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. Vypustíme-li uvozovky, znamená to proměnnou, která by měla obsahovat skutečný název, který bude prověřen. Například: @@ -367,18 +367,18 @@ for (klíč in objekt) { } ``` -Například vydáme všechny vlastnosti objektu `uživatel`: +Vypišme například všechny vlastnosti objektu `uživatel`: ```js run let uživatel = { jméno: "Jan", věk: 30, - jeAdmin: true + jeSprávce: true }; for (let klíč in uživatel) { // klíče - alert( klíč ); // jméno, věk, jeAdmin + alert( klíč ); // jméno, věk, jeSprávce // hodnoty klíčů alert( uživatel[klíč] ); // Jan, 30, true } @@ -386,11 +386,11 @@ for (let klíč in uživatel) { Všimněte si, že všechny konstrukce „for“ nám umožňují deklarovat uvnitř cyklu smyčkovou proměnnou, jako zde `let klíč`. -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)"` *(v angličtině `"for (let prop in obj)"` -- pozn. překl.)*. +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)"`. ### Seřazené jako objekt -Jsou objekty seřazené? Jinými slovy: když procházíme objekt v cyklu, obdržíme všechny vlastnosti ve stejném pořadí, v jakém byly přidány? Můžeme se na to spolehnout? +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? 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. @@ -412,7 +412,7 @@ for (let předvolba in předvolby) { */!* ``` -Objekt můžeme použít k navržení seznamu možností pro uživatele. 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`. +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`. Jenže když kód spustíme, uvidíme úplně jiný obrázek: @@ -498,6 +498,6 @@ V JavaScriptu však existuje i mnoho dalších druhů objektů: - `Error` (chyba) k ukládání informací o chybě, - ...a tak dále. -Mají své speciální vlastnosti, které prostudujeme později. Někdy lidé říkají něco jako „typ Array“ nebo „typ Date“, ale formálně to nejsou samostatné typy, nýbrž patří do jednoduchého datového typu „objekt“ a různými způsoby jej rozšiřují. +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í. 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 cf779a10a..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 @@ -jménojeAdminuživatel \ 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-isadmin.svg b/1-js/04-object-basics/01-object/object-user-isadmin.svg index 8adf3d08e..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 @@ -jménověkjeAdminuživatel \ No newline at end of file +jménověkjeSprávceuživatel \ No newline at end of file diff --git a/images.yml b/images.yml index 16d6c177b..4f8d93a10 100644 --- a/images.yml +++ b/images.yml @@ -592,12 +592,12 @@ 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 From 5f5ea629a63b09d26d626fe06ea4a7999a1c38bc Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Wed, 24 Aug 2022 21:26:01 +0200 Subject: [PATCH 04/55] 1.4.2 --- .../02-object-copy/article.md | 32 +++++++++---------- images.yml | 16 +++++++++- 2 files changed, 31 insertions(+), 17 deletions(-) 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 c241863ab..0c928a7d6 100644 --- a/1-js/04-object-basics/02-object-copy/article.md +++ b/1-js/04-object-basics/02-object-copy/article.md @@ -39,7 +39,7 @@ Objekt je uložen někde v paměti (na obrázku vpravo), zatímco proměnná `u 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. -Když provádíme akci nad objektem, např. zjišťujeme vlastnost `uživatel.jméno`, engine JavaScriptu se podívá, co je na této adrese, a provede operaci nad skutečným objektem. +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. Teď vysvětlíme, proč je to důležité. @@ -50,7 +50,7 @@ Například: ```js no-beautify let uživatel = { jméno: "Jan" }; -let admin = uživatel; // kopírování odkazu +let správce = uživatel; // kopírování odkazu ``` Nyní máme dvě proměnné, v obou jsou uloženy odkazy na tentýž objekt: @@ -64,20 +64,20 @@ Obě proměnné můžeme používat k přístupu k objektu a modifikaci jeho obs ```js run let uživatel = { jméno: 'Jan' }; -let admin = uživatel; +let správce = uživatel; *!* -admin.jméno = 'Petr'; // změna pomocí odkazu „admin“ +správce.jméno = 'Petr'; // změna pomocí odkazu „správce“ */!* alert(*!*uživatel.jméno*/!*); // 'Petr', změny jsou vidět i z odkazu „uživatel“ ``` -Je to, jako kdybychom měli skříň se dvěma klíči a použili jeden z nich (`admin`) 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. +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. ## Porovnání pomocí odkazů -Dva objekty jsou si rovny, jen když představují tentýž objekt. +Dva objekty jsou si rovny, jen když je to jeden a tentýž objekt. Například zde `a` a `b` jsou odkazy na tentýž objekt, takže jsou si rovny: @@ -148,12 +148,12 @@ Například ji můžeme použít ke sloučení několika objektů do jednoho: ```js let uživatel = { jméno: "Jan" }; -let práva1 = { můžeProhlížet: true }; -let práva2 = { můžeEditovat: true }; +let oprávnění1 = { můžeProhlížet: true }; +let oprávnění2 = { můžeEditovat: true }; *!* -// zkopíruje všechny vlastnosti z objektů práva1 a práva2 do objektu uživatel -Object.assign(uživatel, práva1, práva2); +// 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); */!* // nyní uživatel = { jméno: "Jan", můžeProhlížet: true, můžeEditovat: true } @@ -169,7 +169,7 @@ Object.assign(uživatel, { jméno: "Petr" }); alert(uživatel.jméno); // nyní uživatel = { jméno: "Petr" } ``` -Můžeme také využít `Object.assign` k nahrazení cyklu `for..in` jednoduchým klonováním: +Můžeme také využít `Object.assign` k nahrazení cyklu `for..in` pro jednoduché klonování: ```js let uživatel = { @@ -223,7 +223,7 @@ uživatel.míry.šířka++; // změníme vlastnost na jednom místě alert(klon.míry.šířka); // 51, vidíme výsledek z jiného místa ``` -Abychom to opravili a učinily 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é“ nebo „hluboké“. +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é“ nebo „hluboké“. Můžeme to implementovat pomocí rekurze. Nebo, abychom znovu nevynalézali kolo, použít existující implementaci, např. [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) z JavaScriptové knihovny [lodash](https://lodash.com). @@ -244,16 +244,16 @@ uživatel.jméno = "Petr"; // (*) alert(uživatel.jméno); // Petr ``` -Může se zdát, že řádek `(*)` ohlásí chybu, 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. +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. -Jinými slovy, `const uživatel` způsobí chybu, jen pokud se pokusíme nastavit `uživatel=...` jako celek. +Jinými slovy, `const uživatel` vyvolá chybu, jen pokud se pokusíme nastavit `uživatel=...` jako celek. -Jestliže ovšem opravdu 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 . +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 . ```` ## Shrnutí -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) této hodnoty. Zkopírování této hodnoty nebo její předání jako argument funkce tedy zkopíruje tento odkaz, ne objekt samotný. +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ý. 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. diff --git a/images.yml b/images.yml index 4f8d93a10..c54df48a1 100644 --- a/images.yml +++ b/images.yml @@ -529,7 +529,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' From 30aacd49cde2d74d6136425167ed961e36000cb2 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Wed, 24 Aug 2022 21:36:11 +0200 Subject: [PATCH 05/55] 1.4.2 --- .../02-object-copy/variable-contains-reference.svg | 2 +- .../04-object-basics/02-object-copy/variable-copy-reference.svg | 2 +- 1-js/04-object-basics/02-object-copy/variable-copy-value.svg | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 From fabe699352b5119faa9979fa9a28c0c8a4f47ee4 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Wed, 24 Aug 2022 22:38:16 +0200 Subject: [PATCH 06/55] 1.4.3 --- .../03-garbage-collection/article.md | 44 +++++---- .../family-delete-refs.svg | 2 +- .../family-no-family.svg | 2 +- .../family-no-father-2.svg | 2 +- .../family-no-father.svg | 2 +- .../03-garbage-collection/family.svg | 2 +- .../garbage-collection-1.svg | 2 +- .../garbage-collection-2.svg | 2 +- .../garbage-collection-3.svg | 2 +- .../garbage-collection-4.svg | 2 +- .../garbage-collection-5.svg | 2 +- .../memory-user-john-admin.svg | 2 +- .../memory-user-john-lost.svg | 2 +- .../memory-user-john.svg | 2 +- .../proto-constructor-animal-rabbit.svg | 2 +- .../event-order-bubbling.svg | 2 +- .../selection-direction-backward.svg | 2 +- .../selection-direction-forward.svg | 2 +- .../02-selection-range/selection-firefox.svg | 2 +- .../03-event-loop/eventLoop-full.svg | 2 +- 2-ui/99-ui-misc/03-event-loop/eventLoop.svg | 2 +- .../cors-gmail-messages.svg | 2 +- .../xhr-another-domain.svg | 2 +- .../05-fetch-crossorigin/xhr-preflight.svg | 2 +- 5-network/10-long-polling/long-polling.svg | 2 +- .../11-websocket/websocket-handshake.svg | 2 +- 6-data-storage/01-cookie/cookie-xsrf.svg | 2 +- images.yml | 89 ++++++++++++++++--- 28 files changed, 124 insertions(+), 61 deletions(-) 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 33b0f8e05..8982e8bea 100644 --- a/1-js/04-object-basics/03-garbage-collection/article.md +++ b/1-js/04-object-basics/03-garbage-collection/article.md @@ -1,10 +1,8 @@ -# Garbage collection - -*(Pozn. překladatele: výraz „garbage collection“ znamená česky „sbírání odpadu“, ale v programování se většinou ponechává anglický název.)* +# Sběr odpadků 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ěť. -Co se stane, když něco už není potřeba? Jak to JavaScriptový engine odhalí a vyčistí? +Co se stane, když něco už není potřeba? Jak to JavaScriptový motor odhalí a vyčistí? ## Dosažitelnost @@ -27,7 +25,7 @@ Jednoduše řečeno, „dosažitelné“ hodnoty jsou ty, které jsou odněkud p 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. -V JavaScriptovém enginu v pozadí probíhá proces, který se nazývá [garbage collector](https://cs.wikipedia.org/wiki/Garbage_collection) *(česky se mu někdy říká „sběrač odpadků“ -- pozn. překl.)*. Monitoruje všechny objekty a odstraňuje ty, které se staly nedosažitelnými. +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. ## Jednoduchý příklad @@ -52,11 +50,11 @@ uživatel = null; ![](memory-user-john-lost.svg) -Nyní se Jan stal nedosažitelným. Není žádný způsob, jak k němu přistoupit, neexistují na něj žádné odkazy. Garbage collector odstraní jeho data a uvolní paměť. +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ěť. ## Dva odkazy -Nyní si představme, že zkopírujeme odkaz na objekt `uživatel` do objektu `admin`: +Nyní si představme, že zkopírujeme odkaz z objektu `uživatel` do objektu `správce`: ```js // uživatel obsahuje odkaz na objekt @@ -65,7 +63,7 @@ let uživatel = { }; *!* -let admin = uživatel; +let správce = uživatel; */!* ``` @@ -76,7 +74,7 @@ Když nyní uděláme totéž: uživatel = null; ``` -...Pak bude objekt stále dosažitelný z globální proměnné `admin`, a tedy musí zůstat v paměti. Jestliže přepíšeme i `admin`, bude možné jej odstranit. +...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. ## Propojené objekty @@ -125,7 +123,7 @@ Jestliže však smažeme oba, vidíme, že Jan již nemá žádné „příchoz „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. -Po provedení garbage collection: +Po provedení sběru odpadků: ![](family-no-father-2.svg) @@ -147,17 +145,17 @@ Tento příklad demonstruje, jak důležitý je koncept dosažitelnosti. Je vidět, že Jan a Anna jsou stále spojeni a k oběma směřují nějaké odkazy. To ale nestačí. -Bývalý objekt `"rodina"` byl odpojen od kořene, neexistuje na něj už žádný odkaz, takže se celý ostrov objektů stal nedosažitelným a bude odstraněn. +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. ## Interní algoritmy -Základní algoritmus garbage collection se nazývá „mark-and-sweep“ *(česky „označ a zameť“ -- pozn. překl.)*. +Základní algoritmus sběru odpadků se nazývá „označ a zameť“ („mark-and-sweep“). -Pravidelně se provádějí následující kroky „garbage collection“: +Pravidelně se provádějí následující kroky „sběru odpadků“: -- Garbage collector vezme kořeny a „označí“ (zapamatuje) si je. +- 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. +- 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í. @@ -165,7 +163,7 @@ Například nechť naše objektová struktura vypadá takto: ![](garbage-collection-1.svg) -Jasně vidíme „nedosažitelný ostrov“ na pravé straně. Nyní se podívejme, jak si s ním poradí garbage collector typu „mark-and-sweep“. +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ť“. První krok označí kořeny: @@ -183,17 +181,17 @@ Nyní se objekty, které nemohly být v tomto procesu navštíveny, budou považ ![](garbage-collection-5.svg) -Můžeme si tento proces představit i jako rozlévání velkého kbelíku s barvou, která teče od kořenů všemi odkazy a dostane se ke všem dosažitelným objektům. Neoznačené objekty jsou poté odstraněny. +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. 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. Některé z nich: -- **Generační sběr** -- objekty se rozdělí na dvě skupiny: „nové“ a „staré“. V typickém kódu má mnoho objektů jen krátký život: objeví se, odvedou 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 se tedy snaží rozdělit 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 menších prodlev místo jedné velké. +- **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. -Existují i jiné optimalizace a doplňky algoritmů garbage collection. Rád bych je zde popsal, ale musím se toho vzdát, jelikož různé enginy implementují různá vylepšení a techniky. Co je ještě důležitější, během vývoje enginů se vše neustále mění, takže studovat je hlouběji „napřed“, 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. +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. ## Shrnutí @@ -203,12 +201,12 @@ Hlavní věci, které máme vědět: - 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í enginy implementují pokročilé algoritmy garbage collection. +Moderní motory implementují pokročilé algoritmy sběru odpadků. -Některé z nich jsou pokryty v obecné knize „The Garbage Collection Handbook: The Art of Automatic Memory Management“ (R. Jones a kolektiv). +Některé z nich jsou probrány v obecné knize „The Garbage Collection Handbook: The Art of Automatic Memory Management“ (R. Jones a kolektiv). 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](http://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection). -Rovněž [blog V8](https://v8.dev/) občas publikuje články o změnách ve správě paměti. Přirozeně, abyste se naučili o sbírání odpadků víc, měli byste se připravit tak, že se naučíte něco o interních záležitostech V8 obecně a přečtete si blog [Vjačeslava Jegorova](http://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ší. +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](http://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ší. 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 1682a438d..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>nedosažitelný \ 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/08-prototypes/02-function-prototype/proto-constructor-animal-rabbit.svg b/1-js/08-prototypes/02-function-prototype/proto-constructor-animal-rabbit.svg index c344423d6..ede4e1227 100644 --- a/1-js/08-prototypes/02-function-prototype/proto-constructor-animal-rabbit.svg +++ b/1-js/08-prototypes/02-function-prototype/proto-constructor-animal-rabbit.svg @@ -1 +1 @@ -žere: truejméno: "Bílý králík"zvířeKrálíkkrálík[[Prototype]]prototype \ No newline at end of file +eats: truename: "White Rabbit"animalRabbitrabbit[[Prototype]]prototype \ No newline at end of file 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/images.yml b/images.yml index c54df48a1..2c6adb13e 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 @@ -452,13 +448,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í' @@ -617,4 +606,80 @@ 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é From b353e9a647b2233fe0b3bebd67372a3bf85e5749 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Sun, 28 Aug 2022 17:06:53 +0200 Subject: [PATCH 07/55] 1.4.4 --- .../4-object-property-this/solution.md | 18 +++++------ .../4-object-property-this/task.md | 6 ++-- .../04-object-methods/article.md | 32 +++++++++---------- 3 files changed, 28 insertions(+), 28 deletions(-) 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 4bd272ce7..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 @@ -5,22 +5,22 @@ Zkuste to: function vytvořUživatele() { return { jméno: "Jan", - ref: this + odkaz: this }; } let uživatel = vytvořUživatele(); -alert( uživatel.ref.jméno ); // Error: Cannot read property 'jméno' of undefined +alert( uživatel.odkaz.jméno ); // Chyba: Nelze načíst vlastnost 'jméno' objektu undefined ``` -Je to proto, že pravidla, která nastavují `this`, se nedívají do definice objektu. Záleží jen na momentu volání. +Je to proto, že pravidla, která nastavují `this`, se nedívají do definice objektu. Záleží jen na okamžiku volání. Zde je hodnota `this` uvnitř `vytvořUživatele()` `undefined`, protože tato funkce je volána jako funkce, ne jako metoda „tečkovou“ syntaxí. Hodnota `this` je stejná pro celou funkci, bloky kódu a objektové literály ji neovlivňují. -Takže `ref: this` vezme ve skutečnosti aktuální `this` této funkce. +Takže `odkaz: this` vezme ve skutečnosti aktuální `this` této funkce. Můžeme funkci přepsat a vrátit stejné `this` s hodnotou `undefined`: @@ -29,9 +29,9 @@ function vytvořUživatele(){ return this; // tentokrát tady není objektový literál } -alert( vytvořUživatele().jméno ); // Error: Cannot read property 'jméno' of undefined +alert( vytvořUživatele().jméno ); // Chyba: Nelze načíst vlastnost 'jméno' objektu undefined ``` -Jak vidíte, výsledek `alert( vytvořUživatele().jméno )` je stejný jako výsledek `alert( uživatel.ref.jméno )` z předchozího příkladu. +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. Toto je opačný příklad: @@ -40,7 +40,7 @@ function vytvořUživatele() { return { jméno: "Jan", *!* - ref() { + odkaz() { return this; } */!* @@ -49,7 +49,7 @@ function vytvořUživatele() { let uživatel = vytvořUživatele(); -alert( uživatel.ref().jméno ); // Jan +alert( uživatel.odkaz().jméno ); // Jan ``` -Teď to funguje, protože `uživatel.ref()` je metoda. A hodnota `this` se nastaví na objekt před tečkou `.`. \ No newline at end of file +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 f897b11ec..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 @@ -6,18 +6,18 @@ importance: 5 Zde funkce `vytvořUživatele` vrátí objekt. -Jaký je výsledek přístupu k jejímu `ref`? Proč? +Jaký je výsledek přístupu k jeho vlastnosti `odkaz`? Proč? ```js function vytvořUživatele() { return { jméno: "Jan", - ref: this + odkaz: this }; } let uživatel = vytvořUživatele(); -alert( uživatel.ref.jméno ); // Jaký je výsledek? +alert( uživatel.odkaz.jméno ); // Jaký je výsledek? ``` 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 91b323b9b..7effbc17b 100644 --- a/1-js/04-object-basics/04-object-methods/article.md +++ b/1-js/04-object-basics/04-object-methods/article.md @@ -9,7 +9,7 @@ let uživatel = { }; ``` -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. +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. V JavaScriptu jsou tyto akce reprezentovány funkcemi ve vlastnostech. @@ -61,7 +61,7 @@ uživatel.řekniAhoj(); // Ahoj! ``` ```smart header="Objektově orientované programování" -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“. +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 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ší. ``` @@ -90,7 +90,7 @@ uživatel = { Jak vidíme, můžeme vypustit slovo `"function"` a napsat jen `řekniAhoj()`. -Upřímně řečeno, tyto notace nejsou zcela identické. Jsou v nich drobné rozdíly vztahující se k 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. +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“ v metodách @@ -139,9 +139,9 @@ let uživatel = { }; ``` -...Takový kód je však nespolehlivý. Pokud se rozhodneme zkopírovat objekt `uživatel` do jiné proměnné, např. `admin = uživatel`, a přepsat proměnnou `uživatel` něčím jiným, pak budeme přistupovat k nesprávnému objektu. +...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. -To je ukázáno níže: +To je ukázáno zde: ```js run let uživatel = { @@ -157,11 +157,11 @@ let uživatel = { }; -let admin = uživatel; +let správce = uživatel; uživatel = null; // přepíšeme, aby to bylo zřejmé *!* -admin.řekniAhoj(); // TypeError: Cannot read property 'jméno' of null +správce.řekniAhoj(); // TypeError: Cannot read property 'jméno' of null */!* ``` @@ -185,7 +185,7 @@ Například zde bude stejná funkce přiřazena dvěma různým objektům a ve v ```js run let uživatel = { jméno: "Jan" }; -let admin = { jméno: "Admin" }; +let správce = { jméno: "Správce" }; function řekniAhoj() { alert( this.jméno ); @@ -194,18 +194,18 @@ function řekniAhoj() { *!* // použijeme stejnou funkci ve dvou objektech uživatel.f = řekniAhoj; -admin.f = řekniAhoj; +správce.f = řekniAhoj; */!* // tato volání mají různá this // „this“ uvnitř funkce je objekt „před tečkou“ uživatel.f(); // Jan (this == uživatel) -admin.f(); // Admin (this == admin) +správce.f(); // Správce (this == správce) -admin['f'](); // Admin (k metodě přistupuje tečka nebo hranaté závorky - na tom nezáleží) +správce['f'](); // Správce (k metodě přistupuje tečka nebo hranaté závorky - na tom nezáleží) ``` -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 `admin`. +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="Volání bez objektu: `this == undefined`" Můžeme tuto funkci volat dokonce zcela bez objektu: @@ -230,7 +230,7 @@ Pokud přicházíte z jiného programovacího jazyka, pak jste pravděpodobně z 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“. -Koncept vyhodnocování `this` za běhu má své výhody i nevýhody. Na jednu stranu můžeme funkci znovu použít pro různé objekty. Na druhou stranu větší flexibilita vytváří více prostoru pro chyby. +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. 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. ``` @@ -253,7 +253,7 @@ let uživatel = { uživatel.řekniAhoj(); // Ilja ``` -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. Šipkové funkce hlouběji prozkoumáme později v kapitole . +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. ## Shrnutí @@ -264,7 +264,7 @@ To je speciální vlastnost šipkových funkcí. Je užitečná, když ve skute 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 různými objekty. +- 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`. -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. +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. From 469151b99900a9099e58af018fcad6e3821e7f04 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Sun, 28 Aug 2022 17:36:47 +0200 Subject: [PATCH 08/55] 1.4.5 --- .../06-constructor-new/3-accumulator/task.md | 6 ++-- .../06-constructor-new/article.md | 32 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) 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 b0c6f283c..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 @@ -6,10 +6,10 @@ importance: 5 Vytvořte konstruktor `Akumulátor(počátečníHodnota)`. -Objekt, který tento konstruktor vytvoří, by měl: +Objekt, který je tímto konstruktorem vytvořen, by měl: -- Ukládat „aktuální hodnotu“ do vlastnosti `hodnota`. Počáteční hodnota se nastaví argumentem konstruktoru `počátečníHodnota`. -- Metoda `načti()` by se měla pomocí `prompt` zeptat na nové číslo a přičíst je do vlastnosti `hodnota`. +- 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`. Jinými slovy, vlastnost `hodnota` bude součet všech uživatelem zadaných hodnot a úvodní hodnoty `počátečníHodnota`. 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 65483224f..909b6944a 100644 --- a/1-js/04-object-basics/06-constructor-new/article.md +++ b/1-js/04-object-basics/06-constructor-new/article.md @@ -6,7 +6,7 @@ To můžeme učinit pomocí konstruktorů a operátoru `"new"`. ## Konstruktor -Konstruktory jsou z technického hlediska běžné funkce. Platí pro ně však dvě konvence: +Konstruktory jsou z technického hlediska obvyklé funkce. Platí pro ně však dvě konvence: 1. Jejich název začíná velkým písmenem. 2. Měly by být volány jen pomocí operátoru `„new“`. @@ -16,7 +16,7 @@ Například: ```js run function Uživatel(jméno) { this.jméno = jméno; - this.jeAdmin = false; + this.jeSprávce = false; } *!* @@ -24,13 +24,13 @@ let uživatel = new Uživatel("Kuba"); */!* alert(uživatel.jméno); // Kuba -alert(uživatel.jeAdmin); // false +alert(uživatel.jeSprávce); // false ``` Když je funkce volána pomocí `new`, provedou se následující kroky: 1. Vytvoří se nový prázdný objekt a přiřadí se do `this`. -2. Vykoná se tělo funkce. To obvykle modifikuje `this` a přidá do něj nové vlastnosti. +2. Vykoná se tělo funkce. To obvykle modifikuje `this`, do něhož přidá nové vlastnosti. 3. Vrátí se hodnota `this`. Jinými slovy, `new Uživatel(...)` udělá něco jako: @@ -41,9 +41,9 @@ function Uživatel(jméno) { // this = {}; (implicitně) */!* - // přidá do něj vlastnosti + // přidá vlastnosti do this this.jméno = jméno; - this.jeAdmin = false; + this.jeSprávce = false; *!* // return this; (implicitně) @@ -56,11 +56,11 @@ Takže `let uživatel = new Uživatel("Kuba")` vydá stejný výsledek jako: ```js let uživatel = { jméno: "Kuba", - jeAdmin: false + jeSprávce: false }; ``` -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 lépe čitelné. +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é. To je hlavní smysl konstruktorů -- implementovat opakovaně použitelný kód pro vytváření objektů. @@ -73,7 +73,7 @@ Máme-li mnoho řádků kódu a všechny se týkají vytvoření jediného slož // vytvoříme funkci a okamžitě ji zavoláme pomocí new let uživatel = new function() { this.jméno = "Jan"; - this.jeAdmin = false; + this.jeSprávce = false; // ...další kód pro vytváření uživatele // možná složitá logika a příkazy @@ -81,7 +81,7 @@ let uživatel = new function() { }; ``` -Tento konstruktor nemůžeme opakovaně volat, protože není nikde uložen. Jen se vytvoří a zavolá. Smyslem tohoto triku je tedy zapouzdřit kód, který vytvoří jediný objekt a dále se nepoužívá. +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á. ```` ## Test režimu konstruktoru: new.target @@ -90,9 +90,9 @@ Tento konstruktor nemůžeme opakovaně volat, protože není nikde uložen. Jen Syntaxe z této části se používá málokdy. Pokud nechcete znát opravdu všechno, můžete ji přeskočit. ``` -Uvnitř funkce můžeme ověřit, zda byla volána pomocí `new` nebo bez něj, speciální vlastností `new.target`. +Uvnitř funkce můžeme ověřit, zda byla volána pomocí `new` nebo bez něj, pomocí speciální vlastnosti `new.target`. -Ta je při běžném volání `undefined`, ale pokud je funkce volána pomocí `new`, rovná se této funkci: +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 Uživatel() { @@ -127,9 +127,9 @@ let jan = Uživatel("Jan"); // přesměruje volání na new Uživatel alert(jan.jméno); // Jan ``` -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 stále funguje. +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. -Pravděpodobně však není dobré používat jej všude, protože bez uvedení `new` je trochu méně zřejmé, co se tady děje. Když je uvedeno `new`, všichni víme, že se vytváří nový objekt. +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. ## Návrat z konstruktorů @@ -217,8 +217,8 @@ K vytváření složitých objektů existuje i pokročilejší syntaxe -- [tří ## Shrnutí -- Konstruktory jsou obvyklé funkce, avšak panuje běžná úmluva pojmenovávat je s velkým prvním písmenem. -- 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í vyplněné. +- 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é. Konstruktory můžeme používat k vytváření více podobných objektů. From 3d979c16f7dfae238cb29f3f08a804bbeafeaecb Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Sun, 28 Aug 2022 18:51:43 +0200 Subject: [PATCH 09/55] 1.4.6 --- .../07-optional-chaining/article.md | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) 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 f4ce0761f..c2b7d7e54 100644 --- a/1-js/04-object-basics/07-optional-chaining/article.md +++ b/1-js/04-object-basics/07-optional-chaining/article.md @@ -2,7 +2,7 @@ [recent browser="new"] -Volitelné zřetězení `?.` je bezpečný způsob, jak přistupovat k vnořeným vlastnostem objektu, i když vlastnost mezi nimi neexistuje. +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. ## Problém „neexistující vlastnosti“ @@ -53,14 +53,14 @@ let html = document.querySelector('.elem') ? document.querySelector('.elem').inn Vidíme, že hledání prvku `document.querySelector('.elem')` se zde ve skutečnosti volá dvakrát. To není dobré. -Pro hlouběji vnořené vlastnosti to bude ještě ošklivější, protože bude vyžadováno více opakování. +Pro hlouběji vnořené vlastnosti to bude ještě ošklivější, protože bude potřeba více opakování. Například zkusme podobným způsobem získat `uživatel.adresa.ulice.název`. ```js let uživatel = {}; // uživatel nemá adresu -alert(uživatel.adresa ? uživatel.adresa.ulice ? uživatel.adresa.ulice.name : null : null); +alert(uživatel.adresa ? uživatel.adresa.ulice ? uživatel.adresa.ulice.název : null : null); ``` Je to ošklivé a člověk může mít problémy takovému kódu porozumět. @@ -70,7 +70,7 @@ Existuje trochu lepší způsob, jak to napsat, a to pomocí operátoru `&&`: ```js run let uživatel = {}; // uživatel nemá adresu -alert( uživatel.adresa && uživatel.adresa.ulice && uživatel.adresa.ulice.name ); // undefined (žádná chyba) +alert( uživatel.adresa && uživatel.adresa.ulice && uživatel.adresa.ulice.název ); // undefined (žádná chyba) ``` Spojení celé cesty k vlastnosti ANDem sice zajistí, že všechny komponenty existují (pokud ne, vyhodnocení se zastaví), ale ani to není ideální. @@ -117,14 +117,14 @@ alert( uživatel?.adresa.ulice ); // undefined Prosíme všimněte si: syntaxe `?.` umožňuje, aby volitelná byla hodnota před ní, ale žádná další. -Např. `?.` v `uživatel?.adresa.ulice.name` 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 `?.`. +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="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. -Například pokud podle logiky našeho kódování 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`. +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`. -Pak pokud se stane, že `uživatel` bude nedefinovaný, ohlásí se programátorská chyba a my ji opravíme. Kdybychom však přehnaně používali `?.`, mohly by se chyby v kódu neohlásit i tehdy, když to není vhodné, a jejich ladění by bylo obtížnější. +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="Proměnná před `?.` musí být deklarovaná" @@ -139,9 +139,9 @@ Proměnná musí být deklarovaná (tj. `let/const/var uživatel` nebo jako para ## Zkratování -Jak bylo řečeno, `?.` okamžitě pozastaví („vyzkratuje“) vyhodnocování, jestliže levá část neexistuje. +Jak bylo řečeno, `?.` okamžitě zastaví („vyzkratuje“) vyhodnocování, jestliže levá část neexistuje. -Jestliže tedy za pozastaveným `?.` vpravo následují další volání funkcí nebo operace, nevykonají se. +Jestliže tedy vpravo za `?.` následují další volání funkcí nebo operace, nevykonají se. Například: @@ -149,42 +149,42 @@ Například: let uživatel = null; let x = 0; -uživatel?.řekniAhoj(x++); // „uživatel“ není, takže výkon se nedostane k volání řekniAhoj a x++ +uživatel?.řekniAhoj(x++); // „uživatel“ není, takže běh se nedostane k volání řekniAhoj a x++ alert(x); // 0, hodnota se nezvýšila ``` ## Další varianty: ?.(), ?.[] -Volitelné zřetězení `?.` není operátor, ale speciální syntaktická konstrukce, která funguje i s funkcemi a hranatými závorkami. +Volitelné zřetězení `?.` není operátor, ale speciální syntaktický konstrukt, který funguje i s funkcemi a hranatými závorkami. Například `?.()` se používá k volání funkce, která nemusí existovat. -V níže uvedeném kódu někteří z našich uživatelů mají metodu `admin` a někteří ne: +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 uživatelAdmin = { - admin() { - alert("Jsem admin"); +let uživatelSprávce = { + správce() { + alert("Jsem správce"); } }; let uživatelHost = {}; *!* -uživatelAdmin.admin?.(); // Jsem admin +uživatelSprávce.správce?.(); // Jsem správce */!* *!* -uživatelHost.admin?.(); // nic se nestane (taková metoda není) +uživatelHost.správce?.(); // nic se nestane (taková metoda není) */!* ``` -Zde na obou řádcích nejprve použijeme tečku (`uživatelAdmin.admin`) k získání vlastnosti `admin`, protože předpokládáme, že objekt `uživatel` existuje, takže je bezpečné z něj číst. +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. -Pak `?.()` prověří levou stranu: jestliže funkce `admin` existuje, pak se spustí (tak tomu je pro `uživatelAdmin`). Jinak (pro `uživatelHost`) se vyhodnocování zastaví bez chyb. +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. -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 objektu, která nemusí existovat. +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 klíč = "křestníJméno"; From 8cc7eb1ffbf7c091237bdc240f832225eaab9dae Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Sun, 28 Aug 2022 19:15:53 +0200 Subject: [PATCH 10/55] 1.4.7 --- 1-js/04-object-basics/08-symbol/article.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/1-js/04-object-basics/08-symbol/article.md b/1-js/04-object-basics/08-symbol/article.md index 8527e3875..42c99b1f0 100644 --- a/1-js/04-object-basics/08-symbol/article.md +++ b/1-js/04-object-basics/08-symbol/article.md @@ -30,7 +30,7 @@ Po vytvoření můžeme symbolu dát nějaký popis (nazývaný také název sym let id = Symbol("id"); ``` -Symboly jsou zaručeně 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. +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. Například zde jsou dva symboly se stejným popisem -- přesto si nejsou rovny: @@ -59,7 +59,7 @@ alert(id); // TypeError: Nelze převést hodnotu Symbol na řetězec */!* ``` -Je to „jazyková stráž“ proti nepořádku, jelikož řetězce a symboly jsou naprosto odlišné a neměly by se náhodně konvertovat jedny na druhé. +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é. Jestliže opravdu chceme zobrazit symbol, musíme na něm explicitně zavolat `.toString()`, např. zde: @@ -91,7 +91,7 @@ Použijeme pro ně symbolický klíč: ```js run let uživatel = { // patří do jiného kódu - name: "Jan" + jméno: "Jan" }; let id = Symbol("id"); @@ -113,7 +113,7 @@ Pak tento skript může vytvořit svůj vlastní `Symbol("id")`, například tak // ... let id = Symbol("id"); -uživatel[id] = "Jeho hodnota id"; +uživatel[id] = "Jejich hodnota id"; ``` Nenastane žádný konflikt mezi našimi a jeho identifikátory, protože symboly jsou vždy různé, i když mají stejný název. @@ -128,7 +128,7 @@ uživatel.id = "Naše hodnota id"; // ...Jiný skript chce také „id“ pro své vlastní účely... -uživatel.id = "Jeho hodnota id" +uživatel.id = "Jejich hodnota id" // Bum! cizí skript nám ji přepsal! ``` @@ -195,9 +195,9 @@ Jak jsme viděli, všechny symboly jsou zpravidla různé, i když mají stejný 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. -K načtení (nebo vytvoření, pokud neexistuje) symbolu z registru použijeme `Symbol.for(klíč)`. +K načtení (vytvoření, pokud neexistuje) symbolu z registru použijeme `Symbol.for(klíč)`. -Tato metoda zavolá kontrolu globálního registru, 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. +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. Například: @@ -280,10 +280,10 @@ Symboly mají dvě hlavní použití: 1. „Skryté“ vlastnosti objektů. - Chceme-li do objektu přidat vlastnost, 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. + 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. 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. JavaScript používá mnoho systémových symbolů, které jsou dostupné pomocí `Symbol.*`. Někdy je můžeme použít, 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. +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. 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á. From e73d7ff489728a4b5e0b6659b52a0dcbfef89711 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Sun, 28 Aug 2022 20:58:42 +0200 Subject: [PATCH 11/55] 1.4.8 --- .../09-object-toprimitive/article.md | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) 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 b2adc0536..ee3b660fa 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -9,9 +9,9 @@ Při takovýchto operacích se objekty automaticky konvertují na primitivy a pa To je důležité omezení: výsledkem `obj1 + obj2` (nebo jiné matematické operace) nemůže být jiný objekt! -Například nemůžeme vytvořit objekty představující vektory nebo matice (nebo úspěchy č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“. +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“. -Protože zde toho technicky nemůžeme mnoho udělat, v reálných projektech nebývá žádné počítání s objekty. Když se objeví, je to až na vzácné výjimky důsledkem chyby v kódu. +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. V této kapitole probereme, jak převést objekt na primitiv a jak si to přizpůsobit. @@ -25,18 +25,18 @@ Má to dva účely: 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. 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 s nimi 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. +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. Konverzi na řetězec a na číslo si můžeme implementovat sami použitím speciálních objektových metod. Podívejme se nyní na technické podrobnosti, protože to je jediný způsob, jak toto téma pokrýt do hloubky. -## Hinty +## Náznaky Podle čeho se JavaScript rozhoduje, kterou konverzi použít? -Existují tři varianty typové konverze, k nimž dochází v různých situacích. Nazývají se „hinty“ a jsou popsány ve [specifikaci](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"` : Pro konverzi objektu na řetězec, když nad objektem provádíme operaci, která očekává řetězec, např. `alert`: @@ -63,38 +63,38 @@ Existují tři varianty typové konverze, k nimž dochází v různých situací // 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"` : Nastává ve vzácných případech, když si operátor „není jist“, jaký typ má očekávat. - 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 hint `"default"`. + 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"`. - 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 hint `"default"`. + 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 - // binární plus používá hint "default" + // binární plus používá náznak "default" let celkem = obj1 + obj2; - // obj == číslo používá hint "default" + // obj == číslo používá náznak "default" if (uživatel == 1) { ... }; ``` - 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í hint `"number"`, ne `"default"`. Je tomu tak z historických důvodů. + 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ů. V praxi je to však o něco jednodušší. -Všechny vestavěné objekty až na jedinou 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éž. +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éž. -Stále je však důležité znát všechny 3 hinty. Brzy uvidíme proč. +Stále je však důležité znát všechny 3 náznaky. Brzy uvidíme proč. **Když JavaScript provádí konverzi, snaží se najít a zavolat tři objektové metody:** -1. Zavolá `obj[Symbol.toPrimitive](hint)` -- 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 hint `"string"`: +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 hint `"number"` nebo `"default"`: +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 @@ -102,14 +102,14 @@ Stále je však důležité znát všechny 3 hinty. Brzy uvidíme proč. 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) { +obj[Symbol.toPrimitive] = function(náznak) { // sem přijde kód, který převede tento objekt na primitiv // musí vrátit primitivní hodnotu - // hint = jeden ze "string", "number", "default" + // náznak = jeden ze "string", "number", "default" }; ``` -Jestliže metoda `Symbol.toPrimitive` existuje, bude použita pro všechny hinty a žádné další metody nejsou zapotřebí. +Jestliže metoda `Symbol.toPrimitive` existuje, bude použita pro všechny náznaky a žádné další metody nejsou zapotřebí. Například zde ji implementuje objekt `uživatel`: @@ -118,16 +118,16 @@ let uživatel = { jméno: "Jan", peníze: 1000, - [Symbol.toPrimitive](hint) { - alert(`hint: ${hint}`); - return hint == "string" ? `{jméno: "${this.jméno}"}` : this.peníze; + [Symbol.toPrimitive](náznak) { + alert(`náznak: ${náznak}`); + return náznak == "string" ? `{jméno: "${this.jméno}"}` : this.peníze; } }; // demo konverzí: -alert(uživatel); // hint: string -> {jméno: "Jan"} -alert(+uživatel); // hint: number -> 1000 -alert(uživatel + 500); // hint: default -> 1500 +alert(uživatel); // náznak: string -> {jméno: "Jan"} +alert(+uživatel); // náznak: number -> 1000 +alert(uživatel + 500); // náznak: default -> 1500 ``` 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]`. @@ -136,14 +136,14 @@ Jak vidíme z kódu, `uživatel` se stane sebepopisujícím řetězcem nebo pen Neexistuje-li `Symbol.toPrimitive`, pak se JavaScript pokusí najít metody `toString` a `valueOf`: -- Pro hint `"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é hinty: volá se `valueOf`, a jestliže neexistuje nebo vrátí objekt místo primitivní hodnoty, pak se volá `toString` (při výpočtech má tedy přednost `valueOf`). +- 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`). -Metody `toString` a `valueOf` pocházejí z dávných časů. Nejsou to symboly (symboly tak dávno ještě neexistovaly), ale „obvyklé“ metody pojmenované řetězcem. Poskytují alternativní způsob „ve starém stylu“, jak implementovat konverzi. +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. -Tyto metody musejí vracet primitivní hodnotu. Jestliže `toString` nebo `valueOf` vrátí objekt, jsou ignorovány (tak, jako by taková metoda neexistovala). +Tyto metody musejí vracet primitivní hodnotu. Jestliže `toString` nebo `valueOf` vrátí objekt, jsou ignorovány (stejně, jako by taková metoda neexistovala). -Standardně planý objekt obsahuje následující metody `toString` a `valueOf`: +Výchozí planý objekt obsahuje následující metody `toString` a `valueOf`: - Metoda `toString` vrací řetězec `"[object Object]"`. - Metoda `valueOf` vrací objekt samotný. @@ -159,7 +159,7 @@ alert(uživatel.valueOf() === uživatel); // true 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]`. -Standardní `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. +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. Implementujme tyto metody, abychom si konverzi přizpůsobili. @@ -170,12 +170,12 @@ let uživatel = { jméno: "Jan", peníze: 1000, - // pro hint="string" + // pro náznak="string" toString() { return `{jméno: "${this.jméno}"}`; }, - // pro hint="number" nebo "default" + // pro náznak="number" nebo "default" valueOf() { return this.peníze; } @@ -189,7 +189,7 @@ alert(uživatel + 500); // valueOf -> 1500 Jak vidíme, chování je stejné jako v předchozím příkladu se `Symbol.toPrimitive`. -Často chceme jediné místo „pro všechno“, aby obsloužilo všechny konverze na primitivy. V tom případě můžeme implementovat jen `toString`, např. takto: +Č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 uživatel = { @@ -204,25 +204,25 @@ alert(uživatel); // toString -> Jan alert(uživatel + 500); // toString -> Jan500 ``` -Není-li přítomna `Symbol.toPrimitive` a `valueOf`, obstará všechny konverze na primitivy metoda `toString`. +Nejsou-li přítomny metody `Symbol.toPrimitive` a `valueOf`, obstará všechny konverze na primitivy metoda `toString`. ### Konverze může vrátit jakýkoli primitivní typ O všech metodách konverze na primitivy je důležité vědět, že nemusejí nutně vracet „naznačený“ primitiv. -Nekontroluje se, zda metoda `toString` opravdu vrátila řetězec nebo zda metoda `Symbol.toPrimitive` pro hint `"number"` vrátila opravdu číslo. +Nekontroluje se, zda metoda `toString` opravdu vrátila řetězec nebo zda metoda `Symbol.toPrimitive` pro náznak `"number"` vrátila opravdu číslo. Jediné, co je povinné: tyto metody musejí vracet primitiv, ne objekt. ```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ých dobách nebyl v JavaScriptu žádný dobrý „chybový“ koncept. +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. -Naproti tomu `Symbol.toPrimitive` je striktnější a *musí* vrátit primitiv, jinak bude ohlášena chyba. +Naproti tomu `Symbol.toPrimitive` je striktnější a *musí* vrátit primitiv, jinak nastane chyba. ``` ## Další konverze -Jak již víme, mnoho operátorů a funkcí provádí typovou konverzi, např. násobení `*` převádí operandy na čísla. +Jak již víme, typovou konverzi provádí mnoho operátorů a funkcí, např. násobení `*` převádí operandy na čísla. 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). @@ -244,7 +244,7 @@ alert(obj * 2); // 4, objekt se konvertoval na primitiv "2", pak z něj násoben 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). -Binární plus ve stejné situaci spojí řetězce, jelikož s radostí přijme řetězec: +Binární plus ve stejné situaci spojí řetězce, jelikož ochotně přijme řetězec: ```js run let obj = { @@ -260,21 +260,21 @@ alert(obj + 2); // 22 ("2" + 2), konverze na primitiv vrátila řetězec => zře Konverze objektu na primitiv je volána automaticky mnoha vestavěnými funkcemi a operátory, které očekávají primitiv jako hodnotu. -Dělí se na 3 druhy (hinty): +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"` (pro operátory, obvykle ji objekty implementují stejným způsobem jako `"number"`) +- `"default"` (jen málo operátorů, obvykle ji objekty implementují stejným způsobem jako `"number"`) -Specifikace výslovně popisuje, který operátor používá který hint. +Specifikace výslovně popisuje, který operátor používá který náznak. Algoritmus konverze je: -1. Zavolá `obj[Symbol.toPrimitive](hint)`, jestliže tato metoda existuje. -2. V opačném případě, je-li hint `"string"`: +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 hint `"number"` nebo `"default"`: +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). -V praxi často postačí implementovat jen `obj.toString()` jako „zachytávací“ metodu pro konverzi na řetězec, která by měla vracet „člověkem čitelnou“ reprezentaci objektu, pro účely logování nebo ladění. +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í. From 1d40be2b7bc9d47ad6b1aae5cf9c43b056795321 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Sun, 6 Nov 2022 19:20:08 +0100 Subject: [PATCH 12/55] 14.6. --- 1-js/99-js-misc/06-unicode/article.md | 133 +++++++++++++------------- 1 file changed, 67 insertions(+), 66 deletions(-) diff --git a/1-js/99-js-misc/06-unicode/article.md b/1-js/99-js-misc/06-unicode/article.md index 2396fcfaf..7de86ea21 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 value between `00` and `FF`, then it's character whose Unicode code is `XX`. + `XX` musí být dvě hexadecimální číslice s hodnotou mezi `00` a `FF`, pak je to znak, jehož kód v Unicode je `XX`. - Because the `\xXX` notation supports only two digits, it can be used only for the first 256 Unicode characters. + Protože zápis `\xXX` podporuje jen dvě číslice, může být použit jedině pro prvních 256 znaků Unicode. - These first 256 characters include 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 a character whose Unicode code is `XXXX` . - Characters with Unicode value 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 s hodnotou v Unicode 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 hieroglyph (long Unicode) - alert( "\u{1F60D}" ); // 😍, a smiling face symbol (another long Unicode) + alert( "\u{20331}" ); // 佫, vzácný čínský hieroglyf (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. Letters in most european languages, numbers, and even most hieroglyphs, have a 2-byte representation. +Všechny často používané znaky mají 2-bytové kódy. Písmena ve většině evropských jazyků, číslice a dokonce i většina hieroglyfů má 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 hieroglyph +alert( '𝒳'.length ); // 2, VELKÉ X V MATEMATICKÉM PÍSMU +alert( '😂'.length ); // 2, TVÁŘ SE SLZAMI RADOSTI +alert( '𩷶'.length ); // 2, vzácný čínský hieroglyf ``` -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` and `str.codePointAt` were added in JavaScript to deal with surrogate pairs. +Proto byly do JavaScriptu přidány metody `String.fromCodePoint` a `řetězec.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, 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 being 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í. From beb7244cfbe57c965b271a88766e272791afc70a Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Sun, 6 Nov 2022 19:37:06 +0100 Subject: [PATCH 13/55] sync 129 --- 1-js/99-js-misc/06-unicode/article.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/1-js/99-js-misc/06-unicode/article.md b/1-js/99-js-misc/06-unicode/article.md index 7de86ea21..3287169b6 100644 --- a/1-js/99-js-misc/06-unicode/article.md +++ b/1-js/99-js-misc/06-unicode/article.md @@ -11,9 +11,9 @@ JavaScript nám umožňuje vložit znak do řetězce specifikací jeho hexadecim - `\xXX` - `XX` musí být dvě hexadecimální číslice s hodnotou mezi `00` a `FF`, pak je to znak, jehož kód v Unicode je `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`. - Protože zápis `\xXX` podporuje jen dvě číslice, může být použit jedině pro prvních 256 znaků Unicode. + Protože zápis `\xXX` podporuje jen dvě hexadecimální číslice, může být použit jedině pro prvních 256 znaků Unicode. 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`). @@ -26,7 +26,7 @@ JavaScript nám umožňuje vložit znak do řetězce specifikací jeho hexadecim `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 s hodnotou v Unicode 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). + 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" ); // ©, totéž jako \xA9 s použitím 4-číslicového hexadecimálního zápisu @@ -39,13 +39,13 @@ JavaScript nám umožňuje vložit znak do řetězce specifikací jeho hexadecim `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}" ); // 佫, vzácný čínský hieroglyf (dlouhý Unicode) + alert( "\u{20331}" ); // 佫, vzácný čínský znak (dlouhý Unicode) alert( "\u{1F60D}" ); // 😍, symbol usmívající se tváře (další dlouhý Unicode) ``` ## Náhradní páry -Všechny často používané znaky mají 2-bytové kódy. Písmena ve většině evropských jazyků, číslice a dokonce i většina hieroglyfů má 2-bytovou reprezentaci. +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. 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čí. @@ -56,7 +56,7 @@ Vedlejším efektem je, že délka takových symbolů je `2`: ```js run alert( '𝒳'.length ); // 2, VELKÉ X V MATEMATICKÉM PÍSMU alert( '😂'.length ); // 2, TVÁŘ SE SLZAMI RADOSTI -alert( '𩷶'.length ); // 2, vzácný čínský hieroglyf +alert( '𩷶'.length ); // 2, vzácný čínský znak ``` 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! From a088d33e4b5f327760c5b973f5c72b053f7f678e Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Sat, 26 Nov 2022 16:48:11 +0100 Subject: [PATCH 14/55] sync pr 133 --- 1-js/03-code-quality/06-polyfills/article.md | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/1-js/03-code-quality/06-polyfills/article.md b/1-js/03-code-quality/06-polyfills/article.md index f648cbde8..161c6a6e9 100644 --- a/1-js/03-code-quality/06-polyfills/article.md +++ b/1-js/03-code-quality/06-polyfills/article.md @@ -1,11 +1,7 @@ # Polyfilly a transpilátory -<<<<<<< HEAD -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](http://www.ecma-international.org/publications/standards/Ecma-262.htm). -======= -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/). ->>>>>>> 746ad803c878e33182e7fab1578c0d15b9b75ca0 +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/). 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. @@ -75,15 +71,9 @@ if (!Math.trunc) { // není-li taková funkce JavaScript je vysoce dynamický jazyk. Skripty mohou přidávat nebo modifikovat libovolné funkce, dokonce i vestavěné. -<<<<<<< HEAD Dvě zajímavé knihovny polyfillů jsou: - [core js](https://github.com/zloirock/core-js), která toho podporuje mnoho a umožňuje přidávat jen potřebné vlastnosti. -- [polyfill.io](http://polyfill.io) je služba, která poskytuje skript s polyfilly podle vlastností a uživatelova prohlížeče. -======= -Two interesting polyfill libraries are: -- [core js](https://github.com/zloirock/core-js) that supports a lot, allows to include only needed features. -- [polyfill.io](https://polyfill.io/) service that provides a script with polyfills, depending on the features and user's browser. ->>>>>>> 746ad803c878e33182e7fab1578c0d15b9b75ca0 +- [polyfill.io](https://polyfill.io/) je služba, která poskytuje skript s polyfilly podle vlastností a uživatelova prohlížeče. ## Shrnutí From 2d67b42d0123e04f4ff42a5a77f9eb72c76abc8f Mon Sep 17 00:00:00 2001 From: otmon76 <66325539+otmon76@users.noreply.github.com> Date: Sun, 11 Aug 2024 17:55:59 +0200 Subject: [PATCH 15/55] Update article.md --- 1-js/02-first-steps/04-variables/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/02-first-steps/04-variables/article.md b/1-js/02-first-steps/04-variables/article.md index 8259306f4..b313c6c2c 100644 --- a/1-js/02-first-steps/04-variables/article.md +++ b/1-js/02-first-steps/04-variables/article.md @@ -289,7 +289,7 @@ Výhody: Kdy bychom měli používat pro konstantu velká písmena a kdy bychom ji měli pojmenovat obvyklým způsobem? Ujasníme si to. -Být „konstanta“ znamená prostě to, že hodnota proměnné se nikdy nezmění. Existují však konstanty, které jsou známy již před spuštěním programu (například hexadecimální hodnota červené barvy), a pak jsou konstanty, které se *vypočítají* až za běhu programu, ale jejich vypočtená hodnota se nikdy nezmění. +Být „konstanta“ znamená prostě to, že hodnota proměnné se nikdy nezmění. Některé konstanty jsou však známy již před spuštěním programu (například hexadecimální hodnota červené barvy) a pak jsou konstanty, které se *vypočítají* až za běhu programu, ale jejich vypočtená hodnota se nikdy nezmění. Příklad: From 12b6a4c474e699df15ab3a17b6a043ca6f0d42ba Mon Sep 17 00:00:00 2001 From: otmon76 <66325539+otmon76@users.noreply.github.com> Date: Sun, 11 Aug 2024 17:56:56 +0200 Subject: [PATCH 16/55] Update article.md --- 1-js/02-first-steps/05-types/article.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/1-js/02-first-steps/05-types/article.md b/1-js/02-first-steps/05-types/article.md index f246ff9d0..ac27efda1 100644 --- a/1-js/02-first-steps/05-types/article.md +++ b/1-js/02-first-steps/05-types/article.md @@ -95,12 +95,6 @@ const bigInt = 1234567890123456789012345678901234567890n; Protože čísla typu `BigInt` potřebujeme jen málokdy, nebudeme je tady probírat, ale věnujeme jim zvláštní kapitolu . Až budete tak velká čísla potřebovat, přečtěte si ji. -```smart header="Otázka kompatibility" -Právě nyní je `BigInt` podporován ve Firefoxu/Chrome/Edge/Safari, ale ne v IE. -``` - -Nahlédnutím do [*MDN* tabulky kompatibility pro BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility) zjistíte, které verze prohlížeče jej podporují. - ## Řetězec Řetězec (anglicky string) v JavaScriptu musí být uzavřen do uvozovek. From ef0048dd736e0ce2f8113a13a8c3f5b1a28d5ea6 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Mon, 20 Jan 2025 21:20:23 +0100 Subject: [PATCH 17/55] 1.5.1, 1.5.2 --- .../1-string-new-property/solution.md | 10 +-- .../1-string-new-property/task.md | 6 +- .../01-primitives-methods/article.md | 46 ++++++------- .../02-number/2-why-rounded-down/solution.md | 6 +- .../3-repeat-until-number/solution.md | 2 +- .../02-number/3-repeat-until-number/task.md | 6 +- .../9-random-int-min-max/solution.md | 20 +++--- .../02-number/9-random-int-min-max/task.md | 2 +- 1-js/05-data-types/02-number/article.md | 68 +++++++++---------- 9 files changed, 83 insertions(+), 83 deletions(-) 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 6bdfd1952..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 @@ -2,11 +2,11 @@ Zkuste si to spustit: ```js run -let str = "Ahoj"; +let řetězec = "Ahoj"; -str.test = 5; // (*) +řetězec.test = 5; // (*) -alert(str.test); +alert(řetězec.test); ``` Podle toho, zda máte `use strict` nebo ne, výsledek může být: @@ -15,9 +15,9 @@ Podle toho, zda máte `use strict` nebo ne, výsledek může být: Proč? Přehrajme si, co se děje na řádku `(*)`: -1. Když přistoupíme k vlastnosti `str`, vytvoří se „wrapper“. +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. Jinak bude operace s touto vlastností provedena, objekt získá vlastnost `test`, ale poté „wrapper“ zmizí, takže na posledním řádku nemá `str` po této vlastnosti ani stopu. +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. **Tento příklad jednoznačně dokazuje, že primitivy nejsou objekty.** 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 487e5ac50..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 @@ -8,11 +8,11 @@ importance: 5 Uvažujme následující kód: ```js -let str = "Ahoj"; +let řetězec = "Ahoj"; -str.test = 5; +řetězec.test = 5; -alert(str.test); +alert(řetězec.test); ``` 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 7e1a1e4f1..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,6 +1,6 @@ # Metody primitivů -JavaScript nám umožňuje pracovat s primitivy (řetězci, čísly atd.), jako by to byly objekty. Poskytuje i metody, které můžeme takto volat. Brzy 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). +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). Podíváme se na klíčové rozdíly mezi primitivy a objekty. @@ -11,7 +11,7 @@ Primitiv: Objekt: -- Je schopen ukládat více hodnot jako své vlastnosti. +- 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. Jedna z nejlepších věcí na objektech je, že jako jejich vlastnost můžeme uložit funkci. @@ -29,48 +29,48 @@ jan.řekniAhoj(); // Ahoj kámo! Zde jsme tedy vytvořili objekt `jan` s metodou `řekniAhoj`. -Mnoho objektů je již vestavěných, například ty, které pracují s daty, chybami, HTML prvky a podobně. Mají různé vlastnosti a metody. +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. Tyto vlastnosti však mají svou cenu! -Objekty jsou „těžší“ než primitivy. Vyžadují více zdrojů, které zatěžují interní mašinérii. +Objekty jsou „těžší“ než primitivy. Vyžadují více zdrojů, které zatěžují vnitřní stroj. ## Primitiv jako objekt -Tvůrce JavaScriptu čelil následujícímu paradoxu: +Tvůrci JavaScriptu čelili následujícímu paradoxu: - 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 nejlehčí. +- Primitivy musejí být co nejrychlejší a co nejmenší. Řešení vypadá trochu těžkopádně, ale je zde: 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ý „wrapper“ *(česky se mu někdy říká „obal“ -- pozn. překl.)*, který poskytne tuto přídavnou funkcionalitu a pak bude zničen. +3. Aby to fungovalo, vytvoří se speciální objekt zvaný „obal“ neboli „wrapper“, který tuto přídavnou funkcionalitu poskytne a pak bude zničen. -Tyto „objektové wrappery“ jsou pro každý primitivní typ jiné a nazývají se: `String`, `Number`, `Boolean`, `Symbol` a `BigInt`. Poskytují tedy různé sady metod. +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. -Například existuje řetězcová metoda [str.toUpperCase()](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase), která vrací řetězec `str` velkými písmeny. +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. Funguje následovně: ```js run -let str = "Ahoj"; +let řetězec = "Ahoj"; -alert( str.toUpperCase() ); // AHOJ +alert( řetězec.toUpperCase() ); // AHOJ ``` -Jednoduché, že? Ve skutečnosti se ve `str.toUpperCase()` děje následující: +Jednoduché, že? Ve skutečnosti se v `řetězec.toUpperCase()` děje následující: -1. Řetězec `str` 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()`. +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 `str`. +3. Speciální objekt se zničí a zůstane samotný primitiv `řetězec`. -Primitivy tedy mohou poskytovat metody, ale samy zůstávají lehké. +Primitivy tedy mohou poskytovat metody, ale samy zůstávají malé. -JavaScriptový engine tento proces vysoce 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. +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. -I číslo má své vlastní metody, například [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) zaokrouhluje číslo na zadanou přesnost: +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; @@ -82,9 +82,9 @@ Další specifické metody uvidíme v kapitolách a . ````warn header="Konstruktory `String/Number/Boolean` jsou jen pro interní použití" -Některé jazyky, např. Java, nám umožňují explicitně vytvářet „wrappery“ pro primitivy pomocí syntaxe typu `new Number(1)` nebo `new Boolean(false)`. +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)`. -V JavaScriptu je to z historických důvodů také možné, ale silně **nedoporučované**. Věci začnou bláznit hned na několika místech. +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. Například: @@ -104,18 +104,18 @@ if (nula) { // nula je pravdivá, protože je to objekt } ``` -Na druhou stranu 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). +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). Například tohle je zcela v pořádku: ```js -let num = Number("123"); // převede řetězec na číslo +let číslo = Number("123"); // převede řetězec na číslo ``` ```` ````warn header="null/undefined nemají žádné metody" -Speciální primitivy `null` a `undefined` jsou výjimky. Nemají odpovídající „wrappery“ a neposkytují žádné metody. V určitém smyslu slova jsou vlastně „ty nejprimitivnější“. +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ší“. Pokus o přístup k vlastnosti takové hodnoty ohlásí chybu: @@ -126,4 +126,4 @@ alert(null.test); // chyba ## Shrnutí - 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é enginy jsou dobře vyladěny, aby je interně optimalizovaly, takže jejich volání není nákladné. \ No newline at end of file +- 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/2-why-rounded-down/solution.md b/1-js/05-data-types/02-number/2-why-rounded-down/solution.md index 3b58f453e..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 @@ -6,7 +6,7 @@ Podívejme se: alert( 6.35.toFixed(20) ); // 6.34999999999999964473 ``` -Ztráta přesnosti může číslo zvýšit i snížit. V tomto konkrétním případě se číslo stane o něco menším, proto bude zaokrouhleno dolů. +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ů. A co `1.35`? @@ -14,7 +14,7 @@ A co `1.35`? alert( 1.35.toFixed(20) ); // 1.35000000000000008882 ``` -Zde ztráta přesnosti číslo trošičku zvětšila, takže se zaokrouhlilo nahoru. +Zde ztráta přesnosti číslo trošičku zvýšila, takže se zaokrouhlilo nahoru. **Jak můžeme problém s `6.35` vyřešit, chceme-li, aby se zaokrouhlilo správně?** @@ -24,7 +24,7 @@ Měli bychom je před zaokrouhlením přiblížit k celému číslu: alert( (6.35 * 10).toFixed(20) ); // 63.50000000000000000000 ``` -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 dělené mocninami `2` jsou v binární soustavě reprezentovány přesně, takže je nyní můžeme zaokrouhlit: +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 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 0de988e60..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 @@ -17,7 +17,7 @@ alert(`Načteno: ${načtiČíslo()}`); Řešení je trochu složitější, než by mohlo být, protože si musíme poradit s `null`/prázdnými řádky. -Ve skutečnosti tedy přijímáme vstup tak dlouho, dokud to není „obvyklé číslo“. Tuto podmínku splňují i `null` (storno) a prázdný řádek, protože v číselné podobě jsou obě `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`. 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 2a6561582..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 @@ -4,11 +4,11 @@ importance: 5 # Opakování, dokud na vstupu nebude číslo -Vytvořte funkci `načtiČíslo`, která se ptá na číslo tak dlouho, až návštěvník zadá platnou číselnou hodnotu. +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. -Výslednou hodnotu musí vrátit jako číslo. +Výslednou hodnotu funkce musí vrátit jako číslo. -Návštěvník může tento proces ukončit i zadáním prázdného řádku nebo stiskem „Storno“. V takovém případě by funkce měla vrátit `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/9-random-int-min-max/solution.md b/1-js/05-data-types/02-number/9-random-int-min-max/solution.md index 01ced8f22..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 @@ -4,8 +4,8 @@ Jednoduchým, ale nesprávným řešením by bylo generovat hodnotu od `min` do ```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) ); @@ -13,7 +13,7 @@ alert( randomInteger(1, 3) ); 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. -Jestliže si mnohokrát za sebou spustíte výše uvedený příklad, snadno uvidíte, že `2` se objevuje nejčastěji. +Jestliže si spustíte výše uvedený příklad mnohokrát po sobě, brzy uvidíte, že nejčastěji se objevuje `2`. Děje se to proto, že `Math.round()` získává náhodná čísla z intervalu `1..3` a zaokrouhluje je následovně: @@ -27,14 +27,14 @@ Nyní jasně vidíme, že `1` má dvakrát méně hodnot než `2`. Totéž plat # Správné řešení -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 přidat požadované pravděpodobnosti krajních hodnot: +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) { - // nyní rand je od (min-0.5) do (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); } */!* @@ -46,9 +46,9 @@ Alternativním způsobem by bylo použít `Math.floor` pro náhodné číslo od ```js run *!* function randomInteger(min, max) { - // zde rand je od min do (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); } */!* 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 a6bf38216..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 @@ -4,7 +4,7 @@ importance: 2 # Náhodné celé číslo od min do max -Vytvořte funkci `randomInteger(min, max)`, která vygeneruje náhodné *celé* číslo od `min` do `max`, přičemž možnými hodnotami budou i `min` a `max`. +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`. Každé číslo z intervalu `min..max` se musí objevit se stejnou pravděpodobností. diff --git a/1-js/05-data-types/02-number/article.md b/1-js/05-data-types/02-number/article.md index bcd645a8c..6e263e11c 100644 --- a/1-js/05-data-types/02-number/article.md +++ b/1-js/05-data-types/02-number/article.md @@ -1,8 +1,8 @@ # Čísla -V moderním JavaScriptu jsou dva druhy čísel: +Moderní JavaScript obsahuje dva druhy čísel: -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á většinou používáme a v této kapitole o nich budeme hovořit. +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. Čí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 . @@ -64,8 +64,8 @@ Jinými slovy, záporné číslo za `"e"` znamená dělení číslem 1 se zadan // -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 ``` ### Hexadecimální, binární a oktální čísla @@ -76,7 +76,7 @@ Například: ```js run alert( 0xff ); // 255 -alert( 0xFF ); // 255 (totéž, na velikosti písmen nezáleží) +alert( 0xFF ); // 255 (totéž, malá a velká písmena se nerozlišují) ``` 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`: @@ -108,8 +108,8 @@ Hodnota `základ` může být od `2` do `36`. Standardně je to `10`. Běžná použití jsou: - **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 kódová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` je tehdy, 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`: +- **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 @@ -118,7 +118,7 @@ Běžná použití jsou: ```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 `..`. -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í přijde na řadu metoda. +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í přichází metoda. Můžeme napsat i `(123456).toString(36)`. ``` @@ -155,7 +155,7 @@ Rozdíly mezi těmito funkcemi shrnuje následující tabulka: 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 je zaokrouhlit na 2 desetinná místa, abychom dostali jen `1.23`. +Máme například `1.2345` a chceme toto číslo zaokrouhlit na 2 desetinná místa, abychom dostali jen `1.23`. Existují dva způsoby, jak to udělat: @@ -169,7 +169,7 @@ Existují dva způsoby, jak to udělat: alert( Math.round(číslo * 100) / 100 ); // 1.23456 -> 123.456 -> 123 -> 1.23 ``` -2. Metoda [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) zaokrouhluje číslo na `n` číslic za čárkou a vrací řetězcovou reprezentaci výsledku. +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 číslo = 12.34; @@ -196,10 +196,10 @@ Existují dva způsoby, jak to udělat: Čí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. -Je-li číslo opravdu obrovské, může toto 64-bitové úložiště překročit a stát se speciální číselnou hodnotou `Infinity` (nekonečno): +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 (nekonečno) +alert( 1e500 ); // Infinity ``` Co může být trochu méně zřejmé, ale stává se poměrně často, je ztráta přesnosti. @@ -234,7 +234,7 @@ Co je vlastně `0.1`? Je to jedna děleno deseti `1/10`, jedna desetina. V desí 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. -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. +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. Čí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. @@ -260,7 +260,7 @@ let součet = 0.1 + 0.2; alert( součet.toFixed(2) ); // "0.30" ``` -Prosíme všimněte si, že `toFixed` vrací vždy řetězec. Zajišťuje, že za desetinnou čárkou má vždy 2 číslice. To se obzvláště hodí, když máme elektronický obchod a potřebujeme zobrazit `$0.30`. V jiným případech můžeme použít unární plus, abychom jej převedli na číslo: +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 součet = 0.1 + 0.2; @@ -292,7 +292,7 @@ JavaScript při takových událostech nevyvolá chybu. Udělá, co může, aby s ```` ```smart header="Dvě nuly" -Dalším legračním důsledkem interní reprezentace čísel je existence dvou nul: `0` a `-0`. +Dalším legračním důsledkem této interní reprezentace čísel je existence dvou nul: `0` a `-0`. 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. @@ -313,7 +313,7 @@ Patří k typu `number`, ale nejsou to „normální“ čísla, takže existuj ```js run alert( isNaN(NaN) ); // true - alert( isNaN("str") ); // true + alert( isNaN("řetězec") ); // true ``` 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ě: @@ -322,15 +322,15 @@ Patří k typu `number`, ale nejsou to „normální“ čísla, takže existuj alert( NaN === NaN ); // false ``` -- `isFinite(hodnota)` převede svůj argument na číslo a vrátí `true`, jestliže je to běžné číslo a ne `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, protože je to speciální hodnota: NaN + 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 ``` -Někdy se `isFinite` používá k ověření, zda řetězcová hodnota je běžné číslo: +Někdy se `isFinite` používá k ověření, zda řetězcová hodnota je skutečné číslo: ```js run @@ -343,17 +343,17 @@ alert( isFinite(číslo) ); 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` 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`. Automaticky nepřevádějí svůj argument na číslo, ale místo toho ověří, zda jejich argument je typu `number`. +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(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 // Všimněte si rozdílu: - alert( Number.isNaN("str") ); // false, protože "str" je typu řetězec, ne typu číslo - alert( isNaN("str") ); // true, protože isNan převede řetězec "str" na číslo a jako výsledek této konverze získá NaN + 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)` vrací `true`, jestliže argument je typu `number` a není `NaN/Infinity/-Infinity`. V jakémkoli jiném případě vrací `false`. @@ -364,14 +364,14 @@ Metody [Number.isNaN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Re alert( Number.isFinite(2 / 0) ); // false // Všimněte si rozdílu: - alert( Number.isFinite("123") ); // false, protože "123" je typu řetězec, ne typu číslo + 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 ``` 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="Srovnání s `Object.is`" +```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. Funguje pro `NaN`: `Object.is(NaN, NaN) === true`, což je dobrá věc. @@ -379,7 +379,7 @@ Existuje speciální vestavěná metoda `Object.is`, která porovnává hodnoty Ve všech ostatních případech je `Object.is(a, b)` totéž jako `a === b`. -Zmínili jsme zde `Object.is`, 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)). +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)). ``` @@ -393,11 +393,11 @@ alert( +"100px" ); // NaN Jedinou výjimkou jsou mezery na začátku nebo na konci řetězce, které jsou ignorovány. -V reálném životě však často mívá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. +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. K tomu slouží funkce `parseInt` a `parseFloat`. -„Načítají“ číslo z řetězce tak dlouho, dokud to jde. Až nastane chyba, vrátí nahromaděné číslo. Funkce `parseInt` vrátí celé číslo, zatímco `parseFloat` vrátí číslo s pohyblivou řádovou čárkou: +„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 @@ -410,11 +410,11 @@ alert( parseFloat('12.3.4') ); // 12.3, druhá tečka ukončí načítání 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, první symbol tento proces zastaví +alert( parseInt('a123') ); // NaN, první znak tento proces zastaví ``` -````smart header="Druhý argument `parseInt(str, soustava)`" -Funkce `parseInt()` má volitelný druhý parametr. Ten specifikuje základ číselné soustavy, takže `parseInt` může také načítat řetězce hexadecimálních čísel, binárních čísel a podobně: +````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 @@ -454,7 +454,7 @@ Několik příkladů: alert( Math.pow(2, 10) ); // 2 na 10 = 1024 ``` -V objektu `Math` jsou i další funkce a konstanty včetně trigonometrických. Můžete je najít v [dokumentaci k objektu Math](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). ## Shrnutí @@ -466,10 +466,10 @@ Abychom napsali číslo s mnoha nulami: Pro různé číselné soustavy: - Můžeme zapisovat čísla přímo v hexadecimální (`0x`), oktální (`0o`) a binární (`0b`) soustavě. -- `parseInt(str, základ)` parsuje řetězec `str` na celé číslo v číselné soustavě o zadaném základu `základ`, `2 ≤ základ ≤ 36`. +- `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`. -Pro běžné testování čísel: +Pro testování čísel: - `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` From 07971f3ac86a8f4596eb10920bd363c20fae383c Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Mon, 20 Jan 2025 23:18:26 +0100 Subject: [PATCH 18/55] 1.5.3 --- .../03-string/3-truncate/solution.md | 2 +- .../03-string/4-extract-currency/task.md | 2 +- 1-js/05-data-types/03-string/article.md | 82 ++++++++++--------- 3 files changed, 44 insertions(+), 42 deletions(-) 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 0a776ad0a..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,4 +1,4 @@ -Maximální délka musí být `maxDélka`, takže musíme odříznout o něco kratší řetězec, abychom získali místo pro výpustku. +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. Všimněte si, že pro výpustku existuje v Unicode jediný znak. Nejsou to tři tečky za sebou. 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 769654b70..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 @@ -4,7 +4,7 @@ importance: 4 # Vyjmutí částky -Máme cenu ve tvaru `"$120"`. Tedy: jako první je značka dolaru, pak číslo. +Máme cenu ve tvaru `"$120"`. Tedy: jako první je znak dolaru, pak číslo. Vytvořte funkci `vyjmiČástku(řetězec)`, která z takového řetězce vytáhne číselnou hodnotu a vrátí ji. diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md index fc852c185..03c65dcf1 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -1,8 +1,8 @@ # Řetězce -Textová data se v JavaScriptu ukládají jako řetězce. Neexistuje oddělený typ pro jediný znak. +Textová data se v JavaScriptu ukládají jako řetězce. Neexistuje zvláštní typ pro jediný znak. -Interní formát řetězce je vždy [UTF-16](https://cs.wikipedia.org/wiki/UTF-16), nezávisí na kódování stránky. +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. ## Uvozovky @@ -48,9 +48,9 @@ let seznamHostů = "Hosté: // Error: Unexpected token ILLEGAL * Jan"; ``` -Jednoduché a dvojité uvozovky pocházejí ze starých časů vytváření jazyka, kdy potřeba víceřádkových řetězců nebyla brána v úvahu. Zpětné uvozovky se objevily mnohem později, a tak jsou univerzálnější. +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ší. -Zpětné uvozovky nám také umožňují specifikovat „šablonovou funkci“ před levou uvozovkou. 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“ *(„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). +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). ## Speciální znaky @@ -62,7 +62,7 @@ let seznamHostů = "Hosté:\n * Jan\n * Petr\n * Marie"; alert(seznamHostů); // víceřádkový seznam hostů, stejný jako výše ``` -Jednodušší příklad: tyto dva řádky jsou stejné, jen jinak zapsané: +Jednodušší příklad: tyto dva řádky mají stejný význam, jen jsou různě zapsané: ```js run let řetězec1 = "Ahoj\nsvěte"; // dva řádky pomocí „symbolu konce řádku“ @@ -83,15 +83,17 @@ Existují i jiné, méně běžné speciální znaky: |`\'`, `\"`, \\`|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í (nyní na ně můžete zapomenout). | +|`\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). | Jak vidíte, všechny speciální znaky začínají zpětným lomítkem `\`, které se také nazývá „únikový znak“. +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( `Zpětné lomítko: \\` ); // Zpětné lomítko: \ ``` -Tzv. „únikované“ uvozovky `\'`, `\"`, \\` se používají k vložení uvozovek do řetězce, který je ohraničen stejným druhem uvozovek. + K vložení uvozovek do řetězce, který je ohraničen stejným druhem uvozovek, se používají tzv. „únikované“ uvozovky `\'`, `\"`, \\`. Například: @@ -99,7 +101,7 @@ Například: alert( 'To*!*\'*/!*s přehnal!' ); // *!*To's*/!* přehnal! ``` -Jak vidíme, museli jsme před vnitřním apostrofem uvést zpětné lomítko `\'`, jinak by apostrof znamenal konec řetězce. +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. 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: @@ -107,7 +109,7 @@ Samozřejmě musíme předznamenat únikovým znakem jen stejný druh uvozovek j alert( `To's přehnal!` ); // To's přehnal! ``` -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 nepovinné kapitole o [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). ## Délka řetězce @@ -120,14 +122,14 @@ alert( `Já\n`.length ); // 3 Všimněte si, že `\n` je jediný „speciální“ znak, takže délka bude opravdu `3`. ```warn header="`length` je vlastnost" -Lidé zvyklí na některé jiné jazyky někdy nesprávně píší volání funkce `str.length()` místo `str.length`. To nefunguje. +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. -Prosíme všimněte si, že `str.length` je číselná vlastnost, ne funkce. Není důvod za ní uvádět závorky. Nepíše se `.length()`, ale `.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`. ``` ## Přístup ke znakům -Abyste získali znak na pozici `poz`, použijte hranaté závorky `[poz]` nebo zavolejte metodu [str.at(pos)](mdn:js/String/at). První znak se nachází na pozici nula: +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 řetězec = `Ahoj`; @@ -141,17 +143,17 @@ alert( řetězec[řetězec.length - 1] ); // j alert( řetězec.at(-1) ); ``` -Jak vidíte, metoda `.at(poz)` má výhodu v tom, že umožňuje zápornou pozici. Je-li `poz` záporná, počítá se od konce řetězce. +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. Takže `.at(-1)` znamená poslední znak, `.at(-2)` je znak před ním atd. -Hranaté závorky pro záporný index vrátí vždy `undefined`, například: +Hranaté závorky se záporným indexem vrátí vždy `undefined`, například: ```js run let řetězec = `Ahoj`; alert( řetězec[-2] ); // undefined -alert( řetězec.at(-2) ); // h +alert( řetězec.at(-2) ); // o ``` Můžeme také procházet jednotlivé znaky pomocí `for..of`: @@ -175,7 +177,7 @@ let řetězec = 'Ahoj'; alert( řetězec[0] ); // nefunguje to ``` -Obvyklý způsob, jak to obejít, je vytvořit úplně nový řetězec a přiřadit jej do `řetězec` namísto starého. +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. Například: @@ -191,14 +193,14 @@ V následujících podkapitolách uvidíme další příklady. ## Změna písmen na malá nebo velká -Metoda [toLowerCase()](mdn:js/řetězecing/toLowerCase) mění písmena řetězce na malá a metoda [toUpperCase()](mdn:js/řetězecing/toUpperCase) na velká: +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( 'Rozhraní'.toUpperCase() ); // ROZHRANÍ alert( 'Rozhraní'.toLowerCase() ); // rozhraní ``` -Nebo jestliže chceme jediný znak malým písmenem: +Nebo pokud chceme jediný znak, změněný na malé písmeno: ```js run alert( 'Rozhraní'[0].toLowerCase() ); // 'r' @@ -210,9 +212,9 @@ Je mnoho způsobů, jak v řetězci najít podřetězec. ### řetězec.indexOf -První metoda je [řetězec.indexOf(podřetězec, pozice)](mdn:js/řetězecing/indexOf). +První metoda je [řetězec.indexOf(podřetězec, pozice)](mdn:js/string/indexOf). -Hledá `podřetězec` v `řetězec`, počínajíc zadanou pozicí `pozice`, a vrátí pozici, na níž byla nalezena shoda. Jestliže nebylo nic nalezeno, vrátí `-1`. +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`. Například: @@ -225,7 +227,7 @@ alert( řetězec.indexOf('prorokovo') ); // -1, nenalezeno, hledání rozlišuje alert( řetězec.indexOf("oko") ); // 4, "oko" nalezeno na pozici 4 (..okovo oko) ``` -Nepovinný druhý parametr nám umožňuje začít hledání na zadané pozici. +Nepovinný druhý parametr nám umožňuje zahájit hledání na zadané pozici. Například první výskyt `"oko"` je na pozici `4`. Chceme-li hledat další výskyt, začněme hledání od pozice `5`: @@ -235,7 +237,7 @@ let řetězec = 'Prorokovo oko'; alert( řetězec.indexOf('oko', 5) ) // 10 ``` -Pokud nás zajímají všechny výskyty, můžeme spustit `indexOf` v cyklu. Každé nové volání se bude konat od pozice za předchozím nálezem: +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 řetězec = 'Kdyby byly v řece ryby, nebylo by třeba rybníka'; @@ -261,7 +263,7 @@ let cíl = "by"; *!* let poz = -1; while ((poz = řetězec.indexOf(cíl, poz + 1)) != -1) { - alert( `Nalezeno na ${poz}` ); + alert( poz ); } */!* ``` @@ -272,7 +274,7 @@ Existuje i podobná metoda [řetězec.lastIndexOf(podřetězec, pozice)](mdn:js/ Ta by vypsala výskyty v opačném pořadí. ``` -Metoda `indexOf` přináší drobnou nepohodlnost do testu v `if`. Nemůžeme ji umístit do `if` takto: +Metoda `indexOf` vnáší do podmínky v `if` drobnou nepříjemnost. Nemůžeme ji umístit do `if` takto: ```js run let řetězec = "Prorokovo oko"; @@ -282,9 +284,9 @@ if (řetězec.indexOf("Prorokovo")) { } ``` -V uvedeném příkladu se `alert` nezobrazí, protože `ř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`. +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`. -Ve skutečnosti bychom tedy měli kontrolovat na `-1`, např. takto: +Správně bychom tedy měli porovnávat s `-1`, např. takto: ```js run let řetězec = "Prorokovo oko"; @@ -298,9 +300,9 @@ if (řetězec.indexOf("Prorokovo") != -1) { ### includes, startsWith, endsWith -Modernější metoda [řetězec.includes(podřetězec, poz)](mdn:js/řetězecing/includes) vrátí `true/false` podle toho, zda `řetězec` v sobě obsahuje `podřetězec`. +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`. -Je to správná volba, když potřebujeme testovat výskyt, ale nezajímá nás jeho pozice: +Je to ta pravá možnost, když potřebujeme testovat výskyt, ale nezajímá nás jeho pozice: ```js run alert( "Prorokovo oko".includes("Prorok") ); // true @@ -315,7 +317,7 @@ alert( "Prorokovo".includes("oko") ); // true alert( "Prorokovo".includes("oko", 5) ); // false, od pozice 5 není žádné "oko" ``` -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 *(„startsWith“ = začíná na, „endsWith“ = končí na, takže `startsWith` vrátí `true`, jestliže řetězec začíná zadaným podřetězcem, a `endsWith` vrátí `true`, jestliže řetězec končí zadaným podřetězcem -- pozn. překl.)*: +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( "*!*Pro*/!*rok".startsWith("Pro") ); // true, "Prorok" začíná na "Pro" @@ -334,10 +336,10 @@ V JavaScriptu jsou 3 metody pro získání podřetězce: `substring`, `substr` a ```js run 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 0 + alert( řetězec.slice(0, 1) ); // 'ř', od 0 do 1, ale mimo 1, takže jediný znak na pozici 0 ``` - Není-li uveden druhý argument, `slice` jde až na konec řetězce: + Není-li uveden druhý argument, `slice` vrátí podřetězec až do konce řetězce: ```js run let řetězec = "ře*!*tězení*/!*"; @@ -356,14 +358,14 @@ V JavaScriptu jsou 3 metody pro získání podřetězce: `substring`, `substr` a `řetězec.substring(začátek [, konec])` : Vrátí část řetězce *mezi* pozicemi `začátek` a `konec` (nezahrnuje `konec`). - Je to téměř totéž jako `slice`, ale umožňuje, aby `začátek` byl větší než `konec` (v takovém případě hodnoty `začátek` a `konec` jednoduše prohodí). + 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í). Například: ```js run let řetězec = "ře*!*těze*/!*ní"; - // je to totéž pro substring: + // tyto hodnoty jsou totéž pro substring: alert( řetězec.substring(2, 6) ); // "těze" alert( řetězec.substring(6, 2) ); // "těze" @@ -403,7 +405,7 @@ Abychom předešli zmatkům, všechny tyto metody si zrekapitulujme: | `substr(začátek, délka)` | od `začátek` vezme `délka` znaků | umožňuje záporný `začátek` | ```smart header="Kterou zvolit?" -Všechny odvedou svou práci. Formálně má `substr` drobnou nevýhodu: není popsána v jádru specifikace JavaScriptu, ale v Příloze B, která pokrývá pouze prohlížečové vlastnosti, existující zejména z historických důvodů. Neprohlížečová prostředí ji tedy nemusejí podporovat. V praxi však funguje všude. +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. 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í. @@ -430,12 +432,12 @@ Existují však některé zvláštnosti. 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`. -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 je: každý znak má odpovídající číselný kód. +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. Existují speciální metody, které umožňují získat znak pro zadaný kód a naopak: `řetězec.codePointAt(poz)` -: Vrátí desetinné číslo představující kód znaku na pozici `poz`: +: Vrátí desítkové číslo představující kód znaku na pozici `poz`: ```js run // malá a velká písmena mají různé kódy @@ -497,7 +499,7 @@ Například: alert( 'Česko'.localeCompare('Zéland') ); // -1 ``` -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ř. velikost písmen, nebo zda se `"a"` a `"á"` mají brát jako stejné znaky, atd. +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. ## Shrnutí @@ -507,7 +509,7 @@ Tato metoda má ve skutečnosti ještě dva další argumenty specifikované v [ - 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 pravidel jazyka, použijeme `localeCompare`, jinak se budou porovnávat podle kódů znaků. +- Chceme-li porovnat řetězce podle jazykových pravidel, použijeme `localeCompare`, jinak se budou porovnávat podle kódů znaků. Pro řetězce existuje i několik dalších užitečných metod: @@ -515,6 +517,6 @@ Pro řetězce existuje i několik dalších užitečných metod: - `řetězec.repeat(n)` -- zopakuje řetězec `n`-krát. - ...a další lze najít v [manuálu](mdn:js/string). -Ř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, takže je vysvětleno v samostatné části tutoriálu . +Ř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 . -Od nynějška 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é záležitosti s porovnáváním. O Unicode se dozvíte víc v kapitole . +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 . From 4ecc8a0dcb3d51857a8ea79195cb61a86296c8da Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Tue, 21 Jan 2025 22:53:45 +0100 Subject: [PATCH 19/55] 1.5.4 --- .../10-maximal-subarray/_js.view/solution.js | 2 +- .../10-maximal-subarray/_js.view/test.js | 20 ++--- .../04-array/10-maximal-subarray/solution.md | 32 ++++---- .../04-array/10-maximal-subarray/task.md | 16 ++-- .../04-array/5-array-input-sum/task.md | 2 +- 1-js/05-data-types/04-array/article.md | 78 +++++++++---------- 6 files changed, 75 insertions(+), 75 deletions(-) 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 bc22147e6..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,4 +1,4 @@ -function vraťMaxSoučetPod(arr) { +function vraťMaxSoučetPodpole(arr) { let maxSoučet = 0; let částečnýSoučet = 0; 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 be9e2ed1e..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("vraťMaxSoučetPod", function() { +describe("vraťMaxSoučetPodpole", function() { it("maximální podsoučet [1, 2, 3] se rovná 6", function() { - assert.equal(vraťMaxSoučetPod([1, 2, 3]), 6); + assert.equal(vraťMaxSoučetPodpole([1, 2, 3]), 6); }); it("maximální podsoučet [-1, 2, 3, -9] se rovná 5", function() { - assert.equal(vraťMaxSoučetPod([-1, 2, 3, -9]), 5); + assert.equal(vraťMaxSoučetPodpole([-1, 2, 3, -9]), 5); }); it("maximální podsoučet [-1, 2, 3, -9, 11] se rovná 11", function() { - assert.equal(vraťMaxSoučetPod([-1, 2, 3, -9, 11]), 11); + assert.equal(vraťMaxSoučetPodpole([-1, 2, 3, -9, 11]), 11); }); it("maximální podsoučet [-2, -1, 1, 2] se rovná 3", function() { - assert.equal(vraťMaxSoučetPod([-2, -1, 1, 2]), 3); + assert.equal(vraťMaxSoučetPodpole([-2, -1, 1, 2]), 3); }); it("maximální podsoučet [100, -9, 2, -3, 5] se rovná 100", function() { - assert.equal(vraťMaxSoučetPod([100, -9, 2, -3, 5]), 100); + assert.equal(vraťMaxSoučetPodpole([100, -9, 2, -3, 5]), 100); }); it("maximální podsoučet [] se rovná 0", function() { - assert.equal(vraťMaxSoučetPod([]), 0); + assert.equal(vraťMaxSoučetPodpole([]), 0); }); it("maximální podsoučet [-1] se rovná 0", function() { - assert.equal(vraťMaxSoučetPod([-1]), 0); + assert.equal(vraťMaxSoučetPodpole([-1]), 0); }); it("maximální podsoučet [-1, -2] se rovná 0", function() { - assert.equal(vraťMaxSoučetPod([-1, -2]), 0); + assert.equal(vraťMaxSoučetPodpole([-1, -2]), 0); }); it("maximální podsoučet [2, -8, 5, -1, 2, -3, 2] se rovná 6", function() { - assert.equal(vraťMaxSoučetPod([2, -8, 5, -1, 2, -3, 2]), 6); + 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 16272645d..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 @@ -25,18 +25,18 @@ Například pro `[-1, 2, 3, -9, 11]`: 3 + (-9) 3 + (-9) + 11 -// Začínající -9 +// Začínající -9: -9 -9 + 11 -// Začínající 11 +// Začínající 11: 11 ``` 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 vraťMaxSoučetPod(pole) { +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++) { @@ -50,11 +50,11 @@ function vraťMaxSoučetPod(pole) { return maxSoučet; } -alert( vraťMaxSoučetPod([-1, 2, 3, -9]) ); // 5 -alert( vraťMaxSoučetPod([-1, 2, 3, -9, 11]) ); // 11 -alert( vraťMaxSoučetPod([-2, -1, 1, 2]) ); // 3 -alert( vraťMaxSoučetPod([1, 2, 3]) ); // 6 -alert( vraťMaxSoučetPod([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 ``` 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. @@ -68,7 +68,7 @@ Budeme procházet prvky pole a pamatovat si aktuální částečný součet prvk Pokud je popis příliš vágní, prosíme nahlédněte do kódu, je dosti krátký: ```js run demo -function vraťMaxSoučetPod(pole) { +function vraťMaxSoučetPodpole(pole) { let maxSoučet = 0; let částečnýSoučet = 0; @@ -81,14 +81,14 @@ function vraťMaxSoučetPod(pole) { return maxSoučet; } -alert( vraťMaxSoučetPod([-1, 2, 3, -9]) ); // 5 -alert( vraťMaxSoučetPod([-1, 2, 3, -9, 11]) ); // 11 -alert( vraťMaxSoučetPod([-2, -1, 1, 2]) ); // 3 -alert( vraťMaxSoučetPod([100, -9, 2, -3, 5]) ); // 100 -alert( vraťMaxSoučetPod([1, 2, 3]) ); // 6 -alert( vraťMaxSoučetPod([-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 ``` Tento algoritmus vyžaduje přesně 1 průchod polem, takže jeho časová složitost je O(n). -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 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. +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 04d7ced29..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 @@ -8,23 +8,23 @@ Na vstupu je pole čísel, např. `pole = [1, -2, 3, 4, -9, 6]`. Úkol zní: najděte souvislé podpole tohoto pole s maximálním součtem prvků. -Napište funkci `vraťMaxSoučetPod(pole)`, která tento součet vrátí. +Napište funkci `vraťMaxSoučetPodpole(pole)`, která tento součet vrátí. Příklad: ```js -vraťMaxSoučetPod([-1, *!*2, 3*/!*, -9]) == 5 (součet zvýrazněných prvků) -vraťMaxSoučetPod([*!*2, -1, 2, 3*/!*, -9]) == 6 -vraťMaxSoučetPod([-1, 2, 3, -9, *!*11*/!*]) == 11 -vraťMaxSoučetPod([-2, -1, *!*1, 2*/!*]) == 3 -vraťMaxSoučetPod([*!*100*/!*, -9, 2, -3, 5]) == 100 -vraťMaxSoučetPod([*!*1, 2, 3*/!*]) == 6 (vezmi vše) +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) ``` Jsou-li všechny prvky záporné, znamená to, že nevezmeme žádný (podpole je prázdné), takže součet je nulový: ```js -vraťMaxSoučetPod([-1, -2, -3]) = 0 +vraťMaxSoučetPodpole([-1, -2, -3]) = 0 ``` 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/5-array-input-sum/task.md b/1-js/05-data-types/04-array/5-array-input-sum/task.md index 36db3743b..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 @@ -6,7 +6,7 @@ importance: 4 Napište funkci `sečtiVstup()`, která: -- Zeptá se uživatele na hodnoty pomocí `prompt` a uloží tyto hodnoty do pole. +- 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. diff --git a/1-js/05-data-types/04-array/article.md b/1-js/05-data-types/04-array/article.md index ce75fa509..216112a2f 100644 --- a/1-js/05-data-types/04-array/article.md +++ b/1-js/05-data-types/04-array/article.md @@ -79,7 +79,7 @@ pole[3](); // ahoj ``` -````smart header="Koncová čárka" +````smart header="Vlečná čárka" Pole, stejně jako objekt, může končit čárkou: ```js let ovoce = [ @@ -89,41 +89,41 @@ let ovoce = [ ]; ``` -Styl „koncové *(trailing)* čárky“ zjednodušuje přidávání a odstraňování prvků, protože všechny řádky vypadají podobně. +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. ## Metody pop/push, shift/unshift @@ -136,7 +136,7 @@ Jedním z nejběžnějších využití pole je [fronta](https://cs.wikipedia.org Pole podporují obě operace. -V praxi ji potřebujeme velmi často. Například frontu zpráv, které musíme zobrazit na obrazovce. +V praxi ji potřebujeme velmi často. Máme například frontu zpráv, které musíme zobrazit na obrazovce. Dalším využitím polí je datová struktura nazvaná [zásobník](https://cs.wikipedia.org/wiki/Zásobník_(datová_struktura)). @@ -155,7 +155,7 @@ U zásobníků se naposledy vložený prvek odebírá jako první. Tento princip 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. -Datová struktura, která to umožňuje, se v informatice nazývá [deque](https://en.wikipedia.org/wiki/Double-ended_queue) *(z anglického „double-ended queue“ -- „fronta s dvojitým koncem“)*. +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“). **Metody, které pracují s koncem pole:** @@ -170,7 +170,7 @@ Datová struktura, která to umožňuje, se v informatice nazývá [deque](https 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` : Připojí prvek na konec pole: @@ -221,7 +221,7 @@ ovoce.unshift("Ananas", "Citrón"); alert( ovoce ); ``` -## Interní reprezentace +## Vnitřní reprezentace 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. @@ -243,7 +243,7 @@ pole.push("Hruška"); // modifikace pole odkazem alert( ovoce ); // Banán, Hruška - nyní 2 prvky ``` -...Avšak to, co činí pole opravdu speciálními, je jejich interní reprezentace. Engine 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. +...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. 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. @@ -257,9 +257,9 @@ ovoce[99999] = 5; // přidáme vlastnost s indexem daleko větším, než jeho d ovoce.věk = 25; // vytvoříme vlastnost s libovolným názvem ``` -To je možné, protože pole jsou v základu objekty. Můžeme do nich přidávat jakékoli vlastnosti. +To je možné, protože pole jsou od základu objekty. Můžeme do nich přidávat jakékoli vlastnosti. -Avšak engine 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í. +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í. Způsoby nesprávného používání pole: @@ -267,7 +267,7 @@ Způsoby nesprávného používání pole: - 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. -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 enginech 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 `{}`. +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 `{}`. ## Výkon @@ -295,7 +295,7 @@ Operace `shift` musí provést 3 věci: 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. -A jak je to s `push/pop`? Ty nemusejí nic posunovat. Metoda `pop` vyjme prvek z konce tak, že vyčistí index a zkrátí `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`. Akce pro operaci `pop`: @@ -305,7 +305,7 @@ ovoce.pop(); // odebere 1 prvek z konce ![](array-pop.svg) -**Metoda `pop` nemusí nic posunovat, jelikož indexy ostatních prvků se zachovají. Proto je bleskově rychlá.** +**Metoda `pop` nemusí nic posunovat, jelikož indexy ostatních prvků zůstanou zachovány. Proto je bleskově rychlá.** Podobně je tomu u metody `push`. @@ -352,9 +352,9 @@ Ve skutečnosti je to však špatný nápad. Mohou s ním nastat problémy: 1. Cyklus `for..in` prochází *všechny vlastnosti*, nejenom číselné. - V prohlížeči a v jiných prostředích jsou 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. + 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. 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 v úzkých hrdlech. Měli bychom si však být tohoto rozdílu vědomi. +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. Obecně bychom neměli `for..in` používat pro pole. @@ -401,9 +401,9 @@ let pole = *!*new Array*/!*("Jablko", "Hruška", "atd."); Používá se jen zřídka, protože hranaté závorky `[]` jsou kratší. Navíc má jednu ošidnou vlastnost. -Je-li `new Array` voláno s jediným argumentem, kterým je číslo, pak vytvoří pole *bez prvků, ale se zadanou délkou*. +Pokud `new Array` voláme s jediným argumentem, kterým je číslo, pak vytvoří pole *bez prvků, ale se zadanou délkou*. -Podívejme se, jak se můžeme snadno střelit do nohy: +Podívejme se, jak se můžeme snadno postřelit: ```js run let pole = new Array(2); // vznikne pole [2] ? @@ -413,11 +413,11 @@ alert( pole[0] ); // undefined! bez prvků. alert( pole.length ); // délka 2 ``` -Abychom předešli takovým překvapením, používáme zpravidla hranaté závorky, pokud opravdu dobře nevíme, co děláme. +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. ## Vícerozměrná pole -Pole mohou obsahovat prvky, které jsou také pole. To můžeme využít pro vícerozměrná pole, například pro ukládání matic: +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 matice = [ @@ -453,7 +453,7 @@ alert( [1,2] + 1 ); // "1,21" 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"`. -Když operátor binárního plus `"+"` přidává něco do řetězce, převede to také na řetězec, takže další krok vypadá následovně: +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" @@ -465,12 +465,12 @@ alert( "1,2" + 1 ); // "1,21" Pole v JavaScriptu, na rozdíl od jiných programovacích jazyků, by neměla být porovnávána operátorem `==`. -Tento operátor nezná žádné zvláštní zacházení s poli, pracuje s nimi jako s kterýmikoli jinými objekty. +Tento operátor neobsahuje žádné zvláštní zacházení s poli a pracuje s nimi jako s kterýmikoli jinými objekty. Připomeňme si pravidla: - 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 převeden na primitiv, jak bylo vysvětleno v kapitole . +- 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. Striktní porovnání `===` je ještě jednodušší, jelikož neprovádí typovou konverzi. @@ -524,7 +524,7 @@ let pole = new Array(prvek1, prvek2...); Volání `new Array(číslo)` vytvoří pole o zadané délce, ale bez prvků. -- Vlastnost `length` je délka pole nebo, abychom byli přesní, jeho poslední číselný index plus jedna. Metody pole ji automaticky aktualizují. +- 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. Získávání prvků: @@ -544,8 +544,8 @@ Cyklus procházející prvky pole: - `for (let prvek of pole)` -- moderní syntaxe výhradně pro prvky. - `for (let i in pole)` -- nepoužívat. -Pro porovnávání polí nepoužívejte operátor `==` (stejně jako `>`, `<` a jiné), jelikož tyto operátory neznají žádné zvláštní zacházení s poli. Zacházejí s nimi jako s objekty, což není obvykle to, co chceme. +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. -Místo toho můžeme použít cyklus `for..of` a porovnávat pole prvek po prvku. +Místo toho můžete použít cyklus `for..of` a porovnávat pole prvek po prvku. 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 From beff77b9aa6791b1b5c3c565f2d2adb027e51832 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Tue, 21 Jan 2025 22:57:10 +0100 Subject: [PATCH 20/55] 1.5.4 --- 04-array/1-item-value/solution.md | 17 + 04-array/1-item-value/task.md | 19 + .../10-maximal-subarray/_js.view/solution.js | 11 + 04-array/10-maximal-subarray/_js.view/test.js | 37 ++ 04-array/10-maximal-subarray/solution.md | 94 +++ 04-array/10-maximal-subarray/task.md | 30 + 04-array/2-create-array/solution.md | 10 + 04-array/2-create-array/task.md | 24 + 04-array/3-call-array-this/solution.md | 15 + 04-array/3-call-array-this/task.md | 18 + 04-array/5-array-input-sum/solution.md | 28 + 04-array/5-array-input-sum/task.md | 15 + 04-array/array-pop.svg | 1 + 04-array/array-shift.svg | 1 + 04-array/array-speed.svg | 1 + 04-array/article.md | 551 ++++++++++++++++++ 04-array/queue.svg | 1 + 04-array/stack.svg | 1 + 18 files changed, 874 insertions(+) create mode 100644 04-array/1-item-value/solution.md create mode 100644 04-array/1-item-value/task.md create mode 100644 04-array/10-maximal-subarray/_js.view/solution.js create mode 100644 04-array/10-maximal-subarray/_js.view/test.js create mode 100644 04-array/10-maximal-subarray/solution.md create mode 100644 04-array/10-maximal-subarray/task.md create mode 100644 04-array/2-create-array/solution.md create mode 100644 04-array/2-create-array/task.md create mode 100644 04-array/3-call-array-this/solution.md create mode 100644 04-array/3-call-array-this/task.md create mode 100644 04-array/5-array-input-sum/solution.md create mode 100644 04-array/5-array-input-sum/task.md create mode 100644 04-array/array-pop.svg create mode 100644 04-array/array-shift.svg create mode 100644 04-array/array-speed.svg create mode 100644 04-array/article.md create mode 100644 04-array/queue.svg create mode 100644 04-array/stack.svg diff --git a/04-array/1-item-value/solution.md b/04-array/1-item-value/solution.md new file mode 100644 index 000000000..037d070b3 --- /dev/null +++ b/04-array/1-item-value/solution.md @@ -0,0 +1,17 @@ +Výsledek je `4`: + + +```js run +let ovoce = ["Jablko", "Hruška", "Pomeranč"]; + +let nákupníKošík = ovoce; + +nákupníKošík.push("Banán"); + +*!* +alert( ovoce.length ); // 4 +*/!* +``` + +Je to tím, že pole jsou objekty. Proto jsou `nákupníKošík` i `ovoce` odkazy na totéž pole. + diff --git a/04-array/1-item-value/task.md b/04-array/1-item-value/task.md new file mode 100644 index 000000000..f942521f8 --- /dev/null +++ b/04-array/1-item-value/task.md @@ -0,0 +1,19 @@ +importance: 3 + +--- + +# Zkopíruje se pole? + +Co zobrazí tento kód? + +```js +let ovoce = ["Jablko", "Hruška", "Pomeranč"]; + +// přidáme do „kopie“ novou hodnotu +let nákupníKošík = ovoce; +nákupníKošík.push("Banán"); + +// co bude v poli ovoce? +alert( ovoce.length ); // ? +``` + diff --git a/04-array/10-maximal-subarray/_js.view/solution.js b/04-array/10-maximal-subarray/_js.view/solution.js new file mode 100644 index 000000000..8424068dc --- /dev/null +++ b/04-array/10-maximal-subarray/_js.view/solution.js @@ -0,0 +1,11 @@ +function vraťMaxSoučetPodpole(arr) { + let maxSoučet = 0; + let částečnýSoučet = 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 maxSoučet; +} \ No newline at end of file diff --git a/04-array/10-maximal-subarray/_js.view/test.js b/04-array/10-maximal-subarray/_js.view/test.js new file mode 100644 index 000000000..24a829435 --- /dev/null +++ b/04-array/10-maximal-subarray/_js.view/test.js @@ -0,0 +1,37 @@ +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("maximální podsoučet [-1, 2, 3, -9] se rovná 5", function() { + assert.equal(vraťMaxSoučetPodpole([-1, 2, 3, -9]), 5); + }); + + 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("maximální podsoučet [-2, -1, 1, 2] se rovná 3", function() { + assert.equal(vraťMaxSoučetPodpole([-2, -1, 1, 2]), 3); + }); + + 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("maximální podsoučet [] se rovná 0", function() { + assert.equal(vraťMaxSoučetPodpole([]), 0); + }); + + it("maximální podsoučet [-1] se rovná 0", function() { + assert.equal(vraťMaxSoučetPodpole([-1]), 0); + }); + + it("maximální podsoučet [-1, -2] se rovná 0", function() { + assert.equal(vraťMaxSoučetPodpole([-1, -2]), 0); + }); + + 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/04-array/10-maximal-subarray/solution.md b/04-array/10-maximal-subarray/solution.md new file mode 100644 index 000000000..279b93ec5 --- /dev/null +++ b/04-array/10-maximal-subarray/solution.md @@ -0,0 +1,94 @@ +# Pomalé řešení + +Můžeme spočítat všechny možné podsoučty. + +Nejjednodušším způsobem je vzít každý prvek a počítat součty všech podpolí, která jím začínají. + +Například pro `[-1, 2, 3, -9, 11]`: + +```js no-beautify +// Začínající -1: +-1 +-1 + 2 +-1 + 2 + 3 +-1 + 2 + 3 + (-9) +-1 + 2 + 3 + (-9) + 11 + +// Začínající 2: +2 +2 + 3 +2 + 3 + (-9) +2 + 3 + (-9) + 11 + +// Začínající 3: +3 +3 + (-9) +3 + (-9) + 11 + +// Začínající -9: +-9 +-9 + 11 + +// Začínající 11: +11 +``` + +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 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 maxSoučet; +} + +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 +``` + +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. + +Pro velká pole (1000, 10000 nebo více prvků) mohou takové algoritmy vést k vážnému zpomalení. + +# Rychlé řešení + +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`. + +Pokud je popis příliš vágní, prosíme nahlédněte do kódu, je dosti krátký: + +```js run demo +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 maxSoučet; +} + +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 +``` + +Tento algoritmus vyžaduje přesně 1 průchod polem, takže jeho časová složitost je O(n). + +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/04-array/10-maximal-subarray/task.md b/04-array/10-maximal-subarray/task.md new file mode 100644 index 000000000..8e6275ff6 --- /dev/null +++ b/04-array/10-maximal-subarray/task.md @@ -0,0 +1,30 @@ +importance: 2 + +--- + +# Maximální podpole + +Na vstupu je pole čísel, např. `pole = [1, -2, 3, 4, -9, 6]`. + +Úkol zní: najděte souvislé podpole tohoto pole s maximálním součtem prvků. + +Napište funkci `vraťMaxSoučetPodpole(pole)`, která tento součet vrátí. + +Příklad: + +```js +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) +``` + +Jsou-li všechny prvky záporné, znamená to, že nevezmeme žádný (podpole je prázdné), takže součet je nulový: + +```js +vraťMaxSoučetPodpole([-1, -2, -3]) = 0 +``` + +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/04-array/2-create-array/solution.md b/04-array/2-create-array/solution.md new file mode 100644 index 000000000..50d9a1f7d --- /dev/null +++ b/04-array/2-create-array/solution.md @@ -0,0 +1,10 @@ + + +```js run +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/04-array/2-create-array/task.md b/04-array/2-create-array/task.md new file mode 100644 index 000000000..177d1136a --- /dev/null +++ b/04-array/2-create-array/task.md @@ -0,0 +1,24 @@ +importance: 5 + +--- + +# Operace s poli + +Zkusme provést s polem 5 operací. + +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“. + +Pole během tohoto procesu: + +```js no-beautify +Jazz, Blues +Jazz, Blues, Rock-n-Roll +Jazz, Klasika, Rock-n-Roll +Klasika, Rock-n-Roll +Rap, Reggae, Klasika, Rock-n-Roll +``` + diff --git a/04-array/3-call-array-this/solution.md b/04-array/3-call-array-this/solution.md new file mode 100644 index 000000000..1cae6fc0b --- /dev/null +++ b/04-array/3-call-array-this/solution.md @@ -0,0 +1,15 @@ +Volání `pole[2]()` je syntakticky stará dobrá `obj[metoda]()`, v roli `obj` máme `pole` a v roli `metoda` máme `2`. + +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 pole = ["a", "b"]; + +pole.push(function() { + alert( this ); +}) + +pole[2](); // a,b,function(){...} +``` + +Toto pole má 3 hodnoty: na začátku mělo dvě, plus funkce. diff --git a/04-array/3-call-array-this/task.md b/04-array/3-call-array-this/task.md new file mode 100644 index 000000000..e349db367 --- /dev/null +++ b/04-array/3-call-array-this/task.md @@ -0,0 +1,18 @@ +importance: 5 + +--- + +# Volání v kontextu pole + +Jaký je výsledek? Proč? + +```js +let pole = ["a", "b"]; + +pole.push(function() { + alert( this ); +}); + +pole[2](); // ? +``` + diff --git a/04-array/5-array-input-sum/solution.md b/04-array/5-array-input-sum/solution.md new file mode 100644 index 000000000..112db1925 --- /dev/null +++ b/04-array/5-array-input-sum/solution.md @@ -0,0 +1,28 @@ +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 sečtiVstup() { + + let čísla = []; + + while (true) { + + let hodnota = prompt("Číslo, prosím?", 0); + + // měli bychom skončit? + if (hodnota === "" || hodnota === null || !isFinite(hodnota)) break; + + čísla.push(+hodnota); + } + + let součet = 0; + for (let číslo of čísla) { + součet += číslo; + } + return součet; +} + +alert( sečtiVstup() ); +``` + diff --git a/04-array/5-array-input-sum/task.md b/04-array/5-array-input-sum/task.md new file mode 100644 index 000000000..67180115b --- /dev/null +++ b/04-array/5-array-input-sum/task.md @@ -0,0 +1,15 @@ +importance: 4 + +--- + +# Sečtěte čísla na vstupu + +Napište funkci `sečtiVstup()`, která: + +- 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. Nula `0` je platné číslo, proto prosíme neukončujte vstup při nule. + +[demo] diff --git a/04-array/array-pop.svg b/04-array/array-pop.svg new file mode 100644 index 000000000..54e80c656 --- /dev/null +++ b/04-array/array-pop.svg @@ -0,0 +1 @@ +0123"Apple""Orange""Pear""Lemon"length = 4vymazat012"Apple""Orange""Pear"length = 3 \ No newline at end of file diff --git a/04-array/array-shift.svg b/04-array/array-shift.svg new file mode 100644 index 000000000..f82368324 --- /dev/null +++ b/04-array/array-shift.svg @@ -0,0 +1 @@ +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/04-array/array-speed.svg b/04-array/array-speed.svg new file mode 100644 index 000000000..41f7d998b --- /dev/null +++ b/04-array/array-speed.svg @@ -0,0 +1 @@ +0123popunshiftpushshift \ No newline at end of file diff --git a/04-array/article.md b/04-array/article.md new file mode 100644 index 000000000..216112a2f --- /dev/null +++ b/04-array/article.md @@ -0,0 +1,551 @@ +# Pole + +Objekty nám umožňují ukládat kolekci hodnot roztříděnou podle klíčů. To je pěkné. + +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ě. + +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. + +K uložení seřazených kolekcí však existuje speciální datová struktura nazvaná `Array`, česky „pole“. + +## Deklarace + +K vytvoření prázdného pole existují dvě syntaxe: + +```js +let pole = new Array(); +let pole = []; +``` + +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 ovoce = ["Jablko", "Pomeranč", "Švestka"]; +``` + +Prvky pole jsou očíslovány a začínají nulou. + +Získat prvek pole můžeme tak, že uvedeme jeho číslo v hranatých závorkách: + +```js run +let ovoce = ["Jablko", "Pomeranč", "Švestka"]; + +alert( ovoce[0] ); // Jablko +alert( ovoce[1] ); // Pomeranč +alert( ovoce[2] ); // Švestka +``` + +Můžeme nahradit prvek jiným: + +```js +ovoce[2] = 'Hruška'; // nyní ["Jablko", "Pomeranč", "Hruška"] +``` + +...Nebo přidat do pole nový prvek: + +```js +ovoce[3] = 'Citrón'; // nyní ["Jablko", "Pomeranč", "Hruška", "Citrón"] +``` + +Celkový počet prvků pole představuje jeho délku, která je uložena ve vlastnosti `length`: + +```js run +let ovoce = ["Jablko", "Pomeranč", "Švestka"]; + +alert( ovoce.length ); // 3 +``` + +Můžeme také použít `alert` k zobrazení celého pole. + +```js run +let ovoce = ["Jablko", "Pomeranč", "Švestka"]; + +alert( ovoce ); // Jablko,Pomeranč,Švestka +``` + +Do pole lze uložit prvky jakéhokoli typu. + +Například: + +```js run no-beautify +// směs hodnot +let pole = [ 'Jablko', { jméno: 'Jan' }, true, function() { alert('ahoj'); } ]; + +// získáme objekt na indexu 1 a zobrazíme jeho jméno +alert( pole[1].jméno ); // Jan + +// získáme funkci na indexu 3 a zavoláme ji +pole[3](); // ahoj +``` + + +````smart header="Vlečná čárka" +Pole, stejně jako objekt, může končit čárkou: +```js +let ovoce = [ + "Jablko", + "Pomeranč", + "Švestka"*!*,*/!* +]; +``` + +Styl „vlečné (trailing) čárky“ zjednodušuje přidávání a odstraňování prvků, protože všechny řádky vypadají podobně. +```` + +## Získání posledního prvku pomocí „at“ + +[recent browser="new"] + +Dejme tomu, že chceme získat poslední prvek pole. + +Některé programovací jazyky umožňují ke stejnému účelu použít záporné indexy, například `ovoce[-1]`. + +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. + +Můžeme výslovně vypočítat index posledního prvku a pak jej použít: `ovoce[ovoce.length - 1]`. + +```js run +let ovoce = ["Jablko", "Pomeranč", "Švestka"]; + +alert( ovoce[ovoce.length-1] ); // Švestka +``` + +Trochu těžkopádné, že? Musíme napsat název proměnné dvakrát. + +Naštěstí existuje kratší syntaxe: `ovoce.at(-1)`: + +```js run +let ovoce = ["Jablko", "Pomeranč", "Švestka"]; + +// totéž jako ovoce[ovoce.length-1] +alert( ovoce.at(-1) ); // Švestka +``` + +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. + +## Metody pop/push, shift/unshift + +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` připojí prvek na konec. +- `shift` vezme prvek ze začátku a posune frontu, takže druhý prvek se stane prvním. + +![](queue.svg) + +Pole podporují obě operace. + +V praxi ji potřebujeme velmi často. Máme například frontu zpráv, které musíme zobrazit na obrazovce. + +Dalším využitím polí je datová struktura nazvaná [zásobník](https://cs.wikipedia.org/wiki/Zásobník_(datová_struktura)). + +Podporuje dvě operace: + +- `push` přidá prvek na konec. +- `pop` vezme prvek z konce. + +Nové prvky se tedy vždy přidávají a odebírají z „konce“. + +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) + +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“). + +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. + +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“). + +**Metody, které pracují s koncem pole:** + +`pop` +: Vyjme z pole poslední prvek a vrátí jej: + + ```js run + let ovoce = ["Jablko", "Pomeranč", "Hruška"]; + + alert( ovoce.pop() ); // odstraní prvek "Hruška" a zobrazí jej + + alert( ovoce ); // Jablko, Pomeranč + ``` + + 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` +: Připojí prvek na konec pole: + + ```js run + let ovoce = ["Jablko", "Pomeranč"]; + + ovoce.push("Hruška"); + + alert( ovoce ); // Jablko, Pomeranč, Hruška + ``` + + Volání `ovoce.push(...)` se rovná volání `ovoce[ovoce.length] = ...`. + +**Metody, které pracují se začátkem pole:** + +`shift` +: Vyjme první prvek z pole a vrátí jej: + + ```js run + let ovoce = ["Jablko", "Pomeranč", "Hruška"]; + + alert( ovoce.shift() ); // odstraní prvek Jablko a zobrazí jej + + alert( ovoce ); // Pomeranč, Hruška + ``` + +`unshift` +: Přidá prvek na začátek pole: + + ```js run + let ovoce = ["Pomeranč", "Hruška"]; + + ovoce.unshift('Jablko'); + + alert( ovoce ); // Jablko, Pomeranč, Hruška + ``` + +Metody `push` a `unshift` mohou přidávat více prvků najednou: + +```js run +let ovoce = ["Jablko"]; + +ovoce.push("Pomeranč", "Broskev"); +ovoce.unshift("Ananas", "Citrón"); + +// ["Ananas", "Citrón", "Jablko", "Pomeranč", "Broskev"] +alert( ovoce ); +``` + +## Vnitřní reprezentace + +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. + +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. + +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. + +Například je kopírováno odkazem: + +```js run +let ovoce = ["Banán"] + +let pole = ovoce; // kopírování odkazem (dvě proměnné se odkazují na stejné pole) + +alert( pole === ovoce ); // true + +pole.push("Hruška"); // modifikace pole odkazem + +alert( ovoce ); // Banán, Hruška - nyní 2 prvky +``` + +...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. + +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. + +Například technicky můžeme udělat tohle: + +```js +let ovoce = []; // vytvoříme pole + +ovoce[99999] = 5; // přidáme vlastnost s indexem daleko větším, než jeho délka + +ovoce.věk = 25; // vytvoříme vlastnost s libovolným názvem +``` + +To je možné, protože pole jsou od základu objekty. Můžeme do nich přidávat jakékoli vlastnosti. + +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í. + +Způsoby nesprávného používání pole: + +- 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. + +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 `{}`. + +## Výkon + +Metody `push/pop` běží rychle, zatímco `shift/unshift` jsou pomalé. + +![](array-speed.svg) + +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 +ovoce.shift(); // odebere 1 prvek ze začátku +``` + +Nestačí vzít a odstranit prvek s indexem `0`. Je třeba také přečíslovat ostatní prvky. + +Operace `shift` musí provést 3 věci: + +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) + +**Čím více prvků pole obsahuje, tím více času a paměťových operací zabere jejich přesun.** + +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. + +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`. + +Akce pro operaci `pop`: + +```js +ovoce.pop(); // odebere 1 prvek z konce +``` + +![](array-pop.svg) + +**Metoda `pop` nemusí nic posunovat, jelikož indexy ostatních prvků zůstanou zachovány. Proto je bleskově rychlá.** + +Podobně je tomu u metody `push`. + +## Cykly + +Jeden z nejstarších způsobů, jak procházet prvky pole, je cyklus `for` nad jeho indexy: + +```js run +let pole = ["Jablko", "Pomeranč", "Hruška"]; + +*!* +for (let i = 0; i < pole.length; i++) { +*/!* + alert( pole[i] ); +} +``` + +Pro pole však existuje i jiná forma cyklu, `for..of`: + +```js run +let ovoce = ["Jablko", "Pomeranč", "Švestka"]; + +// prochází prvky pole +for (let jednoOvoce of ovoce) { + alert( jednoOvoce ); +} +``` + +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ší. + +Protože pole jsou objekty, je technicky možné použít i `for..in`: + +```js run +let pole = ["Jablko", "Pomeranč", "Hruška"]; + +*!* +for (let klíč in pole) { +*/!* + alert( pole[klíč] ); // Jablko, Pomeranč, Hruška +} +``` + +Ve skutečnosti je to však špatný nápad. Mohou s ním nastat problémy: + +1. Cyklus `for..in` prochází *všechny vlastnosti*, nejenom číselné. + + 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. 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. + +Obecně bychom neměli `for..in` používat pro pole. + + +## Něco o „length“ + +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. + +Například jediný prvek s velkým indexem způsobí, že `length` bude vysoká: + +```js run +let ovoce = []; +ovoce[123] = "Jablko"; + +alert( ovoce.length ); // 124 +``` + +Všimněte si, že pole obvykle takto nepoužíváme. + +Další zajímavostí na vlastnosti `length` je, že do ní lze zapisovat. + +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 pole = [1, 2, 3, 4, 5]; + +pole.length = 2; // zkrácení na 2 prvky +alert( pole ); // [1, 2] + +pole.length = 5; // vrátíme délku zpět +alert( pole[3] ); // undefined: hodnoty se nevrátily +``` + +Nejjednodušší způsob, jak pole vyčistit, je tedy `pole.length = 0;`. + + +## new Array() [#new-array] + +Existuje ještě jedna syntaxe, jak vytvořit pole: + +```js +let pole = *!*new Array*/!*("Jablko", "Hruška", "atd."); +``` + +Používá se jen zřídka, protože hranaté závorky `[]` jsou kratší. Navíc má jednu ošidnou vlastnost. + +Pokud `new Array` voláme s jediným argumentem, kterým je číslo, pak vytvoří pole *bez prvků, ale se zadanou délkou*. + +Podívejme se, jak se můžeme snadno postřelit: + +```js run +let pole = new Array(2); // vznikne pole [2] ? + +alert( pole[0] ); // undefined! bez prvků. + +alert( pole.length ); // délka 2 +``` + +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. + +## Vícerozměrná pole + +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 matice = [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9] +]; + +alert( matice[0][1] ); // 2, druhá hodnota prvního vnitřního pole +``` + +## toString + +Pole mají svou vlastní implementaci metody `toString`, která vrátí seznam prvků oddělených čárkou. + +Příklad: + + +```js run +let pole = [1, 2, 3]; + +alert( pole ); // 1,2,3 +alert( String(pole) === '1,2,3' ); // true +``` + +Zkuste také tohle: + +```js run +alert( [] + 1 ); // "1" +alert( [1] + 1 ); // "11" +alert( [1,2] + 1 ); // "1,21" +``` + +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"`. + +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" +alert( "1" + 1 ); // "11" +alert( "1,2" + 1 ); // "1,21" +``` + +## Neporovnávejte pole pomocí == + +Pole v JavaScriptu, na rozdíl od jiných programovacích jazyků, by neměla být porovnávána operátorem `==`. + +Tento operátor neobsahuje žádné zvláštní zacházení s poli a pracuje s nimi jako s kterýmikoli jinými objekty. + +Připomeňme si pravidla: + +- 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. + +Striktní porovnání `===` je ještě jednodušší, jelikož neprovádí typovou konverzi. + +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. + +Příklad: +```js run +alert( [] == [] ); // false +alert( [0] == [0] ); // false +``` + +Tato pole jsou technicky různé objekty. Proto si nejsou rovna. Operátor `==` neprovádí porovnání prvek po prvku. + +Také porovnání s primitivy mohou vydat zdánlivě podivné výsledky: + +```js run +alert( 0 == [] ); // true + +alert('0' == [] ); // false +``` + +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 `''`. + +Pak proces porovnávání pokračuje na primitivech, jak je popsáno v kapitole : + +```js run +// poté, co [] bylo konvertováno na '' +alert( 0 == '' ); // true, jelikož '' bude konvertováno na číslo 0 + +alert('0' == '' ); // false, žádná typová konverze, různé řetězce +``` + +Jak tedy porovnávat pole? + +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. + +## Shrnutí + +Pole je speciální druh objektu, uzpůsobený k ukládání a spravování seřazených datových prvků. + +Deklarace: + +```js +// hranaté závorky (obvyklé) +let pole = [prvek1, prvek2...]; + +// new Array (výjimečně vzácné) +let pole = new Array(prvek1, prvek2...); +``` + +Volání `new Array(číslo)` vytvoří pole o zadané délce, ale bez prvků. + +- 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. + +Získávání prvků: + +- 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]`. + +Pole můžeme používat jako deque (frontu s dvojitým koncem) s následujícími operacemi: + +- `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. + +Cyklus procházející prvky pole: + - `for (let i=0; i`, `<` 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. + +Místo toho můžete použít cyklus `for..of` a porovnávat pole prvek po prvku. + +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/04-array/queue.svg b/04-array/queue.svg new file mode 100644 index 000000000..e89a3dcd2 --- /dev/null +++ b/04-array/queue.svg @@ -0,0 +1 @@ +pushshift \ No newline at end of file diff --git a/04-array/stack.svg b/04-array/stack.svg new file mode 100644 index 000000000..ae0c474d0 --- /dev/null +++ b/04-array/stack.svg @@ -0,0 +1 @@ +pushpop \ No newline at end of file From 7b540e43dc6124432b5cf795f0a9a34ecc5c1932 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Wed, 22 Jan 2025 20:57:43 +0100 Subject: [PATCH 21/55] 04-array wrong directory deleted --- 04-array/1-item-value/solution.md | 17 - 04-array/1-item-value/task.md | 19 - .../10-maximal-subarray/_js.view/solution.js | 11 - 04-array/10-maximal-subarray/_js.view/test.js | 37 -- 04-array/10-maximal-subarray/solution.md | 94 --- 04-array/10-maximal-subarray/task.md | 30 - 04-array/2-create-array/solution.md | 10 - 04-array/2-create-array/task.md | 24 - 04-array/3-call-array-this/solution.md | 15 - 04-array/3-call-array-this/task.md | 18 - 04-array/5-array-input-sum/solution.md | 28 - 04-array/5-array-input-sum/task.md | 15 - 04-array/array-pop.svg | 1 - 04-array/array-shift.svg | 1 - 04-array/array-speed.svg | 1 - 04-array/article.md | 551 ------------------ 04-array/queue.svg | 1 - 04-array/stack.svg | 1 - 18 files changed, 874 deletions(-) delete mode 100644 04-array/1-item-value/solution.md delete mode 100644 04-array/1-item-value/task.md delete mode 100644 04-array/10-maximal-subarray/_js.view/solution.js delete mode 100644 04-array/10-maximal-subarray/_js.view/test.js delete mode 100644 04-array/10-maximal-subarray/solution.md delete mode 100644 04-array/10-maximal-subarray/task.md delete mode 100644 04-array/2-create-array/solution.md delete mode 100644 04-array/2-create-array/task.md delete mode 100644 04-array/3-call-array-this/solution.md delete mode 100644 04-array/3-call-array-this/task.md delete mode 100644 04-array/5-array-input-sum/solution.md delete mode 100644 04-array/5-array-input-sum/task.md delete mode 100644 04-array/array-pop.svg delete mode 100644 04-array/array-shift.svg delete mode 100644 04-array/array-speed.svg delete mode 100644 04-array/article.md delete mode 100644 04-array/queue.svg delete mode 100644 04-array/stack.svg diff --git a/04-array/1-item-value/solution.md b/04-array/1-item-value/solution.md deleted file mode 100644 index 037d070b3..000000000 --- a/04-array/1-item-value/solution.md +++ /dev/null @@ -1,17 +0,0 @@ -Výsledek je `4`: - - -```js run -let ovoce = ["Jablko", "Hruška", "Pomeranč"]; - -let nákupníKošík = ovoce; - -nákupníKošík.push("Banán"); - -*!* -alert( ovoce.length ); // 4 -*/!* -``` - -Je to tím, že pole jsou objekty. Proto jsou `nákupníKošík` i `ovoce` odkazy na totéž pole. - diff --git a/04-array/1-item-value/task.md b/04-array/1-item-value/task.md deleted file mode 100644 index f942521f8..000000000 --- a/04-array/1-item-value/task.md +++ /dev/null @@ -1,19 +0,0 @@ -importance: 3 - ---- - -# Zkopíruje se pole? - -Co zobrazí tento kód? - -```js -let ovoce = ["Jablko", "Hruška", "Pomeranč"]; - -// přidáme do „kopie“ novou hodnotu -let nákupníKošík = ovoce; -nákupníKošík.push("Banán"); - -// co bude v poli ovoce? -alert( ovoce.length ); // ? -``` - diff --git a/04-array/10-maximal-subarray/_js.view/solution.js b/04-array/10-maximal-subarray/_js.view/solution.js deleted file mode 100644 index 8424068dc..000000000 --- a/04-array/10-maximal-subarray/_js.view/solution.js +++ /dev/null @@ -1,11 +0,0 @@ -function vraťMaxSoučetPodpole(arr) { - let maxSoučet = 0; - let částečnýSoučet = 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 maxSoučet; -} \ No newline at end of file diff --git a/04-array/10-maximal-subarray/_js.view/test.js b/04-array/10-maximal-subarray/_js.view/test.js deleted file mode 100644 index 24a829435..000000000 --- a/04-array/10-maximal-subarray/_js.view/test.js +++ /dev/null @@ -1,37 +0,0 @@ -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("maximální podsoučet [-1, 2, 3, -9] se rovná 5", function() { - assert.equal(vraťMaxSoučetPodpole([-1, 2, 3, -9]), 5); - }); - - 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("maximální podsoučet [-2, -1, 1, 2] se rovná 3", function() { - assert.equal(vraťMaxSoučetPodpole([-2, -1, 1, 2]), 3); - }); - - 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("maximální podsoučet [] se rovná 0", function() { - assert.equal(vraťMaxSoučetPodpole([]), 0); - }); - - it("maximální podsoučet [-1] se rovná 0", function() { - assert.equal(vraťMaxSoučetPodpole([-1]), 0); - }); - - it("maximální podsoučet [-1, -2] se rovná 0", function() { - assert.equal(vraťMaxSoučetPodpole([-1, -2]), 0); - }); - - 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/04-array/10-maximal-subarray/solution.md b/04-array/10-maximal-subarray/solution.md deleted file mode 100644 index 279b93ec5..000000000 --- a/04-array/10-maximal-subarray/solution.md +++ /dev/null @@ -1,94 +0,0 @@ -# Pomalé řešení - -Můžeme spočítat všechny možné podsoučty. - -Nejjednodušším způsobem je vzít každý prvek a počítat součty všech podpolí, která jím začínají. - -Například pro `[-1, 2, 3, -9, 11]`: - -```js no-beautify -// Začínající -1: --1 --1 + 2 --1 + 2 + 3 --1 + 2 + 3 + (-9) --1 + 2 + 3 + (-9) + 11 - -// Začínající 2: -2 -2 + 3 -2 + 3 + (-9) -2 + 3 + (-9) + 11 - -// Začínající 3: -3 -3 + (-9) -3 + (-9) + 11 - -// Začínající -9: --9 --9 + 11 - -// Začínající 11: -11 -``` - -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 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 maxSoučet; -} - -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 -``` - -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. - -Pro velká pole (1000, 10000 nebo více prvků) mohou takové algoritmy vést k vážnému zpomalení. - -# Rychlé řešení - -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`. - -Pokud je popis příliš vágní, prosíme nahlédněte do kódu, je dosti krátký: - -```js run demo -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 maxSoučet; -} - -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 -``` - -Tento algoritmus vyžaduje přesně 1 průchod polem, takže jeho časová složitost je O(n). - -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/04-array/10-maximal-subarray/task.md b/04-array/10-maximal-subarray/task.md deleted file mode 100644 index 8e6275ff6..000000000 --- a/04-array/10-maximal-subarray/task.md +++ /dev/null @@ -1,30 +0,0 @@ -importance: 2 - ---- - -# Maximální podpole - -Na vstupu je pole čísel, např. `pole = [1, -2, 3, 4, -9, 6]`. - -Úkol zní: najděte souvislé podpole tohoto pole s maximálním součtem prvků. - -Napište funkci `vraťMaxSoučetPodpole(pole)`, která tento součet vrátí. - -Příklad: - -```js -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) -``` - -Jsou-li všechny prvky záporné, znamená to, že nevezmeme žádný (podpole je prázdné), takže součet je nulový: - -```js -vraťMaxSoučetPodpole([-1, -2, -3]) = 0 -``` - -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/04-array/2-create-array/solution.md b/04-array/2-create-array/solution.md deleted file mode 100644 index 50d9a1f7d..000000000 --- a/04-array/2-create-array/solution.md +++ /dev/null @@ -1,10 +0,0 @@ - - -```js run -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/04-array/2-create-array/task.md b/04-array/2-create-array/task.md deleted file mode 100644 index 177d1136a..000000000 --- a/04-array/2-create-array/task.md +++ /dev/null @@ -1,24 +0,0 @@ -importance: 5 - ---- - -# Operace s poli - -Zkusme provést s polem 5 operací. - -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“. - -Pole během tohoto procesu: - -```js no-beautify -Jazz, Blues -Jazz, Blues, Rock-n-Roll -Jazz, Klasika, Rock-n-Roll -Klasika, Rock-n-Roll -Rap, Reggae, Klasika, Rock-n-Roll -``` - diff --git a/04-array/3-call-array-this/solution.md b/04-array/3-call-array-this/solution.md deleted file mode 100644 index 1cae6fc0b..000000000 --- a/04-array/3-call-array-this/solution.md +++ /dev/null @@ -1,15 +0,0 @@ -Volání `pole[2]()` je syntakticky stará dobrá `obj[metoda]()`, v roli `obj` máme `pole` a v roli `metoda` máme `2`. - -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 pole = ["a", "b"]; - -pole.push(function() { - alert( this ); -}) - -pole[2](); // a,b,function(){...} -``` - -Toto pole má 3 hodnoty: na začátku mělo dvě, plus funkce. diff --git a/04-array/3-call-array-this/task.md b/04-array/3-call-array-this/task.md deleted file mode 100644 index e349db367..000000000 --- a/04-array/3-call-array-this/task.md +++ /dev/null @@ -1,18 +0,0 @@ -importance: 5 - ---- - -# Volání v kontextu pole - -Jaký je výsledek? Proč? - -```js -let pole = ["a", "b"]; - -pole.push(function() { - alert( this ); -}); - -pole[2](); // ? -``` - diff --git a/04-array/5-array-input-sum/solution.md b/04-array/5-array-input-sum/solution.md deleted file mode 100644 index 112db1925..000000000 --- a/04-array/5-array-input-sum/solution.md +++ /dev/null @@ -1,28 +0,0 @@ -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 sečtiVstup() { - - let čísla = []; - - while (true) { - - let hodnota = prompt("Číslo, prosím?", 0); - - // měli bychom skončit? - if (hodnota === "" || hodnota === null || !isFinite(hodnota)) break; - - čísla.push(+hodnota); - } - - let součet = 0; - for (let číslo of čísla) { - součet += číslo; - } - return součet; -} - -alert( sečtiVstup() ); -``` - diff --git a/04-array/5-array-input-sum/task.md b/04-array/5-array-input-sum/task.md deleted file mode 100644 index 67180115b..000000000 --- a/04-array/5-array-input-sum/task.md +++ /dev/null @@ -1,15 +0,0 @@ -importance: 4 - ---- - -# Sečtěte čísla na vstupu - -Napište funkci `sečtiVstup()`, která: - -- 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. Nula `0` je platné číslo, proto prosíme neukončujte vstup při nule. - -[demo] diff --git a/04-array/array-pop.svg b/04-array/array-pop.svg deleted file mode 100644 index 54e80c656..000000000 --- a/04-array/array-pop.svg +++ /dev/null @@ -1 +0,0 @@ -0123"Apple""Orange""Pear""Lemon"length = 4vymazat012"Apple""Orange""Pear"length = 3 \ No newline at end of file diff --git a/04-array/array-shift.svg b/04-array/array-shift.svg deleted file mode 100644 index f82368324..000000000 --- a/04-array/array-shift.svg +++ /dev/null @@ -1 +0,0 @@ -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/04-array/array-speed.svg b/04-array/array-speed.svg deleted file mode 100644 index 41f7d998b..000000000 --- a/04-array/array-speed.svg +++ /dev/null @@ -1 +0,0 @@ -0123popunshiftpushshift \ No newline at end of file diff --git a/04-array/article.md b/04-array/article.md deleted file mode 100644 index 216112a2f..000000000 --- a/04-array/article.md +++ /dev/null @@ -1,551 +0,0 @@ -# Pole - -Objekty nám umožňují ukládat kolekci hodnot roztříděnou podle klíčů. To je pěkné. - -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ě. - -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. - -K uložení seřazených kolekcí však existuje speciální datová struktura nazvaná `Array`, česky „pole“. - -## Deklarace - -K vytvoření prázdného pole existují dvě syntaxe: - -```js -let pole = new Array(); -let pole = []; -``` - -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 ovoce = ["Jablko", "Pomeranč", "Švestka"]; -``` - -Prvky pole jsou očíslovány a začínají nulou. - -Získat prvek pole můžeme tak, že uvedeme jeho číslo v hranatých závorkách: - -```js run -let ovoce = ["Jablko", "Pomeranč", "Švestka"]; - -alert( ovoce[0] ); // Jablko -alert( ovoce[1] ); // Pomeranč -alert( ovoce[2] ); // Švestka -``` - -Můžeme nahradit prvek jiným: - -```js -ovoce[2] = 'Hruška'; // nyní ["Jablko", "Pomeranč", "Hruška"] -``` - -...Nebo přidat do pole nový prvek: - -```js -ovoce[3] = 'Citrón'; // nyní ["Jablko", "Pomeranč", "Hruška", "Citrón"] -``` - -Celkový počet prvků pole představuje jeho délku, která je uložena ve vlastnosti `length`: - -```js run -let ovoce = ["Jablko", "Pomeranč", "Švestka"]; - -alert( ovoce.length ); // 3 -``` - -Můžeme také použít `alert` k zobrazení celého pole. - -```js run -let ovoce = ["Jablko", "Pomeranč", "Švestka"]; - -alert( ovoce ); // Jablko,Pomeranč,Švestka -``` - -Do pole lze uložit prvky jakéhokoli typu. - -Například: - -```js run no-beautify -// směs hodnot -let pole = [ 'Jablko', { jméno: 'Jan' }, true, function() { alert('ahoj'); } ]; - -// získáme objekt na indexu 1 a zobrazíme jeho jméno -alert( pole[1].jméno ); // Jan - -// získáme funkci na indexu 3 a zavoláme ji -pole[3](); // ahoj -``` - - -````smart header="Vlečná čárka" -Pole, stejně jako objekt, může končit čárkou: -```js -let ovoce = [ - "Jablko", - "Pomeranč", - "Švestka"*!*,*/!* -]; -``` - -Styl „vlečné (trailing) čárky“ zjednodušuje přidávání a odstraňování prvků, protože všechny řádky vypadají podobně. -```` - -## Získání posledního prvku pomocí „at“ - -[recent browser="new"] - -Dejme tomu, že chceme získat poslední prvek pole. - -Některé programovací jazyky umožňují ke stejnému účelu použít záporné indexy, například `ovoce[-1]`. - -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. - -Můžeme výslovně vypočítat index posledního prvku a pak jej použít: `ovoce[ovoce.length - 1]`. - -```js run -let ovoce = ["Jablko", "Pomeranč", "Švestka"]; - -alert( ovoce[ovoce.length-1] ); // Švestka -``` - -Trochu těžkopádné, že? Musíme napsat název proměnné dvakrát. - -Naštěstí existuje kratší syntaxe: `ovoce.at(-1)`: - -```js run -let ovoce = ["Jablko", "Pomeranč", "Švestka"]; - -// totéž jako ovoce[ovoce.length-1] -alert( ovoce.at(-1) ); // Švestka -``` - -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. - -## Metody pop/push, shift/unshift - -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` připojí prvek na konec. -- `shift` vezme prvek ze začátku a posune frontu, takže druhý prvek se stane prvním. - -![](queue.svg) - -Pole podporují obě operace. - -V praxi ji potřebujeme velmi často. Máme například frontu zpráv, které musíme zobrazit na obrazovce. - -Dalším využitím polí je datová struktura nazvaná [zásobník](https://cs.wikipedia.org/wiki/Zásobník_(datová_struktura)). - -Podporuje dvě operace: - -- `push` přidá prvek na konec. -- `pop` vezme prvek z konce. - -Nové prvky se tedy vždy přidávají a odebírají z „konce“. - -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) - -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“). - -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. - -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“). - -**Metody, které pracují s koncem pole:** - -`pop` -: Vyjme z pole poslední prvek a vrátí jej: - - ```js run - let ovoce = ["Jablko", "Pomeranč", "Hruška"]; - - alert( ovoce.pop() ); // odstraní prvek "Hruška" a zobrazí jej - - alert( ovoce ); // Jablko, Pomeranč - ``` - - 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` -: Připojí prvek na konec pole: - - ```js run - let ovoce = ["Jablko", "Pomeranč"]; - - ovoce.push("Hruška"); - - alert( ovoce ); // Jablko, Pomeranč, Hruška - ``` - - Volání `ovoce.push(...)` se rovná volání `ovoce[ovoce.length] = ...`. - -**Metody, které pracují se začátkem pole:** - -`shift` -: Vyjme první prvek z pole a vrátí jej: - - ```js run - let ovoce = ["Jablko", "Pomeranč", "Hruška"]; - - alert( ovoce.shift() ); // odstraní prvek Jablko a zobrazí jej - - alert( ovoce ); // Pomeranč, Hruška - ``` - -`unshift` -: Přidá prvek na začátek pole: - - ```js run - let ovoce = ["Pomeranč", "Hruška"]; - - ovoce.unshift('Jablko'); - - alert( ovoce ); // Jablko, Pomeranč, Hruška - ``` - -Metody `push` a `unshift` mohou přidávat více prvků najednou: - -```js run -let ovoce = ["Jablko"]; - -ovoce.push("Pomeranč", "Broskev"); -ovoce.unshift("Ananas", "Citrón"); - -// ["Ananas", "Citrón", "Jablko", "Pomeranč", "Broskev"] -alert( ovoce ); -``` - -## Vnitřní reprezentace - -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. - -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. - -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. - -Například je kopírováno odkazem: - -```js run -let ovoce = ["Banán"] - -let pole = ovoce; // kopírování odkazem (dvě proměnné se odkazují na stejné pole) - -alert( pole === ovoce ); // true - -pole.push("Hruška"); // modifikace pole odkazem - -alert( ovoce ); // Banán, Hruška - nyní 2 prvky -``` - -...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. - -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. - -Například technicky můžeme udělat tohle: - -```js -let ovoce = []; // vytvoříme pole - -ovoce[99999] = 5; // přidáme vlastnost s indexem daleko větším, než jeho délka - -ovoce.věk = 25; // vytvoříme vlastnost s libovolným názvem -``` - -To je možné, protože pole jsou od základu objekty. Můžeme do nich přidávat jakékoli vlastnosti. - -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í. - -Způsoby nesprávného používání pole: - -- 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. - -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 `{}`. - -## Výkon - -Metody `push/pop` běží rychle, zatímco `shift/unshift` jsou pomalé. - -![](array-speed.svg) - -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 -ovoce.shift(); // odebere 1 prvek ze začátku -``` - -Nestačí vzít a odstranit prvek s indexem `0`. Je třeba také přečíslovat ostatní prvky. - -Operace `shift` musí provést 3 věci: - -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) - -**Čím více prvků pole obsahuje, tím více času a paměťových operací zabere jejich přesun.** - -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. - -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`. - -Akce pro operaci `pop`: - -```js -ovoce.pop(); // odebere 1 prvek z konce -``` - -![](array-pop.svg) - -**Metoda `pop` nemusí nic posunovat, jelikož indexy ostatních prvků zůstanou zachovány. Proto je bleskově rychlá.** - -Podobně je tomu u metody `push`. - -## Cykly - -Jeden z nejstarších způsobů, jak procházet prvky pole, je cyklus `for` nad jeho indexy: - -```js run -let pole = ["Jablko", "Pomeranč", "Hruška"]; - -*!* -for (let i = 0; i < pole.length; i++) { -*/!* - alert( pole[i] ); -} -``` - -Pro pole však existuje i jiná forma cyklu, `for..of`: - -```js run -let ovoce = ["Jablko", "Pomeranč", "Švestka"]; - -// prochází prvky pole -for (let jednoOvoce of ovoce) { - alert( jednoOvoce ); -} -``` - -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ší. - -Protože pole jsou objekty, je technicky možné použít i `for..in`: - -```js run -let pole = ["Jablko", "Pomeranč", "Hruška"]; - -*!* -for (let klíč in pole) { -*/!* - alert( pole[klíč] ); // Jablko, Pomeranč, Hruška -} -``` - -Ve skutečnosti je to však špatný nápad. Mohou s ním nastat problémy: - -1. Cyklus `for..in` prochází *všechny vlastnosti*, nejenom číselné. - - 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. 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. - -Obecně bychom neměli `for..in` používat pro pole. - - -## Něco o „length“ - -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. - -Například jediný prvek s velkým indexem způsobí, že `length` bude vysoká: - -```js run -let ovoce = []; -ovoce[123] = "Jablko"; - -alert( ovoce.length ); // 124 -``` - -Všimněte si, že pole obvykle takto nepoužíváme. - -Další zajímavostí na vlastnosti `length` je, že do ní lze zapisovat. - -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 pole = [1, 2, 3, 4, 5]; - -pole.length = 2; // zkrácení na 2 prvky -alert( pole ); // [1, 2] - -pole.length = 5; // vrátíme délku zpět -alert( pole[3] ); // undefined: hodnoty se nevrátily -``` - -Nejjednodušší způsob, jak pole vyčistit, je tedy `pole.length = 0;`. - - -## new Array() [#new-array] - -Existuje ještě jedna syntaxe, jak vytvořit pole: - -```js -let pole = *!*new Array*/!*("Jablko", "Hruška", "atd."); -``` - -Používá se jen zřídka, protože hranaté závorky `[]` jsou kratší. Navíc má jednu ošidnou vlastnost. - -Pokud `new Array` voláme s jediným argumentem, kterým je číslo, pak vytvoří pole *bez prvků, ale se zadanou délkou*. - -Podívejme se, jak se můžeme snadno postřelit: - -```js run -let pole = new Array(2); // vznikne pole [2] ? - -alert( pole[0] ); // undefined! bez prvků. - -alert( pole.length ); // délka 2 -``` - -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. - -## Vícerozměrná pole - -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 matice = [ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9] -]; - -alert( matice[0][1] ); // 2, druhá hodnota prvního vnitřního pole -``` - -## toString - -Pole mají svou vlastní implementaci metody `toString`, která vrátí seznam prvků oddělených čárkou. - -Příklad: - - -```js run -let pole = [1, 2, 3]; - -alert( pole ); // 1,2,3 -alert( String(pole) === '1,2,3' ); // true -``` - -Zkuste také tohle: - -```js run -alert( [] + 1 ); // "1" -alert( [1] + 1 ); // "11" -alert( [1,2] + 1 ); // "1,21" -``` - -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"`. - -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" -alert( "1" + 1 ); // "11" -alert( "1,2" + 1 ); // "1,21" -``` - -## Neporovnávejte pole pomocí == - -Pole v JavaScriptu, na rozdíl od jiných programovacích jazyků, by neměla být porovnávána operátorem `==`. - -Tento operátor neobsahuje žádné zvláštní zacházení s poli a pracuje s nimi jako s kterýmikoli jinými objekty. - -Připomeňme si pravidla: - -- 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. - -Striktní porovnání `===` je ještě jednodušší, jelikož neprovádí typovou konverzi. - -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. - -Příklad: -```js run -alert( [] == [] ); // false -alert( [0] == [0] ); // false -``` - -Tato pole jsou technicky různé objekty. Proto si nejsou rovna. Operátor `==` neprovádí porovnání prvek po prvku. - -Také porovnání s primitivy mohou vydat zdánlivě podivné výsledky: - -```js run -alert( 0 == [] ); // true - -alert('0' == [] ); // false -``` - -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 `''`. - -Pak proces porovnávání pokračuje na primitivech, jak je popsáno v kapitole : - -```js run -// poté, co [] bylo konvertováno na '' -alert( 0 == '' ); // true, jelikož '' bude konvertováno na číslo 0 - -alert('0' == '' ); // false, žádná typová konverze, různé řetězce -``` - -Jak tedy porovnávat pole? - -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. - -## Shrnutí - -Pole je speciální druh objektu, uzpůsobený k ukládání a spravování seřazených datových prvků. - -Deklarace: - -```js -// hranaté závorky (obvyklé) -let pole = [prvek1, prvek2...]; - -// new Array (výjimečně vzácné) -let pole = new Array(prvek1, prvek2...); -``` - -Volání `new Array(číslo)` vytvoří pole o zadané délce, ale bez prvků. - -- 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. - -Získávání prvků: - -- 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]`. - -Pole můžeme používat jako deque (frontu s dvojitým koncem) s následujícími operacemi: - -- `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. - -Cyklus procházející prvky pole: - - `for (let i=0; i`, `<` 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. - -Místo toho můžete použít cyklus `for..of` a porovnávat pole prvek po prvku. - -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/04-array/queue.svg b/04-array/queue.svg deleted file mode 100644 index e89a3dcd2..000000000 --- a/04-array/queue.svg +++ /dev/null @@ -1 +0,0 @@ -pushshift \ No newline at end of file diff --git a/04-array/stack.svg b/04-array/stack.svg deleted file mode 100644 index ae0c474d0..000000000 --- a/04-array/stack.svg +++ /dev/null @@ -1 +0,0 @@ -pushpop \ No newline at end of file From fb992433ab10284a80bc181665ff20445d3adae5 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Thu, 23 Jan 2025 21:48:39 +0100 Subject: [PATCH 22/55] 1.5.5 --- .../1-camelcase/_js.view/solution.js | 4 +- .../05-array-methods/1-camelcase/task.md | 2 +- .../11-array-unique/_js.view/solution.js | 6 +- .../11-array-unique/solution.md | 12 ++-- .../05-array-methods/11-array-unique/task.md | 2 +- .../_js.view/solution.js | 2 +- .../6-array-get-names/task.md | 2 +- .../_js.view/solution.js | 4 +- .../6-calculator-extendable/task.md | 4 +- .../05-array-methods/7-map-objects/task.md | 6 +- .../05-array-methods/9-shuffle/solution.md | 10 +-- .../05-data-types/05-array-methods/article.md | 72 +++++++++---------- .../05-data-types/05-array-methods/reduce.svg | 2 +- 13 files changed, 64 insertions(+), 64 deletions(-) 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 a73eda419..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,5 +1,5 @@ -function camelizace(str) { - return str +function camelizace(řetězec) { + return řetězec .split('-') // rozdělí 'mé-dlouhé-slovo' na pole ['mé', 'dlouhé', 'slovo'] .map( // převede první písmena všech prvků pole kromě prvního na velká 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 ca41ec884..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 @@ -4,7 +4,7 @@ importance: 5 # Změňte border-left-width na borderLeftWidth -Napište funkci `camelizace(str)`, která změní slova oddělená pomlčkou, např. „můj-krátký-řetězec“, na velbloudí notaci „můjKrátkýŘetězec“. +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“. To znamená, že odstraní všechny pomlčky a u všech slov za pomlčkami změní první písmeno na velké. 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 258caedd0..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,9 +1,9 @@ function unikát(pole) { let výsledek = []; - for (let str of pole) { - if (!výsledek.includes(str)) { - výsledek.push(str); + for (let řetězec of pole) { + if (!výsledek.includes(řetězec)) { + výsledek.push(řetězec); } } 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 b29f90904..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 @@ -6,9 +6,9 @@ Projděme si prvky pole: function unikát(pole) { let výsledek = []; - for (let str of pole) { - if (!výsledek.includes(str)) { - výsledek.push(str); + for (let řetězec of pole) { + if (!výsledek.includes(řetězec)) { + výsledek.push(řetězec); } } @@ -24,11 +24,11 @@ alert( unikát(řetězce) ); // Haré, Kršna, :-O Tento kód funguje, ale má potenciální problém s výkonem. -Metoda `výsledek.includes(str)` interně prochází pole `výsledek` a porovná každý jeho prvek se `str`, aby našla shodu. +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. -Jestliže tedy v poli `výsledek` je `100` prvků a žádný se nerovná `str`, 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í. +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í. -To samo o sobě není problém, jelikož JavaScriptové enginy jsou velmi rychlé, takže projít pole `10000` prvků je otázkou mikrosekund. +To samo o sobě není problém, jelikož JavaScriptové motory jsou velmi rychlé, takže projít pole `10000` prvků je otázkou mikrosekund. My však provádíme takový test pro každý prvek `pole` v cyklu `for`. 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 857950989..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 @@ -6,7 +6,7 @@ importance: 4 Nechť `pole` je nějaké pole. -Vytvořte funkci `unikát(pole)`, která vrátí pole s unikátními prvky `pole`. +Vytvořte funkci `unikát(pole)`, která vrátí pole obsahující všechny různé prvky `pole`. Příklad: 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 5b94b6541..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,5 +1,5 @@ -function filtrujPodleRozsahuNaMístě(arr, a, b) { +function filtrujPodleRozsahuNaMístě(pole, a, b) { for (let i = 0; i < pole.length; i++) { let hodnota = pole[i]; 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 10f166445..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 @@ -4,7 +4,7 @@ importance: 5 # Mapování na jména -Máte pole objektů `uživatel`, každý z nich má `uživatel.jméno`. Napište kód, který je převede na pole jmen. +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. Příklad: 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 462f7fec6..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 @@ -5,9 +5,9 @@ function Kalkulátor() { "+": (a, b) => a + b }; - this.vypočítej = 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]; 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 7e7dd7899..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 @@ -9,7 +9,7 @@ Vytvořte konstruktor `Kalkulátor`, který bude vytvářet „rozšiřitelné Úloha se skládá ze dvou částí. -1. Nejprve implementujte metodu `vypočítej(str)`, 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 `-`. +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í: @@ -18,7 +18,7 @@ Vytvořte konstruktor `Kalkulátor`, který bude vytvářet „rozšiřitelné alert( kalkulátor.vypočítej("3 + 7") ); // 10 ``` -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. +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. Například přidáme násobení`*`, dělení `/` a umocňování `**`: 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 c4b87c52a..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 @@ -4,9 +4,9 @@ importance: 5 # Mapování na objekty -Máme pole objektů `uživatel`, každý z nich má `jméno`, `příjmení` a `id`. +Máme pole objektů `uživatel`, každý z nich má vlastnosti `jméno`, `příjmení` a `id`. -Napište kód, který z něj vytvoří jiné pole, které bude obsahovat objekty s `id` a `celéJméno`, kde `celéJméno` se vygeneruje ze `jméno` a `příjmení`. +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í`. Příklad: @@ -33,4 +33,4 @@ alert( mapovaníUživatelé[0].id ) // 1 alert( mapovaníUživatelé[0].celéJméno ) // Jan Novák ``` -Ve skutečnosti tedy potřebujete namapovat jedno pole objektů na druhé. Zkuste zde použít `=>`. Je tady malý chyták. \ 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/9-shuffle/solution.md b/1-js/05-data-types/05-array-methods/9-shuffle/solution.md index 65964664a..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 @@ -16,7 +16,7 @@ To jakžtakž funguje, protože `Math.random() - 0.5` je náhodné číslo, kter Protože však řadicí funkce není určena k takovému použití, nebudou mít všechny permutace stejnou pravděpodobnost. -Například uvažujte níže uvedený kód. Spustí `zamíchej` 1000000krát a spočítá výskyty všech možných výsledků: +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 zamíchej(pole) { @@ -45,7 +45,7 @@ for (let klíč in počty) { } ``` -Příklad výsledku (závisí na enginu JS): +Příklad výsledku (závisí na motoru JavaScriptu): ```js 123: 250706 @@ -58,9 +58,9 @@ Příklad výsledku (závisí na enginu JS): Jasně vidíme odchylku: `123` a `213` se objevují mnohem častěji než ostatní. -Výsledek kódu se může u jednotlivých JavaScriptových enginů lišit, ale už vidíme, že tento přístup je nespolehlivý. +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ý. -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 enginy liší. +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ší. 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: @@ -70,7 +70,7 @@ function zamíchej(pole) { let j = Math.floor(Math.random() * (i + 1)); // náhodný index od 0 do i // vyměníme prvky pole[i] a pole[j] - // k dosažení tohoto použijeme syntaxi „destrukturačního přiřazení“ + // 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 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 7d095b2a8..cfcb28ddf 100644 --- a/1-js/05-data-types/05-array-methods/article.md +++ b/1-js/05-data-types/05-array-methods/article.md @@ -6,10 +6,10 @@ Pole poskytují mnoho metod. Pro zjednodušení jsme je v této kapitole rozděl Známe už metody, které přidávají a odebírají prvky na začátku nebo na konci pole: -- `arr.push(...prvky)` -- přidává prvky na konec, -- `arr.pop()` -- vybírá prvek z konce, -- `arr.shift()` -- vybírá prvek ze začátku, -- `arr.unshift(...items)` -- přidává prvky na začátek. +- `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. Zde uvedeme několik dalších. @@ -90,7 +90,7 @@ Metoda `splice` dokáže také vkládat prvky bez odstraňování. Toho dosáhne let pole = ["Já", "studuji", "JavaScript"]; // od indexu 2 -// smažeme 0 +// smažeme 0 prvků // pak vložíme "složitý" a "jazyk" pole.splice(2, 0, "složitý", "jazyk"); @@ -122,7 +122,7 @@ Syntaxe je: pole.slice([začátek], [konec]) ``` -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 předpokládá pozice od konce pole. +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. Podobá se řetězcové metodě `str.slice`, ale místo podřetězců vytváří podpole. @@ -136,7 +136,7 @@ alert( pole.slice(1, 3) ); // e,s (kopíruje od 1 do 3) alert( pole.slice(-2) ); // s,t (kopíruje od -2 do konce) ``` -Můžeme ji volat i bez argumentů: `pole.slice()` vytvoří kopii `pole`. To se často používá k vytvoření kopie pro další transformace, které by neměly ovlivnit původní pole. +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 @@ -217,7 +217,7 @@ Například tohle zobrazí každý prvek pole: ["Bilbo", "Gandalf", "Nazgúl"].forEach(alert); ``` -A tento kód vypíše podrobnosti o pozicích prvků v cílovém poli: +A tento kód podrobně vypíše pozice prvků v cílovém poli: ```js run ["Bilbo", "Gandalf", "Nazgúl"].forEach((prvek, index, pole) => { @@ -225,7 +225,7 @@ A tento kód vypíše podrobnosti o pozicích prvků v cílovém poli: }); ``` -Výsledek funkce (pokud funkce nějaký vrátí) je zahozen a ignorován. +Pokud funkce vrátí nějaký výsledek, je zahozen a ignorován. ## Hledání v poli @@ -257,7 +257,7 @@ Prosíme všimněte si, že metoda `indexOf` používá striktní porovnávání 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`. -Metoda [arr.lastIndexOf](mdn:js/Array/lastIndexOf) je totéž jako `indexOf`, ale hledá zprava doleva. +Metoda [pole.lastIndexOf](mdn:js/Array/lastIndexOf) je totéž jako `indexOf`, ale hledá zprava doleva. ```js run let ovoce = ['Jablko', 'Pomeranč', 'Jablko'] @@ -267,14 +267,14 @@ alert( ovoce.lastIndexOf('Jablko') ); // 2 (poslední Jablko) ``` ````smart header="Metoda `includes` zpracovává správně `NaN`" -Drobný, ale zaznamenatelný rozdíl metody `includes` je také v tom, že na rozdíl od `indexOf` správně zpracovává `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 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ě) ``` -Je to proto, že metohda `includes` byla do JavaScriptu přidána mnohem později a interně používá aktuálnější algoritmus porovnávání. +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 a findIndex/findLastIndex @@ -291,7 +291,7 @@ let výsledek = pole.find(function(prvek, index, pole) { }); ``` -Funkce je volána na prvcích pole, na jednom po druhém: +Funkce je volána na prvcích pole postupně na jednom za druhým: - `prvek` je prvek. - `index` je jeho index. @@ -342,7 +342,7 @@ alert(uživatelé.findLastIndex(uživatel => uživatel.jméno == 'Jan')); // 3 Metoda `find` najde jediný (první) prvek, který způsobí, že funkce vrátí `true`. -Jestliže jich může být více, můžeme použít metodu [pole.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). Její syntaxe je podobná `find`, ale `filter` vrací pole všech odpovídajících prvků: @@ -374,7 +374,7 @@ Přejděme nyní k metodám, které pole transformují a přeskupují. ### map -Metoda [pole.map](mdn:js/Array/map) je jedna z nejužitečnějších a používá se často. +Metoda [pole.map](mdn:js/Array/map) je jedna z nejužitečnějších a nejčastěji používaných. Volá zadanou funkci pro každý prvek pole a vrací pole výsledků. @@ -416,7 +416,7 @@ Seřazené pole je `1, 15, 2`. To není správně. Ale proč? **Prvky jsou standardně řazeny jako řetězce.** -Doslova všechny prvky 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"`. +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"`. Abychom použili naše vlastní řazení, musíme jako argument `pole.sort()` poskytnout funkci. @@ -452,7 +452,7 @@ Nyní to funguje tak, jak jsme zamýšleli. 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é. -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ý [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í. +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í. Mimochodem, jestliže chceme vědět, které prvky se porovnávají -- nic nám nebrání je zobrazit: @@ -480,7 +480,7 @@ alert(pole); // *!*1, 2, 15*/!* ```` ````smart header="Nejlepší jsou šipkové funkce" -Vzpomínáte si na [šipkové funkce](info:arrow-functions-basics)? Můžeme je zde použít pro úhlednější řazení: +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 pole.sort( (a, b) => a - b ); @@ -492,7 +492,7 @@ Funguje to přesně stejně jako výše uvedená delší verze. ````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ů. -Pro mnoho abeced je lepší používat metodu `str.localeCompare`, která seřadí správně písmena, např. `Č`. +Pro mnoho abeced je lepší používat metodu `řetězec.localeCompare`, která seřadí správně písmena, např. `Č`. Například seřaďme několik států v češtině: @@ -518,15 +518,15 @@ pole.reverse(); alert( pole ); // 5,4,3,2,1 ``` -I ona vrací `pole` po převrácení. +I ona vrací převrácené `pole`. ### split a join 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? -Přesně tohle dělá metoda [str.split(oddělovač)](mdn:js/String/split), která rozdělí řetězec na pole podle zadaného oddělovače `oddělovač`. +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č`. -V níže uvedeném příkladu jsme oddělovali čárkou, po níž následuje mezera: +V níže uvedeném příkladu oddělujeme čárkou, po níž následuje mezera: ```js run let jména = 'Bilbo, Gandalf, Nazgúl'; @@ -550,22 +550,22 @@ alert(pole); // Bilbo, Gandalf 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 ``` ```` -Volání [pole.join(spojka)](mdn:js/Array/join) provádí opak metody `split`. Vytvoří řetězec z prvků `pole`, které budou spojeny řetězcem `spojka` mezi nimi. +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`. Příklad: ```js run let pole = ['Bilbo', 'Gandalf', 'Nazgúl']; -let str = pole.join(';'); // spojíme pole do řetězce pomocí ; +let řetězec = pole.join(';'); // spojíme pole do řetězce pomocí ; -alert( str ); // Bilbo;Gandalf;Nazgúl +alert( řetězec ); // Bilbo;Gandalf;Nazgúl ``` ### reduce/reduceRight @@ -574,7 +574,7 @@ Když potřebujeme procházet prvky pole -- můžeme použít `forEach`, `for` n Když potřebujeme procházet prvky a pro každý prvek vrátit nějaká data -- můžeme použít `map`. -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 v závislosti na poli. +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. Syntaxe je: @@ -584,7 +584,7 @@ let hodnota = pole.reduce(function(akumulátor, prvek, index, pole) { }, [počátečníHodnota]); ``` -Funkce se volá na všech prvcích pole za sebou a „přenáší“ svůj výsledek do dalšího volání. +Funkce se volá postupně na všech prvcích pole a svůj výsledek „přenáší“ do dalšího volání. Argumenty: @@ -616,10 +616,10 @@ Funkce předaná do `reduce` používá jen 2 argumenty, to zpravidla stačí. Podívejme se na podrobnosti toho, co se děje. 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 tomu 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 tomu další prvek, a tak dále... +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... -Tok výpočtu: +Průběh výpočtu: ![](reduce.svg) @@ -733,7 +733,7 @@ alert(vojáci[1].věk); // 23 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ě. -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 druhá varianta se používá častěji, jelikož pro většinu lidí je trochu srozumitelnější. +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ší. ## Shrnutí @@ -746,7 +746,7 @@ Přehled metod polí: - `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ýkoli prvek z `prvky` pole, pak se vezmou jeho prvky. + - `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. - 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. @@ -775,7 +775,7 @@ Tyto metody jsou nejpoužívanější a v 99% případů dostačují. Existuje v 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`. - Tyto metody se chovají trochu 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ů. + 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: @@ -793,7 +793,7 @@ Tyto metody jsou nejpoužívanější a v 99% případů dostačují. Existuje v - [pole.flat(hloubka)](mdn:js/Array/flat)/[pole.flatMap(fn)](mdn:js/Array/flatMap) vytvoří nové jednorozměrné pole z vícerozměrného. -Pro úplný seznam viz [manuál](mdn:js/Array). +Pro úplný seznam nahlédněte do [manuálu](mdn:js/Array). 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ší. diff --git a/1-js/05-data-types/05-array-methods/reduce.svg b/1-js/05-data-types/05-array-methods/reduce.svg index 180941dc2..7e8ce79cd 100644 --- a/1-js/05-data-types/05-array-methods/reduce.svg +++ b/1-js/05-data-types/05-array-methods/reduce.svg @@ -1 +1 @@ -1sum 0 current 12sum 0+1 current 23sum 0+1+2 current 34sum 0+1+2+3 current 45sum 0+1+2+3+4 current 50+1+2+3+4+5 = 15 \ No newline at end of file +1součet 0 aktuální 12součet 0+1 aktuální 23součet 0+1+2 aktuální 34součet 0+1+2+3 aktuální 45součet 0+1+2+3+4 aktuální 50+1+2+3+4+5 = 15 \ No newline at end of file From bb35211824910ea2e479ee5337f7b94202e56318 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Sat, 25 Jan 2025 16:42:46 +0100 Subject: [PATCH 23/55] 1.5.6 --- 1-js/05-data-types/06-iterable/article.md | 94 +++++++++++------------ 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/1-js/05-data-types/06-iterable/article.md b/1-js/05-data-types/06-iterable/article.md index d79e99e9e..aaa7d4b6a 100644 --- a/1-js/05-data-types/06-iterable/article.md +++ b/1-js/05-data-types/06-iterable/article.md @@ -4,7 +4,7 @@ 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é. -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 rozběhnout. +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 @@ -16,32 +16,32 @@ Například máme objekt, který sice není pole, ale zdá se být vhodný pro ` Třeba objekt `rozsah`, který představuje interval čísel: ```js -let interval = { +let rozsah = { začátek: 1, konec: 5 }; // Chceme, aby for..of fungovalo: -// for(let číslo of interval) ... číslo=1,2,3,4,5 +// for(let číslo of rozsah) ... číslo=1,2,3,4,5 ``` -Abychom učinili objekt `interval` 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). +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. 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. -Zde je úplná implementace objektu `interval` s komentáři: +Zde je úplná implementace objektu `rozsah` s komentáři: ```js run -let interval = { +let rozsah = { začátek: 1, konec: 5 }; // 1. volání for..of nejprve zavolá tuto funkci -interval[Symbol.iterator] = function() { +rozsah[Symbol.iterator] = function() { // ...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 @@ -62,24 +62,24 @@ interval[Symbol.iterator] = function() { }; // teď to funguje! -for (let číslo of interval) { +for (let číslo of rozsah) { alert(číslo); // 1, pak 2, 3, 4, 5 } ``` Prosíme všimněte si důležité vlastnosti iterovatelných objektů: jednotlivé záležitosti jsou odděleny. -- Sám objekt `interval` nemá metodu `next()`. -- Místo toho se voláním `interval[Symbol.iterator]()` vytvoří jiný objekt, tzv. „iterátor“, a hodnoty pro iteraci generuje jeho metoda `next()`. +- 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()`. Objekt iterátoru je tedy oddělen od objektu, nad nímž se iteruje. -Technicky je můžeme spojit a použít jako iterátor samotný `interval`, abychom kód zjednodušili. +Technicky je můžeme spojit a použít jako iterátor samotný `rozsah`, abychom kód zjednodušili. Třeba takto: ```js run -let interval = { +let rozsah = { začátek: 1, konec: 5, @@ -97,21 +97,21 @@ let interval = { } }; -for (let číslo of interval) { +for (let číslo of rozsah) { alert(číslo); // 1, pak 2, 3, 4, 5 } ``` -Nyní `interval[Symbol.iterator]()` vrátí samotný objekt `interval`: ten obsahuje potřebnou metodu `next()` a pamatuje si aktuální krok iterace v `this.current`. Je to kratší? Ano. A někdy je to i vhodné. +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é. -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. +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="Nekonečné iterátory" -Nekonečné iterátory jsou rovněž možné. Například `interval` se stane nekonečným pro `interval.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ý. +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ý. Na metodu `next` nejsou kladena žádná omezení, může vracet další a další hodnoty, to je normální. -Samozřejmě cyklus `for..of` nad takovým iterovatelným objektem by byl nekonečný. Vždy ho však můžeme zastavit pomocí `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`. ``` @@ -119,7 +119,7 @@ Samozřejmě cyklus `for..of` nad takovým iterovatelným objektem by byl nekone Nejčastěji používané iterovatelné objekty jsou pole a řetězce. -U řetězce `for..of` prochází jeho znaky: +U řetězce cyklus `for..of` prochází jeho znaky: ```js run for (let znak of "test") { @@ -128,11 +128,11 @@ for (let znak of "test") { } ``` -Funguje to korektně i se surrogate pairy! +Funguje to korektně i se zástupnými páry! ```js run -let str = '𝒳😂'; -for (let znak of str) { +let řetězec = '𝒳😂'; +for (let znak of řetězec) { alert( znak ); // 𝒳, a pak 😂 } ``` @@ -144,13 +144,13 @@ Abychom tomu hlouběji porozuměli, podíváme se, jak použít iterátor explic 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 = "Ahoj"; +let řetězec = "Ahoj"; // provádí totéž jako -// for (let znak of str) alert(znak); +// for (let znak of řetězec) alert(znak); *!* -let iterator = str[Symbol.iterator](); +let iterator = řetězec[Symbol.iterator](); */!* while (true) { @@ -160,14 +160,14 @@ while (true) { } ``` -Tohle potřebujeme jen vzácně, ale dává nám to 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. +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. -## Iterovatelné objekty a polím podobné objekty [#array-like] +## Iterovatelné objekty a objekty podobné polím [#array-like] 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. - *Iterovatelné objekty* jsou objekty, které implementují metodu `Symbol.iterator`, jak je popsáno výše. -- *Polím podobné objekty* jsou objekty, které mají indexy a vlastnost `length` (délku), takže vypadají jako pole. +- *Objekty podobné polím (array-like)* jsou objekty, které mají indexy a vlastnost `length` (délku), takže vypadají jako pole. 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í. @@ -175,7 +175,7 @@ Například řetězce jsou jak iterovatelné (funguje na nich `for..of`), tak po Iterovatelný objekt však nemusí být podobný poli. A naopak, objekt podobný poli nemusí být iterovatelný. -Například `interval` ve výše uvedeném příkladu je iterovatelný, ale ne podobný poli, jelikož nemá indexované vlastnosti a `length`. +Například `rozsah` ve výše uvedeném příkladu je iterovatelný, ale ne podobný poli, jelikož nemá indexované vlastnosti a `length`. A zde je objekt, který je podobný poli, ale ne iterovatelný: @@ -192,7 +192,7 @@ for (let prvek of objektPodobnýPoli) {} */!* ``` -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 `interval` pomocí metod polí. Jak toho docílit? +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 @@ -218,25 +218,25 @@ alert(pole.pop()); // světe (metoda funguje) Pro iterovatelný objekt se děje totéž: ```js run -// předpokládáme interval z výše uvedeného příkladu -let pole = Array.from(interval); +// 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) ``` -Úplná syntaxe pro `Array.from` nám také umožňuje poskytnout nepovinnou „mapovací“ funkci: +Úplná syntaxe `Array.from` nám také umožňuje poskytnout nepovinnou „mapovací“ funkci: ```js Array.from(obj[, mapFn, thisArg]) ``` -Volitelný 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`. +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`. Příklad: ```js run -// předpokládáme interval z výše uvedeného příkladu +// předpokládáme, že rozsah vezmeme z výše uvedeného příkladu // každé číslo umocníme na druhou -let pole = Array.from(interval, číslo => číslo * číslo); +let pole = Array.from(rozsah, číslo => číslo * číslo); alert(pole); // 1,4,9,16,25 ``` @@ -244,25 +244,25 @@ alert(pole); // 1,4,9,16,25 Zde pomocí `Array.from` přetvoříme řetězec na pole znaků: ```js run -let str = '𝒳😂'; +let řetězec = '𝒳😂'; -// rozdělí str na pole znaků -let znaky = Array.from(str); +// rozdělí řetězec na pole znaků +let znaky = Array.from(řetězec); alert(znaky[0]); // 𝒳 alert(znaky[1]); // 😂 alert(znaky.length); // 2 ``` -Na rozdíl od `str.split` tato metoda využívá iterovatelnou povahu řetězce, a proto, stejně jako `for..of`, funguje korektně se surrogate pairy. +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. Technicky zde provádí totéž jako: ```js run -let str = '𝒳😂'; +let řetězec = '𝒳😂'; let znaky = []; // Array.from interně vykonává stejný cyklus -for (let znak of str) { +for (let znak of řetězec) { znaky.push(znak); } @@ -271,7 +271,7 @@ alert(znaky); ...Ale je to kratší. -Můžeme na ní dokonce postavit metodu `slice`, která bude rozpoznávat surrogate pairy: +Můžeme na ní dokonce postavit metodu `slice`, která bude rozpoznávat zástupné páry: ```js run function slice(řetězec, začátek, konec) { @@ -282,8 +282,8 @@ let řetězec = '𝒳😂𩷶'; alert( slice(řetězec, 1, 3) ); // 😂𩷶 -// nativní metoda nepodporuje surrogate pairy -alert( řetězec.slice(1, 3) ); // nesmysly (dvě části z různých surrogate pairů) +// 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ů) ``` @@ -291,14 +291,14 @@ alert( řetězec.slice(1, 3) ); // nesmysly (dvě části z různých surrogate Objekty, které lze použít ve `for..of`, se nazývají *iterovatelné*. -- Technicky musejí iterovatelné objekty implementovat metodu nazvanou `Symbol.iterator`. +- 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á surrogate pairy. +- Řetězcový iterátor rozpoznává zástupné páry. -Objekty, které mají indexované vlastnosti a vlastnost `length`, se nazývají *polím podobné*. Takové objekty mohou mít i jiné vlastnosti a metody, ale postrádají vestavěné metody polí. +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í. 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ší. From 4019096e2ebd615978b7c243da9b10cffddeda44 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Sat, 25 Jan 2025 18:07:57 +0100 Subject: [PATCH 24/55] 1.5.7 --- .../07-map-set/01-array-unique-map/task.md | 2 +- .../07-map-set/02-filter-anagrams/solution.md | 8 +- .../07-map-set/02-filter-anagrams/task.md | 2 +- .../07-map-set/03-iterable-keys/task.md | 2 +- 1-js/05-data-types/07-map-set/article.md | 86 +++++++++---------- 5 files changed, 50 insertions(+), 50 deletions(-) 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 940545a92..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 @@ -6,7 +6,7 @@ importance: 5 Nechť `pole` je nějaké pole. -Vytvořte funkci `unikát(pole)`, která vrátí pole s unikátními prvky `pole`. +Vytvořte funkci `unikát(pole)`, která vrátí pole obsahující všechny různé prvky `pole`. Příklad: 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 b6aa84482..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,4 +1,4 @@ -Pro nalezení anagramů rozdělíme každé slovo na písmena a ta seřadíme. Po seřazení písmen budou všechny anagramy stejné. +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é. Příklad: @@ -9,7 +9,7 @@ reklama, makrela, karamel -> aaeklmr ... ``` -Varianty se seřazenými písmeny použijeme jako klíče mapy, abychom uložili pro každý klíč jen jednu hodnotu: +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 odstraňAnagramy(pole) { @@ -51,9 +51,9 @@ Další řádek vloží slovo do mapy: mapa.set(seřazené, slovo); ``` -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 formu písmen nejvýše jedno slovo. +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. -Nakonec `Array.from(mapa.values())` vezme iterovatelný objekt nad hodnotami mapy (klíče ve výsledku nepotřebujeme), vytvoří z něj pole a vrátí je. +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. Zde bychom mohli místo `Map` použít i planý objekt, neboť klíče jsou řetězce. 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 bd138c35c..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 @@ -4,7 +4,7 @@ importance: 4 # Filtrace anagramů -[Anagramy](https://cs.wikipedia.org/wiki/Anagram) neboli přesmyčky jsou slova, která obsahují stejná písmena ve stejných počtech, ale v jiném pořadí. +[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í. Příklad: 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 16773d280..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 @@ -4,7 +4,7 @@ importance: 5 # Iterovatelné klíče -Chtěli bychom uložit pole klíčů mapy `mapa.keys()` do proměnné a pak na ně používat metody polí, např. `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`. Tohle však nefunguje: 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 135775057..280451b38 100644 --- a/1-js/05-data-types/07-map-set/article.md +++ b/1-js/05-data-types/07-map-set/article.md @@ -2,7 +2,7 @@ Prozatím jsme se naučili dvěma následujícím složitým datovým strukturám: -- Objekty se používají k ukládání klíčovaných kolekcí. +- 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í. Pro skutečný život to však nestačí. Proto existují také `Map` (mapa) a `Set` (množina). @@ -13,35 +13,35 @@ Pro skutečný život to však nestačí. Proto existují také `Map` (mapa) a ` Její metody a vlastnosti jsou: -- `new Map()` -- vytvoří mapu. -- [`mapa.set(klíč, hodnota)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/Map) -- uloží hodnotu pod klíčem. -- [`mapa.get(klíč)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set) -- vrátí hodnotu podle klíče, 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íč` existuje, jinak `false`. -- [`mapa.delete(klíč)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete) -- odstraní prvek (dvojici klíč/hodnota) podle zadaného klíče. -- [`mapa.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear) -- odstraní z mapy všechny hodnoty. -- [`mapa.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) -- 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ů. Příklad: ```js run let mapa = new Map(); -mapa.set('1', 'str1'); // řetězcový klíč -mapa.set(1, 'num1'); // číselný klíč -mapa.set(true, 'bool1'); // booleovský klíč +mapa.set('1', 'řetězec1'); // řetězcový klíč +mapa.set(1, 'číslo1'); // číselný klíč +mapa.set(true, 'bool1'); // booleovský klíč // 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) ); // 'num1' -alert( mapa.get('1') ); // 'str1' +alert( mapa.get(1) ); // 'číslo1' +alert( mapa.get('1') ); // 'řetězec1' alert( mapa.size ); // 3 ``` -Jak vidíme, na rozdíl od objektů zde nejsou klíče převáděny na řetězce. Je povolen jakýkoli typ klíče. +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="`mapa[klíč]` není správný způsob, jak používat mapu" -Ačkoli `mapa[klíč]` funguje také, např. můžeme nastavit `mapa[klíč] = 2`, zachází s mapou jako s planým JavaScriptovým objektem, takže pro něj platí všechna příslušná omezení (jen řetězcové/symbolické klíče a podobně). +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ě). Měli bychom tedy používat metody mapy: `set`, `get` a tak dále. ``` @@ -81,10 +81,10 @@ alert( objPočetNávštěv["[object Object]"] ); // 123 */!* ``` -Jelikož `objPočetNávštěv` je objekt, převede všechny klíče typu `Object`, např. výše uvedené `jan` a `ben`, na stejný řetězec `"[object Object]"`. To rozhodně není to, co jsme chtěli. +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="Jak `Map` porovnává klíče" -Pro testování ekvivalence klíčů `Map` používá algoritmus [SameValueZero](https://tc39.github.io/ecma262/#sec-samevaluezero). Je to zhruba totéž 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`. +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`. Tento algoritmus nemůžeme změnit nebo si ho přizpůsobit. ``` @@ -93,8 +93,8 @@ Tento algoritmus nemůžeme změnit nebo si ho přizpůsobit. Každé volání `mapa.set` vrátí samotnou mapu, takže volání můžeme „zřetězit“: ```js -mapa.set('1', 'str1') - .set(1, 'num1') +mapa.set('1', 'řetězec1') + .set(1, 'číslo1') .set(true, 'bool1'); ``` ```` @@ -147,17 +147,17 @@ mapaRecepty.forEach( (hodnota, klíč, mapa) => { ## Object.entries: mapa z objektu -Když je vytvořena mapa, můžeme do ní při inicializaci předat pole (nebo jiný iterovatelný objekt) dvojic klíč/hodnota, například: +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 // pole dvojic [klíč, hodnota] let mapa = new Map([ - ['1', 'str1'], - [1, 'num1'], + ['1', 'řetězec1'], + [1, 'číslo1'], [true, 'bool1'] ]); -alert( mapa.get('1') ); // str1 +alert( mapa.get('1') ); // řetězec1 ``` 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. @@ -236,13 +236,13 @@ Množina [`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Referen Její hlavní metody jsou: - [`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, 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, vrátí `true`, jestliže `hodnota` v okamžiku volání 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 v množině existuje, jinak `false`. +- [`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. -Hlavní vlastností množiny je, že opakovaná volání `množina.add(hodnota)` se stejnou hodnotou nic neprovedou. To je důvod, proč se každá hodnota v množině objeví pouze jednou. +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. 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. @@ -270,7 +270,7 @@ for (let uživatel of množina) { } ``` -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í [arr.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. +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. ## Iterace nad množinou @@ -287,14 +287,14 @@ množina.forEach((hodnota, hodnotaZnovu, množina) => { }); ``` -Všimněte si něčeho legračního. Funkce zpětného volání 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. +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. -To slouží ke kompatibilitě s `Map`, v níž zpětné volání 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. +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. -Rovněž jsou podporovány stejné metody, jaké má `Map` pro iterovatelné objekty: +Množina také poskytuje stejné metody, jaké má `Map` pro iterátory: - [`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()`, kvůli kompatibilitě s `Map`, +- [`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`. ## Shrnutí @@ -304,27 +304,27 @@ Rovněž jsou podporovány stejné metody, jaké má `Map` pro iterovatelné obj Metody a vlastnosti: - [`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 pod klíčem, vrátí samotnou mapu. -- [`mapa.get(klíč)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get) -- vrátí hodnotu podle klíče, 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íč` existuje, jinak `false`. -- [`mapa.delete(klíč)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete) -- odstraní prvek podle zadaného klíče, vrátí `true`, jestliže `klíč` v okamžiku volání existoval, jinak `false`. -- [`mapa.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear) -- odstraní z mapy všechny hodnoty. +- [`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ů. Rozdíly oproti běžnému objektu: -- Klíče mohou být libovolné včetně objektů. -- Další příhodné metody, vlastnost `size`. +- 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) -- je kolekce unikátních hodnot. Metody a vlastnosti: - [`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 (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, vrátí `true`, jestliže `hodnota` v okamžiku volání 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 v množině existuje, jinak `false`. +- [`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. -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 podle jeho pořadí. \ No newline at end of file +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 From bb0d0ddf472f3442d6a15eb00288fd0f9e7e7fdf Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Sat, 25 Jan 2025 20:14:39 +0100 Subject: [PATCH 25/55] 1.5.8 --- .../01-recipients-read/solution.md | 6 +- .../01-recipients-read/task.md | 2 +- .../02-recipients-when-read/task.md | 2 +- .../08-weakmap-weakset/article.md | 72 +++++++++---------- 4 files changed, 41 insertions(+), 41 deletions(-) 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 d54db7298..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 @@ -4,7 +4,7 @@ Uložme přečtené zprávy do `WeakSet`: let zprávy = [ {text: "Ahoj", od: "Jan"}, {text: "Jak se máš?", od: "Jan"}, - {text: "Brzy se uvidíme", od: "Alice"} + {text: "Brzy nashle", od: "Alice"} ]; let přečtenéZprávy = new WeakSet(); @@ -27,9 +27,9 @@ zprávy.shift(); `WeakSet` nám umožňuje uložit množinu zpráv a snadno ověřovat, zda v ní zpráva existuje. -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é nejsou v této množině. +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ě. -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. Protože objekty zpráv spravuje jiný kód, obecně se to nedoporučuje, ale můžeme se vyhnout konfliktům použitím symbolické vlastnosti. +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. Třeba takto: ```js 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 fd43af70c..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 @@ -10,7 +10,7 @@ Máme pole zpráv: let zprávy = [ {text: "Ahoj", od: "Jan"}, {text: "Jak se máš?", od: "Jan"}, - {text: "Brzy se uvidíme", od: "Alice"} + {text: "Brzy nashle", od: "Alice"} ]; ``` 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 cec811065..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 @@ -16,6 +16,6 @@ let zprávy = [ Otázka teď zní: kterou datovou strukturu byste doporučili k uložení informace „kdy byla zpráva přečtena“? -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 garbage collectorem. +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. 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 8ea784e10..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,7 +1,7 @@ # Slabá mapa a slabá množina -Jak víme z kapitoly , engine JavaScriptu si udržuje hodnotu v paměti, dokud je „dosažitelná“ a může být použita. +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. Příklad: @@ -33,12 +33,12 @@ jan = null; // přepíšeme odkaz *!* // objekt, na který se dříve odkazoval jan, je uložen uvnitř pole -// proto nebude odklizen garbage collectorem +// proto nebude odklizen sběračem odpadků // můžeme k němu přistoupit pomocí pole[0] */!* ``` -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 garbage collectorem. +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ů. Příklad: @@ -101,9 +101,9 @@ Srovnejte si to s výše uvedeným příkladem běžné mapy `Map`. Když nyní - [`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) -Proč takové omezení? Je tomu tak z technických důvodů. Pokud objekt ztratil všechny ostatní odkazy (např. `jan` ve výše uvedeném kódu), má být automaticky odstraněn garbage collectorem. Technicky však není přesně specifikováno, *kdy k odstranění dojde*. +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*. -O tom rozhoduje JavaScriptový engine. 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ž dojde k dalšímu mazání. Technicky tedy není znám momentální počet prvků `WeakMap`. Engine 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. +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. K čemu nyní takovou datovou strukturu potřebujeme? @@ -113,7 +113,7 @@ Hlavní oblastí použití `WeakMap` je *úložiště dodatečných dat*. 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. -Uložíme data do `WeakMap` a tento objekt použijeme jako klíč. Když bude objekt odklizen garbage collectorem, data automaticky zmizí s ním. +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 slabáMapa.set(jan, "tajné dokumenty"); @@ -122,12 +122,12 @@ slabáMapa.set(jan, "tajné dokumenty"); Podívejme se na příklad. -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 garbage collectorem), nechceme již nadále mít počet jeho návštěv uložen. +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. -Zde je příklad počítací funkce s `Map`. +Zde je příklad počítací funkce s `Map`: ```js -// 📁 visitsCount.js +// 📁 početNávštěv.js let mapaPočetNávštěv = new Map(); // mapa: uživatel => počet návštěv // zvýší počet návštěv @@ -137,10 +137,10 @@ function započítejUživatele(uživatel) { } ``` -A zde je další část kódu, třeba další soubor, který ji používá: +A zde je další část kódu, třeba další soubor, který tuto funkci používá: ```js -// 📁 main.js +// 📁 hlavní.js let jan = { jméno: "Jan" }; započítejUživatele(jan); // počet jeho návštěv @@ -151,12 +151,12 @@ jan = null; 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`. -Když tedy odstraňujeme uživatele, musíme `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. +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. Můžeme se tomu vyhnout, když použijeme `WeakMap`: ```js -// 📁 visitsCount.js +// 📁 početNávštěv.js let mapaPočetNávštěv = new WeakMap(); // slabá mapa: uživatel => počet návštěv // zvýší počet návštěv @@ -166,71 +166,71 @@ function započítejUživatele(uživatel) { } ``` -Nyní nemusíme čistit `mapaPočetNávštěv`. 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`. +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`. -## Případ použití: cache +## Případ použití: mezipaměť -Dalším běžným příkladem je cache. Můžeme si ukládat do paměti (tato paměť se nazývá „cache“) výsledky funkce, abychom je mohli znovu použít při jejích dalších voláních na témže objektu. +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. 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(); // vypočítá a zapamatuje si výsledek function proces(obj) { - if (!cache.has(obj)) { + if (!mezipaměť.has(obj)) { let výsledek = /* výpočet výsledku pro */ obj; - cache.set(obj, výsledek); + mezipaměť.set(obj, výsledek); return výsledek; } - return cache.get(obj); + return mezipaměť.get(obj); } *!* // Nyní použijeme proces() v jiném souboru: */!* -// 📁 main.js +// 📁 hlavní.js let obj = {/* řekněme, že máme nějaký objekt */}; let výsledek1 = proces(obj); // vypočteno // ...později z jiného místa kódu... -let výsledek2 = proces(obj); // vezmeme z cache výsledek, který si pamatujeme +let výsledek2 = proces(obj); // vezmeme z mezipaměti výsledek, který si pamatujeme // ...později, když už tento objekt nebudeme potřebovat: obj = null; -alert(cache.size); // 1 (Ouha! Objekt je stále v cache a zabírá paměť!) +alert(mezipaměť.size); // 1 (Ouha! Objekt je stále v mezipaměti a zabírá paměť!) ``` -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 `cache`. Nevýhodou je, že když už objekt nebudeme potřebovat, musíme `cache` vyčistit. +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. -Když nahradíme `Map` za `WeakMap`, tento problém zmizí. Výsledek v cache bude z paměti odstraněn automaticky poté, co bude objekt odklizen garbage collectorem. +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(); */!* // vypočítá a zapamatuje si výsledek function proces(obj) { - if (!cache.has(obj)) { + if (!mezipaměť.has(obj)) { let výsledek = /* výpočet výsledku pro */ obj; - cache.set(obj, výsledek); + mezipaměť.set(obj, výsledek); return výsledek; } - return cache.get(obj); + return mezipaměť.get(obj); } -// 📁 main.js +// 📁 hlavní.js let obj = {/* nějaký objekt */}; let výsledek1 = proces(obj); @@ -239,9 +239,9 @@ let výsledek2 = proces(obj); // ...později, když už tento objekt nebudeme potřebovat: obj = null; -// Nemůžeme získat cache.size, protože to je WeakMap, +// 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 cache +// Když bude obj odklizen, budou odstraněna i data z mezipaměti ``` ## WeakSet @@ -252,7 +252,7 @@ obj = null; - 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. -Přestože je „slabá“, může sloužit i jako dodatečné úložiště. Ne však pro libovolná data, ale jen pro skutečnost „ano/ne“. Členství ve `WeakSet` může o objektu něco znamenat. +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. Například můžeme do `WeakSet` přidávat uživatele, abychom si pamatovali ty, kteří navštívili naše stránky: @@ -280,7 +280,7 @@ jan = null; // množinaNávštěvníků bude automaticky pročištěna ``` -Nejvýznamnějším omezením `WeakMap` a `WeakSet` je absence iterací a nemožnost získat celý jejich momentální 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ě. +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ě. ## Shrnutí From 261fcb2a30fbbdeea489c0fd283a99d0c4ac5aea Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Sun, 26 Jan 2025 18:57:21 +0100 Subject: [PATCH 26/55] 1.5.9 --- .../01-sum-salaries/task.md | 2 +- .../09-keys-values-entries/article.md | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) 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 79c334fc4..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 @@ -4,7 +4,7 @@ importance: 5 # Součet vlastností -Máme objekt `prodeje` s určitým počtem prodejů. +Máme objekt `prodeje` obsahující libovolný počet prodejů. 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`. 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 26ac2bf76..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 @@ -9,11 +9,11 @@ Tyto metody jsou generické, existuje společná dohoda ohledně jejich použív Jsou podporovány v: -- `Map` -- `Set` -- `Array` +- mapách (`Map`) +- množinách (`Set`) +- polích (`Array`) -Plané objekty rovněž podporují podobné metody, ale jejich syntaxe je trochu jiná. +Podobné metody jsou podporovány i v planých objektech, ale jejich syntaxe je trochu jiná. ## Object.keys, values, entries @@ -28,7 +28,7 @@ Prosíme, všimněte si rozdílů (například ve srovnání s mapou): | | Mapa | Objekt | |----------------|---------------------|-----------------------------------------| | Syntaxe volání | `mapa.keys()` | `Object.keys(obj)`, ale ne `obj.keys()` | -| Vrací | iterovatelný objekt | „skutečné“ pole | +| Vrací | iterovatelný objekt | „opravdové“ pole | Prvním rozdílem je, že musíme volat `Object.keys(obj)`, ne `obj.keys()`. @@ -49,7 +49,7 @@ let uživatel = { - `Object.values(uživatel) = ["Jan", 30]` - `Object.entries(uživatel) = [ ["jméno","Jan"], ["věk",30] ]` -Zde je příklad použití `Object.values` k procházení hodnot vlastností: +Zde je příklad použití `Object.values` k vytvoření cyklu nad hodnotami vlastností: ```js run let uživatel = { @@ -84,8 +84,8 @@ Například máme objekt s cenami a rádi bychom je zdvojnásobili: ```js run let ceny = { - banány: 1, - pomeranče: 2, + banán: 1, + pomeranč: 2, maso: 4, }; From c0ef67abbbeb9742d3a1bb44b9d00f1874a106df Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Sun, 26 Jan 2025 21:04:00 +0100 Subject: [PATCH 27/55] 1.5.10 --- .../1-destruct-user/task.md | 2 +- .../10-destructuring-assignment/article.md | 66 +++++++++---------- .../destructuring-complex.svg | 2 +- 3 files changed, 35 insertions(+), 35 deletions(-) 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 a344d76cc..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 @@ -17,7 +17,7 @@ Napište destrukturační přiřazení, které načte: - 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í) +- vlastnost `jeAdmin` do proměnné `jeAdmin` (false, pokud taková vlastnost není). Zde je příklad hodnot po vašem přiřazení: 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 805f64d2a..28440bb3c 100644 --- a/1-js/05-data-types/10-destructuring-assignment/article.md +++ b/1-js/05-data-types/10-destructuring-assignment/article.md @@ -2,7 +2,7 @@ Dvě nejpoužívanější datové struktury v JavaScriptu jsou objekty a pole. -- Objekty nám umožňují vytvořit jednoduchou entitu, v níž jsou datové prvky uloženy podle klíčů. +- Objekty nám umožňují vytvořit jednoduchou entitu, v níž jsou datové prvky uloženy pod klíči. - Pole nám umožňují shromáždit datové prvky do seřazeného seznamu. Když je však předáváme nějaké funkci, nemusíme je potřebovat celé. Funkce může požadovat jen určité prvky nebo vlastnosti. @@ -54,7 +54,7 @@ let příjmení = pole[1]; ```` ````smart header="Ignorování prvků pomocí čárek" -Nechtěné prvky pole můžeme zahodit pomocí čárky navíc: +Nechtěné prvky pole můžeme zahodit přidáním čárky: ```js run *!* @@ -65,7 +65,7 @@ let [křestníJméno, , titul] = ["Julius", "Caesar", "Konzul", "Římské repub alert( titul ); // Konzul ``` -Ve výše 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é). +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="Funguje s libovolným iterovatelným objektem na pravé straně" @@ -76,7 +76,7 @@ Ve výše uvedeném kódu byl druhý prvek pole přeskočen, třetí přiřazen let [a, b, c] = "abc"; // ["a", "b", "c"] let [jedna, dvě, tři] = new Set([1, 2, 3]); ``` -To funguje, protože interně 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. +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. ```` @@ -129,7 +129,7 @@ for (let [klíč, hodnota] of uživatel) { ``` ```` -````smart header="Trik s výměnou proměnných" +````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 @@ -149,11 +149,11 @@ Zde jsme vytvořili dočasné pole dvou proměnných a okamžitě je destrukturo Tímto způsobem můžeme vyměnit i více než dvě proměnné. ```` -### Zbytek '...' +### Zbytek „...“ Jestliže je pole delší než seznam nalevo, „přebývající“ prvky jsou obvykle vypuštěny. -Například zde se vezmou jen první dva prvky a ostatní se prostě ignorují: +Například zde se vezmou jen první dva prvky a ostatní se jednoduše ignorují: ```js run let [jméno1, jméno2] = ["Julius", "Caesar", "Konzul", "Římské republiky"]; @@ -185,7 +185,7 @@ let [jméno1, jméno2, *!*...tituly*/!*] = ["Julius", "Caesar", "Konzul", "Řím // nyní tituly = ["Konzul", "Římské republiky"] ``` -### Defaultní hodnoty +### Standardní hodnoty Pokud je pole kratší než seznam proměnných nalevo, nedojde k chybě. Neuvedené hodnoty se považují za nedefinované: @@ -198,21 +198,21 @@ alert(křestníJméno); // undefined alert(příjmení); // undefined ``` -Chceme-li, aby chybějící hodnoty nahradila nějaká „defaultní“ hodnota, můžeme ji uvést pomocí `=`: +Chceme-li, aby chybějící hodnoty nahradila nějaká „standardní“ hodnota, můžeme ji uvést pomocí `=`: ```js run *!* -// defaultní hodnoty +// standardní hodnoty let [jméno = "Host", příjmení = "Anonym"] = ["Julius"]; */!* alert(jméno); // Julius (z pole) -alert(příjmení); // Anonym (použita defaultní hodnota) +alert(příjmení); // Anonym (použita standardní hodnota) ``` -Defaultními hodnotami mohou být další složité výrazy nebo dokonce volání funkcí. Vyhodnocují se jen tehdy, není-li hodnota poskytnuta. +Standardními hodnotami mohou být i složitější výrazy nebo dokonce volání funkcí. Vyhodnocují se jen tehdy, když hodnota není poskytnuta. -Například zde použijeme pro dvě defaultní hodnoty funkci `prompt`: +Například zde použijeme pro dvě standardní hodnoty funkci `prompt`: ```js run // spustí prompt jen pro příjmení @@ -254,7 +254,7 @@ alert(šířka); // 100 alert(výška); // 200 ``` -Vlastnosti `možnosti.title`, `možnosti.šířka` a `možnosti.výška` jsou přiřazeny do příslušných proměnných. +Vlastnosti `možnosti.titulek`, `možnosti.šířka` a `možnosti.výška` jsou přiřazeny do příslušných proměnných. Na pořadí nezáleží. Tohle bude fungovat také: @@ -288,9 +288,9 @@ alert(š); // 100 alert(v); // 200 ``` -Dvojtečka ukazuje, „co : jde kam“. V uvedeném příkladu vlastnost `šířka` jde do `š`, vlastnost `výška` jde do `v` a `titulek` se přiřadí do proměnné stejného názvu. +Dvojtečka ukazuje, „co : jde kam“. V uvedeném příkladu vlastnost `šířka` jde do `š`, vlastnost `výška` jde do `v` a `titulek` se přiřadí do proměnné se stejným názvem. -Pro vlastnosti, které mohou chybět, můžeme nastavit defaultní hodnoty pomocí `"="` takto: +Pro vlastnosti, které mohou chybět, můžeme nastavit standardní hodnoty pomocí `"="` takto: ```js run let možnosti = { @@ -306,9 +306,9 @@ alert(šířka); // 100 alert(výška); // 200 ``` -Stejně jako u polí nebo parametrů funkcí mohou defaultní hodnoty být libovolné výrazy nebo dokonce volání funkcí. Budou vyhodnoceny, jestliže hodnota nebude poskytnuta. +Stejně jako u polí nebo parametrů funkcí mohou standardní hodnoty být libovolné výrazy nebo dokonce volání funkcí. Budou vyhodnoceny jen tehdy, když hodnota nebude poskytnuta. -V níže uvedeném kódu se `prompt` zeptá na proměnnou `šířka`, ale ne na `titulek`: +V následujícím kódu se `prompt` zeptá na proměnnou `šířka`, ale ne na `titulek`: ```js run let možnosti = { @@ -320,7 +320,7 @@ let {šířka = prompt("šířka?"), titulek = prompt("titulek?")} = možnosti; */!* alert(titulek); // Menu -alert(šířka); // (to, co vydal prompt) +alert(šířka); // (to, co vrátil prompt) ``` Můžeme také zkombinovat dvojtečku a rovnítko: @@ -358,7 +358,7 @@ alert(titulek); // Menu Co když má objekt více vlastností, než my máme proměnných? Můžeme některé z nich vzít a „zbytek“ někam přiřadit? -Můžeme použít zbytkový vzor, stejně jako jsme to dělali u polí. Některé starší prohlížeče to nepodporují (IE, jako polyfill použijte Babel), ale v moderních to funguje. +Můžeme použít zbytkový vzor, stejně jako jsme to udělali u polí. Některé starší prohlížeče to nepodporují (IE, jako polyfill použijte Babel), ale v moderních to funguje. Vypadá to takto: @@ -391,7 +391,7 @@ let titulek, šířka, výška; {titulek, šířka, výška} = {titulek: "Menu", šířka: 200, výška: 100}; ``` -Problém je v tom, že JavaScript zachází s `{...}` v toku hlavního 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: +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 { @@ -418,9 +418,9 @@ alert( titulek ); // Menu ## Vnořená destrukturace -Jestliže objekt nebo pole obsahuje jiné vnořené objekty a pole, můžeme vyjmout hlubší části pomocí složitějších konstrukcí na levé straně. +Jestliže objekt nebo pole obsahuje jiné vnořené objekty a pole, můžeme vyjmout hlubší části pomocí složitějších vzorů na levé straně. -V níže uvedené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: +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 možnosti = { @@ -439,7 +439,7 @@ let { výška }, prvky: [prvek1, prvek2], // zde přiřadíme prvky - titulek = "Menu" // v objektu není přítomen (použije se defaultní hodnota) + titulek = "Menu" // v objektu není přítomen (použije se standardní hodnota) } = možnosti; alert(titulek); // Menu @@ -453,7 +453,7 @@ Do příslušných proměnných se přiřadí všechny vlastnosti objektu `možn ![](destructuring-complex.svg) -Nakonec tedy máme `šířka`, `výška`, `prvek1`, `prvek2` a `titulek` z defaultní hodnoty. +Nakonec tedy máme `šířka`, `výška`, `prvek1`, `prvek2` a `titulek` ze standardní hodnoty. Všimněte si, že zde nejsou žádné proměnné pro `velikost` a `prvky`, jelikož jsme místo nich vzali jejich obsah. @@ -474,7 +474,7 @@ Problém v reálném životě spočívá v tom, jak si pamatovat pořadí argume Takhle? ```js -// undefined tam, kde se má použít defaultní hodnota +// undefined tam, kde se má použít standardní hodnota zobrazMenu("Moje menu", undefined, undefined, ["Prvek1", "Prvek2"]) ``` @@ -494,7 +494,7 @@ let možnosti = { // ...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 defaultní hodnoty + // šířka, výška – použity standardní hodnoty alert( `${titulek} ${šířka} ${výška}` ); // Moje menu 200 100 alert( prvky ); // Prvek1,Prvek2 } @@ -534,17 +534,17 @@ function({ }) ``` -Pak budeme mít pro objekt parametrů proměnnou `názevProměnné` obsahující vlastnost `vstupujícíVlastnost`, jejíž standardní hodnota bude `standardníHodnota`. +Pro objekt parametrů pak budeme mít pro vlastnost `vstupujícíVlastnost` proměnnou `názevProměnné` , jejíž standardní hodnotou bude `standardníHodnota`. Prosíme všimněte si, že taková destrukturace předpokládá, že `zobrazMenu()` má argument. Chceme-li všechny hodnoty standardní, měli bychom uvést prázdný objekt: ```js -zobrazMenu({}); // ok, všechny hodnoty jsou defaultní +zobrazMenu({}); // ok, všechny hodnoty jsou standardní zobrazMenu(); // tohle ohlásí chybu ``` -To můžeme opravit tak, že učiníme `{}` defaultní hodnotou celého objektu parametrů: +To můžeme opravit tak, že učiníme `{}` standardní hodnotou celého objektu parametrů: ```js run function zobrazMenu({ titulek = "Menu", šířka = 100, výška = 200 }*!* = {}*/!*) { @@ -554,11 +554,11 @@ function zobrazMenu({ titulek = "Menu", šířka = 100, výška = 200 }*!* = {}* zobrazMenu(); // Menu 100 200 ``` -V uvedeném kódu je celý argumentový objekt defaultně `{}`, takže vždy bude co destrukturovat. +V uvedeném kódu je celý argumentový objekt standardně `{}`, takže vždy bude co destrukturovat. ## Shrnutí -- Destrukturační přiřazení umožňuje okamžité mapování objektu nebo pole do mnoha proměnných. +- Destrukturační přiřazení umožňuje rychlé mapování objektu nebo pole do mnoha proměnných. - Úplná syntaxe pro objekt: ```js let {vlastnost : názevProměnné = standardníHodnota, ...zbytek} = objekt @@ -566,7 +566,7 @@ V uvedeném kódu je celý argumentový objekt defaultně `{}`, takže vždy bud 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`. - Objektové vlastnosti, které nejsou mapovány, se zkopírují do objektu `zbytek`. + Objektové vlastnosti, pro které není uvedeno mapování, se zkopírují do objektu `zbytek`. - Úplná syntaxe pro pole: diff --git a/1-js/05-data-types/10-destructuring-assignment/destructuring-complex.svg b/1-js/05-data-types/10-destructuring-assignment/destructuring-complex.svg index 8a1ff1a93..01faf9968 100644 --- a/1-js/05-data-types/10-destructuring-assignment/destructuring-complex.svg +++ b/1-js/05-data-types/10-destructuring-assignment/destructuring-complex.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From d88ef1e590e64fa571b22a8a9d09a78ee2da9622 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Sun, 26 Jan 2025 23:00:41 +0100 Subject: [PATCH 28/55] 1.5.11 --- 1-js/05-data-types/11-date/3-weekday/task.md | 2 +- .../11-date/4-get-date-ago/task.md | 2 +- .../11-date/6-get-seconds-today/solution.md | 2 +- .../_js.view/solution.js | 2 +- .../8-format-date-relative/solution.md | 4 +- .../11-date/8-format-date-relative/task.md | 2 +- 1-js/05-data-types/11-date/article.md | 78 +++++++++---------- 7 files changed, 46 insertions(+), 46 deletions(-) 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 6a305afc6..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 @@ -4,7 +4,7 @@ importance: 5 # Evropský den v týdnu -V evropských zemích začíná týden pondělím (číslo 1), pak je úterý (číslo 2) atd., 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`. +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 datum = new Date(2012, 0, 3); // 3. leden 2012 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 fc80059ef..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 @@ -6,7 +6,7 @@ importance: 4 Vytvořte funkci `vraťDenPřed(datum, dny)`, která vrátí den v měsíci, který byl `dny` dnů přede dnem `datum`. -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. +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. Měla by spolehlivě fungovat i pro `dny=365` nebo více: 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 2629f9e48..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 @@ -16,7 +16,7 @@ function vraťDnešníSekundy() { alert( vraťDnešníSekundy() ); ``` -Alternativním řešením by bylo získat hodiny, minuty, sekundy a převést je na sekundy: +Alternativním řešením by bylo získat hodiny, minuty a sekundy a převést je na sekundy: ```js run function vraťDnešníSekundy() { 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 8044f9a01..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 @@ -18,7 +18,7 @@ function formátujDatum(datum) { } // naformátujeme datum - // před jednočíslicový den/měsíc/hodiny/minuty přidáme nulu + // před jednociferný den/měsíc/hodiny/minuty přidáme nulu let d = datum; d = [ '0' + d.getDate(), 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 83a1db577..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 @@ -20,7 +20,7 @@ function formátujDatum(datum) { } // naformátujeme datum - // před jednočíslicový den/měsíc/hodiny/minuty přidáme nulu + // před jednociferný den/měsíc/hodiny/minuty přidáme nulu let d = datum; d = [ '0' + d.getDate(), @@ -40,7 +40,7 @@ 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 +// včerejší datum ve formátu 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 fe04be34b..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 @@ -20,6 +20,6 @@ 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.16 20:00 +// 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 86f0b277a..66cabf211 100644 --- a/1-js/05-data-types/11-date/article.md +++ b/1-js/05-data-types/11-date/article.md @@ -1,8 +1,8 @@ # Datum a čas -Seznámíme se s novým vestavěným objektem: [Date](mdn:js/Date). Tento objekt ukládá datum a čas a poskytuje metody pro práci s nimi. +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. -Můžeme jej například použít k uložení doby vytvoření nebo modifikace, k měření času nebo jen k vypsání dnešního data. +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. ## Vytvoření @@ -21,12 +21,12 @@ Abychom vytvořili objekt `Date`, zavoláme `new Date()` s jedním z následují ```js run // 0 znamená 01.01.1970 UTC+0 - let Leden01_1970 = new Date(0); - alert( Leden01_1970 ); + let leden01_1970 = new Date(0); + alert( leden01_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 ); + let leden02_1970 = new Date(24 * 3600 * 1000); + alert( leden02_1970 ); ``` 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*). @@ -36,30 +36,30 @@ Abychom vytvořili objekt `Date`, zavoláme `new Date()` s jedním z následují Data před 1. lednem 1970 mají záporná časová razítka, např.: ```js run // 31. prosinec 1969 - let Pros31_1969 = new Date(-24 * 3600 * 1000); - alert( Pros31_1969 ); + let pros31_1969 = new Date(-24 * 3600 * 1000); + alert( pros31_1969 ); ``` `new Date(datovýŘetězec)` -: Jestliže je uveden jediný argument a je to řetězec, bude automaticky rozparsován. Algoritmus je stejný, jaký používá `Date.parse`. Probereme ho později. +: 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 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 + // 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) - // nebo + // nebo: // Wed Jan 25 2017 16:00:00 GMT-0800 (Pacific Standard Time) // V Česku zřejmě bude: - // Thu Jan 26 2017 11:00:00 GMT+1100 (Středoevropský standardní čas) - pozn. překl. + // Thu Jan 26 2017 01:00:00 GMT+1100 (Středoevropský standardní čas) - pozn. překl. ``` `new Date(rok, měsíc, den, hodiny, minuty, sekundy, ms)` -: Vytvoří datum ze zadaných součástí v místním časovém pásmu. Povinné jsou jen první dva argumenty. +: Vytvoří datum ze zadaných složek v místním časovém pásmu. Povinné jsou jen první dva argumenty. - - Parametr `rok` musí 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 silně se doporučuje používat vždy 4 číslice. + - 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`. @@ -80,7 +80,7 @@ Abychom vytvořili objekt `Date`, zavoláme `new Date()` s jedním z následují ## Přístup ke složkám data -Existují metody, kterými můžeme přistupovat k roku, měsíci a tak dále objektu `Date`: +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) : Vrací rok (4-číslicový). @@ -92,10 +92,10 @@ Existují metody, kterými můžeme přistupovat k roku, měsíci a tak dále ob : 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) -: Vracejí odpovídající časové složky (`getHours()` vrací hodiny, `getMinutes()` minuty, `getSeconds()` sekundy, `getMilliseconds()` milisekundy -- pozn. překl.). +: Vracejí odpovídající časové složky (`getHours()` vrací hodiny, `getMinutes()` minuty, `getSeconds()` sekundy a `getMilliseconds()` milisekundy -- pozn. překl.). ```warn header="Ne `getYear()`, ale `getFullYear()`" -Mnoho JavaScriptových enginů 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()`. +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()`. ``` Navíc můžeme získat i den v týdnu: @@ -107,7 +107,7 @@ Navíc můžeme získat i den v týdnu: 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"`. -Jestliže je vaše místní časové pásmo vzhledem k UTC posunuto, pak níže uvedený kód zobrazí různé hodiny: +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 // nynější datum @@ -147,7 +147,7 @@ Následující metody umožňují nastavit složky data a času: - [`setMinutes(minuty, [sekundy], [ms])`](mdn:js/Date/setMinutes) - [`setSeconds(sekundy, [ms])`](mdn:js/Date/setSeconds) - [`setMilliseconds(ms)`](mdn:js/Date/setMilliseconds) -- [`setTime(milisekundy)`](mdn:js/Date/setTime) (nastaví celé datum podle milisekund uplynulých od 1.1.1970 UTC) +- [`setTime(milisekundy)`](mdn:js/Date/setTime) (nastaví celé datum z milisekund uplynulých od 1. 1. 1970 UTC) Každá z nich kromě `setTime()` má UTC-variantu, např. `setUTCHours()`. @@ -242,9 +242,9 @@ Jestliže chceme jenom měřit čas, nepotřebujeme objekt `Date`. Existuje speciální metoda `Date.now()`, která vrací aktuální časové razítko. -Je sémanticky ekvivalentní `new Date().getTime()`, ale nevytváří dočasný objekt `Date`. Je tedy rychlejší a nezatěžuje garbage collector. +Je sémanticky ekvivalentní `new Date().getTime()`, ale nevytváří dočasný objekt `Date`. Je tedy rychlejší a nezatěžuje sběrač odpadků. -Používá se většinou kvůli pohodlí nebo tehdy, když záleží na výkonu, například v JavaScriptových hrách nebo jiných specializovaných aplikacích. +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. Tohle je tedy pravděpodobně lepší: @@ -265,7 +265,7 @@ let konec = Date.now(); // hotovo alert( `Cyklus trval ${konec - začátek} ms` ); // odečítáme čísla, ne data ``` -## Benchmarking +## Benchmarky Jestliže chceme spolehlivý benchmark funkce náročné na CPU, měli bychom být opatrní. @@ -289,7 +289,7 @@ Tyto dvě funkce dělají přesně totéž, ale jedna z nich používá explicit Která je tedy rychlejší? -První myšlenka může být spustit je mnohokrát za sebou a změřit rozdíl časů. V našem případě jsou tyto funkce velmi jednoduché, takže to musíme udělat alespoň 100000krát. +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. Změřme to: @@ -315,17 +315,17 @@ alert( 'Čas funkce rozdílOdečtením: ' + bench(rozdílOdečtením) + ' ms' ); alert( 'Čas funkce rozdílPomocíGetTime: ' + bench(rozdílPomocíGetTime) + ' ms' ); ``` -Páni! Použití `getTime()` je mnohem rychlejší! Je to proto, že když tam není typová konverze, je pro enginy mnohem snadnější funkci optimalizovat. +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. Dobrá, něco tedy máme. To však ještě není dobrý benchmark. -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 něco mu ubíralo zdroje. A v době spuštění `bench(rozdílPomocíGetTime)` tahle práce skončila. +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. V moderních multiprocesních operačních systémech je to dosti reálný scénář. Výsledkem je, že první benchmark měl méně zdrojů CPU než druhý. To mohlo vést ke špatným výsledkům. -**Pro spolehlivější benchmarking bychom měli celý balíček benchmarků spustit několikrát za sebou.** +**Pro spolehlivější benchmarkové testování bychom měli celý balíček benchmarků spustit několikrát za sebou.** Například takto: @@ -362,7 +362,7 @@ alert( 'Celkový čas funkce rozdílOdečtením: ' + čas1 ); alert( 'Celkový čas funkce rozdílPomocíGetTime: ' + čas2 ); ``` -Moderní JavaScriptové enginy začínají aplikovat pokročilejší 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: +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 // přidáno pro „zahřátí“ před hlavní smyčkou @@ -376,15 +376,15 @@ for (let i = 0; i < 10; i++) { } ``` -```warn header="Při mikrobenchmarkingu buďte opatrní" -Moderní JavaScriptové enginy 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ž benchmarkujeme něco velmi malého, např. práci operátoru nebo vestavěnou funkci. Pokud tedy chcete skutečně porozumět výkonu, pak si prosíme prostudujte, jak funguje JavaScriptový engine. A pak už pravděpodobně nebudete mikrobenchmarky vůbec potřebovat. +```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. Výborný balík článků o V8 naleznete na . ``` -## Parsování data z řetězce +## Načítání data z řetězce -Metoda [Date.parse(str)](mdn:js/Date/parse) dokáže načíst datum z řetězce. +Metoda [Date.parse(řetězec)](mdn:js/Date/parse) dokáže načíst datum z řetězce. Řetězec by měl mít formát `RRRR-MM-DDTHH:mm:ss.sssZ`, kde: @@ -395,7 +395,7 @@ Metoda [Date.parse(str)](mdn:js/Date/parse) dokáže načíst datum z řetězce. Jsou možné i kratší varianty, např. `RRRR-MM-DD` nebo `RRRR-MM` nebo jen `RRRR`. -Volání `Date.parse(str)` parsuje řetězec v zadané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`. +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`. Příklad: @@ -415,16 +415,16 @@ alert(datum); ## Shrnutí -- Datum a čas v JavaScriptu představuje objekt [Date](mdn:js/Date). Nemůžeme vytvořit „jen datum“ nebo „jen čas“: objekty `Date` obsahují vždy obojí. +- 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 rozsah. To je dobré pro přičítání/odečítání dnů/měsíců/hodin. -- Data od sebe lze 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. -- Aktuální časové razítko rychle získáme pomocí `Date.now()`. +- `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()`. 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. -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č má 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): +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(`Načítání začalo před ${performance.now()}ms`); @@ -433,4 +433,4 @@ alert(`Načítání začalo před ${performance.now()}ms`); // více než 3 číslice za desetinnou čárkou jsou chyba přesnosti, jedině první 3 jsou správné ``` -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 to není v `Date`. \ No newline at end of file +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 From de4708d6353119674da836f343f4b60f71e539e1 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Mon, 27 Jan 2025 22:11:50 +0100 Subject: [PATCH 29/55] 1.5.12 --- .../12-json/1-serialize-object/task.md | 4 +- .../2-serialize-event-circular/solution.md | 4 +- .../2-serialize-event-circular/task.md | 6 +- 1-js/05-data-types/12-json/article.md | 86 +++++++++---------- 1-js/05-data-types/12-json/json-meetup.svg | 2 +- 5 files changed, 51 insertions(+), 51 deletions(-) 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 32b0a445f..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,9 +2,9 @@ importance: 5 --- -# Převeďte objekt na JSON a zpět +# Převeďte objekt do JSONu a zpět -Převeďte objekt `uživatel` na JSON a pak jej načtěte zpět do jiné proměnné. +Převeďte objekt `uživatel` do JSONu a pak jej načtěte zpět do jiné proměnné. ```js let uživatel = { 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 d081bb9b0..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 @@ -11,9 +11,9 @@ let mítink = { }; místnost.obsazenoČím = mítink; -mítink.self = mítink; +mítink.onSám = mítink; -alert( JSON.stringify(mítink, function replacer(klíč, hodnota) { +alert( JSON.stringify(mítink, function nahrazení(klíč, hodnota) { return (klíč != "" && hodnota == mítink) ? undefined : hodnota; })); 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 e4e2028e4..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 @@ -8,7 +8,7 @@ V jednoduchých případech kruhových odkazů můžeme závadnou vlastnost vyř 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. -Napište funkci `replacer`, která zřetězí všechno, ale odstraní vlastnosti, které se odkazují na `mítink`: +Napište funkci `nahrazení`, která zřetězí všechno, ale odstraní vlastnosti, které se odkazují na `mítink`: ```js run let místnost = { @@ -24,10 +24,10 @@ let mítink = { *!* // kruhové odkazy místnost.obsazenoČím = mítink; -mítink.self = mítink; +mítink.onSám = mítink; */!* -alert( JSON.stringify(mítink, function replacer(klíč, hodnota) { +alert( JSON.stringify(mítink, function nahrazení(klíč, hodnota) { /* váš kód */ })); diff --git a/1-js/05-data-types/12-json/article.md b/1-js/05-data-types/12-json/article.md index 79975b55e..891fcb050 100644 --- a/1-js/05-data-types/12-json/article.md +++ b/1-js/05-data-types/12-json/article.md @@ -1,4 +1,4 @@ -# Metody JSON, toJSON +# Metody pro JSON, toJSON 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í. @@ -21,18 +21,18 @@ let uživatel = { alert(uživatel); // {jméno: "Jan", věk: 30} ``` -...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 bolestivé. 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. +...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. 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 -[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 psán v Ruby, PHP, Javě nebo čemkoli jiném. +[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 poskytuje metody: - `JSON.stringify` pro konverzi objektů na JSON. -- `JSON.parse` pro konverzi JSON zpět na objekty. +- `JSON.parse` pro konverzi JSONu zpět na objekty. Například zde zavoláme `JSON.stringify` na studenta: ```js run @@ -68,10 +68,10 @@ Metoda `JSON.stringify(student)` vezme objekt a konvertuje ho na řetězec. 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 JSONem zakódovaný objekt má několik důležitých rozdílů oproti objektovému literálu: +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: -- Řetězce používají uvozovky. V JSON nejsou apostrofy ani gravisy. Z `'Jan'` se tedy stane `"Jan"`. -- Názvy vlastností objektů jsou rovněž v uvozovkách. To je povinné. Z `věk:30` se tedy stane `"věk":30`. +- Ř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`. `JSON.stringify` lze aplikovat i na primitivy. @@ -99,7 +99,7 @@ alert( JSON.stringify(true) ); // true alert( JSON.stringify([1, 2, 3]) ); // [1,2,3] ``` -JSON je jazykově nezávislá specifikace určená jen pro data, takže některé objektové vlastnosti specifické pro JavaScript `JSON.stringify` přeskakuje. +JSON je jazykově nezávislá specifikace určená jen pro data, takže některé objektové vlastnosti specifické pro JavaScript `JSON.stringify` vynechává. Konkrétně: @@ -119,7 +119,7 @@ let uživatel = { alert( JSON.stringify(uživatel) ); // {} (prázdný objekt) ``` -Obvykle je to dobře. Pokud to není to, co chceme, brzy uvidíme, jak si tento proces můžeme přizpůsobit. +Obvykle je to dobře. Pokud to chceme nějak jinak, brzy uvidíme, jak si tento proces můžeme přizpůsobit. Skvělé je, že vnořené objekty jsou podporovány a automaticky se konvertují. @@ -172,26 +172,26 @@ Zde konverze selže kvůli kruhovému odkazu: `místnost.obsazenoČím` se odkaz ![](json-meetup.svg) -## Vyloučení a transformace: replacer +## Vyloučení a transformace: funkce nahrazení Úplná syntaxe `JSON.stringify` je: ```js -let json = JSON.stringify(hodnota[, replacer, mezery]) +let json = JSON.stringify(hodnota[, nahrazení, mezery]) ``` hodnota : Hodnota k zakódování. -replacer +nahrazení : Pole vlastností, které se mají zakódovat, nebo mapovací funkce `function(klíč, hodnota)`. mezery : Počet mezer, které se použijí při formátování. -Většinou se `JSON.stringify` používá jen s prvním argumentem. Jestliže však potřebujeme proces nahrazení vyladit, například vyfiltrovat kruhové odkazy, můžeme použít druhý argument funkce `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`. -Předáme-li do něj pole vlastností, budou zakódovány pouze tyto vlastnosti. +Předáme-li do něj pole vlastností, budou zakódovány pouze vlastnosti uvedené v tomto poli. Příklad: @@ -212,7 +212,7 @@ alert( JSON.stringify(mítink, *!*['titul', 'účastníci']*/!*) ); // {"titul":"Konference","účastníci":[{},{}]} ``` -Tady jsme asi příliš přísní. Seznam vlastností se použije na celou strukturu. Objekty v `účastníci` jsou tedy prázdné, protože `jméno` není na seznamu. +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. Zahrňme na seznam všechny vlastnosti kromě `místnost.obsazenoČím`, která by způsobila kruhový odkaz: @@ -241,11 +241,11 @@ alert( JSON.stringify(mítink, *!*['titul', 'účastníci', 'místo', 'jméno', Nyní je serializováno všechno kromě `obsazenoČím`. Seznam vlastností je však poměrně dlouhý. -Naštěstí můžeme jako `replacer` použít funkci místo pole. +Naštěstí můžeme jako `nahrazení` místo pole použít funkci. 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. -V našem případě můžeme vracet hodnotu `hodnota` tak, „jak je“, pro všechno kromě `obsazenoČím`. Abychom `obsazenoČím` ignorovali, níže uvedený kód vrátí `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 místnost = { @@ -260,12 +260,12 @@ let mítink = { místnost.obsazenoČím = mítink; // místnost se odkazuje na mítink -alert( JSON.stringify(mítink, function replacer(klíč, hodnota) { +alert( JSON.stringify(mítink, function nahrazení(klíč, hodnota) { alert(`${klíč}: ${hodnota}`); return (klíč == 'obsazenoČím') ? undefined : hodnota; })); -/* dvojice klíč:hodnota, které vstoupily do replaceru: +/* dvojice klíč:hodnota, které vstoupily do nahrazení: : [object Object] titul: Konference účastníci: [object Object],[object Object] @@ -279,18 +279,18 @@ obsazenoČím: [object Object] */ ``` -Prosíme všimněte si, že funkce `replacer` obdrží každou dvojici klíč/hodnota včetně vnořených objektů a prvků pole. Aplikuje se rekurzívně. Hodnota `this` uvnitř funkce `replacer` je objekt, který obsahuje aktuální vlastnost. +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. -První volání je speciální. Učiní se pomocí speciálního „wrapperového objektu“: `{"": mítink}`. Jinými slovy, první dvojice `(klíč, hodnota)` má prázdný klíč a hodnotou je celý cílový objekt. To je důvod, proč je první řádek ve výše uvedeném příkladu `":[object Object]"`. +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]"`. -Myšlenkou je poskytnout funkci `replacer` co největší moc: má možnost analyzovat a nahradit či přeskočit i celý objekt, je-li to nutné. +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é. ## Formátování: mezery -Třetí argument `JSON.stringify(hodnota, replacer, mezery)` je počet mezer, které se použijí pro pěkné formátování. +Třetí argument `JSON.stringify(hodnota, nahrazení, mezery)` je počet mezer, které se použijí pro pěkné formátování. -Žá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 pěkný výstup. +Žá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. Zde `mezery = 2` říká JavaScriptu, aby zobrazil vnořené objekty na více řádcích s odsazením 2 mezery uvnitř objektu: @@ -328,7 +328,7 @@ alert(JSON.stringify(uživatel, null, 2)); */ ``` -Třetí argument může být i řetězec. V tom případě se pro odsazení místo mezer použije tento řetězec. +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. Parametr `mezery` se používá výhradně pro účely logování a pěkného výstupu. @@ -361,7 +361,7 @@ alert( JSON.stringify(mítink) ); */ ``` -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 takovéhoto druhu. +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. Nyní přidáme vlastní metodu `toJSON` do našeho objektu `místnost` `(2)`: @@ -400,17 +400,17 @@ Jak vidíme, `toJSON` se používá jak při přímém volání `JSON.stringify( ## JSON.parse -K dekódování řetězce JSON potřebujeme další metodu, která se nazývá [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). Syntaxe: ```js -let hodnota = JSON.parse(řetězec[, reviver]); +let hodnota = JSON.parse(řetězec[, oživení]); ``` řetězec -: Řetězec JSON, který se má dekódovat. +: Řetězec v JSONu, který se má dekódovat. -reviver +oživení : Nepovinná funkce `function(klíč, hodnota)`, která bude volána pro každou dvojici `(klíč, hodnota)` a může hodnotu transformovat. Příklad: @@ -434,27 +434,27 @@ let uživatel = JSON.parse(dataUživatele); alert( uživatel.přátelé[1] ); // 1 ``` -JSON může být tak složitý, jak jen potřebujeme, objekty a pole mohou obsahovat jiné objekty a pole. Všechny však musejí dodržovat stejný formát JSON. +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. -Toto jsou typické chyby v ručně psaném JSON (někdy jej musíme napsat ručně pro účely ladění): +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 = `{ *!*jméno*/!*: "Jan", // chyba: název vlastnosti bez uvozovek - "příjmení": *!*'Novák'*/!*, // chyba: hodnota v apostrofech (musí být v uvozovkách) - *!*'jeAdmin'*/!*: false // chyba: klíč v apostrofech (musí být v uvozovkách) + "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 }`; ``` -Kromě toho JSON nepodporuje komentáře. Přidání komentáře do JSON jej učiní neplatným. +Kromě toho JSON nepodporuje komentáře. Přidání komentáře do JSONu jej učiní neplatným. -Existuje i jiný formát jménem [JSON5](https://json5.org/), který umožňuje klíče bez uvozovek, komentáře apod. To je však samostatná knihovna, která není obsažena ve specifikaci jazyka. +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. -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 parsovacího algoritmu. +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. -## Použití reviveru +## Použití oživení Představme si, že jsme ze serveru získali zřetězený objekt `mítink`. @@ -483,13 +483,13 @@ Ouha! Chyba! 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`? -Jako druhý argument předáme do `JSON.parse` funkci reviveru, která vrátí všechny hodnoty tak, „jak jsou“, ale `datum` změní na `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 = '{"titul":"Konference","datum":"2017-11-30T12:00:00.000Z"}'; +let řetězec = '{"titul":"Konference","datum":"2017-11-30T12:00:00.000Z"}'; *!* -let mítink = JSON.parse(str, function(klíč, hodnota) { +let mítink = JSON.parse(řetězec, function(klíč, hodnota) { if (klíč == 'datum') return new Date(hodnota); return hodnota; }); @@ -524,6 +524,6 @@ alert( rozvrh.seznamMítinků[1].datum.getDate() ); // funguje to! - 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 JSON a [JSON.parse](mdn:js/JSON/parse) pro načítání z JSON. -- Obě metody podporují transformační funkce pro elegantní načítání a zápis. +- 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/12-json/json-meetup.svg b/1-js/05-data-types/12-json/json-meetup.svg index 3fa32a261..47c2b4651 100644 --- a/1-js/05-data-types/12-json/json-meetup.svg +++ b/1-js/05-data-types/12-json/json-meetup.svg @@ -1 +1 @@ -number: 23title: "Conference"...placeoccupiedByparticipants \ No newline at end of file +číslo: 23titul: "Konference"...místoobsazenoČímúčastníci \ No newline at end of file From d7cd06deb4b04fc3658aec3711c5edd1e1ddca55 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Wed, 29 Jan 2025 22:42:36 +0100 Subject: [PATCH 30/55] 1.6.1 --- .../01-recursion/01-sum-to/solution.md | 4 +- .../01-recursion/02-factorial/solution.md | 2 +- .../03-fibonacci-numbers/solution.md | 6 +- .../04-output-single-linked-list/solution.md | 14 +- .../solution.md | 12 +- .../01-recursion/article.md | 80 ++--- .../01-recursion/linked-list-0.svg | 273 ++++++++++++++++- .../01-recursion/linked-list-remove-1.svg | 278 +++++++++++++++++- .../01-recursion/linked-list-split.svg | 251 +++++++++++++++- .../01-recursion/linked-list.svg | 233 ++++++++++++++- .../01-recursion/recursion-pow.svg | 204 ++++++++++++- 11 files changed, 1293 insertions(+), 64 deletions(-) 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 382a1da54..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 @@ -35,6 +35,6 @@ alert( sečtiDo(100) ); P.S. Nejrychlejší řešení je pochopitelně pomocí vzorce. Pro jakékoli číslo `n` vykonává pouze 3 operace. Matematika pomáhá! -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 také vyžaduje zdroje, takže je to pomalejší. +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. Některé enginy 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 engine nemusí pamatovat její prováděcí kontext. To odstraní paměťovou zátěž. Pokud však engine JavaScriptu nepodporuje optimalizaci koncového volání (a většina enginů ji nepodporuje), nastane chyba: bude překročena maximální velikost zásobníku, protože celková velikost zásobníku je obvykle omezena. +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/02-factorial/solution.md b/1-js/06-advanced-functions/01-recursion/02-factorial/solution.md index 8bee93235..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,6 +1,6 @@ Podle definice můžeme faktoriál `n!` zapsat jako `n * (n-1)!`. -Jinými slovy, výsledek funkce `faktoriál(n)` můžeme vypočítat jako `n` vynásobené výsledkem `faktoriál(n-1)`. A volání pro `n-1` může rekurzívně klesat níž a níž až k `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 faktoriál(n) { 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 3484f1674..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 @@ -12,7 +12,7 @@ alert( fib(7) ); // 13 // fib(77); // bude extrémně pomalé! ``` -...Ale pro velké hodnoty `n` to bude velmi pomalé. Například `fib(77)` může na nějaký čas zablokovat engine, protože spotřebuje všechny zdroje CPU. +...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. Je to proto, že funkce učiní příliš mnoho vnořených volání. Stejné hodnoty se budou počítat znovu a znovu. @@ -84,7 +84,7 @@ c = a + b; // c = fib(5) */ ``` -...A tak dále, dokud nezískáme požadovanou hodnotu. Je to mnohem rychlejší než rekurze a neobsahuje žádné dvojí výpočty. +...A tak dále, dokud nezískáme požadovanou hodnotu. Je to mnohem rychlejší než rekurze a neobsahuje žádné duplicitní výpočty. Úplný kód: @@ -105,6 +105,6 @@ alert( fib(7) ); // 13 alert( fib(77) ); // 5527939700884757 ``` -Cyklus začíná `i=3`, protože první a druhá hodnota posloupnosti jsou napevno zakódovány do proměnných `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`. 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/04-output-single-linked-list/solution.md b/1-js/06-advanced-functions/01-recursion/04-output-single-linked-list/solution.md index d4c45778e..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 @@ -18,11 +18,11 @@ let seznam = { }; function vypišSeznam(seznam) { - let tmp = seznam; + let dočasná = seznam; - while (tmp) { - alert(tmp.hodnota); - tmp = tmp.další; + while (dočasná) { + alert(dočasná.hodnota); + dočasná = dočasná.další; } } @@ -30,7 +30,7 @@ function vypišSeznam(seznam) { vypišSeznam(seznam); ``` -Prosíme všimněte si, že k procházení seznamem používáme dočasnou proměnnou `tmp`. Technicky bychom místo ní mohli použít parametr funkce `seznam`: +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 vypišSeznam(seznam) { @@ -47,7 +47,7 @@ function vypišSeznam(seznam) { 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é. -Na druhou stranu role `tmp` je výhradně procházení seznamu, podobně jako `i` v cyklu `for`. +Naproti tomu role proměnné `dočasná` je výhradně procházení seznamu, podobně jako u proměnné `i` v cyklu `for`. # Rekurzívní řešení @@ -85,4 +85,4 @@ Které řešení je nyní lepší? Technicky je cyklus efektivnější. Obě varianty dělají totéž, ale cyklus nespotřebovává zdroje pro vnořená volání funkce. -Na druhou stranu je rekurzívní varianta kratší a někdy je snadnější jí porozumět. +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/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 f369501c7..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 @@ -35,7 +35,7 @@ vypišSeznamObráceně(seznam); Také cyklová varianta je trochu složitější než přímý výpis. -Není žádný způsob, jak získat poslední hodnotu našeho `seznamu`. Nemůžeme se také „vracet“. +Není žádný způsob, jak získat poslední hodnotu našeho `seznamu`. Nemůžeme se ani „vracet“. 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í: @@ -56,11 +56,11 @@ let seznam = { function vypišSeznamObráceně(seznam) { let pole = []; - let tmp = seznam; + let dočasná = seznam; - while (tmp) { - pole.push(tmp.hodnota); - tmp = tmp.další; + while (dočasná) { + pole.push(dočasná.hodnota); + dočasná = dočasná.další; } for (let i = pole.length - 1; i >= 0; i--) { @@ -71,4 +71,4 @@ function vypišSeznamObráceně(seznam) { vypišSeznamObráceně(seznam); ``` -Prosíme všimněte si, že rekurzívní řešení dělá ve skutečnosti přesně totéž: prochází seznam, pamatuje si prvky v řetězci vnořených volání (v zásobníku prováděcích kontextů) a pak je vypisuje. +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/article.md b/1-js/06-advanced-functions/01-recursion/article.md index 47143d5af..436d4078b 100644 --- a/1-js/06-advanced-functions/01-recursion/article.md +++ b/1-js/06-advanced-functions/01-recursion/article.md @@ -39,7 +39,7 @@ Existují dva způsoby, jak ji implementovat. alert( mocnina(2, 3) ); // 8 ``` -2. Rekurzívní myšlení: zjednodušit úlohu a volat sebe samu: +2. Rekurzívní myšlení: zjednodušit úlohu a volat sebe sama: ```js run function mocnina(x, n) { @@ -65,11 +65,11 @@ mocnina(x, n) = else = x * mocnina(x, n - 1) ``` -1. Je-li `n == 1`, pak je vše triviální. To se nazývá *základ* rekurze, jelikož okamžitě vydá zřejmý výsledek: `mocnina(x, 1)` se rovná `x`. -2. Jinak můžeme reprezentovat `mocnina(x, n)` jako `x * mocnina(x, n - 1)`. V matematice můžeme zapsat xn = x * xn-1. -To 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`. +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`. -Můžeme také říci, že `mocnina` *rekurzívně volá sebe sama*, dokud není `n == 1`. +Můžeme také říci, že funkce `mocnina` *rekurzívně volá sebe sama*, dokud není `n == 1`. ![rekurzívní diagram funkce mocnina](recursion-pow.svg) @@ -97,7 +97,7 @@ function mocnina(x, 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`. -Maximální možná hloubka rekurze je omezena enginem JavaScriptu. Můžeme se spolehnout, že to bude aspoň 10000, některé enginy umožňují víc, ale 100000 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. +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. 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. @@ -107,7 +107,7 @@ Nyní prozkoumejme, jak rekurzívní volání fungují. K tomu se podíváme fun 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*. -[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í tok řízení právě teď, aktuální proměnné, hodnotu `this` (zde ji nepoužíváme) a některé další interní detaily. +[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. S každou funkcí je spojen právě jeden prováděcí kontext. @@ -115,14 +115,14 @@ Když funkce vykoná vnořené volání, stane se následující: - 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ů*. -- Je spuštěno vnořené volání. -- Až toto volání skončí, starý prováděcí kontext se vyjme ze zásobníku a vnější funkce se obnoví od místa, kde byla zastavena. +- 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. Podívejme se, co se děje během volání `mocnina(2, 3)`. ### mocnina(2, 3) -Na začátku volání `mocnina(2, 3)` si prováděcí kontext uloží proměnné: `x = 2, n = 3`, tok řízení je na řádku `1` této funkce. +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. Můžeme si to zapsat jako: @@ -133,7 +133,7 @@ Můžeme si to zapsat jako: -Na tomto místě začne výkon funkce. Podmínka `n == 1` není splněna, takže tok pokračuje druhou větví `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 mocnina(x, n) { @@ -171,7 +171,7 @@ Zde voláme stejnou funkci `mocnina`, ale na tom vůbec nezáleží. Proces je p 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. -Zde je zásobník kontextů ve chvíli, kdy jsme vstoupili do vnořeného volání `mocnina(2, 2)`: +Takto vypadá zásobník kontextů ve chvíli, kdy jsme vstoupili do vnořeného volání `mocnina(2, 2)`:

  • @@ -186,12 +186,12 @@ Zde je zásobník kontextů ve chvíli, kdy jsme vstoupili do vnořeného volán Nový aktuální prováděcí kontext je na vrcholu (a uveden tučně), předchozí uložené kontexty jsou níže. -Až vnořené volání skončí -- bude snadné obnovit předchozí kontext, jelikož si udržuje obě proměnné i přesné místo kódu, na němž se zastavil. +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 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(…)`. -Bylo by tedy přesnější říkat, že provádění se obnoví „ihned po vnořeném volání“. +Bylo by tedy přesnější říkat, že provádění se obnoví „ihned za vnořeným voláním“. ``` ### mocnina(2, 1) @@ -219,7 +219,7 @@ Nyní máme 2 staré kontexty a 1 právě probíhající pro `mocnina(2, 1)`. ### Konec -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 pracovat první větev `if`: +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 mocnina(x, n) { @@ -265,7 +265,7 @@ Hloubka rekurze v tomto případě byla **3**. Jak vidíme z výše uvedených ilustrací, hloubka rekurze se rovná nejvyššímu počtu kontextů v zásobníku. -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ů pro všechny nižší hodnoty `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`. Algoritmus založený na cyklu ušetří více paměti: @@ -283,15 +283,15 @@ function mocnina(x, 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`. -**Každou rekurzi lze přepsat do smyčky. Variantu se smyčkou lze obvykle napsat efektivněji.** +**Každou rekurzi lze přepsat do cyklu. Variantu s cyklem lze obvykle napsat efektivněji.** ...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. -Rekurze mohou vydat kratší kód, jednodušší na porozumění a podporu. Optimalizace nejsou nutné všude, většinou potřebujeme dobrý kód, proto používáme rekurzi. +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. -## Rekurzívní traversaly +## Rekurzívní traverzování -Další skvělé využití rekurze je rekurzívní traversal. +Další skvělé využití rekurze je rekurzívní traverzování. Představme si, že máme firmu. Struktura jejího personálu se dá vyjádřit jako objekt: @@ -336,7 +336,7 @@ Iterativní přístup není snadný, protože struktura není jednoduchá. Prvn Zkusme rekurzi. -Jak vidíme, když naše funkce obdrží oddělení, které má sečíst, mohou nastat dva případy: +Jak vidíme, když naše funkce obdrží oddělení, jehož platy má sečíst, mohou nastat dva případy: 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. @@ -375,7 +375,7 @@ function sečtiPlaty(oddělení) { alert(sečtiPlaty(firma)); // 7700 ``` -Kód je krátký a snadno srozumitelný (doufejme?). V tom spočívá síla rekurze. Funguje pro jakoukoli úroveň vnoření oddělení. +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í. Zde je diagram volání: @@ -383,9 +383,9 @@ Zde je diagram volání: 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. -Všimněte si, že kód využívá elegantní vlastnosti, které jsme uvedli již dříve: +Všimněte si, že kód využívá elegantní prvky, které jsme uvedli již dříve: -- Metodu `arr.reduce` vysvětlenou v kapitole k získání součtu pole. +- 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. @@ -393,11 +393,11 @@ Všimněte si, že kód využívá elegantní vlastnosti, které jsme uvedli ji Rekurzívní (rekurzívně definovaná) datová struktura je struktura, která částečně replikuje sama sebe. -Právě jsme ji viděli ve výše uvedeném příkladu struktury firmy. +Ve výše uvedeném příkladu struktury firmy jsme ji právě viděli. Firemní *oddělení* je: -- Buď pole lidí. -- Nebo objekt s *odděleními*. +- buď pole lidí, +- nebo objekt s *odděleními*. Pro vývojáře webů existují mnohem lépe známé příklady: HTML a XML dokumenty. @@ -420,15 +420,15 @@ Přirozenou volbou by bylo pole: let pole = [obj1, obj2, obj3]; ``` -...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 `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()`. -Jediné strukturální modifikace, které nevyžadují masové přečíslování, jsou ty, které pracují s koncem pole: `pole.push/pop`. Pole tedy může být poměrně pomalé pro velké fronty, když musíme pracovat s jeho začátkem. +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. 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). *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 *null*, jestliže tento prvek je poslední. +- vlastnost `další`, která se odkazuje na další *prvek spojového seznamu* nebo, jestliže tento prvek je poslední, je rovna `null`. Příklad: @@ -455,11 +455,11 @@ Grafické zobrazení seznamu: Alternativní kód pro vytvoření: ```js no-beautify -let list = { hodnota: 1 }; -list.další = { hodnota: 2 }; -list.další.další = { hodnota: 3 }; -list.další.další.další = { hodnota: 4 }; -list.další.další.další.další = 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; ``` 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. @@ -481,7 +481,7 @@ seznam.další.další = druhýSeznam; A samozřejmě můžeme na kterémkoli místě vkládat nebo odstraňovat prvky. -Například chceme-li připojit novou hodnotu na začátek seznamu, musíme změnit jeho hlavičku: +Například chceme-li přidat novou hodnotu na začátek seznamu, musíme změnit jeho hlavičku: ```js let seznam = { hodnota: 1 }; @@ -497,7 +497,7 @@ seznam = { hodnota: "nový prvek", další: seznam }; ![spojový seznam](linked-list-0.svg) -Abychom odstranili prvek zprostředka, změníme `další` u předchozího prvku: +Abychom odstranili prvek uprostřed, změníme `další` u předchozího prvku: ```js seznam.další = seznam.další.další; @@ -525,7 +525,7 @@ Seznamy můžeme vylepšit: 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. - Když funkce volá sebe sama, nazývá se to *rekurzívní krok*. *Základ* rekurze jsou funkční argumenty, s nimiž je úloha natolik jednoduchá, že funkce už neučiní další volání. + 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í. - [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. @@ -535,8 +535,8 @@ Pojmy: seznam = { hodnota, další -> seznam } ``` - Stromy jako strom HTML prvků nebo strom firemních oddělení z této kapitoly jsou rovněž přirozeně rekurzívní: mají větve a každá větev může obsahovat další větve. + 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. - K procházení skrz ně mohou být použity rekurzívní funkce, jak jsme viděli v příkladu `sečtiPlaty`. + K jejich procházení mohou být použity rekurzívní funkce, jak jsme viděli v příkladu `sečtiPlaty`. 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/linked-list-0.svg b/1-js/06-advanced-functions/01-recursion/linked-list-0.svg index 5d23c7a4c..d3c552d8c 100644 --- a/1-js/06-advanced-functions/01-recursion/linked-list-0.svg +++ b/1-js/06-advanced-functions/01-recursion/linked-list-0.svg @@ -1 +1,272 @@ -value1nextvalue"new item"nextvalue2nextvalue3nextvalue4nextnulllist \ No newline at end of file + + + + + + + + + + hodnota + 1 + + další + + hodnota + "nový prvek" + + další + + hodnota + 2 + + další + + hodnota + 3 + + další + + hodnota + 4 + + další + null + seznam + + + diff --git a/1-js/06-advanced-functions/01-recursion/linked-list-remove-1.svg b/1-js/06-advanced-functions/01-recursion/linked-list-remove-1.svg index 2f37449c4..46ef2a82a 100644 --- a/1-js/06-advanced-functions/01-recursion/linked-list-remove-1.svg +++ b/1-js/06-advanced-functions/01-recursion/linked-list-remove-1.svg @@ -1 +1,277 @@ -value"new item"nextvalue1nextvalue2nextvalue3nextvalue4nextnulllist \ No newline at end of file + + + + + + + + + + hodnota + "nový prvek" + + další + + hodnota + 1 + + další + + hodnota + 2 + + další + + hodnota + 3 + + další + + hodnota + 4 + + další + null + seznam + + + diff --git a/1-js/06-advanced-functions/01-recursion/linked-list-split.svg b/1-js/06-advanced-functions/01-recursion/linked-list-split.svg index 6c3072130..175895c35 100644 --- a/1-js/06-advanced-functions/01-recursion/linked-list-split.svg +++ b/1-js/06-advanced-functions/01-recursion/linked-list-split.svg @@ -1 +1,250 @@ -value1nextvalue2nextvalue3nextvalue4nextnullnullsecondListlist \ No newline at end of file + + + + + + + + + + hodnota + 1 + + další + + hodnota + 2 + + další + + hodnota + 3 + + další + + hodnota + 4 + + další + null + null + druhýSeznam + seznam + + + diff --git a/1-js/06-advanced-functions/01-recursion/linked-list.svg b/1-js/06-advanced-functions/01-recursion/linked-list.svg index c02744f39..746e5811c 100644 --- a/1-js/06-advanced-functions/01-recursion/linked-list.svg +++ b/1-js/06-advanced-functions/01-recursion/linked-list.svg @@ -1 +1,232 @@ -value1nextvalue2nextvalue3nextvalue4nextnulllist \ No newline at end of file + + + + + + + + + + hodnota + 1 + + další + + hodnota + 2 + + další + + hodnota + 3 + + další + + hodnota + 4 + + další + null + seznam + + + 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 9a6081b50..a7c4e3ebb 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,203 @@ -pow(x,n)xx * pow(x, n-1)n == 1 ?AnoNerekurzívní volání až do n==1 \ No newline at end of file + + + + + + + + + + + mocnina(x, n) + + + + + x + + + + x * mocnina(x, n-1) + + + + + + n == 1 ? + + Ano + Ne + + + + rekurzívní volání až do n==1 + + + + From 79c47af96d8762e78be4147bdcc18bf2512baebe Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Sun, 2 Feb 2025 22:01:41 +0100 Subject: [PATCH 31/55] 1.6.2 --- .../02-rest-parameters-spread/article.md | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) 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 e3be505e2..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,6 +1,6 @@ # Zbytkové parametry a roztažená syntaxe -Mnoho vestavěných funkcí v JavaScriptu podporuje volitelný počet argumentů. +Mnoho vestavěných funkcí v JavaScriptu umožňuje uvést libovolný počet argumentů. Například: @@ -8,7 +8,7 @@ Například: - `Object.assign(cíl, zdroj1, ..., zdrojN)` -- zkopíruje vlastnosti ze `zdroj1..N` do `cíl`. - ...a tak dále. -V této kapitole se naučíme, jak udělat totéž a také jak předávat do takových funkcí pole jako parametry. +V této kapitole se naučíme, jak udělat totéž, a také, jak předávat do takových funkcí pole jako parametry. ## Zbytkové parametry `...` @@ -25,7 +25,7 @@ alert( součet(1, 2, 3, 4, 5) ); 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`. -Zbytek parametrů 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 zbytek parametrů do pole“. +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“. Například abychom shromáždili všechny argumenty do pole `argumenty`: @@ -62,7 +62,7 @@ zobrazJméno("Julius", "Caesar", "Konzul", "Imperátor"); ``` ````warn header="Zbytkové parametry musejí být na konci" -Zbytkové parametry shromažďují všechny zbývající argumenty, takže následující zápis nedává smysl a vyvolá chybu: +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, ...zbytek, arg2) { // arg2 po ...zbytek ?! @@ -75,7 +75,7 @@ function f(arg1, ...zbytek, arg2) { // arg2 po ...zbytek ?! ## Proměnná „arguments“ -Existuje také speciální objekt podobný poli nazvaný `arguments`, který obsahuje všechny argumenty podle jejich indexu. +Existuje také speciální objekt podobný poli nazvaný `arguments`, který obsahuje všechny argumenty uložené podle jejich indexu. Například: @@ -96,7 +96,7 @@ zobrazJméno("Julius", "Caesar"); zobrazJméno("Ilja"); ``` -Za starých časů 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ém kódu. +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. 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(...)`. @@ -105,7 +105,7 @@ Navíc obsahuje vždy všechny argumenty. Nemůžeme je zachytit jen částečn Když tedy tuto vlastnost potřebujeme, dáváme přednost zbytkovým parametrům. ````smart header="Šipkové funkce nemají `„arguments“`" -Jestliže přistoupíme k objektu `arguments` v šipkové funkci, vezme jej z vnější „normální“ funkce. +Jestliže přistoupíme k objektu `arguments` v šipkové funkci, převezme se z vnější „normální“ funkce. Příklad: @@ -146,11 +146,11 @@ alert( Math.max(pole) ); // NaN */!* ``` -A samozřejmě nemůžeme ručně vyjmenovat prvky pole v kódu `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 bylo by to ošklivé. +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. 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. -Když ve volání funkce použijeme `...pole`, „roztáhne“ iterovatelný objekt `pole` do seznamu argumentů. +Když ve volání funkce použijeme `...pole`, iterovatelný objekt `pole` se „roztáhne“ do seznamu argumentů. Pro `Math.max`: @@ -192,7 +192,7 @@ let spojené = [0, ...pole, 2, ...pole2]; alert(spojené); // 0,3,5,1,2,8,9,15 (0, pak pole, pak 2, pak pole2) ``` -Ve výše uvedených příkladech jsme k předvedení roztažené syntaxe použili pole, ale funguje to na jakémkoli iterovatelném objektu. +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. Například zde použijeme roztaženou syntaxi k převedení řetězce na pole znaků: @@ -202,9 +202,9 @@ let řetězec = "Ahoj"; alert( [...řetězec] ); // A,h,o,j ``` -Roztažená syntaxe interně využívá iterátory ke shromažďování prvků stejným způsobem, jako cyklus `for..of`. +Roztažená syntaxe vnitřně využívá iterátory ke shromažďování prvků stejným způsobem, jako cyklus `for..of`. -Takže pro řetězec `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]`. +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]`. 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: @@ -219,10 +219,10 @@ Výsledek je stejný jako u `[...řetězec]`. Existuje však drobný rozdíl mezi `Array.from(obj)` a `[...obj]`: -- `Array.from` funguje na poli podobných objektech i na iterovatelných objektech. +- `Array.from` funguje na objektech podobných poli i na iterovatelných objektech. - Roztažená syntaxe funguje jen na iterovatelných objektech. -Pro účel převedení něčeho na pole tedy `Array.from` bývá univerzálnější. +Pro účel převedení něčeho jiného na pole tedy `Array.from` bývá univerzálnější. ## Kopírování pole/objektu @@ -286,9 +286,9 @@ Je možné mezi nimi snadno rozlišovat: Vzory použití: -- Zbytkové parametry se používají k vytváření funkcí, které přijímají volitelný počet argumentů. +- 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ů. Společně nám pomáhají snadno přepínat mezi seznamem a polem parametrů. -Všechny argumenty volání funkce jsou rovněž k dispozici v objektu `arguments` ve starém stylu: iterovatelném objektu podobném poli. +Všechny argumenty volání funkce jsou rovněž k dispozici „ve starém stylu“ v objektu `arguments`: iterovatelném objektu podobném poli. From 96da1f1c172ccfe0e41ac925221222c3be96bee5 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Tue, 4 Feb 2025 22:40:02 +0100 Subject: [PATCH 32/55] 1.6.3 --- .../1-closure-latest-changes/solution.md | 2 +- .../1-closure-latest-changes/task.md | 2 +- .../03-closure/10-make-army/solution.md | 4 +- .../2-closure-variable-access/solution.md | 4 +- .../2-closure-variable-access/task.md | 2 +- .../4-counter-object-independent/task.md | 2 +- .../03-closure/7-let-scope/solution.md | 8 +- .../8-filter-through-function/task.md | 6 +- .../03-closure/article.md | 88 +++++++++---------- 9 files changed, 59 insertions(+), 59 deletions(-) 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 62310d030..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 @@ Odpověď zní: **Petr**. -Funkce načítá vnější proměnné tak, jak jsou právě teď. Používá poslední hodnoty. +Funkce načítá vnější proměnné tak, jak vypadají právě v tuto chvíli. Používá poslední hodnoty. 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 44be5407e..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 @@ -4,7 +4,7 @@ importance: 5 # Odrážejí se ve funkci poslední změny? -Funkce `řekniAhoj` používá název externí proměnné. Když bude spuštěna, kterou hodnotu použije? +Funkce `řekniAhoj` využívá název externí proměnné. Když bude spuštěna, kterou hodnotu použije? ```js let jméno = "Jan"; 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 c064beb24..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 @@ -31,7 +31,7 @@ Prozkoumejme, co přesně se děje uvnitř funkce `vytvořArmádu`, a řešení Proč nyní všechny tyto funkce zobrazí stejnou hodnotu, `10`? - Je to proto, že uvnitř funkce `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í. + 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í. Jaká pak bude hodnota proměnné `i`? @@ -125,4 +125,4 @@ Když jste vložili tolik námahy do přečtení tohoto řešení a konečný re 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`, a jiné scénáře, kde takové problémy opravdu nastanou. +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/2-closure-variable-access/solution.md b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/solution.md index c0857833c..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 @@ Odpověď zní: **Petr**. -Funkce `pracuj()` uvedená v kódu níže načte `jméno` z místa svého vzniku skrz odkaz na vnější lexikální prostředí: +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) Výsledkem zde je tedy `"Petr"`. -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 z výše uvedeného řetězce. V tom případě by výsledek byl `"Jan"`. +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 425c23628..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 @@ -4,7 +4,7 @@ importance: 5 # Které proměnné jsou dostupné? -Níže uvedená funkce `vytvořPracovníka` vytvoří jinou funkci a vrátí ji. Nová funkce může být volána odjinud. +Následující funkce `vytvořPracovníka` vytvoří jinou funkci a vrátí ji. Nová funkce může být volána odjinud. 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? 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 52fb2d5f2..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 @@ -4,7 +4,7 @@ importance: 5 # Objekt čítače -Zde je vytvořen objekt čítače s pomocí konstruktoru. +Zde je vytvořen objekt čítače pomocí konstruktoru. Bude to fungovat? Co se zobrazí? 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 eae0f8885..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 @@ -15,18 +15,18 @@ function funkce() { funkce(); ``` -V tomto příkladu můžeme vidět podivný rozdíl mezi „neexistující“ a „neinicializovanou“ proměnnou. +V tomto příkladu můžeme vidět pozoruhodný rozdíl mezi „neexistující“ a „neinicializovanou“ proměnnou. -Jak jste si mohli přečíst v článku [](info:closure), proměnná začíná v „neinicializovaném“ stavu ve chvíli, kdy výkon vstoupí do kódového bloku (nebo funkce). A zůstane neinicializovaná až do příslušného příkazu `let`. +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`. Jinými slovy, před `let` proměnná technicky existuje, ale nemůže být používána. -Výše uvedený kód to demonstruje. +Uvedený kód to demonstruje. ```js function funkce() { *!* - // engine zná lokální proměnnou x od začátku této funkce, + // 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 */!* 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 71abe5ea6..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 @@ -4,14 +4,14 @@ importance: 5 # Filtrace pomocí funkce -Máme vestavěnou metodu `pole.filter(f)` pro pole, která filtruje všechny prvky pomocí funkce `f`. Jestliže `f` vrátí `true`, bude prvek vrácen ve výsledném poli. +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. Vytvořte sadu filtrů „připravených k použití“: -- `mezi(a, b)` -- mezi `a` a `b` nebo rovno jim (inkluzívně). +- `mezi(a, b)` -- mezi `a` a `b` nebo rovno některému z nich (inkluzívně). - `vPoli([...])` -- v zadaném poli. -Použití musí být takovéto: +Použití musí být následující: - `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]`. diff --git a/1-js/06-advanced-functions/03-closure/article.md b/1-js/06-advanced-functions/03-closure/article.md index a3b5792c2..edbc7b343 100644 --- a/1-js/06-advanced-functions/03-closure/article.md +++ b/1-js/06-advanced-functions/03-closure/article.md @@ -1,21 +1,21 @@ # Oblast platnosti proměnné, uzávěr -JavaScript je velmi funkcionálně orientovaný jazyk. Dává nám velké množství svobody. Funkci můžeme vytvořit kdykoli, předat ji jako argument jiné funkci a později ji volat ze zcela odlišného místa kódu. +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. Víme již, že funkce může přistupovat k proměnným, které leží mimo ni (k „vnějším“ proměnným). -Co se však stane, když se poté, co je funkce vytvořena, vnější proměnné změní? Dostanou se do funkce jejich nové hodnoty nebo staré? +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? -A co když je funkce předána jako parametr 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? +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? Rozšiřme si znalosti, abychom porozuměli těmto i složitějším scénářům. ```smart header="Zde budeme hovořit o proměnných deklarovaných pomocí `let/const`" -V JavaScriptu jsou 3 způsoby, jak deklarovat proměnnou: `let`, `const` (tyto dva jsou moderní) a `var` (pozůstatek minulosti). +V JavaScriptu jsou tři způsoby, jak deklarovat proměnnou: `let`, `const` (tyto dva jsou moderní) a `var` (pozůstatek minulosti). - 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 je i o `const`. -- Staré `var` má určité významné rozdíly, které probereme v článku . +- 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 . ``` ## Kódové bloky @@ -36,7 +36,7 @@ Příklad: alert(zpráva); // Chyba: zpráva není definována ``` -Díky tomu můžeme izolovat kus kódu, který odvede svou vlastní práci, s proměnnými, které budou patřit pouze jemu: +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 { @@ -80,7 +80,7 @@ if (true) { alert(věta); // Chyba, taková proměnná neexistuje! ``` -Zde poté, co `if` skončí, `alert` pod ním neuvidí proměnnou `věta`, takže nastane chyba. +Zde po skončení `if` funkce `alert` pod ním neuvidí proměnnou `věta`, takže nastane chyba. To je skvělé, protože nám to umožňuje vytvářet blokově lokální proměnné, specifické pro větev `if`. @@ -95,7 +95,7 @@ for (let i = 0; i < 3; i++) { alert(i); // Chyba, taková proměnná neexistuje ``` -Vizuálně je `let i` mimo `{...}`. Avšak konstrukce `for` je v tomto speciální: proměnná, která je deklarována uvnitř ní, se považuje za součást bloku. +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. ## Vnořené funkce @@ -121,9 +121,9 @@ function řekniAhojNashle(křestníJméno, příjmení) { 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é. -Co je ještě zajímavější, vnořenou funkci můžeme vrátit: buď jako vlastnost nového objektu, nebo jako samotný výsledek. Pak ji můžeme použít někde jinde. Ať to bude kdekoli, stále bude mít přístup k vnějším proměnným. +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. -Níže `vytvořČítač` vytvoří funkci „čítače“, která při každém zavolání vrátí další číslo: +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 vytvořČítač() { @@ -141,11 +141,11 @@ alert( čítač() ); // 1 alert( čítač() ); // 2 ``` -Ačkoli jsou jednoduché, mírně upravené varianty tohoto kódu 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 automatické testy. +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. Jak to funguje? Když vytvoříme více čítačů, budou nezávislé? Co se bude dít se zdejšími proměnnými? -Porozumět takovým věcem je skvělé pro celkovou znalost JavaScriptu a vyplatí se při složitějších scénářích. Pojďme tedy trochu do hloubky. +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. ## Lexikální prostředí @@ -174,19 +174,19 @@ V tomto jednoduchém kódu bez funkcí existuje pouze jedno lexikální prostře To je tzv. *globální* lexikální prostředí, připojené k celému skriptu. -Obdélník ve výše uvedeném obrázku znamená záznam prostředí (skladiště proměnných) a šipka znamená odkaz vně. Globální lexikální prostředí nemá žádný odkaz vně, proto šipka ukazuje na `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`. -Když se kód začne vykonávat a pokračuje, lexikální prostředí se mění. +Když se kód začne provádět, lexikální prostředí se s jeho během mění. Zde je trochu delší kód: ![lexikální prostředí](closure-variable-phrase.svg) -Obdélníky napravo ukazují, jak se globální lexikální prostředí mění během výkonu kódu: +Obdélníky napravo ukazují, jak se globální lexikální prostředí mění během provádění kódu: 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í interní stav, který znamená, že engine ví o proměnné, ale ta nemůže být odkazována, 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 její hodnota je `undefined`. Od této chvíle můžeme tuto proměnnou používat. + - 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í. @@ -196,18 +196,18 @@ Prozatím to všechno vypadá jednoduše, že? - Práce s proměnnými je ve skutečnosti práce s vlastnostmi tohoto objektu. ```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ěci fungují. V našem kódu nemůžeme tento objekt získat a přímo s ním manipulovat. +„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. -Enginy JavaScriptu jej také mohou optimalizovat, vyřazovat nepoužívané proměnné, aby ušetřily paměť, a provádět jiné interní triky, pokud jeho viditelné chování zůstává takové, jak je zde popsáno. +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. ``` ### Krok 2. Deklarace funkcí Funkce je také hodnota, stejně jako proměnná. -**Rozdíl je v tom, že deklarace funkce je okamžitě plně inicializována.** +**Rozdíl je v tom, že při deklaraci je funkce okamžitě plně inicializována.** -Když je vytvořeno lexikální prostředí, funkce z deklarace se okamžitě stane funkcí připravenou k použití (na rozdíl od proměnné v `let`, která je až do deklarace nepoužitelná). +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á). Z tohoto důvodu můžeme používat funkci, deklarovanou deklarací funkce, ještě před samotnou deklarací. @@ -221,7 +221,7 @@ Pochopitelně toto chování platí jen pro deklarace funkcí, ne pro funkční 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í. -Například pro `řekni("Jan")` vypadá takto (výkon je na řádku označeném šipkou): +Například pro `řekni("Jan")` vypadá takto (běh je na řádku označeném šipkou): předá výsledek do generátoru ![](genYield2.svg) -1. První volání `generátor.next()` by mělo být vždy učiněno bez argumentu (je-li argument předán, je ignorován). Zahájí výkon a vrátí výsledek prvního `yield "2+2=?"`. V tuto chvíli generátor pozastaví svůj výkon a zůstane na řádku `(*)`. -2. Pak, jak je znázorněno na obrázku výše, se výsledek `yield` stane hodnotou proměnné `otázka` ve volajícím kódu. +1. První volání `generátor.next()` by mělo být vždy učiněno bez argumentu (je-li argument předán, je ignorován). Zahájí běh a vrátí výsledek prvního `yield "2+2=?"`. V tuto chvíli generátor pozastaví svůj běh a zůstane na řádku `(*)`. +2. Pak, jak je znázorněno na obrázku, se výsledek `yield` stane hodnotou proměnné `otázka` ve volajícím kódu. 3. Na `generátor.next(4)` se generátor obnoví a jako výsledek získá `4`: `let výsledek = 4`. Prosíme všimněte si, že vnější kód nemusí volat `next(4)` okamžitě. Může to nějakou dobu trvat. To není problém: generátor počká. @@ -380,21 +380,21 @@ alert( generátor.next(4).value ); // "3 * 3 = ?" alert( generátor.next(9).done ); // true ``` -Obrázek výkonu: +Běh kódu vidíme na obrázku: ![](genYield2-2.svg) -1. První `.next()` zahájí výkon... Dosáhne prvního `yield`. +1. První `.next()` zahájí běh... Dosáhne prvního `yield`. 2. Výsledek je vrácen vnějšímu kódu. -3. Druhé `.next(4)` předá `4` zpět generátoru jako výsledek prvního `yield` a obnoví výkon. -4. ...Dosáhne druhého `yield`, které se stane výsledkem volání generátoru. -5. Třetí `.next(9)` předá do generátoru `9` jako výsledek druhého `yield` a obnoví výkon, který dosáhne konce funkce, takže `done: true`. +3. Druhé `.next(4)` předá `4` zpět generátoru jako výsledek prvního `yield` a obnoví jeho běh. +4. ...Běh dosáhne druhého `yield`, které se stane výsledkem volání generátoru. +5. Třetí `.next(9)` předá do generátoru `9` jako výsledek druhého `yield` a obnoví jeho běh, který dosáhne konce funkce, takže `done: true`. -Je to jako ping-pong. Každé `next(value)` (s výjimkou prvního) předá do generátoru hodnotu, která se stane výsledkem aktuálního `yield`, a pak získá zpět výsledek dalšího `yield`. +Je to jako pingpong. Každé `next(hodnota)` (s výjimkou prvního) předá do generátoru hodnotu, která se stane výsledkem aktuálního `yield`, a pak získá zpět výsledek dalšího `yield`. ## generátor.throw -Jak jsme viděli ve výše uvedených příkladech, vnější kód může předat generátoru hodnotu jako výsledek `yield`. +Jak jsme viděli v uvedených příkladech, vnější kód může předat generátoru hodnotu jako výsledek `yield`. ...Může v něm však také vyvolat chybu. To je přirozené, neboť chyba je druh výsledku. @@ -407,7 +407,7 @@ function* gen() { try { let výsledek = yield "2 + 2 = ?"; // (1) - alert("Výkon se sem nedostane, protože výše bude vyvolána výjimka"); + alert("Běh se sem nedostane, protože výše bude vyvolána výjimka"); } catch(e) { alert(e); // zobrazí chybu } @@ -426,7 +426,7 @@ Chyba, vhozená do generátoru na řádku `(2)`, povede k výjimce na řádku `( Pokud ji nezachytíme, pak stejně jako každá výjimka „vypadne“ z generátoru do volajícího kódu. -Aktuální řádek volajícího kódu je řádek s `generátor.throw`, označený `(2)`. Můžeme ji tedy zachytit tam, například takto: +Aktuální řádek volajícího kódu je řádek s `generátor.throw`, označený `(2)`. Tam ji tedy můžeme zachytit, například takto: ```js run function* generuj() { @@ -446,11 +446,11 @@ try { */!* ``` -Pokud tuto chybu nezachytíme zde, pak jako obvykle propadne do vnějšího volajícího kódu (je-li nějaký), a není-li zachycena, shodí skript. +Pokud zde tuto chybu nezachytíme, pak jako obvykle propadne do vnějšího volajícího kódu (je-li nějaký), a není-li zachycena, shodí skript. ## generátor.return -`generátor.return(hodnota)` ukončí výkon generátoru a vrátí zadanou hodnotu `hodnota`. +`generátor.return(hodnota)` ukončí běh generátoru a vrátí zadanou hodnotu `hodnota`. ```js function* gen() { @@ -462,13 +462,13 @@ function* gen() { const g = gen(); g.next(); // { value: 1, done: false } -g.return('foo'); // { value: "foo", done: true } +g.return('nic'); // { value: "nic", done: true } g.next(); // { value: undefined, done: true } ``` Jestliže na dokončeném generátoru znovu použijeme `generátor.return()`, vrátí tuto hodnotu znovu ([MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/return)). -Tuto metodu nepoužíváme často, protože většinou chceme získat všechny vracené hodnoty, ale může být užitečná, když chceme za specifických podmínek generátor zastavit. +Tuto metodu nepoužíváme často, protože většinou chceme získat všechny vracené hodnoty, ale může být užitečná, když chceme generátor zastavit za specifických podmínek. ## Shrnutí @@ -476,8 +476,8 @@ Tuto metodu nepoužíváme často, protože většinou chceme získat všechny v - Uvnitř generátorů (pouze tam) existuje operátor `yield`. - Vnější kód a generátor si mohou vyměňovat výsledky pomocí volání `next/yield`. -V moderním JavaScriptu se generátory používají jen zřídka, ale někdy se mohou hodit, protože schopnost funkce vyměňovat si data s volajícím kódem během jejího výkonu je poměrně unikátní. A samozřejmě jsou vynikající pro vytváření iterovatelných objektů. +V moderním JavaScriptu se generátory používají jen zřídka, ale někdy se mohou hodit, protože schopnost funkce vyměňovat si data s volajícím kódem při jejím běhu je poměrně unikátní. A samozřejmě jsou vynikající pro vytváření iterovatelných objektů. -V další kapitole se navíc dozvíme o asynchronních generátorech, které se používají k načítání proudů asynchronně generovaných dat (např. stránkovaných při stahování ze sítě) v cyklech `for await ... of`. +V další kapitole se navíc dozvíme o asynchronních generátorech, které se používají k načítání proudů asynchronně generovaných dat (např. stránkovaných dat při stahování ze sítě) v cyklech `for await ... of`. Při programování webů pracujeme s datovými proudy často, takže to je další velmi důležitý případ použití. From af35b4981e91247a11189a833f0b6fc2497700b4 Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Tue, 4 Mar 2025 22:31:24 +0100 Subject: [PATCH 52/55] 1.12.2 --- .../2-async-iterators-generators/article.md | 94 +++++++++---------- .../2-async-iterators-generators/head.html | 22 ++--- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/1-js/12-generators-iterators/2-async-iterators-generators/article.md b/1-js/12-generators-iterators/2-async-iterators-generators/article.md index a15dea005..bac049e14 100644 --- a/1-js/12-generators-iterators/2-async-iterators-generators/article.md +++ b/1-js/12-generators-iterators/2-async-iterators-generators/article.md @@ -21,9 +21,9 @@ let rozsah = { Jinými slovy, chceme přidat objektu *schopnost iterace*. -To můžeme implementovat použitím speciální metody s názvem `Symbol.iterator`: +To můžeme implementovat pomocí speciální metody s názvem `Symbol.iterator`: -- Tato metoda je volána konstrukcí `for..of`, když je cyklus zahájen, a měla by vrátit objekt obsahující metodu `next`. +- Tato metoda je volána konstruktem `for..of`, když je cyklus zahájen, a měla by vrátit objekt obsahující metodu `next`. - Při každé iteraci je metoda `next()` volána pro další hodnotu. - Metoda `next()` by měla vrátit hodnotu ve tvaru `{done: true/false, value:}`, kde `done:true` znamená konec cyklu. @@ -55,23 +55,23 @@ let rozsah = { }; for(let hodnota of rozsah) { - alert(hodnota); // 1 pak 2, pak 3, pak 4, pak 5 + alert(hodnota); // 1, pak 2, pak 3, pak 4, pak 5 } ``` -Není-li vám něco jasné, prosíme navštivte kapitolu [](info:iterable), která vysvětluje všechny podrobnosti o běžných iterovatelných objektech. +Pokud vám něco není jasné, prosíme navštivte kapitolu [](info:iterable), která vysvětluje všechny podrobnosti o běžných iterovatelných objektech. ## Asynchronní iterovatelné objekty Asynchronní iteraci potřebujeme, když hodnoty přicházejí asynchronně: po `setTimeout` nebo prodlevě jiného druhu. -Nejběžnějším případem je, že objekt potřebuje vytvořit síťový požadavek k doručení další hodnoty. Příklad z reálného života uvidíme o něco později. +Nejběžnějším případem je, že objekt potřebuje k doručení další hodnoty vytvořit síťový požadavek. Příklad z reálného života uvidíme o něco později. Abychom učinili objekt asynchronně iterovatelným: -1. Použijeme `Symbol.asyncIterator` namísto `Symbol.iterator`. +1. Použijeme `Symbol.asyncIterator` místo `Symbol.iterator`. 2. Metoda `next()` by měla vrátit příslib (aby byl splněn další hodnotou). - - Zajistí to klíčové slovo `async`. Můžeme jednoduše napsat `async next()`. + - Zajistí to klíčové slovo `async`. Můžeme jednoduše vytvořit `async next()`. 3. K iteraci nad takovým objektem bychom měli používat cyklus `for await (let prvek of iterovatelnýObjekt)`. - Všimněte si slova `await`. @@ -96,8 +96,8 @@ let rozsah = { */!* *!* - // poznámka: uvnitř funkce async next můžeme použít „await“: - await new Promise(resolve => setTimeout(resolve, 1000)); // (3) + // poznámka: uvnitř asynchronní funkce next můžeme použít „await“: + await new Promise(splň => setTimeout(splň, 1000)); // (3) */!* if (this.aktuální <= this.poslední) { @@ -128,7 +128,7 @@ Jak vidíme, tato struktura se podobá obyčejným iterátorům: 3. Metoda `next()` nemusí být `async`, může to být běžná metoda vracející příslib, ale `async` nám umožňuje použít `await`, takže je vhodné. Zde prostě sekundu počkáme `(3)`. 4. K iteraci použijeme `for await(let hodnota of rozsah)` `(4)`, jmenovitě přidáme „await“ za „for“. Tento cyklus jedenkrát volá `rozsah[Symbol.asyncIterator]()` a pak pro získávání hodnot volá jeho `next()`. -Zde je malá tabulka s rozdíly: +Uvedeme malou tabulku s rozdíly: | | Iterátory | Asynchronní iterátory | |-------|-----------|-----------------| @@ -139,7 +139,7 @@ Objektová metoda, která poskytne iterátor | `Symbol.iterator` | `Symbol.async ````warn header="Roztažená syntaxe `...` asynchronně nefunguje" Prvky jazyka, které vyžadují obvyklé, synchronní iterátory, nefungují s asynchronními. -Například roztažená syntaxe nebude fungovat: +Nebude fungovat například roztažená syntaxe: ```js alert( [...rozsah] ); // Chyba, není Symbol.iterator ``` @@ -151,7 +151,7 @@ To je také případ cyklu `for..of`: syntaxe bez `await` potřebuje `Symbol.ite ## Připomínka generátorů -Nyní si připomeňme generátory, protože ty nám umožňují iterační kód značně zkrátit. Většinou, když bychom rádi vytvořili iterovatelný objekt, použijeme generátory. +Nyní si připomeňme generátory, protože ty nám umožňují iterační kód značně zkrátit. Když bychom rádi vytvořili iterovatelný objekt, většinou použijeme generátory. Pro zjednodušení, když vypustíme některé důležité věci, to jsou „funkce, které generují (vydávají) hodnoty“. Jsou podrobně vysvětleny v kapitole [](info:generators). @@ -185,7 +185,7 @@ let rozsah = { } ``` -Běžnou praxí pro `Symbol.iterator` je vrátit generátor, který kód zkrátí, jak vidíte: +Běžnou praxí pro `Symbol.iterator` je vrátit generátor, tím se kód zkrátí, jak vidíte: ```js run let rozsah = { @@ -204,17 +204,17 @@ for(let hodnota of rozsah) { } ``` -Pokud by vás zajímaly další podrobnosti, navštivte prosíme kapitolu [](info:generators). +Pokud by vás zajímaly další podrobnosti, přečtěte si prosíme kapitolu [](info:generators). -V obyčejných generátorech nemůžeme používat `await`. Všechny hodnoty musejí přicházet synchronně, jak vyžaduje konstrukce `for..of`. +V obyčejných generátorech nemůžeme používat `await`. Všechny hodnoty musejí přicházet synchronně, jak vyžaduje konstrukt `for..of`. -Co kdybychom chtěli generovat hodnoty asynchronně? Například ze síťových požadavků. +Co kdybychom chtěli generovat hodnoty asynchronně, například ze síťových požadavků? Přejděme k asynchronním generátorům, které nám to umožní. ## Asynchronní generátory (konečně) -Ve většině praktických aplikací, když chceme vytvořit objekt, který asynchronně generuje posloupnost hodnot, můžeme použít asynchronní generátor. +Když chceme vytvořit objekt, který asynchronně generuje posloupnost hodnot, ve většině praktických aplikací můžeme použít asynchronní generátor. Syntaxe je jednoduchá: před `function*` uvedeme `async`. To učiní generátor asynchronním. @@ -226,8 +226,8 @@ A pak k iteraci nad ním použijeme `for await (...)`, například: for (let i = začátek; i <= konec; i++) { *!* - // Wow, můžeme použít await! - await new Promise(resolve => setTimeout(resolve, 1000)); + // Hurá, můžeme použít await! + await new Promise(splň => setTimeout(splň, 1000)); */!* yield i; @@ -245,10 +245,10 @@ A pak k iteraci nad ním použijeme `for await (...)`, například: })(); ``` -Jelikož je generátor asynchronní, můžeme uvnitř něj používat `await`, spoléhat se na přísliby, provádět síťové požadavky a tak dále. +Jelikož je generátor asynchronní, můžeme uvnitř něj používat `await`, spoléhat se na přísliby, provádět síťové požadavky a podobně. -````smart header="Rozdíl pod kapucí" -Technicky, jestliže jste pokročilý čtenář a pamatujete si podrobnosti o generátorech, je tady interní rozdíl. +````smart header="Rozdíl pod kapotou" +Jestliže jste pokročilý čtenář a pamatujete si podrobnosti o generátorech, je tady technicky vnitřní rozdíl. U asynchronních generátorů je metoda `generátor.next()` asynchronní, vrací přísliby. @@ -257,7 +257,7 @@ V obyčejném generátoru bychom k získávání hodnot použili `výsledek = ge ```js výsledek = await generator.next(); // výsledek = {value: ..., done: true/false} ``` -To je důvod, proč asynchronní generátory fungují s `for await...of`. +Z tohoto důvodu asynchronní generátory fungují s `for await...of`. ```` ### Asynchronní iterovatelný rozsah @@ -280,7 +280,7 @@ let rozsah = { for(let hodnota = this.začátek; hodnota <= this.konec; hodnota++) { // učiňme přestávku mezi hodnotami, na něco čekáme - await new Promise(resolve => setTimeout(resolve, 1000)); + await new Promise(splň => setTimeout(splň, 1000)); yield hodnota; } @@ -296,10 +296,10 @@ let rozsah = { })(); ``` -Nyní hodnoty přicházejí s prodlevou 1 sekunda mezi nimi. +Nyní hodnoty přicházejí s prodlevou 1 sekunda mezi sebou. ```smart -Technicky můžeme do objektu přidat `Symbol.iterator` i `Symbol.asyncIterator`, bude tedy iterovatelný jak synchronně (`for..of`), tak asynchronně (`for await..of`). +Technicky můžeme do objektu přidat `Symbol.iterator` i `Symbol.asyncIterator` současně, bude tedy iterovatelný jak synchronně (`for..of`), tak asynchronně (`for await..of`). V praxi by to však bylo podivné. ``` @@ -308,24 +308,24 @@ V praxi by to však bylo podivné. Dosud jsme viděli základní příklady, abychom tomu porozuměli. Nyní se podívejme na případ použití z reálného života. -Je mnoho online služeb, které doručují stránkovaná data. Například když potřebujeme seznam uživatelů, požadavek vrátí předdefinovaný počet (např. 100 uživatelů) -- „jednu stránku“ a poskytne URL další stránky. +Existuje mnoho online služeb, které doručují stránkovaná data. Například když potřebujeme seznam uživatelů, požadavek vrátí předdefinovaný počet (např. 100 uživatelů) -- „jednu stránku“ a poskytne URL další stránky. -Tento vzorec je zcela běžný. Neplatí to jen pro uživatele, ale prostě pro cokoli. +Tento vzorec je zcela běžný. Neplatí to jen pro uživatele, ale v zásadě pro cokoli. Například GitHub nám umožňuje získávat commity stejným způsobem, po stránkách: -- Měli bychom vytvořit požadavek do `fetch` ve tvaru `https://api.github.com/repos//commits`. -- GitHub odpoví JSONem se 30 commity a také nám v headeru `Link` poskytne odkaz na další stránku. +- Měli bychom vytvořit požadavek do `fetch` ve tvaru `https://api.github.com/repos/<úložiště>/commits`. +- GitHub odpoví JSONem se 30 commity a také nám v hlavičce `Link` poskytne odkaz na další stránku. - Tento odkaz pak můžeme použít pro další požadavek, k získání dalších commitů, a tak dále. V našem kódu bychom rádi měli jednodušší způsob, jak získávat commity. -Vytvořme funkci `fetchCommits(repo)`, která nám bude načítat commity a bude vytvářet požadavky, kdykoli budou zapotřebí. A nechme ji, aby se postarala o všechny záležitosti ohledně stránkování. Pro nás to bude jednoduchá asynchronní iterace `for await..of`. +Vytvořme funkci `stáhniCommity(úložiště)`, která nám bude načítat commity a bude vytvářet požadavky, kdykoli budou zapotřebí. A nechme ji, aby se postarala o všechny záležitosti ohledně stránkování. Pro nás to bude jednoduchá asynchronní iterace `for await..of`. Použití tedy bude následující: ```js -for await (let commit of fetchCommits("username/repository")) { +for await (let commit of stáhniCommity("uživatel/úložiště")) { // zpracování commitu } ``` @@ -333,18 +333,18 @@ for await (let commit of fetchCommits("username/repository")) { Zde je taková funkce, implementovaná jako asynchronní generátor: ```js -async function* fetchCommits(repo) { - let url = `https://api.github.com/repos/${repo}/commits`; +async function* stáhniCommity(úložiště) { + let url = `https://api.github.com/repos/${úložiště}/commits`; while (url) { const odpověď = await fetch(url, { // (1) - headers: {'User-Agent': 'Our script'}, // GitHub potřebuje header s uživatelským agentem + headers: {'User-Agent': 'Our script'}, // GitHub potřebuje hlavičku s uživatelským agentem }); const tělo = await odpověď.json(); // (2) odpověď v JSONu (pole commitů) - // (3) v headerech je URL další stránky, vydolujeme ho - let dalšíStránka = response.headers.get('Link').match(/<(.*?)>; rel="next"/); + // (3) v hlavičkách je URL další stránky, vydolujeme ho + let dalšíStránka = odpověď.headers.get('Link').match(/<(.*?)>; rel="next"/); dalšíStránka = dalšíStránka?.[1]; url = dalšíStránka; @@ -360,10 +360,10 @@ Podrobnější vysvětlení, jak to funguje: 1. K načtení commitů používáme metodu prohlížeče [fetch](info:fetch). - - Úvodní URL je `https://api.github.com/repos//commits` a další stránka bude v headeru odpovědi `Link`. - - Metoda `fetch` nám umožňuje poskytnout autorizaci a další headery, pokud jsou zapotřebí -- zde GitHub vyžaduje header `User-Agent`. + - Úvodní URL je `https://api.github.com/repos/<úložiště>/commits` a další stránka bude v hlavičce odpovědi `Link`. + - Metoda `fetch` nám umožňuje poskytnout autorizaci a další hlavičky, pokud jsou zapotřebí -- zde GitHub vyžaduje hlavičku `User-Agent`. 2. Commity jsou vráceny ve formátu JSON. -3. Z headeru `Link` odpovědi bychom měli získat URL další stránky. Má speciální formát, takže pro něj použijeme regulární výraz (o tomto prvku jazyka se dozvíme v kapitole [Regulární výrazy](info:regular-expressions)). +3. Z hlavičky `Link` odpovědi bychom měli získat URL další stránky. Hlavička má speciální formát, takže pro ni použijeme regulární výraz (o tomto prvku jazyka se dozvíme v kapitole [Regulární výrazy](info:regular-expressions)). - URL další stránky může vypadat jako `https://api.github.com/repositories/93253246/commits?page=2`. Generuje je samotný GitHub. 4. Pak budeme vydávat získané commity jeden po druhém, a když dojdou, spustí se další iterace `while(url)`, která vytvoří další požadavek. @@ -374,7 +374,7 @@ Příklad použití (zobrazí na konzoli autory commitů): let počet = 0; - for await (const commit of fetchCommits('javascript-tutorial/en.javascript.info')) { + for await (const commit of stáhniCommity('javascript-tutorial/en.javascript.info')) { console.log(commit.author.login); @@ -385,7 +385,7 @@ Příklad použití (zobrazí na konzoli autory commitů): })(); -// Poznámka: Pokud tohle spouštíte v externím pískovišti, musíte sem zkopírovat výše popsanou funkci fetchCommits +// Poznámka: Pokud tohle spouštíte v externím pískovišti, musíte sem zkopírovat výše uvedenou funkci stáhniCommity ``` To je přesně to, co jsme chtěli. @@ -394,24 +394,24 @@ Vnitřní mechaniky stránkovaných požadavků jsou zvnějšku neviditelné. Pr ## Shrnutí -Obyčejné iterátory a generátory fungují dobře s daty, jejichž generování nevyžaduje více času. +Obyčejné iterátory a generátory fungují dobře s daty, jejichž generování netrvá dlouhou dobu. -Když očekáváme, že data budou přicházet asynchronně s přestávkami, můžeme použít jejich asynchronní protějšky a `for await..of` namísto `for..of`. +Když očekáváme, že data budou přicházet asynchronně s prodlevami, můžeme použít jejich asynchronní protějšky a `for await..of` místo `for..of`. Syntaktické rozdíly mezi asynchronními a běžnými iterátory: | | Iterovatelný objekt | Asynchronní iterovatelný objekt | |-------|-----------|-----------------| | Metoda poskytující iterátor | `Symbol.iterator` | `Symbol.asyncIterator` | -| Návratová hodnota `next()` je | `{value:…, done: true/false}` | `Promise`, který se vyhodnotí na `{value:…, done: true/false}` | +| Návratová hodnota `next()` je | `{value:…, done: true/false}` | `Promise`, který se splní s `{value:…, done: true/false}` | Syntaktické rozdíly mezi asynchronními a běžnými generátory: | | Generátory | Asynchronní generátory | |-------|-----------|-----------------| | Deklarace | `function*` | `async function*` | -| Návratová hodnota `next()` je | `{value:…, done: true/false}` | `Promise`, který se vyhodnotí na `{value:…, done: true/false}` | +| Návratová hodnota `next()` je | `{value:…, done: true/false}` | `Promise`, který se splní s `{value:…, done: true/false}` | -Při vývoji webů se často setkáváme s proudy dat, která přitékají po částech, například při stahování nebo uploadování velkého souboru. +Při vývoji webů se často setkáváme s proudy dat, která přitékají po částech, například při stahování nebo odesílání velkého souboru. Ke zpracování takových dat můžeme používat asynchronní generátory. Stojí také za zmínku, že v některých prostředích, např. v prohlížečích, existuje i další API nazvané Streams, které poskytuje speciální rozhraní pro práci s takovými proudy (streamy), pro transformaci dat a jejich předávání z jednoho proudu do druhého (např. při stahování z jednoho místa a okamžitém odesílání jinam). \ No newline at end of file diff --git a/1-js/12-generators-iterators/2-async-iterators-generators/head.html b/1-js/12-generators-iterators/2-async-iterators-generators/head.html index 03f21e2bd..70e299a94 100644 --- a/1-js/12-generators-iterators/2-async-iterators-generators/head.html +++ b/1-js/12-generators-iterators/2-async-iterators-generators/head.html @@ -1,22 +1,22 @@ ``` -### V modulu je „this“ nedefinováno +### V modulu není definováno „this“ Není to významná vlastnost, ale pro úplnost bychom ji měli uvést. @@ -265,12 +265,12 @@ Jestliže tento článek čtete poprvé nebo jestliže nepoužíváte JavaScript ### Modulové skripty jsou deferované -Modulové skripty jsou *vždy* deferované. Je to stejný efekt jako u atributu `defer` (popsaného v kapitole [](info:script-async-defer)), pro externí i inline skripty. +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. Jinými slovy: - stahování externích modulových skriptů ` Porovnejme si to s běžným skriptem: @@ -296,23 +296,23 @@ Porovnejme si to s běžným skriptem: ``` -Prosíme všimněte si: druhý skript se ve skutečnosti spustí před prvním! Nejprve tedy uvidíme `undefined`, až pak `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`. 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í. -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 tam umístit „indikátory načítání“ nebo jinak zajistit, aby to návštěvníka nezmátlo. +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. -### Na inline skriptech funguje async +### Na vložených skriptech funguje async 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. -Pro modulové skripty funguje i na inline skriptech. +Pro modulové skripty funguje i na vložených skriptech. -Například níže uvedený inline skript má `async`, takže nebude na nic čekat. +Například následující vložený skript má `async`, takže nebude na nic čekat. 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í. -To je dobré pro funkcionalitu, která na ničem nezávisí, např. čítače, reklamy, listenery událostí na dokumentové úrovni. +To je dobré pro funkcionalitu, která na ničem nezávisí, např. čítače, reklamy, posluchače událostí na dokumentové úrovni. ```html @@ -335,14 +335,14 @@ Externí skripty, které mají `type="module"`, se liší ve dvou aspektech: ``` -2. Externí skripty, které jsou staženy z jiného zdroje (např. z jiné stránky), vyžadují header [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 header `Access-Control-Allow-Origin`, který stažení umožní. +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 ``` - To zajišťuje větší bezpečnost. + To standardně zajišťuje větší bezpečnost. ### „Holé“ moduly nejsou povoleny @@ -351,10 +351,10 @@ V prohlížeči musí `import` obdržet relativní nebo absolutní URL. Moduly b Například tento `import` je chybný: ```js import {řekniAhoj} from 'řekniAhoj'; // Chyba, „holý“ modul -// modul musí mít cestu, např. './řekniAhoj.js' nebo kde tento modul je +// modul musí obsahovat cestu, např. './řekniAhoj.js' nebo jinou, kde tento modul je ``` -Určitá prostředí, např. Node.js nebo spojovací nástroje, umožňují holé moduly bez jakékoli cesty, 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í. +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í. ### Kompatibilita, „nomodule“ @@ -373,7 +373,7 @@ Staré prohlížeče nerozumějí `type="module"`. Skripty neznámého typu pros ## Sestavovací nástroje -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. +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. 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. @@ -396,7 +396,7 @@ Používáme-li bundlery, pak když jsou skripty spojeny dohromady do jediného ``` -Při tom všem jsou však použitelné i nativní moduly. Nebudeme tedy zde používat Webpack: můžete si jej nakonfigurovat později. +I přesto jsou ovšem použitelné i nativní moduly. Zde tedy Webpack používat nebudeme: můžete si jej nakonfigurovat později. ## Shrnutí @@ -404,15 +404,15 @@ Abychom to shrnuli, základní koncepty jsou: 1. Modul je soubor. Aby fungoval `import/export`, prohlížeče potřebují ` 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 ca920d700..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 @@ -7,5 +7,5 @@ export function nashle() { } export default function() { - alert("Modul načten (defaultní export)!"); + alert("Modul načten (výchozí export)!"); } From d19963b7ad4c338d5305a2f0351ae84d230ae79f Mon Sep 17 00:00:00 2001 From: Otmar Onderek Date: Sat, 8 Mar 2025 22:38:10 +0100 Subject: [PATCH 55/55] 1.14.1 --- .../01-proxy/01-error-nonexisting/solution.md | 4 +- .../01-proxy/01-error-nonexisting/task.md | 8 +- .../01-proxy/02-array-negative/task.md | 4 +- .../99-js-misc/01-proxy/03-observable/task.md | 2 +- 1-js/99-js-misc/01-proxy/article.md | 164 +++++++++--------- 5 files changed, 91 insertions(+), 91 deletions(-) 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 9bb1d3dae..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 @@ -4,7 +4,7 @@ let uživatel = { jméno: "Jan" }; -function wrap(cíl) { +function obal(cíl) { return new Proxy(cíl, { get(cíl, vlastnost, příjemce) { if (vlastnost in cíl) { @@ -16,7 +16,7 @@ function wrap(cíl) { }); } -uživatel = wrap(uživatel); +uživatel = obal(uživatel); 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 063c20f70..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 @@ -4,9 +4,9 @@ Pokus o načtení neexistující vlastnosti zpravidla vrátí `undefined`. Vytvořte proxy, která při pokusu o načtení neexistující vlastnosti místo toho vyvolá chybu. -To nám může pomoci brzy detekovat programátorské chyby. +To nám může pomoci dříve detekovat programátorské chyby. -Napište funkci `wrap(cíl)`, která vezme objekt `cíl` a vrátí proxy, která přidá tento funkcionální aspekt. +Napište funkci `obal(cíl)`, která vezme objekt `cíl` a vrátí proxy, která přidá tento funkcionální aspekt. Mělo by to fungovat takto: @@ -15,7 +15,7 @@ let uživatel = { jméno: "Jan" }; -function wrap(cíl) { +function obal(cíl) { return new Proxy(cíl, { *!* /* váš kód */ @@ -23,7 +23,7 @@ function wrap(cíl) { }); } -uživatel = wrap(uživatel); +uživatel = obal(uživatel); alert(uživatel.jméno); // Jan *!* 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 de636724f..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,7 +1,7 @@ # Přístup k poli[-1] -V některých programovacích jazycích můžeme přistupovat k prvkům pole pomocí záporných indexů, počítaných od konce. +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. Například: @@ -29,5 +29,5 @@ pole = new Proxy(pole, { alert( pole[-1] ); // 3 alert( pole[-2] ); // 2 -// Ostatní funkcionalita pole by měla zůstat tak, „jak je“ +// Ostatní funkcionalita pole by měla zůstat nezměněná ``` 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 2fcd62304..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 @@ -22,6 +22,6 @@ uživatel.jméno = "Jan"; // oznámí: SET jméno=Jan 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. -Kdykoli se změní některá vlastnost, je zavolán `handler(klíč, hodnota)` s názvem a hodnotou oné vlastnosti. +Kdykoli se změní některá vlastnost, je zavolán `handler(klíč, hodnota)` s jejím názvem a hodnotou. 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 810af6a53..a017c08c8 100644 --- a/1-js/99-js-misc/01-proxy/article.md +++ b/1-js/99-js-misc/01-proxy/article.md @@ -1,6 +1,6 @@ -# Proxy a Reflect +# Třídy Proxy a Reflect -Objekt `Proxy` zapouzdřuje jiný objekt a zachytává operace na něm, například čtení/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. +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. 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í. @@ -12,7 +12,7 @@ Syntaxe: let proxy = new Proxy(cíl, handler) ``` -- `cíl` -- je objekt, který má být zapouzdřen, může to být cokoli včetně funkcí. +- `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. 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`. @@ -41,17 +41,17 @@ Jak vidíme, bez pastí je `proxy` průhledným obalem kolem objektu `cíl`. ![](proxy.svg) -`Proxy` je speciální „exotický objekt“. Nemá své vlastní vlastnosti. Je-li objekt `handler` prázdný, průhledně předává operace objektu `cíl`. +`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`. -Abychom aktivovali další schopnosti, přidejme pasti. +Abychom aktivovali jeho další schopnosti, přidejme pasti. Co s nimi můžeme zachytávat? -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, přímo názvem je volat nemůžeme. +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. -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íže uvedené tabulce. +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. -Pro každou interní metodu existuje 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: +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: | Interní metoda | Metoda handleru | Spustí se při... | |-----------------|----------------|-------------| @@ -78,7 +78,7 @@ Většina z nich se týká návratových hodnot: - ...a tak dále, další uvidíme v příkladech níže. Existují i některé další invarianty, například: -- `[[GetPrototypeOf]]` aplikovaná na proxy objekt musí vracet stejnou hodnotu jako `[[GetPrototypeOf]]` aplikovaná na cílový objekt proxy objektu. Jinými slovy, načítání prototypu proxy musí vždy vrátit prototyp cílového objektu. +- `[[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. Pasti mohou tyto operace zachytávat, ale musejí dodržovat tato pravidla. @@ -87,23 +87,23 @@ Invarianty zajišťují korektní a konzistentní chování prvků jazyka. Úpln Podívejme se na praktických příkladech, jak to funguje. -## Defaultní hodnota s pastí „get“ +## Výchozí hodnota s pastí „get“ -Nejběžnější pasti jsou pro čtení/zápis vlastností. +Nejběžnější pasti jsou pro čtení a zápis vlastností. Abychom zachytili čtení, `handler` by měl obsahovat metodu `get(cíl, vlastnost, příjemce)`. -Ta se spustí, když je vlastnost načítána, s následujícími argumenty: +Když je vlastnost načítána, tato metoda se spustí s následujícími argumenty: - `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 jeho volání použit jako `this`. Obvykle je to samotný objekt `proxy` (nebo objekt, který je z něj zděděn, dědíme-li z proxy). Prozatím tento argument nepotřebujeme, takže ho podrobněji vysvětlíme později. +- `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. -Použijme `get` k implementaci defaultních hodnot objektu. +Použijme `get` k implementaci výchozích hodnot objektu. Vytvořme číselné pole, které bude pro neexistující hodnoty vracet `0`. -Když se pokoušíme načíst neexistující prvek pole, obyčejně získáme `undefined`, ale my zapouzdříme běžné pole do proxy, která bude obsahovat past na načítání a vracet `0`, pokud taková vlastnost neexistuje: +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 čísla = [0, 1, 2]; @@ -113,7 +113,7 @@ let čísla = [0, 1, 2]; if (vlastnost in cíl) { return cíl[vlastnost]; } else { - return 0; // defaultní hodnota + return 0; // výchozí hodnota } } }); @@ -124,9 +124,9 @@ alert( čísla[123] ); // 0 (takový prvek není) */!* ``` -Jak vidíme, s pastí `get` je to docela snadné. +Jak vidíme, s pastí `get` je něco takového docela snadné. -Můžeme použít `Proxy` k implementaci jakékoli logiky pro „defaultní“ hodnoty. +Můžeme použít `Proxy` k implementaci jakékoli logiky pro „výchozí“ hodnoty. Představme si, že máme slovník s větami a jejich překlady: @@ -140,9 +140,9 @@ alert( slovník['Ahoj'] ); // Hola alert( slovník['Vítejte'] ); // undefined ``` -Momentálně načtení věty, kterou `slovník` neobsahuje, vrací `undefined`. V praxi je však obvykle lepší nechat větu nepřeloženou než `undefined`. Nechme tedy slovník, aby v takovém případě vrátil místo `undefined` nepřeloženou větu. +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. -Abychom toho dosáhli, zapouzdříme `slovník` do proxy, která zachytává operace načítání: +Abychom toho dosáhli, obalíme `slovník` do proxy, která zachytává operace načítání: ```js run let slovník = { @@ -178,14 +178,14 @@ Prosíme všimněte si, jak proxy přepisuje proměnnou: slovník = new Proxy(slovník, ...); ``` -Proxy by měl cílový objekt všude zcela nahradit. Nikdo by se nikde neměl odkazovat na cílový objekt poté, co je nahrazen proxy objektem. Jinak snadno naděláme nepořádek. +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. ```` ## Ověřování pomocí pasti „set“ Řekněme, že chceme pole výlučně pro čísla. Bude-li přidána hodnota jiného typu, měla by nastat chyba. -Past `set` se spustí, když se zapisuje do vlastnosti. +Když se zapisuje do vlastnosti, spustí se past `set`. `set(cíl, vlastnost, hodnota, příjemce)`: @@ -194,7 +194,7 @@ Past `set` se spustí, když se zapisuje do vlastnosti. - `hodnota` -- hodnota vlastnosti, - `příjemce` -- podobně jako u pasti `get`, má význam jen pro settery. -Past `set` by měla vracet `true`, je-li nastavení úspěšné, a `false` jinak (vyvolá `TypeError`). +Past `set` by měla vracet `true`, je-li nastavení úspěšné, a jinak `false` (vyvolá `TypeError`). Použijme ji k ověřování nových hodnot: @@ -225,9 +225,9 @@ alert("Délka pole je: " + čísla.length); // 2 alert("Na tento řádek se nikdy nedostaneme (chyba na řádku výše)"); ``` -Prosíme všimněte si: zabudovaná funkcionalita polí stále funguje! Hodnoty se přidávají metodou `push`. Vlastnost `length` se automaticky zvyšuje, když jsou hodnoty přidávány. Naše proxy nic nepokazila. +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. -Nemusíme přepisovat metody přidávání hodnot do polí jako `push`, `unshift` a tak dále, abychom tam přidali ověření, protože ty interně používají operaci `[[Set]]`, kterou proxy zachytává. +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á. Kód je tedy čistý a výstižný. @@ -249,9 +249,9 @@ Tyto metody se liší v detailech: - `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. -...Všechny však začínají s tímto seznamem. +...Všechny však začínají se seznamem vlastností vráceným touto metodou. -V níže uvedené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 `_`: +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 uživatel = { @@ -294,7 +294,7 @@ uživatel = new Proxy(uživatel, { alert( Object.keys(uživatel) ); // ``` -Proč? Důvod je prostý: `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ý, neobsahuje přepínač `enumerable`, a tak je přeskočen. +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. 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`. @@ -338,12 +338,12 @@ let uživatel = { alert(uživatel._heslo); // tajné ``` -Použijme proxy, abychom zabránili jakémukoli přístupu k vlastnostem, které začínají `_`. +Abychom zabránili jakémukoli přístupu k vlastnostem, které začínají `_`, použijme proxy. 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í, -- `defineProperty` k vyvolání chyby při jejím mazá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`. Zde je kód: @@ -438,18 +438,18 @@ uživatel = { 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. -Proto na řádku `(*)` navážeme kontext objektových metod na původní objekt, `cíl`. Pak jejich budoucí volání budou jako `this` používat `cíl` bez jakýchkoli pastí. +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í. -Toto řešení zpravidla funguje, ale není ideální, protože metoda může předat neproxovaný objekt někam jinam a pak nastane zmatek: kde je původní objekt a kde proxovaný? +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ý? -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 nezapouzdřený objekt, důsledky mohou být nečekané. +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é. Taková proxy by tedy neměla být používána všude. ```smart header="Soukromé vlastnosti třídy" -Moderní JavaScriptové enginy nativně podporují ve třídách soukromé vlastnosti, začínající znakem `#`. Jsou popsány v článku . Žádné proxy nejsou zapotřebí. +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í. -Takové vlastnosti však mají své vlastní problémy. Konkrétně nejsou děděny. +Takové vlastnosti však mají své vlastní problémy. Například nejsou děděny. ``` ## „in“ pro rozsah s pastí „has“ @@ -465,7 +465,7 @@ let rozsah = { }; ``` -Rádi bychom používali operátor `in` k ověření, zda číslo leží v rozsahu `rozsah`. +K ověření, zda číslo leží v rozsahu `rozsah`, bychom rádi používali operátor `in`. Volání `in` zachytává past `has`. @@ -498,9 +498,9 @@ alert(50 in rozsah); // false Pěkný syntaktický cukr, že? A implementuje se velmi jednoduše. -## Wrapovací funkce: „apply“ [#proxy-apply] +## Obalování funkcí: „apply“ [#proxy-apply] -Do proxy můžeme zapouzdřit i funkci. +Do proxy můžeme obalit i funkci. Past `apply(cíl, thisArg, args)` zpracovává volání proxy jako funkce: @@ -508,15 +508,15 @@ Past `apply(cíl, thisArg, args)` zpracovává volání proxy jako funkce: - `thisArg` je hodnota `this`, - `args` je seznam argumentů. -Vzpomeňme si například na dekorátor `čekej(f, ms)`, který jsme vytvořili v článku . +Vzpomeňme si například na dekorátor `zpozdi(f, ms)`, který jsme vytvořili v článku . -V onom článku jsme to udělali bez proxy. Volání `čekej(f, ms)` vrátilo funkci, která funkci `f` předává všechna volání za `ms` milisekund. +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. Zde je předchozí implementace založená na funkcích: ```js run -function čekej(f, ms) { - // vrátí wrapper, který po uplynutí času předá volání funkci f +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); }; @@ -526,18 +526,18 @@ function řekniAhoj(uživatel) { alert(`Ahoj, ${uživatel}!`); } -// po tomto wrapování budou volání řekniAhoj pozdržena o 3 sekundy -řekniAhoj = čekej(řekniAhoj, 3000); +// po tomto obalení budou volání řekniAhoj pozdržena o 3 sekundy +řekniAhoj = zpozdi(řekniAhoj, 3000); řekniAhoj("Jan"); // Ahoj, Jan! (po 3 sekundách) ``` -Jak jsme již viděli, většinou to funguje. Wrapperová funkce `(*)` provede volání po stanoveném čase. +Jak jsme již viděli, většinou to funguje. Obalová funkce `(*)` provede volání po stanoveném čase. -Avšak wrapperová funkce nepředává dál operace čtení/zápisu do vlastností nebo cokoli jiného. Po wrapování ztratíme přístup k vlastnostem původní funkce, např. `name`, `length` a jiným: +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 čekej(f, ms) { +function zpozdi(f, ms) { return function() { setTimeout(() => f.apply(this, arguments), ms); }; @@ -551,19 +551,19 @@ function řekniAhoj(uživatel) { alert(řekniAhoj.length); // 1 (length=délka, délka funkce je počet argumentů v její deklaraci) */!* -řekniAhoj = čekej(řekniAhoj, 3000); +řekniAhoj = zpozdi(řekniAhoj, 3000); *!* -alert(řekniAhoj.length); // 0 (v deklaraci wrapperu je 0 argumentů) +alert(řekniAhoj.length); // 0 (v deklaraci obalu je 0 argumentů) */!* ``` `Proxy` je mnohem silnější, jelikož cílovému objektu předává všechno. -Použijme `Proxy` místo wrapovací funkce: +Použijme `Proxy` místo obalové funkce: ```js run -function čekej(f, ms) { +function zpozdi(f, ms) { return new Proxy(f, { apply(cíl, thisArg, args) { setTimeout(() => cíl.apply(thisArg, args), ms); @@ -575,7 +575,7 @@ function řekniAhoj(uživatel) { alert(`Ahoj, ${uživatel}!`); } -řekniAhoj = čekej(řekniAhoj, 3000); +řekniAhoj = zpozdi(řekniAhoj, 3000); *!* alert(řekniAhoj.length); // 1 (*) proxy předá cíli operaci „get length“ @@ -584,11 +584,11 @@ alert(řekniAhoj.length); // 1 (*) proxy předá cíli operaci „get length“ řekniAhoj("Jan"); // Ahoj, Jan! (po 3 sekundách) ``` -Výsledek je stejný, ale nyní se původní funkci předávají nejen volání, ale všechny operace na proxy. Po wrapování se tedy `řekniAhoj.length` na řádku `(*)` vrátí správně. +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ě. -Získali jsme „bohatší“ wrapper. +Získali jsme „bohatší“ obal. -Existují i jiné pasti: jejich úplný seznam je uveden na začátku tohoto článku. Jejich vzor použití je podobný tomu uvedenému výše. +Existují i jiné pasti: jejich úplný seznam je uveden na začátku tohoto článku. Jejich vzorec použití je podobný uvedenému. ## Reflect @@ -596,7 +596,7 @@ Existují i jiné pasti: jejich úplný seznam je uveden na začátku tohoto čl Již jsme uvedli, že interní metody, např. `[[Get]]`, `[[Set]]` a jiné, jsou jen specifikační a nemůžeme je volat přímo. -Objekt `Reflect` to částečně umožňuje. Jeho metody jsou minimální wrappery okolo interních metod. +Objekt `Reflect` to částečně umožňuje. Jeho metody jsou minimální obaly okolo interních metod. Zde jsou příklady operací a volání `Reflect`, která udělají totéž: @@ -624,7 +624,7 @@ Konkrétně nám `Reflect` umožňuje volat operátory (`new`, `delete`...) jako Můžeme tedy používat `Reflect` k předání operace původnímu objektu. -V tomto příkladu obě pasti `get` a `set` průhledně (jako by neexistovaly) předají objektu operace čtení/zápisu a zobrazí zprávu: +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 uživatel = { @@ -655,7 +655,7 @@ Zde: - `Reflect.get` načte vlastnost objektu. - `Reflect.set` zapíše vlastnost objektu a vrátí `true`, je-li úspěšná, jinak `false`. -Přitom je všechno jednoduché: jestliže past chce předat objektu volání, stačí jí volat `Reflect.` se stejnými argumenty. +Všechno je přitom jednoduché: jestliže past chce předat volání objektu, stačí jí volat `Reflect.` se stejnými argumenty. 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. @@ -733,7 +733,7 @@ Problém je ve skutečnosti v proxy na řádku `(*)`. 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`. -Jak předat kontext getteru? Pro běžnou funkci můžeme použít `call/apply`, ale tohle je getter, ten se „nevolá“, jenom se k němu přistupuje. +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. Může to udělat `Reflect.get`. Pokud ji použijeme, bude všechno fungovat správně. @@ -776,19 +776,19 @@ get(cíl, vlastnost, příjemce) { } ``` -Volání `Reflect` jsou pojmenována přesně stejně jako pasti a přijímají stejné argumenty. Byla tak úmyslně navržena. +Metody `Reflect` jsou pojmenovány přesně stejně jako pasti a přijímají stejné argumenty. Byly tak úmyslně navrženy. `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. ## Omezení proxy -Proxy poskytují unikátní způsob, jak změnit nebo upravit chování existujících objektů na nejnižší úrovni. Přesto ovšem nejsou dokonalé. Mají svá omezení. +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í. ### Zabudované objekty: Interní sloty Mnoho zabudovaných objektů, např. `Map`, `Set`, `Date`, `Promise` a jiné, využívá tzv. „interní sloty“. -Podobají se vlastnostem, ale jsou rezervovány pro interní, 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. +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. Proč se o to starat? Jsou přece interní! @@ -806,7 +806,7 @@ proxy.set('test', 1); // Chyba */!* ``` -Interně 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. +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. Naštěstí existuje způsob, jak to opravit: @@ -828,17 +828,17 @@ alert(proxy.get('test')); // 1 (funguje!) Teď to funguje dobře, protože past `get` naváže funkční vlastnosti, např. `mapa.set`, na samotný cílový objekt (`mapa`). -Na rozdíl od předchozího příkladu hodnota `this` uvnitř `proxy.set(...)` nebude `proxy`, ale původní `mapa`. Když se tedy interní implementace metody `set` pokusí přistoupit k internímu slotu `this.[[MapData]]`, uspěje. +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` nemá žádné 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ž dávno. +```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. Při proxování pole tedy takový problém nenastává. ``` ### Soukromá pole -Obdobná věc nastává se soukromými třídními poli. +Obdobný problém nastává se soukromými třídními poli. Například metoda `vraťJméno()` přistupuje k soukromé vlastnosti `#jméno` a po proxování se rozbije: @@ -891,9 +891,9 @@ Při tom všem však toto řešení má nevýhody, jak bylo vysvětleno dříve: ### Proxy != cíl -Proxy a původní objekt jsou různé objekty. To je přirozené, ne? +Proxovaný a původní objekt jsou různé objekty. To je přirozené, ne? -Když tedy použijeme původní objekt jako klíč a pak jej naproxujeme, proxy nebude nalezena: +Když tedy použijeme původní objekt jako klíč a pak jej naproxujeme, proxovaný objekt nebude nalezen: ```js run let všichniUživatelé = new Set(); @@ -916,7 +916,7 @@ alert(všichniUživatelé.has(uživatel)); // false */!* ``` -Jak vidíme, po naproxování nenajdeme objekt `uživatel` v množině `všichniUživatelé`, jelikož proxy je jiný objekt. +Jak vidíme, po naproxování nenajdeme objekt `uživatel` v množině `všichniUživatelé`, jelikož proxovaný objekt je jiný. ```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. @@ -930,9 +930,9 @@ Všechny operace a vestavěné třídy, které porovnávají objekty, tedy budou *Zrušitelná* proxy je proxy, která může být zakázána. -Řekněme, že máme zdroj a chtěli bychom v libovolném okamžiku uzavřít přístup k němu. +Řekněme, že máme zdroj a chtěli bychom k němu kdykoli uzavřít přístup. -To, co můžeme udělat, je zapouzdřit jej 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. +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. Syntaxe je: @@ -940,7 +940,7 @@ Syntaxe je: let {proxy, revoke} = Proxy.revocable(cíl, handler) ``` -Toto volání vrátí objekt s `proxy` a funkcí `revoke`, která tuto proxy zakáže. +Toto volání vrátí objekt s `proxy` a funkci `revoke`, která tuto proxy zakáže. Zde je příklad: @@ -951,7 +951,7 @@ let objekt = { let {proxy, revoke} = Proxy.revocable(objekt, {}); -// předáme proxy někam místo objektu... +// předáme někam proxy místo objektu... alert(proxy.data); // Cenná data // později v našem kódu @@ -989,7 +989,7 @@ revoke(); alert(proxy.data); // Chyba (zakázáno) ``` -Zde používáme `WeakMap` místo `Map`, protože neblokuje garbage collection. Pokud se proxy 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í. +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í. ## Odkazy @@ -998,9 +998,9 @@ Zde používáme `WeakMap` místo `Map`, protože neblokuje garbage collection. ## Shrnutí -`Proxy` je wrapper okolo objektu, který objektu předává operace na něm prováděné a může některé z nich zachytit. +`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. -Může zapouzdřovat objekt jakéhokoli druhu včetně tříd a funkcí. +Může obalit objekt jakéhokoli druhu včetně tříd a funkcí. Syntaxe je: @@ -1018,15 +1018,15 @@ Můžeme zachytávat: - 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)). -To nám umožňuje vytvářet „virtuální“ vlastnosti a metody, implementovat defaultní vlastnosti, pozorovatelné objekty, dekorátory funkcí a mnoho dalšího. +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. -Můžeme také zapouzdřit objekt vícekrát do různých proxy a dekorovat jej tak různými aspekty funkcionality. +Můžeme také obalit objekt vícekrát do různých proxy a dekorovat jej tak různými aspekty funkcionality. -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 odpovídající volání `Reflect` se stejnými argumenty. Měli bychom je používat k předávání volání cílovým objektům. +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. Proxy mají určitá omezení: - 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 interně implementována pomocí slotů. Volání proxovaných metod tedy musí nastavovat cílový objekt jako `this`, aby se k nim dalo přistupovat. +- 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: benchmarky závisejí na enginu, 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ů v „úzkém hrdle“. +- 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“.