├── .gitattributes ├── .github └── FUNDING.yml ├── .gitignore ├── 1-js ├── 01-getting-started │ ├── 1-intro │ │ ├── article.md │ │ └── limitations.svg │ ├── 2-manuals-specifications │ │ └── article.md │ ├── 3-code-editors │ │ └── article.md │ ├── 4-devtools │ │ ├── article.md │ │ ├── bug.html │ │ ├── chrome.webp │ │ ├── chrome@2.webp │ │ ├── safari.png │ │ └── safari@2x.png │ └── index.md ├── 02-first-steps │ ├── 01-hello-world │ │ ├── 1-hello-alert │ │ │ ├── index.html │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 2-hello-alert-ext │ │ │ ├── alert.js │ │ │ ├── index.html │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 02-structure │ │ └── article.md │ ├── 03-strict-mode │ │ └── article.md │ ├── 04-variables │ │ ├── 1-hello-variables │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-declare-variables │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-uppercast-constant │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ ├── variable-change.svg │ │ └── variable.svg │ ├── 05-types │ │ ├── 1-string-quotes │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 06-alert-prompt-confirm │ │ ├── 1-simple-page │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 07-type-conversions │ │ └── article.md │ ├── 08-operators │ │ ├── 1-increment-order │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-assignment-result │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-primitive-conversions-questions │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 4-fix-prompt │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 09-comparison │ │ ├── 1-comparison-questions │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 10-ifelse │ │ ├── 1-if-zero-string │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-check-standard │ │ │ ├── ifelse_task2.svg │ │ │ ├── ifelse_task2 │ │ │ │ └── index.html │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-sign │ │ │ ├── if_sign │ │ │ │ └── index.html │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 5-rewrite-if-question │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 6-rewrite-if-else-question │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 11-logical-operators │ │ ├── 1-alert-null-2-undefined │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-alert-or │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-alert-1-null-2 │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 4-alert-and │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 5-alert-and-or │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 6-check-if-in-range │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 7-check-if-out-range │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 8-if-question │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 9-check-login │ │ │ ├── ifelse_task.svg │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 12-nullish-coalescing-operator │ │ └── article.md │ ├── 13-while-for │ │ ├── 1-loop-last-value │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-which-value-while │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-which-value-for │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 4-for-even │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 5-replace-for-while │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 6-repeat-until-correct │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 7-list-primes │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 14-switch │ │ ├── 1-rewrite-switch-if-else │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-rewrite-if-switch │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 15-function-basics │ │ ├── 1-if-else-required │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-rewrite-function-question-or │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-min │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 4-pow │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 16-function-expressions │ │ └── article.md │ ├── 17-arrow-functions-basics │ │ ├── 1-rewrite-arrow │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 18-javascript-specials │ │ └── article.md │ └── index.md ├── 03-code-quality │ ├── 01-debugging-chrome │ │ ├── article.md │ │ ├── chrome-open-sources.svg │ │ ├── chrome-sources-breakpoint.svg │ │ ├── chrome-sources-console.svg │ │ ├── chrome-sources-debugger-pause.svg │ │ ├── chrome-sources-debugger-trace-1.svg │ │ ├── chrome-tabs.svg │ │ ├── debugging.view │ │ │ ├── hello.js │ │ │ └── index.html │ │ ├── head.html │ │ └── largeIcons.svg │ ├── 02-coding-style │ │ ├── 1-style-errors │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ └── code-style.svg │ ├── 03-comments │ │ └── article.md │ ├── 04-ninja-code │ │ └── article.md │ ├── 05-testing-mocha │ │ ├── 3-pow-test-wrong │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ ├── beforeafter.view │ │ │ ├── index.html │ │ │ └── test.js │ │ ├── index.html │ │ ├── pow-1.view │ │ │ ├── index.html │ │ │ └── test.js │ │ ├── pow-2.view │ │ │ ├── index.html │ │ │ └── test.js │ │ ├── pow-3.view │ │ │ ├── index.html │ │ │ └── test.js │ │ ├── pow-4.view │ │ │ ├── index.html │ │ │ └── test.js │ │ ├── pow-full.view │ │ │ ├── index.html │ │ │ └── test.js │ │ ├── pow-min.view │ │ │ ├── index.html │ │ │ └── test.js │ │ └── pow-nan.view │ │ │ ├── index.html │ │ │ └── test.js │ ├── 06-polyfills │ │ └── article.md │ └── index.md ├── 04-object-basics │ ├── 01-object │ │ ├── 2-hello-object │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-is-empty │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 5-sum-object │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 8-multiply-numeric │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ ├── source.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ ├── object-user-delete.svg │ │ ├── object-user-empty.svg │ │ ├── object-user-isadmin.svg │ │ ├── object-user-props.svg │ │ ├── object-user.svg │ │ └── object.svg │ ├── 02-object-copy │ │ ├── article.md │ │ ├── variable-contains-reference.svg │ │ ├── variable-copy-reference.svg │ │ └── variable-copy-value.svg │ ├── 03-garbage-collection │ │ ├── article.md │ │ ├── family-delete-refs.svg │ │ ├── family-no-family.svg │ │ ├── family-no-father-2.svg │ │ ├── family-no-father.svg │ │ ├── family.svg │ │ ├── garbage-collection-1.svg │ │ ├── garbage-collection-2.svg │ │ ├── garbage-collection-3.svg │ │ ├── garbage-collection-4.svg │ │ ├── garbage-collection-5.svg │ │ ├── memory-user-john-admin.svg │ │ ├── memory-user-john-lost.svg │ │ └── memory-user-john.svg │ ├── 04-object-methods │ │ ├── 4-object-property-this │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 7-calculator │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 8-chain-calls │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 06-constructor-new │ │ ├── 1-two-functions-one-object │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-calculator-constructor │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-accumulator │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 07-optional-chaining │ │ └── article.md │ ├── 08-symbol │ │ └── article.md │ ├── 09-object-toprimitive │ │ └── article.md │ └── index.md ├── 05-data-types │ ├── 01-primitives-methods │ │ ├── 1-string-new-property │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 02-number │ │ ├── 1-sum-interface │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-why-rounded-down │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-repeat-until-number │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 4-endless-loop-error │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 8-random-min-max │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 9-random-int-min-max │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 03-string │ │ ├── 1-ucfirst │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-check-spam │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-truncate │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 4-extract-currency │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 04-array │ │ ├── 1-item-value │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 10-maximal-subarray │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-create-array │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-call-array-this │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 5-array-input-sum │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── array-pop.svg │ │ ├── array-shift.svg │ │ ├── array-speed.svg │ │ ├── article.md │ │ ├── queue.svg │ │ └── stack.svg │ ├── 05-array-methods │ │ ├── 1-camelcase │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 10-average-age │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 11-array-unique │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 12-reduce-object │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-filter-range │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-filter-range-in-place │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 4-sort-back │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 5-copy-sort-array │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 6-array-get-names │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 6-calculator-extendable │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 7-map-objects │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 8-sort-objects │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 9-shuffle │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ └── reduce.svg │ ├── 06-iterable │ │ └── article.md │ ├── 07-map-set │ │ ├── 01-array-unique-map │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 02-filter-anagrams │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 03-iterable-keys │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 08-weakmap-weakset │ │ ├── 01-recipients-read │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 02-recipients-when-read │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 09-keys-values-entries │ │ ├── 01-sum-salaries │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 02-count-properties │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 10-destructuring-assignment │ │ ├── 1-destruct-user │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 6-max-salary │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ └── destructuring-complex.svg │ ├── 11-date │ │ ├── 1-new-date │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-get-week-day │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-weekday │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 4-get-date-ago │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 5-last-day-of-month │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 6-get-seconds-today │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 7-get-seconds-to-tomorrow │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 8-format-date-relative │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 12-json │ │ ├── 1-serialize-object │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-serialize-event-circular │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ └── json-meetup.svg │ └── index.md ├── 06-advanced-functions │ ├── 01-recursion │ │ ├── 01-sum-to │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 02-factorial │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 03-fibonacci-numbers │ │ │ ├── fibonacci-recursion-tree.svg │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 04-output-single-linked-list │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 05-output-single-linked-list-reverse │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ ├── head.html │ │ ├── linked-list-0.svg │ │ ├── linked-list-remove-1.svg │ │ ├── linked-list-split.svg │ │ ├── linked-list.svg │ │ ├── recursion-pow.svg │ │ └── recursive-salaries.svg │ ├── 02-rest-parameters-spread │ │ └── article.md │ ├── 03-closure │ │ ├── 1-closure-latest-changes │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 10-make-army │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ ├── source.js │ │ │ │ └── test.js │ │ │ ├── lexenv-makearmy-empty.svg │ │ │ ├── lexenv-makearmy-for-fixed.svg │ │ │ ├── lexenv-makearmy-while-fixed.svg │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-closure-variable-access │ │ │ ├── lexenv-nested-work.svg │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-counter-independent │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 4-counter-object-independent │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 5-function-in-if │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 6-closure-sum │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 7-let-scope │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 8-filter-through-function │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ ├── source.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 9-sort-by-field │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ ├── source.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ ├── closure-function-declaration.svg │ │ ├── closure-makecounter-environment.svg │ │ ├── closure-makecounter-nested-call-2.svg │ │ ├── closure-makecounter-nested-call.svg │ │ ├── closure-makecounter.svg │ │ ├── closure-variable-phrase.svg │ │ ├── lexenv-if.svg │ │ ├── lexenv-nested-makecounter-1.svg │ │ ├── lexenv-nested-makecounter-2.svg │ │ ├── lexenv-nested-makecounter-3.svg │ │ ├── lexenv-nested-makecounter-4.svg │ │ ├── lexenv-nested-makecounter-5.svg │ │ ├── lexenv-nested-makecounter-6.svg │ │ ├── lexical-environment-global-2.svg │ │ ├── lexical-environment-global-3.svg │ │ ├── lexical-environment-global.svg │ │ ├── lexical-environment-simple-lookup.svg │ │ ├── lexical-environment-simple.svg │ │ ├── lexical-search-order.svg │ │ └── variable-scope-lookup.svg │ ├── 04-var │ │ └── article.md │ ├── 05-global-object │ │ └── article.md │ ├── 06-function-object │ │ ├── 2-counter-inc-dec │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ ├── source.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 5-sum-many-brackets │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ ├── source.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 07-new-function │ │ └── article.md │ ├── 08-settimeout-setinterval │ │ ├── 1-output-numbers-100ms │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 4-settimeout-result │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ ├── setinterval-interval.svg │ │ └── settimeout-interval.svg │ ├── 09-call-apply-decorators │ │ ├── 01-spy-decorator │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ ├── source.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 02-delay │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 03-debounce │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── debounce.svg │ │ │ ├── debounce.view │ │ │ │ └── index.html │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 04-throttle │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ └── decorator-makecaching-wrapper.svg │ ├── 10-bind │ │ ├── 2-write-to-object-after-bind │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-second-bind │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 4-function-property-after-bind │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 5-question-use-bind │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 6-ask-partial │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ └── head.html │ ├── 12-arrow-functions │ │ └── article.md │ └── index.md ├── 07-object-properties │ ├── 01-property-descriptors │ │ └── article.md │ ├── 02-property-accessors │ │ └── article.md │ └── index.md ├── 08-prototypes │ ├── 01-prototype-inheritance │ │ ├── 1-property-after-delete │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-search-algorithm │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-proto-and-this │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 4-hamster-proto │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ ├── object-prototype-empty.svg │ │ ├── proto-animal-rabbit-chain.svg │ │ ├── proto-animal-rabbit-walk-2.svg │ │ ├── proto-animal-rabbit-walk-3.svg │ │ ├── proto-animal-rabbit-walk.svg │ │ ├── proto-animal-rabbit.svg │ │ ├── proto-user-admin.svg │ │ └── rabbit-animal-object.svg │ ├── 02-function-prototype │ │ ├── 1-changing-prototype │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 4-new-object-same-constructor │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ ├── function-prototype-constructor.svg │ │ ├── proto-constructor-animal-rabbit.svg │ │ └── rabbit-prototype-constructor.svg │ ├── 03-native-prototypes │ │ ├── 1-defer-to-prototype │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-defer-to-prototype-extended │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ ├── console_dir_array.png │ │ ├── function-prototype-constructor.svg │ │ ├── native-prototypes-array-tostring.svg │ │ ├── native-prototypes-classes.svg │ │ ├── object-prototype-1.svg │ │ ├── object-prototype-null.svg │ │ ├── object-prototype.svg │ │ └── rabbit-prototype-constructor.svg │ ├── 04-prototype-methods │ │ ├── 2-dictionary-tostring │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-compare-calls │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ ├── object-prototype-2.svg │ │ └── object-prototype-null.svg │ └── index.md ├── 09-classes │ ├── 01-class │ │ ├── 1-rewrite-to-class │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── source.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ └── class-user.svg │ ├── 02-class-inheritance │ │ ├── 1-class-constructor-error │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-clock-class-extended │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ ├── clock.js │ │ │ │ ├── extended-clock.js │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ ├── clock.js │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── animal-rabbit-extends.svg │ │ ├── article.md │ │ ├── class-inheritance-array-object.svg │ │ ├── class-inheritance-rabbit-animal-2.svg │ │ ├── class-inheritance-rabbit-animal.svg │ │ ├── rabbit-animal-independent-animal.svg │ │ ├── rabbit-animal-independent-rabbit.svg │ │ ├── super-homeobject-wrong.svg │ │ └── this-super-loop.svg │ ├── 03-static-properties-methods │ │ ├── 3-class-extend-object │ │ │ ├── rabbit-extends-object.svg │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── animal-rabbit-static.svg │ │ └── article.md │ ├── 04-private-protected-properties-methods │ │ ├── article.md │ │ ├── coffee-inside.jpg │ │ └── coffee.jpg │ ├── 05-extend-natives │ │ ├── article.md │ │ └── object-date-inheritance.svg │ ├── 06-instanceof │ │ ├── 1-strange-instanceof │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ └── instanceof.svg │ ├── 07-mixins │ │ ├── article.md │ │ ├── head.html │ │ └── mixin-inheritance.svg │ └── index.md ├── 10-error-handling │ ├── 1-try-catch │ │ ├── 1-finally-or-code-after │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ └── try-catch-flow.svg │ ├── 2-custom-errors │ │ ├── 1-format-error │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ └── index.md ├── 11-async │ ├── 01-callbacks │ │ ├── article.md │ │ ├── callback-hell.svg │ │ └── one.js │ ├── 02-promise-basics │ │ ├── 01-re-resolve │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 02-delay-promise │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 03-animate-circle-promise │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── article.md │ │ ├── head.html │ │ ├── promise-reject-1.svg │ │ ├── promise-resolve-1.svg │ │ └── promise-resolve-reject.svg │ ├── 03-promise-chaining │ │ ├── 01-then-vs-catch │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ ├── getMessage.js │ │ ├── head.html │ │ ├── one.js │ │ ├── promise-handler-variants.svg │ │ ├── promise-then-chain.svg │ │ ├── promise-then-many.svg │ │ ├── three.js │ │ ├── two.js │ │ └── user.json │ ├── 04-promise-error-handling │ │ ├── 01-error-async │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ ├── getMessage.js │ │ ├── head.html │ │ ├── one.js │ │ ├── promise-then-chain.svg │ │ ├── promise-then-many.svg │ │ ├── three.js │ │ ├── two.js │ │ └── user.json │ ├── 05-promise-api │ │ ├── article.md │ │ ├── head.html │ │ ├── iliakan.json │ │ ├── one.js │ │ └── two.js │ ├── 06-promisify │ │ └── article.md │ ├── 07-microtask-queue │ │ ├── article.md │ │ └── promiseQueue.svg │ ├── 08-async-await │ │ ├── 01-rewrite-async │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 02-rewrite-async-2 │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 03-async-from-regular │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 04-promise-all-failure │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ └── head.html │ └── index.md ├── 12-generators-iterators │ ├── 1-generators │ │ ├── 01-pseudo-random-generator │ │ │ ├── _js.view │ │ │ │ ├── solution.js │ │ │ │ └── test.js │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ ├── genYield2-2.svg │ │ ├── genYield2.svg │ │ ├── generateSequence-1.svg │ │ ├── generateSequence-2.svg │ │ ├── generateSequence-3.svg │ │ └── generateSequence-4.svg │ ├── 2-async-iterators-generators │ │ ├── article.md │ │ └── head.html │ └── index.md ├── 13-modules │ ├── 01-modules-intro │ │ ├── article.md │ │ ├── say.view │ │ │ ├── index.html │ │ │ └── say.js │ │ ├── scopes-working.view │ │ │ ├── hello.js │ │ │ ├── index.html │ │ │ └── user.js │ │ └── scopes.view │ │ │ ├── hello.js │ │ │ ├── index.html │ │ │ └── user.js │ ├── 02-import-export │ │ └── article.md │ ├── 03-modules-dynamic-imports │ │ ├── article.md │ │ └── say.view │ │ │ ├── index.html │ │ │ └── say.js │ └── index.md ├── 99-js-misc │ ├── 01-proxy │ │ ├── 01-error-nonexisting │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 02-array-negative │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 03-observable │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ ├── proxy-inherit-admin.svg │ │ ├── proxy-inherit.svg │ │ └── proxy.svg │ ├── 02-eval │ │ ├── 1-eval-calculator │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 03-currying-partials │ │ └── article.md │ ├── 04-reference-type │ │ ├── 2-check-syntax │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-why-this │ │ │ ├── solution.md │ │ │ └── task.md │ │ └── article.md │ ├── 05-bigint │ │ └── article.md │ ├── 06-unicode │ │ └── article.md │ ├── 07-weakref-finalizationregistry │ │ ├── article.md │ │ ├── google-chrome-developer-tools.png │ │ ├── weakref-dom.view │ │ │ ├── index.css │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── weakref-finalizationregistry-01.svg │ │ ├── weakref-finalizationregistry-02.svg │ │ ├── weakref-finalizationregistry-03.svg │ │ ├── weakref-finalizationregistry-04.svg │ │ ├── weakref-finalizationregistry-05.svg │ │ ├── weakref-finalizationregistry-demo-01.png │ │ ├── weakref-finalizationregistry-demo-02.png │ │ ├── weakref-finalizationregistry-demo-03.gif │ │ ├── weakref-finalizationregistry-demo-04.jpg │ │ ├── weakref-finalizationregistry-demo-05.gif │ │ ├── weakref-finalizationregistry-demo-06.jpg │ │ ├── weakref-finalizationregistry-demo-07.gif │ │ ├── weakref-finalizationregistry-demo-08.jpg │ │ └── weakref-finalizationregistry.view │ │ │ ├── index.css │ │ │ ├── index.html │ │ │ ├── index.js │ │ │ └── utils.js │ └── index.md └── index.md ├── 2-ui ├── 1-document │ ├── 01-browser-environment │ │ ├── article.md │ │ └── windowObjects.svg │ ├── 02-dom-nodes │ │ ├── article.md │ │ ├── domconsole0.svg │ │ ├── domconsole1.svg │ │ ├── elk.html │ │ ├── elk.svg │ │ ├── head.html │ │ ├── inspect.svg │ │ └── toolbarButtonGlyphs.svg │ ├── 03-dom-navigation │ │ ├── 1-dom-children │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 3-navigation-links-which-null │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 4-select-diagonal-cells │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── article.md │ │ ├── dom-links-elements.svg │ │ ├── dom-links.svg │ │ └── head.html │ ├── 04-searching-elements-dom │ │ ├── 1-find-elements │ │ │ ├── solution.md │ │ │ ├── table.html │ │ │ └── task.md │ │ └── article.md │ ├── 05-basic-dom-node-properties │ │ ├── 2-lastchild-nodetype-inline │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-tree-info │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 3-tag-in-comment │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 4-where-document-in-hierarchy │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ └── dom-class-hierarchy.svg │ ├── 06-dom-attributes-and-properties │ │ ├── 1-get-user-attribute │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-yellow-links │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ └── article.md │ ├── 07-modifying-document │ │ ├── 1-createtextnode-vs-innerhtml │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 10-clock-setinterval │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 11-append-to-list │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 12-sort-table │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 4-clear-elem │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 5-why-aaa │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 6-create-list │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 7-create-object-tree │ │ │ ├── build-tree-dom.view │ │ │ │ └── index.html │ │ │ ├── innerhtml.view │ │ │ │ └── index.html │ │ │ ├── solution.md │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 8-tree-count │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 9-calendar-table │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── article.md │ │ ├── before-prepend-append-after.svg │ │ └── insert-adjacent.svg │ ├── 08-styles-and-classes │ │ ├── 2-create-notification │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ ├── index.css │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ ├── index.css │ │ │ │ └── index.html │ │ │ └── task.md │ │ └── article.md │ ├── 09-size-and-scroll │ │ ├── 1-get-scroll-height-bottom │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-scrollbar-width │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 4-put-ball-in-center │ │ │ ├── ball-half │ │ │ │ └── index.html │ │ │ ├── field.svg │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 6-width-vs-clientwidth │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ ├── cssWidthScroll.view │ │ │ └── index.html │ │ ├── metric-all.svg │ │ ├── metric-client-left-top-rtl.svg │ │ ├── metric-client-left-top.svg │ │ ├── metric-client-width-height.svg │ │ ├── metric-client-width-nopadding.svg │ │ ├── metric-css.svg │ │ ├── metric-offset-parent.svg │ │ ├── metric-offset-width-height.svg │ │ ├── metric-scroll-top.svg │ │ ├── metric-scroll-width-height.svg │ │ └── metric.view │ │ │ └── index.html │ ├── 10-size-and-scroll-window │ │ ├── article.md │ │ └── document-client-width-height.svg │ ├── 11-coordinates │ │ ├── 1-find-point-coordinates │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ ├── index.css │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ ├── index.css │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 2-position-at │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ ├── index.css │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ ├── index.css │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 3-position-at-absolute │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ ├── index.css │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 4-position-inside-absolute │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ ├── index.css │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── article.md │ │ ├── coordinates-negative.svg │ │ ├── coordinates.svg │ │ ├── document-and-window-coordinates-scrolled.svg │ │ └── head.html │ └── index.md ├── 2-events │ ├── 01-introduction-browser-events │ │ ├── 01-hide-other │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 02-hide-self-onclick │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 03-which-handlers-run │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 04-move-ball-field │ │ │ ├── move-ball-coords.svg │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 05-sliding-menu │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 06-hide-message │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ ├── index.html │ │ │ │ └── messages.css │ │ │ ├── source.view │ │ │ │ ├── index.html │ │ │ │ └── messages.css │ │ │ └── task.md │ │ ├── 07-carousel │ │ │ ├── carousel1.svg │ │ │ ├── carousel2.svg │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ ├── index.html │ │ │ │ └── style.css │ │ │ ├── source.view │ │ │ │ ├── index.html │ │ │ │ └── style.css │ │ │ └── task.md │ │ ├── article.md │ │ └── head.html │ ├── 02-bubbling-and-capturing │ │ ├── article.md │ │ ├── both.view │ │ │ ├── example.css │ │ │ ├── index.html │ │ │ └── script.js │ │ ├── bubble-target.view │ │ │ ├── example.css │ │ │ ├── index.html │ │ │ └── script.js │ │ ├── capture.view │ │ │ ├── example.css │ │ │ ├── index.html │ │ │ └── script.js │ │ ├── event-order-bubbling.svg │ │ └── eventflow.svg │ ├── 03-event-delegation │ │ ├── 1-hide-message-delegate │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ ├── index.html │ │ │ │ └── messages.css │ │ │ ├── source.view │ │ │ │ ├── index.html │ │ │ │ └── messages.css │ │ │ └── task.md │ │ ├── 2-sliding-tree │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 3-sortable-table │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 4-behavior-tooltip │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── article.md │ │ ├── bagua-bubble.svg │ │ └── bagua.view │ │ │ ├── bagua.css │ │ │ └── index.html │ ├── 04-default-browser-action │ │ ├── 1-why-return-false-fails │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── 2-catch-link-navigation │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 3-image-gallery │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ ├── gallery.css │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ ├── gallery.css │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── article.md │ │ └── menu.view │ │ │ ├── index.html │ │ │ ├── menu.css │ │ │ └── menu.js │ ├── 05-dispatch-events │ │ └── article.md │ └── index.md ├── 3-event-details │ ├── 1-mouse-events-basics │ │ ├── 01-selectable-list │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── article.md │ │ └── head.html │ ├── 3-mousemove-mouseover-mouseout-mouseenter-mouseleave │ │ ├── 1-behavior-nested-tooltip │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 2-hoverintent │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ ├── hoverIntent.js │ │ │ │ ├── index.html │ │ │ │ ├── style.css │ │ │ │ └── test.js │ │ │ ├── source.view │ │ │ │ ├── hoverIntent.js │ │ │ │ ├── index.html │ │ │ │ ├── style.css │ │ │ │ └── test.js │ │ │ └── task.md │ │ ├── article.md │ │ ├── mouseenter-mouseleave-delegation-2.view │ │ │ ├── index.html │ │ │ ├── script.js │ │ │ └── style.css │ │ ├── mouseenter-mouseleave-delegation.view │ │ │ ├── index.html │ │ │ ├── script.js │ │ │ └── style.css │ │ ├── mouseleave-table.view │ │ │ ├── index.html │ │ │ ├── script.js │ │ │ └── style.css │ │ ├── mouseleave.view │ │ │ ├── index.html │ │ │ ├── script.js │ │ │ └── style.css │ │ ├── mouseover-bubble-nested.svg │ │ ├── mouseover-mouseout-from-outside.svg │ │ ├── mouseover-mouseout-over-elems.svg │ │ ├── mouseover-mouseout.svg │ │ ├── mouseover-to-child.svg │ │ ├── mouseoverout-child.view │ │ │ ├── index.html │ │ │ ├── script.js │ │ │ └── style.css │ │ ├── mouseoverout-fast.view │ │ │ ├── index.html │ │ │ ├── script.js │ │ │ └── style.css │ │ └── mouseoverout.view │ │ │ ├── index.html │ │ │ ├── script.js │ │ │ └── style.css │ ├── 4-mouse-drag-and-drop │ │ ├── 1-slider │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ ├── index.html │ │ │ │ └── style.css │ │ │ ├── source.view │ │ │ │ ├── index.html │ │ │ │ └── style.css │ │ │ └── task.md │ │ ├── 2-drag-heroes │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ ├── field.svg │ │ │ │ ├── index.html │ │ │ │ ├── soccer.css │ │ │ │ └── soccer.js │ │ │ ├── source.view │ │ │ │ ├── index.html │ │ │ │ ├── soccer.css │ │ │ │ └── soccer.js │ │ │ └── task.md │ │ ├── article.md │ │ ├── ball.view │ │ │ └── index.html │ │ ├── ball2.view │ │ │ └── index.html │ │ ├── ball3.view │ │ │ └── index.html │ │ ├── ball4.view │ │ │ ├── index.html │ │ │ └── style.css │ │ └── ball_shift.svg │ ├── 6-pointer-events │ │ ├── article.md │ │ ├── ball-2.view │ │ │ └── index.html │ │ ├── ball.view │ │ │ └── index.html │ │ ├── multitouch.view │ │ │ └── index.html │ │ ├── slider-html.view │ │ │ ├── index.html │ │ │ └── style.css │ │ └── slider.view │ │ │ ├── index.html │ │ │ └── style.css │ ├── 7-keyboard-events │ │ ├── 2-check-sync-keydown │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── article.md │ │ ├── german-layout.svg │ │ ├── keyboard-dump.view │ │ │ ├── index.html │ │ │ ├── script.js │ │ │ └── style.css │ │ └── us-layout.svg │ ├── 8-onscroll │ │ ├── 1-endless-page │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 2-updown-button │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 3-load-visible-img │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ ├── index.html │ │ │ │ └── placeholder.svg │ │ │ ├── source.view │ │ │ │ ├── index.html │ │ │ │ └── placeholder.svg │ │ │ └── task.md │ │ └── article.md │ └── index.md ├── 4-forms-controls │ ├── 1-form-elements │ │ ├── 1-add-select-option │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ └── form-navigation.svg │ ├── 2-focus-blur │ │ ├── 3-editable-div │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ ├── index.html │ │ │ │ └── my.css │ │ │ ├── source.view │ │ │ │ ├── index.html │ │ │ │ └── my.css │ │ │ └── task.md │ │ ├── 4-edit-td-click │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ ├── bagua.css │ │ │ │ ├── index.html │ │ │ │ ├── my.css │ │ │ │ └── script.js │ │ │ ├── source.view │ │ │ │ ├── bagua.css │ │ │ │ ├── index.html │ │ │ │ ├── my.css │ │ │ │ └── script.js │ │ │ └── task.md │ │ ├── 5-keyboard-mouse │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ └── article.md │ ├── 3-events-change-input │ │ ├── 1-deposit-calculator │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ └── article.md │ ├── 4-forms-submit │ │ ├── 1-modal-dialog │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ ├── index.html │ │ │ │ └── style.css │ │ │ ├── source.view │ │ │ │ ├── index.html │ │ │ │ └── style.css │ │ │ └── task.md │ │ └── article.md │ └── index.md ├── 5-loading │ ├── 01-onload-ondomcontentloaded │ │ ├── article.md │ │ ├── readystate.view │ │ │ ├── iframe.html │ │ │ └── index.html │ │ └── window-onbeforeunload.view │ │ │ └── index.html │ ├── 02-script-async-defer │ │ ├── article.md │ │ ├── long.js │ │ └── small.js │ ├── 03-onload-onerror │ │ ├── 1-load-img-callback │ │ │ ├── solution.md │ │ │ ├── solution.view │ │ │ │ └── index.html │ │ │ ├── source.view │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── article.md │ │ └── crossorigin.view │ │ │ └── error.js │ └── index.md ├── 99-ui-misc │ ├── 01-mutation-observer │ │ └── article.md │ ├── 02-selection-range │ │ ├── article.md │ │ ├── range-example-p-0-1.svg │ │ ├── range-example-p-1-3.svg │ │ ├── range-example-p-2-b-3-range.svg │ │ ├── range-example-p-2-b-3.svg │ │ ├── range-hello-1.svg │ │ ├── selection-direction-backward.svg │ │ ├── selection-direction-forward.svg │ │ └── selection-firefox.svg │ ├── 03-event-loop │ │ ├── 2-micro-macro-queue │ │ │ ├── solution.md │ │ │ └── task.md │ │ ├── article.md │ │ ├── eventLoop-full.svg │ │ └── eventLoop.svg │ └── index.md └── index.md ├── 3-frames-and-windows ├── 01-popup-windows │ └── article.md ├── 03-cross-window-communication │ ├── article.md │ ├── postmessage.view │ │ ├── iframe.html │ │ └── index.html │ └── sandbox.view │ │ ├── index.html │ │ └── sandboxed.html ├── 06-clickjacking │ ├── article.md │ ├── clickjacking-visible.view │ │ ├── facebook.html │ │ └── index.html │ ├── clickjacking.view │ │ ├── facebook.html │ │ └── index.html │ ├── protector.view │ │ ├── iframe.html │ │ └── index.html │ └── top-location.view │ │ ├── iframe.html │ │ └── index.html └── index.md ├── 4-binary ├── 01-arraybuffer-binary-arrays │ ├── 01-concat │ │ ├── _js.view │ │ │ ├── solution.js │ │ │ ├── source.js │ │ │ └── test.js │ │ ├── solution.md │ │ └── task.md │ ├── 8bit-integer-256.svg │ ├── 8bit-integer-257.svg │ ├── arraybuffer-view-buffersource.svg │ ├── arraybuffer-views.svg │ └── article.md ├── 02-text-decoder │ └── article.md ├── 03-blob │ ├── article.md │ └── blob.svg ├── 04-file │ └── article.md └── index.md ├── 5-network ├── 01-fetch │ ├── 01-fetch-users │ │ ├── _js.view │ │ │ ├── solution.js │ │ │ ├── source.js │ │ │ └── test.js │ │ ├── solution.md │ │ └── task.md │ ├── article.md │ ├── logo-fetch.svg │ └── post.view │ │ └── server.js ├── 02-formdata │ ├── article.md │ └── post.view │ │ └── server.js ├── 03-fetch-progress │ ├── article.md │ ├── logo-fetch.svg │ └── progress.view │ │ ├── index.html │ │ └── long.txt ├── 04-fetch-abort │ ├── article.md │ └── demo.view │ │ └── server.js ├── 05-fetch-crossorigin │ ├── 1-do-we-need-origin │ │ ├── solution.md │ │ └── task.md │ ├── article.md │ ├── cors-gmail-messages.svg │ ├── xhr-another-domain.svg │ └── xhr-preflight.svg ├── 06-fetch-api │ ├── article.md │ ├── logo-fetch.svg │ └── post.view │ │ ├── index.html │ │ └── server.js ├── 07-url │ ├── article.md │ └── url-object.svg ├── 08-xmlhttprequest │ ├── article.md │ ├── example.view │ │ ├── index.html │ │ └── server.js │ ├── hello.txt │ ├── phones-async.view │ │ ├── index.html │ │ ├── phones.json │ │ └── server.js │ ├── phones.json │ ├── phones.view │ │ ├── index.html │ │ ├── phones.json │ │ └── server.js │ └── post.view │ │ ├── index.html │ │ └── server.js ├── 09-resume-upload │ ├── article.md │ └── upload-resume.view │ │ ├── index.html │ │ ├── server.js │ │ └── uploader.js ├── 10-long-polling │ ├── article.md │ ├── long-polling.svg │ └── longpoll.view │ │ ├── browser.js │ │ ├── index.html │ │ └── server.js ├── 11-websocket │ ├── article.md │ ├── chat.view │ │ ├── index.html │ │ └── server.js │ ├── demo.view │ │ └── server.js │ └── websocket-handshake.svg ├── 12-server-sent-events │ ├── article.md │ └── eventsource.view │ │ ├── index.html │ │ └── server.js └── index.md ├── 6-data-storage ├── 01-cookie │ ├── article.md │ ├── cookie-third-party-2.svg │ ├── cookie-third-party-3.svg │ ├── cookie-third-party.svg │ ├── cookie-xsrf.svg │ └── cookie.js ├── 02-localstorage │ ├── 1-form-autosave │ │ ├── solution.md │ │ ├── solution.view │ │ │ └── index.html │ │ ├── source.view │ │ │ └── index.html │ │ └── task.md │ ├── article.md │ └── sessionstorage.view │ │ ├── iframe.html │ │ └── index.html ├── 03-indexeddb │ ├── article.md │ ├── books.view │ │ └── index.html │ ├── indexeddb-cursor.svg │ ├── indexeddb-index.svg │ └── indexeddb-structure.svg └── index.md ├── 7-animation ├── 1-bezier-curve │ ├── article.md │ ├── bezier-car.svg │ ├── bezier-letter.svg │ ├── bezier-vase.svg │ ├── bezier2.svg │ ├── bezier3-draw1.svg │ ├── bezier3-draw2.svg │ ├── bezier3-e.svg │ ├── bezier3.svg │ ├── bezier4-e.svg │ ├── bezier4.svg │ ├── demo.svg │ ├── pause.png │ └── play.png ├── 2-css-animations │ ├── 1-animate-logo-css │ │ ├── solution.md │ │ ├── solution.view │ │ │ └── index.html │ │ ├── source.view │ │ │ └── index.html │ │ └── task.md │ ├── 2-animate-logo-bezier-css │ │ ├── bezier-up.svg │ │ ├── solution.md │ │ ├── solution.view │ │ │ └── index.html │ │ └── task.md │ ├── 3-animate-circle │ │ ├── solution.md │ │ ├── solution.view │ │ │ └── index.html │ │ ├── source.view │ │ │ └── index.html │ │ └── task.md │ ├── 4-animate-circle-callback │ │ ├── solution.md │ │ ├── solution.view │ │ │ └── index.html │ │ └── task.md │ ├── article.md │ ├── bezier-linear.svg │ ├── bezier-train-over.svg │ ├── boat.view │ │ ├── index.html │ │ └── style.css │ ├── digits-negative-delay.view │ │ ├── index.html │ │ ├── script.js │ │ └── style.css │ ├── digits.view │ │ ├── index.html │ │ ├── script.js │ │ └── style.css │ ├── ease-in-out.svg │ ├── ease-in.svg │ ├── ease-out.svg │ ├── ease.svg │ ├── step-end.view │ │ ├── index.html │ │ └── style.css │ ├── step-list.view │ │ ├── index.html │ │ └── style.css │ ├── step.view │ │ ├── index.html │ │ └── style.css │ ├── train-curve.svg │ ├── train-linear.view │ │ ├── index.html │ │ └── style.css │ ├── train-over.view │ │ ├── index.html │ │ └── style.css │ └── train.view │ │ ├── index.html │ │ └── style.css ├── 3-js-animation │ ├── 1-animate-ball │ │ ├── solution.md │ │ ├── solution.view │ │ │ ├── index.html │ │ │ └── style.css │ │ ├── source.view │ │ │ ├── index.html │ │ │ └── style.css │ │ └── task.md │ ├── 2-animate-ball-hops │ │ ├── solution.md │ │ ├── solution.view │ │ │ ├── index.html │ │ │ └── style.css │ │ └── task.md │ ├── article.md │ ├── back.svg │ ├── back.view │ │ ├── index.html │ │ └── style.css │ ├── bezier-linear.svg │ ├── bounce-easeinout.view │ │ ├── index.html │ │ └── style.css │ ├── bounce-easeout.view │ │ ├── index.html │ │ └── style.css │ ├── bounce-inout.svg │ ├── bounce.view │ │ ├── index.html │ │ └── style.css │ ├── circ-ease.svg │ ├── circ.svg │ ├── circ.view │ │ ├── index.html │ │ └── style.css │ ├── elastic.svg │ ├── elastic.view │ │ ├── index.html │ │ └── style.css │ ├── linear.svg │ ├── move-raf.view │ │ └── index.html │ ├── move.view │ │ └── index.html │ ├── quad.svg │ ├── quad.view │ │ ├── index.html │ │ └── style.css │ ├── quint.svg │ ├── quint.view │ │ ├── index.html │ │ └── style.css │ ├── text.view │ │ ├── index.html │ │ └── style.css │ └── width.view │ │ ├── animate.js │ │ └── index.html └── index.md ├── 8-web-components ├── 1-webcomponents-intro │ ├── article.md │ ├── satellite-expanded.jpg │ ├── satellite-expanded@2x.jpg │ ├── satellite.jpg │ ├── satellite@2x.jpg │ └── web-components-twitter.svg ├── 2-custom-elements │ ├── 1-live-timer │ │ ├── solution.md │ │ ├── solution.view │ │ │ ├── index.html │ │ │ ├── live-timer.js │ │ │ └── time-formatted.js │ │ ├── source.view │ │ │ ├── index.html │ │ │ ├── live-timer.js │ │ │ └── time-formatted.js │ │ └── task.md │ ├── article.md │ └── head.html ├── 3-shadow-dom │ ├── article.md │ ├── shadow-dom-range.png │ ├── shadow-dom-range@2x.png │ ├── shadow-dom-say-hello.png │ └── shadow-dom-say-hello@2x.png ├── 4-template-element │ └── article.md ├── 5-slots-composition │ ├── article.md │ ├── menu.view │ │ └── index.html │ └── shadow-dom-user-card.svg ├── 6-shadow-dom-style │ └── article.md ├── 7-shadow-dom-events │ └── article.md └── index.md ├── 9-regular-expressions ├── 01-regexp-introduction │ └── article.md ├── 02-regexp-character-classes │ ├── article.md │ └── love-html5-classes.svg ├── 03-regexp-unicode │ └── article.md ├── 04-regexp-anchors │ ├── 1-start-end │ │ ├── solution.md │ │ └── task.md │ └── article.md ├── 05-regexp-multiline-mode │ └── article.md ├── 06-regexp-boundary │ ├── 1-find-time-hh-mm │ │ ├── solution.md │ │ └── task.md │ ├── article.md │ └── hello-java-boundaries.svg ├── 07-regexp-escaping │ └── article.md ├── 08-regexp-character-sets-and-ranges │ ├── 1-find-range-1 │ │ ├── solution.md │ │ └── task.md │ ├── 2-find-time-2-formats │ │ ├── solution.md │ │ └── task.md │ └── article.md ├── 09-regexp-quantifiers │ ├── 1-find-text-manydots │ │ ├── solution.md │ │ └── task.md │ ├── 2-find-html-colors-6hex │ │ ├── solution.md │ │ └── task.md │ └── article.md ├── 10-regexp-greedy-and-lazy │ ├── 1-lazy-greedy │ │ ├── solution.md │ │ └── task.md │ ├── 3-find-html-comments │ │ ├── solution.md │ │ └── task.md │ ├── 4-find-html-tags-greedy-lazy │ │ ├── solution.md │ │ └── task.md │ ├── article.md │ ├── witch_greedy1.svg │ ├── witch_greedy2.svg │ ├── witch_greedy3.svg │ ├── witch_greedy4.svg │ ├── witch_greedy5.svg │ ├── witch_greedy6.svg │ ├── witch_lazy3.svg │ ├── witch_lazy4.svg │ ├── witch_lazy5.svg │ └── witch_lazy6.svg ├── 11-regexp-groups │ ├── 01-test-mac │ │ ├── solution.md │ │ └── task.md │ ├── 02-find-webcolor-3-or-6 │ │ ├── solution.md │ │ └── task.md │ ├── 03-find-decimal-numbers │ │ ├── solution.md │ │ └── task.md │ ├── 04-parse-expression │ │ ├── solution.md │ │ └── task.md │ ├── article.md │ ├── regexp-nested-groups-matches.svg │ └── regexp-nested-groups-pattern.svg ├── 12-regexp-backreferences │ └── article.md ├── 13-regexp-alternation │ ├── 01-find-programming-language │ │ ├── solution.md │ │ └── task.md │ ├── 02-find-matching-bbtags │ │ ├── solution.md │ │ └── task.md │ ├── 03-match-quoted-string │ │ ├── solution.md │ │ └── task.md │ ├── 04-match-exact-tag │ │ ├── solution.md │ │ └── task.md │ └── article.md ├── 14-regexp-lookahead-lookbehind │ ├── 1-find-non-negative-integers │ │ ├── solution.md │ │ └── task.md │ ├── 2-insert-after-head │ │ ├── solution.md │ │ └── task.md │ └── article.md ├── 15-regexp-catastrophic-backtracking │ └── article.md ├── 16-regexp-sticky │ └── article.md ├── 17-regexp-methods │ └── article.md └── index.md ├── AUTHORING.md ├── BACKERS.md ├── LICENSE.md ├── README.md ├── changes.sketch ├── css.md ├── figures.sketch ├── script └── clean-unused-png.php ├── svgs.zip └── todo.md /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | *.svg binary 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: iliakan 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.diff 2 | *.err 3 | *.orig 4 | *.log 5 | *.rej 6 | *.swo 7 | *.swp 8 | *.vi 9 | *~ 10 | *.sass-cache 11 | 12 | # OS or Editor folders 13 | .DS_Store 14 | .idea 15 | .cache 16 | .project 17 | .settings 18 | .tmproj 19 | .nvmrc 20 | sftp-config.json 21 | Thumbs.db 22 | 23 | 24 | /svgs -------------------------------------------------------------------------------- /1-js/01-getting-started/4-devtools/bug.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | There is an error in the script on this page. 11 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /1-js/01-getting-started/4-devtools/chrome.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/01-getting-started/4-devtools/chrome.webp -------------------------------------------------------------------------------- /1-js/01-getting-started/4-devtools/chrome@2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/01-getting-started/4-devtools/chrome@2.webp -------------------------------------------------------------------------------- /1-js/01-getting-started/4-devtools/safari.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/01-getting-started/4-devtools/safari.png -------------------------------------------------------------------------------- /1-js/01-getting-started/4-devtools/safari@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/01-getting-started/4-devtools/safari@2x.png -------------------------------------------------------------------------------- /1-js/01-getting-started/index.md: -------------------------------------------------------------------------------- 1 | # An introduction 2 | 3 | About the JavaScript language and the environment to develop with it. 4 | -------------------------------------------------------------------------------- /1-js/02-first-steps/01-hello-world/1-hello-alert/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /1-js/02-first-steps/01-hello-world/1-hello-alert/solution.md: -------------------------------------------------------------------------------- 1 | 2 | [html src="index.html"] 3 | -------------------------------------------------------------------------------- /1-js/02-first-steps/01-hello-world/1-hello-alert/solution.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /1-js/02-first-steps/01-hello-world/1-hello-alert/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Show an alert 6 | 7 | Create a page that shows a message "I'm JavaScript!". 8 | 9 | Do it in a sandbox, or on your hard drive, doesn't matter, just ensure that it works. 10 | 11 | [demo src="solution"] 12 | 13 | -------------------------------------------------------------------------------- /1-js/02-first-steps/01-hello-world/2-hello-alert-ext/alert.js: -------------------------------------------------------------------------------- 1 | alert("I'm JavaScript!"); -------------------------------------------------------------------------------- /1-js/02-first-steps/01-hello-world/2-hello-alert-ext/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /1-js/02-first-steps/01-hello-world/2-hello-alert-ext/solution.md: -------------------------------------------------------------------------------- 1 | The HTML code: 2 | 3 | [html src="index.html"] 4 | 5 | For the file `alert.js` in the same folder: 6 | 7 | [js src="alert.js"] 8 | 9 | -------------------------------------------------------------------------------- /1-js/02-first-steps/01-hello-world/2-hello-alert-ext/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Show an alert with an external script 6 | 7 | Take the solution of the previous task . Modify it by extracting the script content into an external file `alert.js`, residing in the same folder. 8 | 9 | Open the page, ensure that the alert works. 10 | -------------------------------------------------------------------------------- /1-js/02-first-steps/04-variables/1-hello-variables/solution.md: -------------------------------------------------------------------------------- 1 | In the code below, each line corresponds to the item in the task list. 2 | 3 | ```js run 4 | let admin, name; // can declare two variables at once 5 | 6 | name = "John"; 7 | 8 | admin = name; 9 | 10 | alert( admin ); // "John" 11 | ``` 12 | 13 | -------------------------------------------------------------------------------- /1-js/02-first-steps/04-variables/1-hello-variables/task.md: -------------------------------------------------------------------------------- 1 | importance: 2 2 | 3 | --- 4 | 5 | # Working with variables 6 | 7 | 1. Declare two variables: `admin` and `name`. 8 | 2. Assign the value `"John"` to `name`. 9 | 3. Copy the value from `name` to `admin`. 10 | 4. Show the value of `admin` using `alert` (must output "John"). 11 | -------------------------------------------------------------------------------- /1-js/02-first-steps/04-variables/2-declare-variables/task.md: -------------------------------------------------------------------------------- 1 | importance: 3 2 | 3 | --- 4 | 5 | # Giving the right name 6 | 7 | 1. Create a variable with the name of our planet. How would you name such a variable? 8 | 2. Create a variable to store the name of a current visitor to a website. How would you name that variable? 9 | -------------------------------------------------------------------------------- /1-js/02-first-steps/05-types/1-string-quotes/solution.md: -------------------------------------------------------------------------------- 1 | 2 | Backticks embed the expression inside `${...}` into the string. 3 | 4 | ```js run 5 | let name = "Ilya"; 6 | 7 | // the expression is a number 1 8 | alert( `hello ${1}` ); // hello 1 9 | 10 | // the expression is a string "name" 11 | alert( `hello ${"name"}` ); // hello name 12 | 13 | // the expression is a variable, embed it 14 | alert( `hello ${name}` ); // hello Ilya 15 | ``` 16 | -------------------------------------------------------------------------------- /1-js/02-first-steps/05-types/1-string-quotes/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # String quotes 6 | 7 | What is the output of the script? 8 | 9 | ```js 10 | let name = "Ilya"; 11 | 12 | alert( `hello ${1}` ); // ? 13 | 14 | alert( `hello ${"name"}` ); // ? 15 | 16 | alert( `hello ${name}` ); // ? 17 | ``` -------------------------------------------------------------------------------- /1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/solution.md: -------------------------------------------------------------------------------- 1 | JavaScript-code: 2 | 3 | ```js demo run 4 | let name = prompt("What is your name?", ""); 5 | alert(name); 6 | ``` 7 | 8 | The full page: 9 | 10 | ```html 11 | 12 | 13 | 14 | 15 | 21 | 22 | 23 | 24 | ``` 25 | -------------------------------------------------------------------------------- /1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/task.md: -------------------------------------------------------------------------------- 1 | importance: 4 2 | 3 | --- 4 | 5 | # A simple page 6 | 7 | Create a web-page that asks for a name and outputs it. 8 | 9 | [demo] 10 | -------------------------------------------------------------------------------- /1-js/02-first-steps/08-operators/1-increment-order/solution.md: -------------------------------------------------------------------------------- 1 | 2 | The answer is: 3 | 4 | - `a = 2` 5 | - `b = 2` 6 | - `c = 2` 7 | - `d = 1` 8 | 9 | ```js run no-beautify 10 | let a = 1, b = 1; 11 | 12 | alert( ++a ); // 2, prefix form returns the new value 13 | alert( b++ ); // 1, postfix form returns the old value 14 | 15 | alert( a ); // 2, incremented once 16 | alert( b ); // 2, incremented once 17 | ``` 18 | 19 | -------------------------------------------------------------------------------- /1-js/02-first-steps/08-operators/1-increment-order/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # The postfix and prefix forms 6 | 7 | What are the final values of all variables `a`, `b`, `c` and `d` after the code below? 8 | 9 | ```js 10 | let a = 1, b = 1; 11 | 12 | let c = ++a; // ? 13 | let d = b++; // ? 14 | ``` 15 | -------------------------------------------------------------------------------- /1-js/02-first-steps/08-operators/2-assignment-result/solution.md: -------------------------------------------------------------------------------- 1 | The answer is: 2 | 3 | - `a = 4` (multiplied by 2) 4 | - `x = 5` (calculated as 1 + 4) 5 | 6 | -------------------------------------------------------------------------------- /1-js/02-first-steps/08-operators/2-assignment-result/task.md: -------------------------------------------------------------------------------- 1 | importance: 3 2 | 3 | --- 4 | 5 | # Assignment result 6 | 7 | What are the values of `a` and `x` after the code below? 8 | 9 | ```js 10 | let a = 2; 11 | 12 | let x = 1 + (a *= 2); 13 | ``` 14 | -------------------------------------------------------------------------------- /1-js/02-first-steps/08-operators/3-primitive-conversions-questions/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Type conversions 6 | 7 | What are results of these expressions? 8 | 9 | ```js no-beautify 10 | "" + 1 + 0 11 | "" - 1 + 0 12 | true + false 13 | 6 / "3" 14 | "2" * "3" 15 | 4 + 5 + "px" 16 | "$" + 4 + 5 17 | "4" - 2 18 | "4px" - 2 19 | " -9 " + 5 20 | " -9 " - 5 21 | null + 1 22 | undefined + 1 23 | " \t \n" - 2 24 | ``` 25 | 26 | Think well, write down and then compare with the answer. 27 | -------------------------------------------------------------------------------- /1-js/02-first-steps/08-operators/4-fix-prompt/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Fix the addition 6 | 7 | Here's a code that asks the user for two numbers and shows their sum. 8 | 9 | It works incorrectly. The output in the example below is `12` (for default prompt values). 10 | 11 | Why? Fix it. The result should be `3`. 12 | 13 | ```js run 14 | let a = prompt("First number?", 1); 15 | let b = prompt("Second number?", 2); 16 | 17 | alert(a + b); // 12 18 | ``` 19 | -------------------------------------------------------------------------------- /1-js/02-first-steps/09-comparison/1-comparison-questions/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Comparisons 6 | 7 | What will be the result for these expressions? 8 | 9 | ```js no-beautify 10 | 5 > 4 11 | "apple" > "pineapple" 12 | "2" > "12" 13 | undefined == null 14 | undefined === null 15 | null == "\n0\n" 16 | null === +"\n0\n" 17 | ``` 18 | 19 | -------------------------------------------------------------------------------- /1-js/02-first-steps/10-ifelse/1-if-zero-string/solution.md: -------------------------------------------------------------------------------- 1 | **Yes, it will.** 2 | 3 | Any string except an empty one (and `"0"` is not empty) becomes `true` in the logical context. 4 | 5 | We can run and check: 6 | 7 | ```js run 8 | if ("0") { 9 | alert( 'Hello' ); 10 | } 11 | ``` 12 | 13 | -------------------------------------------------------------------------------- /1-js/02-first-steps/10-ifelse/1-if-zero-string/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # if (a string with zero) 6 | 7 | Will `alert` be shown? 8 | 9 | ```js 10 | if ("0") { 11 | alert( 'Hello' ); 12 | } 13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /1-js/02-first-steps/10-ifelse/2-check-standard/solution.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [html run src="ifelse_task2/index.html"] 4 | 5 | -------------------------------------------------------------------------------- /1-js/02-first-steps/10-ifelse/2-check-standard/task.md: -------------------------------------------------------------------------------- 1 | importance: 2 2 | 3 | --- 4 | 5 | # The name of JavaScript 6 | 7 | Using the `if..else` construct, write the code which asks: 'What is the "official" name of JavaScript?' 8 | 9 | If the visitor enters "ECMAScript", then output "Right!", otherwise -- output: "You don't know? ECMAScript!" 10 | 11 | ![](ifelse_task2.svg) 12 | 13 | [demo src="ifelse_task2"] 14 | -------------------------------------------------------------------------------- /1-js/02-first-steps/10-ifelse/3-sign/if_sign/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /1-js/02-first-steps/10-ifelse/3-sign/solution.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```js run 4 | let value = prompt('Type a number', 0); 5 | 6 | if (value > 0) { 7 | alert( 1 ); 8 | } else if (value < 0) { 9 | alert( -1 ); 10 | } else { 11 | alert( 0 ); 12 | } 13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /1-js/02-first-steps/10-ifelse/3-sign/task.md: -------------------------------------------------------------------------------- 1 | importance: 2 2 | 3 | --- 4 | 5 | # Show the sign 6 | 7 | Using `if..else`, write the code which gets a number via `prompt` and then shows in `alert`: 8 | 9 | - `1`, if the value is greater than zero, 10 | - `-1`, if less than zero, 11 | - `0`, if equals zero. 12 | 13 | In this task we assume that the input is always a number. 14 | 15 | [demo src="if_sign"] 16 | -------------------------------------------------------------------------------- /1-js/02-first-steps/10-ifelse/5-rewrite-if-question/solution.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```js 4 | let result = (a + b < 4) ? 'Below' : 'Over'; 5 | ``` 6 | 7 | -------------------------------------------------------------------------------- /1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Rewrite 'if' into '?' 6 | 7 | Rewrite this `if` using the conditional operator `'?'`: 8 | 9 | ```js 10 | let result; 11 | 12 | if (a + b < 4) { 13 | result = 'Below'; 14 | } else { 15 | result = 'Over'; 16 | } 17 | ``` 18 | -------------------------------------------------------------------------------- /1-js/02-first-steps/10-ifelse/6-rewrite-if-else-question/solution.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```js 4 | let message = (login == 'Employee') ? 'Hello' : 5 | (login == 'Director') ? 'Greetings' : 6 | (login == '') ? 'No login' : 7 | ''; 8 | ``` 9 | 10 | -------------------------------------------------------------------------------- /1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/solution.md: -------------------------------------------------------------------------------- 1 | The answer is `2`, that's the first truthy value. 2 | 3 | ```js run 4 | alert( null || 2 || undefined ); 5 | ``` 6 | 7 | -------------------------------------------------------------------------------- /1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # What's the result of OR? 6 | 7 | What is the code below going to output? 8 | 9 | ```js 10 | alert( null || 2 || undefined ); 11 | ``` 12 | 13 | -------------------------------------------------------------------------------- /1-js/02-first-steps/11-logical-operators/2-alert-or/task.md: -------------------------------------------------------------------------------- 1 | importance: 3 2 | 3 | --- 4 | 5 | # What's the result of OR'ed alerts? 6 | 7 | What will the code below output? 8 | 9 | ```js 10 | alert( alert(1) || 2 || alert(3) ); 11 | ``` 12 | 13 | -------------------------------------------------------------------------------- /1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md: -------------------------------------------------------------------------------- 1 | The answer: `null`, because it's the first falsy value from the list. 2 | 3 | ```js run 4 | alert(1 && null && 2); 5 | ``` 6 | 7 | -------------------------------------------------------------------------------- /1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # What is the result of AND? 6 | 7 | What is this code going to show? 8 | 9 | ```js 10 | alert( 1 && null && 2 ); 11 | ``` 12 | 13 | -------------------------------------------------------------------------------- /1-js/02-first-steps/11-logical-operators/4-alert-and/solution.md: -------------------------------------------------------------------------------- 1 | The answer: `1`, and then `undefined`. 2 | 3 | ```js run 4 | alert( alert(1) && alert(2) ); 5 | ``` 6 | 7 | The call to `alert` returns `undefined` (it just shows a message, so there's no meaningful return). 8 | 9 | Because of that, `&&` evaluates the left operand (outputs `1`), and immediately stops, because `undefined` is a falsy value. And `&&` looks for a falsy value and returns it, so it's done. 10 | 11 | -------------------------------------------------------------------------------- /1-js/02-first-steps/11-logical-operators/4-alert-and/task.md: -------------------------------------------------------------------------------- 1 | importance: 3 2 | 3 | --- 4 | 5 | # What is the result of AND'ed alerts? 6 | 7 | What will this code show? 8 | 9 | ```js 10 | alert( alert(1) && alert(2) ); 11 | ``` 12 | 13 | -------------------------------------------------------------------------------- /1-js/02-first-steps/11-logical-operators/5-alert-and-or/solution.md: -------------------------------------------------------------------------------- 1 | The answer: `3`. 2 | 3 | ```js run 4 | alert( null || 2 && 3 || 4 ); 5 | ``` 6 | 7 | The precedence of AND `&&` is higher than `||`, so it executes first. 8 | 9 | The result of `2 && 3 = 3`, so the expression becomes: 10 | 11 | ``` 12 | null || 3 || 4 13 | ``` 14 | 15 | Now the result is the first truthy value: `3`. 16 | 17 | -------------------------------------------------------------------------------- /1-js/02-first-steps/11-logical-operators/5-alert-and-or/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # The result of OR AND OR 6 | 7 | What will the result be? 8 | 9 | ```js 10 | alert( null || 2 && 3 || 4 ); 11 | ``` 12 | 13 | -------------------------------------------------------------------------------- /1-js/02-first-steps/11-logical-operators/6-check-if-in-range/solution.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```js 4 | if (age >= 14 && age <= 90) 5 | ``` 6 | 7 | -------------------------------------------------------------------------------- /1-js/02-first-steps/11-logical-operators/6-check-if-in-range/task.md: -------------------------------------------------------------------------------- 1 | importance: 3 2 | 3 | --- 4 | 5 | # Check the range between 6 | 7 | Write an `if` condition to check that `age` is between `14` and `90` inclusively. 8 | 9 | "Inclusively" means that `age` can reach the edges `14` or `90`. 10 | -------------------------------------------------------------------------------- /1-js/02-first-steps/11-logical-operators/7-check-if-out-range/solution.md: -------------------------------------------------------------------------------- 1 | The first variant: 2 | 3 | ```js 4 | if (!(age >= 14 && age <= 90)) 5 | ``` 6 | 7 | The second variant: 8 | 9 | ```js 10 | if (age < 14 || age > 90) 11 | ``` 12 | 13 | -------------------------------------------------------------------------------- /1-js/02-first-steps/11-logical-operators/7-check-if-out-range/task.md: -------------------------------------------------------------------------------- 1 | importance: 3 2 | 3 | --- 4 | 5 | # Check the range outside 6 | 7 | Write an `if` condition to check that `age` is NOT between `14` and `90` inclusively. 8 | 9 | Create two variants: the first one using NOT `!`, the second one -- without it. 10 | -------------------------------------------------------------------------------- /1-js/02-first-steps/11-logical-operators/8-if-question/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # A question about "if" 6 | 7 | Which of these `alert`s are going to execute? 8 | 9 | What will the results of the expressions be inside `if(...)`? 10 | 11 | ```js 12 | if (-1 || 0) alert( 'first' ); 13 | if (-1 && 0) alert( 'second' ); 14 | if (null || -1 && 1) alert( 'third' ); 15 | ``` 16 | 17 | -------------------------------------------------------------------------------- /1-js/02-first-steps/13-while-for/1-loop-last-value/task.md: -------------------------------------------------------------------------------- 1 | importance: 3 2 | 3 | --- 4 | 5 | # Last loop value 6 | 7 | What is the last value alerted by this code? Why? 8 | 9 | ```js 10 | let i = 3; 11 | 12 | while (i) { 13 | alert( i-- ); 14 | } 15 | ``` 16 | -------------------------------------------------------------------------------- /1-js/02-first-steps/13-while-for/2-which-value-while/task.md: -------------------------------------------------------------------------------- 1 | importance: 4 2 | 3 | --- 4 | 5 | # Which values does the while loop show? 6 | 7 | For every loop iteration, write down which value it outputs and then compare it with the solution. 8 | 9 | Both loops `alert` the same values, or not? 10 | 11 | 1. The prefix form `++i`: 12 | 13 | ```js 14 | let i = 0; 15 | while (++i < 5) alert( i ); 16 | ``` 17 | 2. The postfix form `i++` 18 | 19 | ```js 20 | let i = 0; 21 | while (i++ < 5) alert( i ); 22 | ``` 23 | -------------------------------------------------------------------------------- /1-js/02-first-steps/13-while-for/3-which-value-for/task.md: -------------------------------------------------------------------------------- 1 | importance: 4 2 | 3 | --- 4 | 5 | # Which values get shown by the "for" loop? 6 | 7 | For each loop write down which values it is going to show. Then compare with the answer. 8 | 9 | Both loops `alert` same values or not? 10 | 11 | 1. The postfix form: 12 | 13 | ```js 14 | for (let i = 0; i < 5; i++) alert( i ); 15 | ``` 16 | 2. The prefix form: 17 | 18 | ```js 19 | for (let i = 0; i < 5; ++i) alert( i ); 20 | ``` 21 | -------------------------------------------------------------------------------- /1-js/02-first-steps/13-while-for/4-for-even/solution.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```js run demo 4 | for (let i = 2; i <= 10; i++) { 5 | if (i % 2 == 0) { 6 | alert( i ); 7 | } 8 | } 9 | ``` 10 | 11 | We use the "modulo" operator `%` to get the remainder and check for the evenness here. 12 | -------------------------------------------------------------------------------- /1-js/02-first-steps/13-while-for/4-for-even/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Output even numbers in the loop 6 | 7 | Use the `for` loop to output even numbers from `2` to `10`. 8 | 9 | [demo] 10 | -------------------------------------------------------------------------------- /1-js/02-first-steps/13-while-for/5-replace-for-while/solution.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```js run 4 | let i = 0; 5 | while (i < 3) { 6 | alert( `number ${i}!` ); 7 | i++; 8 | } 9 | ``` 10 | 11 | -------------------------------------------------------------------------------- /1-js/02-first-steps/13-while-for/5-replace-for-while/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Replace "for" with "while" 6 | 7 | Rewrite the code changing the `for` loop to `while` without altering its behavior (the output should stay same). 8 | 9 | ```js run 10 | for (let i = 0; i < 3; i++) { 11 | alert( `number ${i}!` ); 12 | } 13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /1-js/02-first-steps/14-switch/2-rewrite-if-switch/task.md: -------------------------------------------------------------------------------- 1 | importance: 4 2 | 3 | --- 4 | 5 | # Rewrite "if" into "switch" 6 | 7 | Rewrite the code below using a single `switch` statement: 8 | 9 | ```js run 10 | let a = +prompt('a?', ''); 11 | 12 | if (a == 0) { 13 | alert( 0 ); 14 | } 15 | if (a == 1) { 16 | alert( 1 ); 17 | } 18 | 19 | if (a == 2 || a == 3) { 20 | alert( '2,3' ); 21 | } 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md: -------------------------------------------------------------------------------- 1 | No difference! 2 | 3 | In both cases, `return confirm('Did parents allow you?')` executes exactly when the `if` condition is falsy. -------------------------------------------------------------------------------- /1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/solution.md: -------------------------------------------------------------------------------- 1 | Using a question mark operator `'?'`: 2 | 3 | ```js 4 | function checkAge(age) { 5 | return (age > 18) ? true : confirm('Did parents allow you?'); 6 | } 7 | ``` 8 | 9 | Using OR `||` (the shortest variant): 10 | 11 | ```js 12 | function checkAge(age) { 13 | return (age > 18) || confirm('Did parents allow you?'); 14 | } 15 | ``` 16 | 17 | Note that the parentheses around `age > 18` are not required here. They exist for better readability. 18 | -------------------------------------------------------------------------------- /1-js/02-first-steps/15-function-basics/3-min/solution.md: -------------------------------------------------------------------------------- 1 | A solution using `if`: 2 | 3 | ```js 4 | function min(a, b) { 5 | if (a < b) { 6 | return a; 7 | } else { 8 | return b; 9 | } 10 | } 11 | ``` 12 | 13 | A solution with a question mark operator `'?'`: 14 | 15 | ```js 16 | function min(a, b) { 17 | return a < b ? a : b; 18 | } 19 | ``` 20 | 21 | P.S. In the case of an equality `a == b` it does not matter what to return. -------------------------------------------------------------------------------- /1-js/02-first-steps/15-function-basics/3-min/task.md: -------------------------------------------------------------------------------- 1 | importance: 1 2 | 3 | --- 4 | 5 | # Function min(a, b) 6 | 7 | Write a function `min(a,b)` which returns the least of two numbers `a` and `b`. 8 | 9 | For instance: 10 | 11 | ```js 12 | min(2, 5) == 2 13 | min(3, -1) == -1 14 | min(1, 1) == 1 15 | ``` 16 | 17 | -------------------------------------------------------------------------------- /1-js/02-first-steps/15-function-basics/4-pow/solution.md: -------------------------------------------------------------------------------- 1 | 2 | ```js run demo 3 | function pow(x, n) { 4 | let result = x; 5 | 6 | for (let i = 1; i < n; i++) { 7 | result *= x; 8 | } 9 | 10 | return result; 11 | } 12 | 13 | let x = prompt("x?", ''); 14 | let n = prompt("n?", ''); 15 | 16 | if (n < 1) { 17 | alert(`Power ${n} is not supported, use a positive integer`); 18 | } else { 19 | alert( pow(x, n) ); 20 | } 21 | ``` 22 | -------------------------------------------------------------------------------- /1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/solution.md: -------------------------------------------------------------------------------- 1 | 2 | ```js run 3 | function ask(question, yes, no) { 4 | if (confirm(question)) yes(); 5 | else no(); 6 | } 7 | 8 | ask( 9 | "Do you agree?", 10 | *!* 11 | () => alert("You agreed."), 12 | () => alert("You canceled the execution.") 13 | */!* 14 | ); 15 | ``` 16 | 17 | Looks short and clean, right? 18 | -------------------------------------------------------------------------------- /1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/task.md: -------------------------------------------------------------------------------- 1 | 2 | # Rewrite with arrow functions 3 | 4 | Replace Function Expressions with arrow functions in the code below: 5 | 6 | ```js run 7 | function ask(question, yes, no) { 8 | if (confirm(question)) yes(); 9 | else no(); 10 | } 11 | 12 | ask( 13 | "Do you agree?", 14 | function() { alert("You agreed."); }, 15 | function() { alert("You canceled the execution."); } 16 | ); 17 | ``` 18 | -------------------------------------------------------------------------------- /1-js/02-first-steps/index.md: -------------------------------------------------------------------------------- 1 | # JavaScript Fundamentals 2 | 3 | Let's learn the fundamentals of script building. -------------------------------------------------------------------------------- /1-js/03-code-quality/01-debugging-chrome/debugging.view/hello.js: -------------------------------------------------------------------------------- 1 | function hello(name) { 2 | let phrase = `Hello, ${name}!`; 3 | 4 | say(phrase); 5 | } 6 | 7 | function say(phrase) { 8 | alert(`** ${phrase} **`); 9 | } 10 | -------------------------------------------------------------------------------- /1-js/03-code-quality/01-debugging-chrome/debugging.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | An example for debugging. 8 | 9 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /1-js/03-code-quality/01-debugging-chrome/head.html: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # What's wrong in the test? 6 | 7 | What's wrong in the test of `pow` below? 8 | 9 | ```js 10 | it("Raises x to the power n", function() { 11 | let x = 5; 12 | 13 | let result = x; 14 | assert.equal(pow(x, 1), result); 15 | 16 | result *= x; 17 | assert.equal(pow(x, 2), result); 18 | 19 | result *= x; 20 | assert.equal(pow(x, 3), result); 21 | }); 22 | ``` 23 | 24 | P.S. Syntactically the test is correct and passes. 25 | -------------------------------------------------------------------------------- /1-js/03-code-quality/05-testing-mocha/pow-1.view/test.js: -------------------------------------------------------------------------------- 1 | describe("pow", function() { 2 | 3 | it("raises to n-th power", function() { 4 | assert.equal(pow(2, 3), 8); 5 | }); 6 | 7 | }); 8 | -------------------------------------------------------------------------------- /1-js/03-code-quality/05-testing-mocha/pow-2.view/test.js: -------------------------------------------------------------------------------- 1 | describe("pow", function() { 2 | 3 | it("2 raised to power 3 is 8", function() { 4 | assert.equal(pow(2, 3), 8); 5 | }); 6 | 7 | it("3 raised to power 4 is 81", function() { 8 | assert.equal(pow(3, 4), 81); 9 | }); 10 | 11 | }); 12 | -------------------------------------------------------------------------------- /1-js/03-code-quality/05-testing-mocha/pow-3.view/test.js: -------------------------------------------------------------------------------- 1 | describe("pow", function() { 2 | 3 | function makeTest(x) { 4 | let expected = x * x * x; 5 | it(`${x} in the power 3 is ${expected}`, function() { 6 | assert.equal(pow(x, 3), expected); 7 | }); 8 | } 9 | 10 | for (let x = 1; x <= 5; x++) { 11 | makeTest(x); 12 | } 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /1-js/03-code-quality/05-testing-mocha/pow-4.view/test.js: -------------------------------------------------------------------------------- 1 | describe("pow", function() { 2 | 3 | describe("raises x to power 3", function() { 4 | 5 | function makeTest(x) { 6 | let expected = x * x * x; 7 | it(`${x} in the power 3 is ${expected}`, function() { 8 | assert.equal(pow(x, 3), expected); 9 | }); 10 | } 11 | 12 | for (let x = 1; x <= 5; x++) { 13 | makeTest(x); 14 | } 15 | 16 | }); 17 | 18 | // ... more tests to follow here, both describe and it can be added 19 | }); 20 | -------------------------------------------------------------------------------- /1-js/03-code-quality/05-testing-mocha/pow-min.view/test.js: -------------------------------------------------------------------------------- 1 | describe("pow", function() { 2 | 3 | it("raises to n-th power", function() { 4 | assert.equal(pow(2, 3), 8); 5 | }); 6 | 7 | }); 8 | -------------------------------------------------------------------------------- /1-js/03-code-quality/index.md: -------------------------------------------------------------------------------- 1 | # Code quality 2 | 3 | This chapter explains coding practices that we'll use further in the development. 4 | -------------------------------------------------------------------------------- /1-js/04-object-basics/01-object/2-hello-object/solution.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```js 4 | let user = {}; 5 | user.name = "John"; 6 | user.surname = "Smith"; 7 | user.name = "Pete"; 8 | delete user.name; 9 | ``` 10 | 11 | -------------------------------------------------------------------------------- /1-js/04-object-basics/01-object/2-hello-object/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Hello, object 6 | 7 | Write the code, one line for each action: 8 | 9 | 1. Create an empty object `user`. 10 | 2. Add the property `name` with the value `John`. 11 | 3. Add the property `surname` with the value `Smith`. 12 | 4. Change the value of the `name` to `Pete`. 13 | 5. Remove the property `name` from the object. 14 | 15 | -------------------------------------------------------------------------------- /1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function isEmpty(obj) { 2 | for (let key in obj) { 3 | // if the loop has started, there is a property 4 | return false; 5 | } 6 | return true; 7 | } 8 | -------------------------------------------------------------------------------- /1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js: -------------------------------------------------------------------------------- 1 | describe("isEmpty", function() { 2 | it("returns true for an empty object", function() { 3 | assert.isTrue(isEmpty({})); 4 | }); 5 | 6 | it("returns false if a property exists", function() { 7 | assert.isFalse(isEmpty({ 8 | anything: false 9 | })); 10 | }); 11 | }); -------------------------------------------------------------------------------- /1-js/04-object-basics/01-object/3-is-empty/solution.md: -------------------------------------------------------------------------------- 1 | Just loop over the object and `return false` immediately if there's at least one property. 2 | -------------------------------------------------------------------------------- /1-js/04-object-basics/01-object/3-is-empty/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Check for emptiness 6 | 7 | Write the function `isEmpty(obj)` which returns `true` if the object has no properties, `false` otherwise. 8 | 9 | Should work like that: 10 | 11 | ```js 12 | let schedule = {}; 13 | 14 | alert( isEmpty(schedule) ); // true 15 | 16 | schedule["8:30"] = "get up"; 17 | 18 | alert( isEmpty(schedule) ); // false 19 | ``` 20 | 21 | -------------------------------------------------------------------------------- /1-js/04-object-basics/01-object/5-sum-object/solution.md: -------------------------------------------------------------------------------- 1 | 2 | ```js run 3 | let salaries = { 4 | John: 100, 5 | Ann: 160, 6 | Pete: 130 7 | }; 8 | 9 | let sum = 0; 10 | for (let key in salaries) { 11 | sum += salaries[key]; 12 | } 13 | 14 | alert(sum); // 390 15 | ``` 16 | 17 | -------------------------------------------------------------------------------- /1-js/04-object-basics/01-object/5-sum-object/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Sum object properties 6 | 7 | We have an object storing salaries of our team: 8 | 9 | ```js 10 | let salaries = { 11 | John: 100, 12 | Ann: 160, 13 | Pete: 130 14 | } 15 | ``` 16 | 17 | Write the code to sum all salaries and store in the variable `sum`. Should be `390` in the example above. 18 | 19 | If `salaries` is empty, then the result must be `0`. -------------------------------------------------------------------------------- /1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function multiplyNumeric(obj) { 2 | for (let key in obj) { 3 | if (typeof obj[key] == 'number') { 4 | obj[key] *= 2; 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js: -------------------------------------------------------------------------------- 1 | let menu = { 2 | width: 200, 3 | height: 300, 4 | title: "My menu" 5 | }; 6 | 7 | 8 | function multiplyNumeric(obj) { 9 | 10 | /* your code */ 11 | 12 | } 13 | 14 | multiplyNumeric(menu); 15 | 16 | alert( "menu width=" + menu.width + " height=" + menu.height + " title=" + menu.title ); 17 | 18 | -------------------------------------------------------------------------------- /1-js/04-object-basics/01-object/8-multiply-numeric/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/04-object-basics/01-object/8-multiply-numeric/solution.md -------------------------------------------------------------------------------- /1-js/04-object-basics/04-object-methods/4-object-property-this/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Using "this" in object literal 6 | 7 | Here the function `makeUser` returns an object. 8 | 9 | What is the result of accessing its `ref`? Why? 10 | 11 | ```js 12 | function makeUser() { 13 | return { 14 | name: "John", 15 | ref: this 16 | }; 17 | } 18 | 19 | let user = makeUser(); 20 | 21 | alert( user.ref.name ); // What's the result? 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /1-js/04-object-basics/04-object-methods/7-calculator/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | let calculator = { 2 | sum() { 3 | return this.a + this.b; 4 | }, 5 | 6 | mul() { 7 | return this.a * this.b; 8 | }, 9 | 10 | read() { 11 | this.a = +prompt('a?', 0); 12 | this.b = +prompt('b?', 0); 13 | } 14 | }; -------------------------------------------------------------------------------- /1-js/04-object-basics/04-object-methods/7-calculator/solution.md: -------------------------------------------------------------------------------- 1 | 2 | ```js run demo solution 3 | let calculator = { 4 | sum() { 5 | return this.a + this.b; 6 | }, 7 | 8 | mul() { 9 | return this.a * this.b; 10 | }, 11 | 12 | read() { 13 | this.a = +prompt('a?', 0); 14 | this.b = +prompt('b?', 0); 15 | } 16 | }; 17 | 18 | calculator.read(); 19 | alert( calculator.sum() ); 20 | alert( calculator.mul() ); 21 | ``` 22 | -------------------------------------------------------------------------------- /1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | 2 | let ladder = { 3 | step: 0, 4 | up: function() { 5 | this.step++; 6 | return this; 7 | }, 8 | down: function() { 9 | this.step--; 10 | return this; 11 | }, 12 | showStep: function() { 13 | alert(this.step); 14 | return this; 15 | } 16 | }; -------------------------------------------------------------------------------- /1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/solution.md: -------------------------------------------------------------------------------- 1 | Yes, it's possible. 2 | 3 | If a function returns an object then `new` returns it instead of `this`. 4 | 5 | So they can, for instance, return the same externally defined object `obj`: 6 | 7 | ```js run no-beautify 8 | let obj = {}; 9 | 10 | function A() { return obj; } 11 | function B() { return obj; } 12 | 13 | alert( new A() == new B() ); // true 14 | ``` 15 | -------------------------------------------------------------------------------- /1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md: -------------------------------------------------------------------------------- 1 | importance: 2 2 | 3 | --- 4 | 5 | # Two functions – one object 6 | 7 | Is it possible to create functions `A` and `B` so that `new A() == new B()`? 8 | 9 | ```js no-beautify 10 | function A() { ... } 11 | function B() { ... } 12 | 13 | let a = new A(); 14 | let b = new B(); 15 | 16 | alert( a == b ); // true 17 | ``` 18 | 19 | If it is, then provide an example of their code. 20 | -------------------------------------------------------------------------------- /1-js/04-object-basics/06-constructor-new/2-calculator-constructor/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function Calculator() { 2 | 3 | this.read = function() { 4 | this.a = +prompt('a?', 0); 5 | this.b = +prompt('b?', 0); 6 | }; 7 | 8 | this.sum = function() { 9 | return this.a + this.b; 10 | }; 11 | 12 | this.mul = function() { 13 | return this.a * this.b; 14 | }; 15 | } -------------------------------------------------------------------------------- /1-js/04-object-basics/06-constructor-new/3-accumulator/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function Accumulator(startingValue) { 2 | this.value = startingValue; 3 | 4 | this.read = function() { 5 | this.value += +prompt('How much to add?', 0); 6 | }; 7 | 8 | } 9 | -------------------------------------------------------------------------------- /1-js/04-object-basics/06-constructor-new/3-accumulator/solution.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```js run demo 4 | function Accumulator(startingValue) { 5 | this.value = startingValue; 6 | 7 | this.read = function() { 8 | this.value += +prompt('How much to add?', 0); 9 | }; 10 | 11 | } 12 | 13 | let accumulator = new Accumulator(1); 14 | accumulator.read(); 15 | accumulator.read(); 16 | alert(accumulator.value); 17 | ``` 18 | -------------------------------------------------------------------------------- /1-js/04-object-basics/index.md: -------------------------------------------------------------------------------- 1 | # Objects: the basics 2 | -------------------------------------------------------------------------------- /1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Can I add a string property? 6 | 7 | 8 | Consider the following code: 9 | 10 | ```js 11 | let str = "Hello"; 12 | 13 | str.test = 5; 14 | 15 | alert(str.test); 16 | ``` 17 | 18 | What do you think, will it work? What will be shown? 19 | -------------------------------------------------------------------------------- /1-js/05-data-types/02-number/1-sum-interface/solution.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```js run demo 4 | let a = +prompt("The first number?", ""); 5 | let b = +prompt("The second number?", ""); 6 | 7 | alert( a + b ); 8 | ``` 9 | 10 | Note the unary plus `+` before `prompt`. It immediately converts the value to a number. 11 | 12 | Otherwise, `a` and `b` would be string their sum would be their concatenation, that is: `"1" + "2" = "12"`. -------------------------------------------------------------------------------- /1-js/05-data-types/02-number/1-sum-interface/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Sum numbers from the visitor 6 | 7 | Create a script that prompts the visitor to enter two numbers and then shows their sum. 8 | 9 | [demo] 10 | 11 | P.S. There is a gotcha with types. 12 | -------------------------------------------------------------------------------- /1-js/05-data-types/02-number/3-repeat-until-number/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | 2 | function readNumber() { 3 | let num; 4 | 5 | do { 6 | num = prompt("Enter a number please?", 0); 7 | } while ( !isFinite(num) ); 8 | 9 | if (num === null || num === '') return null; 10 | 11 | return +num; 12 | } -------------------------------------------------------------------------------- /1-js/05-data-types/02-number/3-repeat-until-number/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Repeat until the input is a number 6 | 7 | Create a function `readNumber` which prompts for a number until the visitor enters a valid numeric value. 8 | 9 | The resulting value must be returned as a number. 10 | 11 | The visitor can also stop the process by entering an empty line or pressing "CANCEL". In that case, the function should return `null`. 12 | 13 | [demo] 14 | 15 | -------------------------------------------------------------------------------- /1-js/05-data-types/02-number/4-endless-loop-error/solution.md: -------------------------------------------------------------------------------- 1 | That's because `i` would never equal `10`. 2 | 3 | Run it to see the *real* values of `i`: 4 | 5 | ```js run 6 | let i = 0; 7 | while (i < 11) { 8 | i += 0.2; 9 | if (i > 9.8 && i < 10.2) alert( i ); 10 | } 11 | ``` 12 | 13 | None of them is exactly `10`. 14 | 15 | Such things happen because of the precision losses when adding fractions like `0.2`. 16 | 17 | Conclusion: evade equality checks when working with decimal fractions. -------------------------------------------------------------------------------- /1-js/05-data-types/02-number/4-endless-loop-error/task.md: -------------------------------------------------------------------------------- 1 | importance: 4 2 | 3 | --- 4 | 5 | # An occasional infinite loop 6 | 7 | This loop is infinite. It never ends. Why? 8 | 9 | ```js 10 | let i = 0; 11 | while (i != 10) { 12 | i += 0.2; 13 | } 14 | ``` 15 | 16 | -------------------------------------------------------------------------------- /1-js/05-data-types/03-string/1-ucfirst/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function ucFirst(str) { 2 | if (!str) return str; 3 | 4 | return str[0].toUpperCase() + str.slice(1); 5 | } -------------------------------------------------------------------------------- /1-js/05-data-types/03-string/1-ucfirst/_js.view/test.js: -------------------------------------------------------------------------------- 1 | describe("ucFirst", function() { 2 | it('Uppercases the first symbol', function() { 3 | assert.strictEqual(ucFirst("john"), "John"); 4 | }); 5 | 6 | it("Doesn't die on an empty string", function() { 7 | assert.strictEqual(ucFirst(""), ""); 8 | }); 9 | }); -------------------------------------------------------------------------------- /1-js/05-data-types/03-string/1-ucfirst/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Uppercase the first character 6 | 7 | Write a function `ucFirst(str)` that returns the string `str` with the uppercased first character, for instance: 8 | 9 | ```js 10 | ucFirst("john") == "John"; 11 | ``` 12 | 13 | -------------------------------------------------------------------------------- /1-js/05-data-types/03-string/2-check-spam/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function checkSpam(str) { 2 | let lowerStr = str.toLowerCase(); 3 | 4 | return lowerStr.includes('viagra') || lowerStr.includes('xxx'); 5 | } -------------------------------------------------------------------------------- /1-js/05-data-types/03-string/2-check-spam/_js.view/test.js: -------------------------------------------------------------------------------- 1 | describe("checkSpam", function() { 2 | it('finds spam in "buy ViAgRA now"', function() { 3 | assert.isTrue(checkSpam('buy ViAgRA now')); 4 | }); 5 | 6 | it('finds spam in "free xxxxx"', function() { 7 | assert.isTrue(checkSpam('free xxxxx')); 8 | }); 9 | 10 | it('no spam in "innocent rabbit"', function() { 11 | assert.isFalse(checkSpam('innocent rabbit')); 12 | }); 13 | }); -------------------------------------------------------------------------------- /1-js/05-data-types/03-string/2-check-spam/solution.md: -------------------------------------------------------------------------------- 1 | To make the search case-insensitive, let's bring the string to lower case and then search: 2 | 3 | ```js run demo 4 | function checkSpam(str) { 5 | let lowerStr = str.toLowerCase(); 6 | 7 | return lowerStr.includes('viagra') || lowerStr.includes('xxx'); 8 | } 9 | 10 | alert( checkSpam('buy ViAgRA now') ); 11 | alert( checkSpam('free xxxxx') ); 12 | alert( checkSpam("innocent rabbit") ); 13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /1-js/05-data-types/03-string/2-check-spam/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Check for spam 6 | 7 | Write a function `checkSpam(str)` that returns `true` if `str` contains 'viagra' or 'XXX', otherwise `false`. 8 | 9 | The function must be case-insensitive: 10 | 11 | ```js 12 | checkSpam('buy ViAgRA now') == true 13 | checkSpam('free xxxxx') == true 14 | checkSpam("innocent rabbit") == false 15 | ``` 16 | 17 | -------------------------------------------------------------------------------- /1-js/05-data-types/03-string/3-truncate/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function truncate(str, maxlength) { 2 | return (str.length > maxlength) ? 3 | str.slice(0, maxlength - 1) + '…' : str; 4 | } -------------------------------------------------------------------------------- /1-js/05-data-types/03-string/3-truncate/_js.view/test.js: -------------------------------------------------------------------------------- 1 | describe("truncate", function() { 2 | it("truncate the long string to the given length (including the ellipsis)", function() { 3 | assert.equal( 4 | truncate("What I'd like to tell on this topic is:", 20), 5 | "What I'd like to te…" 6 | ); 7 | }); 8 | 9 | it("doesn't change short strings", function() { 10 | assert.equal( 11 | truncate("Hi everyone!", 20), 12 | "Hi everyone!" 13 | ); 14 | }); 15 | 16 | }); 17 | -------------------------------------------------------------------------------- /1-js/05-data-types/03-string/3-truncate/solution.md: -------------------------------------------------------------------------------- 1 | The maximal length must be `maxlength`, so we need to cut it a little shorter, to give space for the ellipsis. 2 | 3 | Note that there is actually a single Unicode character for an ellipsis. That's not three dots. 4 | 5 | ```js run demo 6 | function truncate(str, maxlength) { 7 | return (str.length > maxlength) ? 8 | str.slice(0, maxlength - 1) + '…' : str; 9 | } 10 | ``` 11 | -------------------------------------------------------------------------------- /1-js/05-data-types/03-string/4-extract-currency/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function extractCurrencyValue(str) { 2 | return +str.slice(1); 3 | } -------------------------------------------------------------------------------- /1-js/05-data-types/03-string/4-extract-currency/_js.view/test.js: -------------------------------------------------------------------------------- 1 | describe("extractCurrencyValue", function() { 2 | 3 | it("for the string $120 returns the number 120", function() { 4 | assert.strictEqual(extractCurrencyValue('$120'), 120); 5 | }); 6 | 7 | 8 | }); -------------------------------------------------------------------------------- /1-js/05-data-types/03-string/4-extract-currency/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/05-data-types/03-string/4-extract-currency/solution.md -------------------------------------------------------------------------------- /1-js/05-data-types/03-string/4-extract-currency/task.md: -------------------------------------------------------------------------------- 1 | importance: 4 2 | 3 | --- 4 | 5 | # Extract the money 6 | 7 | We have a cost in the form `"$120"`. That is: the dollar sign goes first, and then the number. 8 | 9 | Create a function `extractCurrencyValue(str)` that would extract the numeric value from such string and return it. 10 | 11 | The example: 12 | 13 | ```js 14 | alert( extractCurrencyValue('$120') === 120 ); // true 15 | ``` 16 | 17 | -------------------------------------------------------------------------------- /1-js/05-data-types/04-array/1-item-value/solution.md: -------------------------------------------------------------------------------- 1 | The result is `4`: 2 | 3 | 4 | ```js run 5 | let fruits = ["Apples", "Pear", "Orange"]; 6 | 7 | let shoppingCart = fruits; 8 | 9 | shoppingCart.push("Banana"); 10 | 11 | *!* 12 | alert( fruits.length ); // 4 13 | */!* 14 | ``` 15 | 16 | That's because arrays are objects. So both `shoppingCart` and `fruits` are the references to the same array. 17 | 18 | -------------------------------------------------------------------------------- /1-js/05-data-types/04-array/1-item-value/task.md: -------------------------------------------------------------------------------- 1 | importance: 3 2 | 3 | --- 4 | 5 | # Is array copied? 6 | 7 | What is this code going to show? 8 | 9 | ```js 10 | let fruits = ["Apples", "Pear", "Orange"]; 11 | 12 | // push a new value into the "copy" 13 | let shoppingCart = fruits; 14 | shoppingCart.push("Banana"); 15 | 16 | // what's in fruits? 17 | alert( fruits.length ); // ? 18 | ``` 19 | 20 | -------------------------------------------------------------------------------- /1-js/05-data-types/04-array/10-maximal-subarray/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function getMaxSubSum(arr) { 2 | let maxSum = 0; 3 | let partialSum = 0; 4 | 5 | for (let item of arr) { 6 | partialSum += item; 7 | maxSum = Math.max(maxSum, partialSum); 8 | if (partialSum < 0) partialSum = 0; 9 | } 10 | return maxSum; 11 | } -------------------------------------------------------------------------------- /1-js/05-data-types/04-array/2-create-array/solution.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```js run 4 | let styles = ["Jazz", "Blues"]; 5 | styles.push("Rock-n-Roll"); 6 | styles[Math.floor((styles.length - 1) / 2)] = "Classics"; 7 | alert( styles.shift() ); 8 | styles.unshift("Rap", "Reggae"); 9 | ``` 10 | 11 | -------------------------------------------------------------------------------- /1-js/05-data-types/04-array/3-call-array-this/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Calling in an array context 6 | 7 | What is the result? Why? 8 | 9 | ```js 10 | let arr = ["a", "b"]; 11 | 12 | arr.push(function() { 13 | alert( this ); 14 | }); 15 | 16 | arr[2](); // ? 17 | ``` 18 | 19 | -------------------------------------------------------------------------------- /1-js/05-data-types/04-array/5-array-input-sum/task.md: -------------------------------------------------------------------------------- 1 | importance: 4 2 | 3 | --- 4 | 5 | # Sum input numbers 6 | 7 | Write the function `sumInput()` that: 8 | 9 | - Asks the user for values using `prompt` and stores the values in the array. 10 | - Finishes asking when the user enters a non-numeric value, an empty string, or presses "Cancel". 11 | - Calculates and returns the sum of array items. 12 | 13 | P.S. A zero `0` is a valid number, please don't stop the input on zero. 14 | 15 | [demo] 16 | -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function camelize(str) { 2 | return str 3 | .split('-') // splits 'my-long-word' into array ['my', 'long', 'word'] 4 | .map( 5 | // capitalizes first letters of all array items except the first one 6 | // converts ['my', 'long', 'word'] into ['my', 'Long', 'Word'] 7 | (word, index) => index == 0 ? word : word[0].toUpperCase() + word.slice(1) 8 | ) 9 | .join(''); // joins ['my', 'Long', 'Word'] into 'myLongWord' 10 | } 11 | -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/1-camelcase/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/05-data-types/05-array-methods/1-camelcase/solution.md -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/10-average-age/solution.md: -------------------------------------------------------------------------------- 1 | ```js run 2 | function getAverageAge(users) { 3 | return users.reduce((prev, user) => prev + user.age, 0) / users.length; 4 | } 5 | 6 | let john = { name: "John", age: 25 }; 7 | let pete = { name: "Pete", age: 30 }; 8 | let mary = { name: "Mary", age: 29 }; 9 | 10 | let arr = [ john, pete, mary ]; 11 | 12 | alert( getAverageAge(arr) ); // 28 13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/11-array-unique/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function unique(arr) { 2 | let result = []; 3 | 4 | for (let str of arr) { 5 | if (!result.includes(str)) { 6 | result.push(str); 7 | } 8 | } 9 | 10 | return result; 11 | } 12 | -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/11-array-unique/task.md: -------------------------------------------------------------------------------- 1 | importance: 4 2 | 3 | --- 4 | 5 | # Filter unique array members 6 | 7 | Let `arr` be an array. 8 | 9 | Create a function `unique(arr)` that should return an array with unique items of `arr`. 10 | 11 | For instance: 12 | 13 | ```js 14 | function unique(arr) { 15 | /* your code */ 16 | } 17 | 18 | let strings = ["Hare", "Krishna", "Hare", "Krishna", 19 | "Krishna", "Krishna", "Hare", "Hare", ":-O" 20 | ]; 21 | 22 | alert( unique(strings) ); // Hare, Krishna, :-O 23 | ``` 24 | -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function groupById(array) { 2 | return array.reduce((obj, value) => { 3 | obj[value.id] = value; 4 | return obj; 5 | }, {}) 6 | } 7 | -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/12-reduce-object/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/05-data-types/05-array-methods/12-reduce-object/solution.md -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/2-filter-range/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | 2 | function filterRange(arr, a, b) { 3 | // added brackets around the expression for better readability 4 | return arr.filter(item => (a <= item && item <= b)); 5 | } -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/2-filter-range/_js.view/test.js: -------------------------------------------------------------------------------- 1 | describe("filterRange", function() { 2 | 3 | it("returns the filtered values", function() { 4 | 5 | let arr = [5, 3, 8, 1]; 6 | 7 | let filtered = filterRange(arr, 1, 4); 8 | 9 | assert.deepEqual(filtered, [3, 1]); 10 | }); 11 | 12 | it("doesn't change the array", function() { 13 | 14 | let arr = [5, 3, 8, 1]; 15 | 16 | let filtered = filterRange(arr, 1, 4); 17 | 18 | assert.deepEqual(arr, [5,3,8,1]); 19 | }); 20 | 21 | }); -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/2-filter-range/solution.md: -------------------------------------------------------------------------------- 1 | ```js run demo 2 | function filterRange(arr, a, b) { 3 | // added brackets around the expression for better readability 4 | return arr.filter(item => (a <= item && item <= b)); 5 | } 6 | 7 | let arr = [5, 3, 8, 1]; 8 | 9 | let filtered = filterRange(arr, 1, 4); 10 | 11 | alert( filtered ); // 3,1 (matching values) 12 | 13 | alert( arr ); // 5,3,8,1 (not modified) 14 | ``` 15 | -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | 2 | function filterRangeInPlace(arr, a, b) { 3 | 4 | for (let i = 0; i < arr.length; i++) { 5 | let val = arr[i]; 6 | 7 | // remove if outside of the interval 8 | if (val < a || val > b) { 9 | arr.splice(i, 1); 10 | i--; 11 | } 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/test.js: -------------------------------------------------------------------------------- 1 | describe("filterRangeInPlace", function() { 2 | 3 | it("returns the filtered values", function() { 4 | 5 | let arr = [5, 3, 8, 1]; 6 | 7 | filterRangeInPlace(arr, 2, 5); 8 | 9 | assert.deepEqual(arr, [5, 3]); 10 | }); 11 | 12 | it("doesn't return anything", function() { 13 | assert.isUndefined(filterRangeInPlace([1,2,3], 1, 4)); 14 | }); 15 | 16 | }); 17 | -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/4-sort-back/solution.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```js run 4 | let arr = [5, 2, 1, -10, 8]; 5 | 6 | arr.sort((a, b) => b - a); 7 | 8 | alert( arr ); 9 | ``` 10 | 11 | -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/4-sort-back/task.md: -------------------------------------------------------------------------------- 1 | importance: 4 2 | 3 | --- 4 | 5 | # Sort in decreasing order 6 | 7 | ```js 8 | let arr = [5, 2, 1, -10, 8]; 9 | 10 | // ... your code to sort it in decreasing order 11 | 12 | alert( arr ); // 8, 5, 2, 1, -10 13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/5-copy-sort-array/solution.md: -------------------------------------------------------------------------------- 1 | We can use `slice()` to make a copy and run the sort on it: 2 | 3 | ```js run 4 | function copySorted(arr) { 5 | return arr.slice().sort(); 6 | } 7 | 8 | let arr = ["HTML", "JavaScript", "CSS"]; 9 | 10 | *!* 11 | let sorted = copySorted(arr); 12 | */!* 13 | 14 | alert( sorted ); 15 | alert( arr ); 16 | ``` 17 | 18 | -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/5-copy-sort-array/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Copy and sort array 6 | 7 | We have an array of strings `arr`. We'd like to have a sorted copy of it, but keep `arr` unmodified. 8 | 9 | Create a function `copySorted(arr)` that returns such a copy. 10 | 11 | ```js 12 | let arr = ["HTML", "JavaScript", "CSS"]; 13 | 14 | let sorted = copySorted(arr); 15 | 16 | alert( sorted ); // CSS, HTML, JavaScript 17 | alert( arr ); // HTML, JavaScript, CSS (no changes) 18 | ``` 19 | -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/6-array-get-names/solution.md: -------------------------------------------------------------------------------- 1 | ```js run 2 | 3 | let john = { name: "John", age: 25 }; 4 | let pete = { name: "Pete", age: 30 }; 5 | let mary = { name: "Mary", age: 28 }; 6 | 7 | let users = [ john, pete, mary ]; 8 | 9 | let names = users.map(item => item.name); 10 | 11 | alert( names ); // John, Pete, Mary 12 | ``` 13 | 14 | -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/6-calculator-extendable/solution.md: -------------------------------------------------------------------------------- 1 | 2 | - Please note how methods are stored. They are simply added to `this.methods` property. 3 | - All tests and numeric conversions are done in the `calculate` method. In future it may be extended to support more complex expressions. 4 | -------------------------------------------------------------------------------- /1-js/05-data-types/05-array-methods/8-sort-objects/solution.md: -------------------------------------------------------------------------------- 1 | ```js run no-beautify 2 | function sortByAge(arr) { 3 | arr.sort((a, b) => a.age - b.age); 4 | } 5 | 6 | let john = { name: "John", age: 25 }; 7 | let pete = { name: "Pete", age: 30 }; 8 | let mary = { name: "Mary", age: 28 }; 9 | 10 | let arr = [ pete, john, mary ]; 11 | 12 | sortByAge(arr); 13 | 14 | // now sorted is: [john, mary, pete] 15 | alert(arr[0].name); // John 16 | alert(arr[1].name); // Mary 17 | alert(arr[2].name); // Pete 18 | ``` 19 | -------------------------------------------------------------------------------- /1-js/05-data-types/07-map-set/01-array-unique-map/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function unique(arr) { 2 | return Array.from(new Set(arr)); 3 | } 4 | -------------------------------------------------------------------------------- /1-js/05-data-types/07-map-set/01-array-unique-map/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/05-data-types/07-map-set/01-array-unique-map/solution.md -------------------------------------------------------------------------------- /1-js/05-data-types/07-map-set/02-filter-anagrams/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | 2 | function aclean(arr) { 3 | let map = new Map(); 4 | 5 | for(let word of arr) { 6 | let sorted = word.toLowerCase().split("").sort().join(""); 7 | map.set(sorted, word); 8 | } 9 | 10 | return Array.from(map.values()); 11 | } -------------------------------------------------------------------------------- /1-js/05-data-types/07-map-set/03-iterable-keys/solution.md: -------------------------------------------------------------------------------- 1 | 2 | That's because `map.keys()` returns an iterable, but not an array. 3 | 4 | We can convert it into an array using `Array.from`: 5 | 6 | 7 | ```js run 8 | let map = new Map(); 9 | 10 | map.set("name", "John"); 11 | 12 | *!* 13 | let keys = Array.from(map.keys()); 14 | */!* 15 | 16 | keys.push("more"); 17 | 18 | alert(keys); // name, more 19 | ``` 20 | -------------------------------------------------------------------------------- /1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/solution.md: -------------------------------------------------------------------------------- 1 | 2 | To store a date, we can use `WeakMap`: 3 | 4 | ```js 5 | let messages = [ 6 | {text: "Hello", from: "John"}, 7 | {text: "How goes?", from: "John"}, 8 | {text: "See you soon", from: "Alice"} 9 | ]; 10 | 11 | let readMap = new WeakMap(); 12 | 13 | readMap.set(messages[0], new Date(2017, 1, 1)); 14 | // Date object we'll study later 15 | ``` 16 | -------------------------------------------------------------------------------- /1-js/05-data-types/09-keys-values-entries/01-sum-salaries/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function sumSalaries(salaries) { 2 | 3 | let sum = 0; 4 | for (let salary of Object.values(salaries)) { 5 | sum += salary; 6 | } 7 | 8 | return sum; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /1-js/05-data-types/09-keys-values-entries/01-sum-salaries/_js.view/test.js: -------------------------------------------------------------------------------- 1 | describe("sumSalaries", function() { 2 | it("returns sum of salaries", function() { 3 | let salaries = { 4 | "John": 100, 5 | "Pete": 300, 6 | "Mary": 250 7 | }; 8 | 9 | assert.equal( sumSalaries(salaries), 650 ); 10 | }); 11 | 12 | it("returns 0 for the empty object", function() { 13 | assert.strictEqual( sumSalaries({}), 0); 14 | }); 15 | }); -------------------------------------------------------------------------------- /1-js/05-data-types/09-keys-values-entries/02-count-properties/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function count(obj) { 2 | return Object.keys(obj).length; 3 | } 4 | 5 | -------------------------------------------------------------------------------- /1-js/05-data-types/09-keys-values-entries/02-count-properties/_js.view/test.js: -------------------------------------------------------------------------------- 1 | describe("count", function() { 2 | it("counts the number of properties", function() { 3 | assert.equal( count({a: 1, b: 2}), 2 ); 4 | }); 5 | 6 | it("returns 0 for an empty object", function() { 7 | assert.equal( count({}), 0 ); 8 | }); 9 | 10 | it("ignores symbolic properties", function() { 11 | assert.equal( count({ [Symbol('id')]: 1 }), 0 ); 12 | }); 13 | }); -------------------------------------------------------------------------------- /1-js/05-data-types/09-keys-values-entries/02-count-properties/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/05-data-types/09-keys-values-entries/02-count-properties/solution.md -------------------------------------------------------------------------------- /1-js/05-data-types/09-keys-values-entries/02-count-properties/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Count properties 6 | 7 | Write a function `count(obj)` that returns the number of properties in the object: 8 | 9 | ```js 10 | let user = { 11 | name: 'John', 12 | age: 30 13 | }; 14 | 15 | alert( count(user) ); // 2 16 | ``` 17 | 18 | Try to make the code as short as possible. 19 | 20 | P.S. Ignore symbolic properties, count only "regular" ones. 21 | 22 | -------------------------------------------------------------------------------- /1-js/05-data-types/10-destructuring-assignment/1-destruct-user/solution.md: -------------------------------------------------------------------------------- 1 | 2 | ```js run 3 | let user = { 4 | name: "John", 5 | years: 30 6 | }; 7 | 8 | let {name, years: age, isAdmin = false} = user; 9 | 10 | alert( name ); // John 11 | alert( age ); // 30 12 | alert( isAdmin ); // false 13 | ``` -------------------------------------------------------------------------------- /1-js/05-data-types/10-destructuring-assignment/6-max-salary/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function topSalary(salaries) { 2 | 3 | let maxSalary = 0; 4 | let maxName = null; 5 | 6 | for(const [name, salary] of Object.entries(salaries)) { 7 | if (maxSalary < salary) { 8 | maxSalary = salary; 9 | maxName = name; 10 | } 11 | } 12 | 13 | return maxName; 14 | } -------------------------------------------------------------------------------- /1-js/05-data-types/10-destructuring-assignment/6-max-salary/_js.view/test.js: -------------------------------------------------------------------------------- 1 | describe("topSalary", function() { 2 | it("returns top-paid person", function() { 3 | let salaries = { 4 | "John": 100, 5 | "Pete": 300, 6 | "Mary": 250 7 | }; 8 | 9 | assert.equal( topSalary(salaries), "Pete" ); 10 | }); 11 | 12 | it("returns null for the empty object", function() { 13 | assert.isNull( topSalary({}) ); 14 | }); 15 | }); -------------------------------------------------------------------------------- /1-js/05-data-types/10-destructuring-assignment/6-max-salary/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/05-data-types/10-destructuring-assignment/6-max-salary/solution.md -------------------------------------------------------------------------------- /1-js/05-data-types/11-date/1-new-date/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Create a date 6 | 7 | Create a `Date` object for the date: Feb 20, 2012, 3:12am. The time zone is local. 8 | 9 | Show it using `alert`. 10 | -------------------------------------------------------------------------------- /1-js/05-data-types/11-date/2-get-week-day/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function getWeekDay(date) { 2 | let days = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA']; 3 | 4 | return days[date.getDay()]; 5 | } 6 | -------------------------------------------------------------------------------- /1-js/05-data-types/11-date/2-get-week-day/solution.md: -------------------------------------------------------------------------------- 1 | The method `date.getDay()` returns the number of the weekday, starting from sunday. 2 | 3 | Let's make an array of weekdays, so that we can get the proper day name by its number: 4 | 5 | ```js run demo 6 | function getWeekDay(date) { 7 | let days = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA']; 8 | 9 | return days[date.getDay()]; 10 | } 11 | 12 | let date = new Date(2014, 0, 3); // 3 Jan 2014 13 | alert( getWeekDay(date) ); // FR 14 | ``` 15 | -------------------------------------------------------------------------------- /1-js/05-data-types/11-date/2-get-week-day/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Show a weekday 6 | 7 | Write a function `getWeekDay(date)` to show the weekday in short format: 'MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU'. 8 | 9 | For instance: 10 | 11 | ```js no-beautify 12 | let date = new Date(2012, 0, 3); // 3 Jan 2012 13 | alert( getWeekDay(date) ); // should output "TU" 14 | ``` 15 | -------------------------------------------------------------------------------- /1-js/05-data-types/11-date/3-weekday/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function getLocalDay(date) { 2 | 3 | let day = date.getDay(); 4 | 5 | if (day == 0) { // weekday 0 (sunday) is 7 in european 6 | day = 7; 7 | } 8 | 9 | return day; 10 | } 11 | -------------------------------------------------------------------------------- /1-js/05-data-types/11-date/3-weekday/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/05-data-types/11-date/3-weekday/solution.md -------------------------------------------------------------------------------- /1-js/05-data-types/11-date/3-weekday/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # European weekday 6 | 7 | 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`. 8 | 9 | ```js no-beautify 10 | let date = new Date(2012, 0, 3); // 3 Jan 2012 11 | alert( getLocalDay(date) ); // tuesday, should show 2 12 | ``` 13 | -------------------------------------------------------------------------------- /1-js/05-data-types/11-date/4-get-date-ago/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function getDateAgo(date, days) { 2 | let dateCopy = new Date(date); 3 | 4 | dateCopy.setDate(date.getDate() - days); 5 | return dateCopy.getDate(); 6 | } 7 | -------------------------------------------------------------------------------- /1-js/05-data-types/11-date/5-last-day-of-month/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function getLastDayOfMonth(year, month) { 2 | let date = new Date(year, month + 1, 0); 3 | return date.getDate(); 4 | } 5 | -------------------------------------------------------------------------------- /1-js/05-data-types/11-date/5-last-day-of-month/_js.view/test.js: -------------------------------------------------------------------------------- 1 | describe("getLastDayOfMonth", function() { 2 | it("last day of 01.01.2012 - 31", function() { 3 | assert.equal(getLastDayOfMonth(2012, 0), 31); 4 | }); 5 | 6 | it("last day of 01.02.2012 - 29 (leap year)", function() { 7 | assert.equal(getLastDayOfMonth(2012, 1), 29); 8 | }); 9 | 10 | it("last day of 01.02.2013 - 28", function() { 11 | assert.equal(getLastDayOfMonth(2013, 1), 28); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /1-js/05-data-types/11-date/5-last-day-of-month/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Last day of month? 6 | 7 | Write a function `getLastDayOfMonth(year, month)` that returns the last day of month. Sometimes it is 30th, 31st or even 28/29th for Feb. 8 | 9 | Parameters: 10 | 11 | - `year` -- four-digits year, for instance 2012. 12 | - `month` -- month, from 0 to 11. 13 | 14 | For instance, `getLastDayOfMonth(2012, 1) = 29` (leap year, Feb). 15 | -------------------------------------------------------------------------------- /1-js/05-data-types/11-date/6-get-seconds-today/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # How many seconds have passed today? 6 | 7 | Write a function `getSecondsToday()` that returns the number of seconds from the beginning of today. 8 | 9 | For instance, if now were `10:00 am`, and there was no daylight savings shift, then: 10 | 11 | ```js 12 | getSecondsToday() == 36000 // (3600 * 10) 13 | ``` 14 | 15 | The function should work in any day. That is, it should not have a hard-coded value of "today". 16 | -------------------------------------------------------------------------------- /1-js/05-data-types/11-date/7-get-seconds-to-tomorrow/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # How many seconds till tomorrow? 6 | 7 | Create a function `getSecondsToTomorrow()` that returns the number of seconds till tomorrow. 8 | 9 | For instance, if now is `23:00`, then: 10 | 11 | ```js 12 | getSecondsToTomorrow() == 3600 13 | ``` 14 | 15 | P.S. The function should work at any day, the "today" is not hardcoded. 16 | -------------------------------------------------------------------------------- /1-js/05-data-types/12-json/1-serialize-object/solution.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```js 4 | let user = { 5 | name: "John Smith", 6 | age: 35 7 | }; 8 | 9 | *!* 10 | let user2 = JSON.parse(JSON.stringify(user)); 11 | */!* 12 | ``` 13 | 14 | -------------------------------------------------------------------------------- /1-js/05-data-types/12-json/1-serialize-object/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Turn the object into JSON and back 6 | 7 | Turn the `user` into JSON and then read it back into another variable. 8 | 9 | ```js 10 | let user = { 11 | name: "John Smith", 12 | age: 35 13 | }; 14 | ``` 15 | -------------------------------------------------------------------------------- /1-js/05-data-types/index.md: -------------------------------------------------------------------------------- 1 | # Data types 2 | 3 | More data structures and more in-depth study of the types. 4 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/01-recursion/05-output-single-linked-list-reverse/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Output a single-linked list in the reverse order 6 | 7 | Output a single-linked list from the previous task in the reverse order. 8 | 9 | Make two solutions: using a loop and using a recursion. 10 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/03-closure/1-closure-latest-changes/solution.md: -------------------------------------------------------------------------------- 1 | The answer is: **Pete**. 2 | 3 | A function gets outer variables as they are now, it uses the most recent values. 4 | 5 | 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. 6 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/03-closure/10-make-army/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function makeArmy() { 2 | 3 | let shooters = []; 4 | 5 | for(let i = 0; i < 10; i++) { 6 | let shooter = function() { // shooter function 7 | alert( i ); // should show its number 8 | }; 9 | shooters.push(shooter); 10 | } 11 | 12 | return shooters; 13 | } 14 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/03-closure/2-closure-variable-access/solution.md: -------------------------------------------------------------------------------- 1 | The answer is: **Pete**. 2 | 3 | The `work()` function in the code below gets `name` from the place of its origin through the outer lexical environment reference: 4 | 5 | ![](lexenv-nested-work.svg) 6 | 7 | So, the result is `"Pete"` here. 8 | 9 | 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"`. 10 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/03-closure/3-counter-independent/solution.md: -------------------------------------------------------------------------------- 1 | The answer: **0,1.** 2 | 3 | Functions `counter` and `counter2` are created by different invocations of `makeCounter`. 4 | 5 | So they have independent outer Lexical Environments, each one has its own `count`. 6 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/03-closure/5-function-in-if/solution.md: -------------------------------------------------------------------------------- 1 | The result is **an error**. 2 | 3 | The function `sayHi` is declared inside the `if`, so it only lives inside it. There is no `sayHi` outside. -------------------------------------------------------------------------------- /1-js/06-advanced-functions/03-closure/5-function-in-if/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | # Function in if 5 | 6 | Look at the code. What will be the result of the call at the last line? 7 | 8 | ```js run 9 | let phrase = "Hello"; 10 | 11 | if (true) { 12 | let user = "John"; 13 | 14 | function sayHi() { 15 | alert(`${phrase}, ${user}`); 16 | } 17 | } 18 | 19 | *!* 20 | sayHi(); 21 | */!* 22 | ``` 23 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/03-closure/6-closure-sum/solution.md: -------------------------------------------------------------------------------- 1 | For the second parentheses to work, the first ones must return a function. 2 | 3 | Like this: 4 | 5 | ```js run 6 | function sum(a) { 7 | 8 | return function(b) { 9 | return a + b; // takes "a" from the outer lexical environment 10 | }; 11 | 12 | } 13 | 14 | alert( sum(1)(2) ); // 3 15 | alert( sum(5)(-1) ); // 4 16 | ``` 17 | 18 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/03-closure/6-closure-sum/task.md: -------------------------------------------------------------------------------- 1 | importance: 4 2 | 3 | --- 4 | 5 | # Sum with closures 6 | 7 | Write function `sum` that works like this: `sum(a)(b) = a+b`. 8 | 9 | Yes, exactly this way, using double parentheses (not a mistype). 10 | 11 | For instance: 12 | 13 | ```js 14 | sum(1)(2) = 3 15 | sum(5)(-1) = 4 16 | ``` 17 | 18 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/03-closure/7-let-scope/task.md: -------------------------------------------------------------------------------- 1 | importance: 4 2 | 3 | --- 4 | 5 | # Is variable visible? 6 | 7 | What will be the result of this code? 8 | 9 | ```js 10 | let x = 1; 11 | 12 | function func() { 13 | console.log(x); // ? 14 | 15 | let x = 2; 16 | } 17 | 18 | func(); 19 | ``` 20 | 21 | P.S. There's a pitfall in this task. The solution is not obvious. 22 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | 2 | function inArray(arr) { 3 | return x => arr.includes(x); 4 | } 5 | 6 | function inBetween(a, b) { 7 | return x => (x >= a && x <= b); 8 | } -------------------------------------------------------------------------------- /1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/source.js: -------------------------------------------------------------------------------- 1 | 2 | let arr = [1, 2, 3, 4, 5, 6, 7]; 3 | 4 | function inBetween(a, b) { 5 | // ...your code... 6 | } 7 | 8 | function inArray(arr) { 9 | // ...your code... 10 | } 11 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function byField(fieldName){ 2 | return (a, b) => a[fieldName] > b[fieldName] ? 1 : -1; 3 | } 4 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/source.js: -------------------------------------------------------------------------------- 1 | function byField(fieldName){ 2 | 3 | // Your code goes here. 4 | 5 | } 6 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/03-closure/9-sort-by-field/solution.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function makeCounter() { 2 | let count = 0; 3 | 4 | function counter() { 5 | return count++; 6 | } 7 | 8 | counter.set = value => count = value; 9 | 10 | counter.decrease = () => count--; 11 | 12 | return counter; 13 | } 14 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/_js.view/source.js: -------------------------------------------------------------------------------- 1 | function makeCounter() { 2 | let count = 0; 3 | 4 | // ... your code ... 5 | } 6 | 7 | let counter = makeCounter(); 8 | 9 | alert( counter() ); // 0 10 | alert( counter() ); // 1 11 | 12 | counter.set(10); // set the new count 13 | 14 | alert( counter() ); // 10 15 | 16 | counter.decrease(); // decrease the count by 1 17 | 18 | alert( counter() ); // 10 (instead of 11) 19 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/solution.md: -------------------------------------------------------------------------------- 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`. 3 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function sum(a) { 2 | 3 | let currentSum = a; 4 | 5 | function f(b) { 6 | currentSum += b; 7 | return f; 8 | } 9 | 10 | f.toString = function() { 11 | return currentSum; 12 | }; 13 | 14 | return f; 15 | } 16 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/source.js: -------------------------------------------------------------------------------- 1 | function sum(a){ 2 | // Your code goes here. 3 | 4 | } 5 | 6 | /* 7 | sum(1)(2) == 3; // 1 + 2 8 | sum(1)(2)(3) == 6; // 1 + 2 + 3 9 | sum(5)(-1)(2) == 6 10 | sum(6)(-1)(-2)(-3) == 0 11 | sum(0)(1)(2)(3)(4)(5) == 15 12 | */ 13 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/task.md: -------------------------------------------------------------------------------- 1 | importance: 2 2 | 3 | --- 4 | 5 | # Sum with an arbitrary amount of brackets 6 | 7 | Write function `sum` that would work like this: 8 | 9 | ```js 10 | sum(1)(2) == 3; // 1 + 2 11 | sum(1)(2)(3) == 6; // 1 + 2 + 3 12 | sum(5)(-1)(2) == 6 13 | sum(6)(-1)(-2)(-3) == 0 14 | sum(0)(1)(2)(3)(4)(5) == 15 15 | ``` 16 | 17 | P.S. Hint: you may need to setup custom object to primitive conversion for your function. -------------------------------------------------------------------------------- /1-js/06-advanced-functions/08-settimeout-setinterval/1-output-numbers-100ms/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Output every second 6 | 7 | Write a function `printNumbers(from, to)` that outputs a number every second, starting from `from` and ending with `to`. 8 | 9 | Make two variants of the solution. 10 | 11 | 1. Using `setInterval`. 12 | 2. Using nested `setTimeout`. 13 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/08-settimeout-setinterval/4-settimeout-result/solution.md: -------------------------------------------------------------------------------- 1 | 2 | Any `setTimeout` will run only after the current code has finished. 3 | 4 | The `i` will be the last one: `100000000`. 5 | 6 | ```js run 7 | let i = 0; 8 | 9 | setTimeout(() => alert(i), 100); // 100000000 10 | 11 | // assume that the time to execute this function is >100ms 12 | for(let j = 0; j < 100000000; j++) { 13 | i++; 14 | } 15 | ``` 16 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function spy(func) { 2 | 3 | function wrapper(...args) { 4 | // using ...args instead of arguments to store "real" array in wrapper.calls 5 | wrapper.calls.push(args); 6 | return func.apply(this, args); 7 | } 8 | 9 | wrapper.calls = []; 10 | 11 | return wrapper; 12 | } 13 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/source.js: -------------------------------------------------------------------------------- 1 | function spy(func) { 2 | // your code 3 | } 4 | 5 | 6 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md: -------------------------------------------------------------------------------- 1 | The wrapper returned by `spy(f)` should store all arguments and then use `f.apply` to forward the call. 2 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/09-call-apply-decorators/02-delay/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function delay(f, ms) { 2 | 3 | return function() { 4 | setTimeout(() => f.apply(this, arguments), ms); 5 | }; 6 | 7 | }; -------------------------------------------------------------------------------- /1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function debounce(func, ms) { 2 | let timeout; 3 | return function() { 4 | clearTimeout(timeout); 5 | timeout = setTimeout(() => func.apply(this, arguments), ms); 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md: -------------------------------------------------------------------------------- 1 | ```js demo 2 | function debounce(func, ms) { 3 | let timeout; 4 | return function() { 5 | clearTimeout(timeout); 6 | timeout = setTimeout(() => func.apply(this, arguments), ms); 7 | }; 8 | } 9 | 10 | ``` 11 | 12 | A call to `debounce` returns a wrapper. When called, it schedules the original function call after given `ms` and cancels the previous such timeout. 13 | 14 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/10-bind/2-write-to-object-after-bind/solution.md: -------------------------------------------------------------------------------- 1 | The answer: `null`. 2 | 3 | 4 | ```js run 5 | function f() { 6 | alert( this ); // null 7 | } 8 | 9 | let user = { 10 | g: f.bind(null) 11 | }; 12 | 13 | user.g(); 14 | ``` 15 | 16 | The context of a bound function is hard-fixed. There's just no way to further change it. 17 | 18 | So even while we run `user.g()`, the original function is called with `this=null`. 19 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/10-bind/2-write-to-object-after-bind/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Bound function as a method 6 | 7 | What will be the output? 8 | 9 | ```js 10 | function f() { 11 | alert( this ); // ? 12 | } 13 | 14 | let user = { 15 | g: f.bind(null) 16 | }; 17 | 18 | user.g(); 19 | ``` 20 | 21 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/10-bind/3-second-bind/solution.md: -------------------------------------------------------------------------------- 1 | The answer: **John**. 2 | 3 | ```js run no-beautify 4 | function f() { 5 | alert(this.name); 6 | } 7 | 8 | f = f.bind( {name: "John"} ).bind( {name: "Pete"} ); 9 | 10 | f(); // John 11 | ``` 12 | 13 | The exotic [bound function](https://tc39.github.io/ecma262/#sec-bound-function-exotic-objects) object returned by `f.bind(...)` remembers the context (and arguments if provided) only at creation time. 14 | 15 | A function cannot be re-bound. 16 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/10-bind/3-second-bind/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Second bind 6 | 7 | Can we change `this` by additional binding? 8 | 9 | What will be the output? 10 | 11 | ```js no-beautify 12 | function f() { 13 | alert(this.name); 14 | } 15 | 16 | f = f.bind( {name: "John"} ).bind( {name: "Ann" } ); 17 | 18 | f(); 19 | ``` 20 | 21 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/10-bind/4-function-property-after-bind/solution.md: -------------------------------------------------------------------------------- 1 | The answer: `undefined`. 2 | 3 | The result of `bind` is another object. It does not have the `test` property. 4 | 5 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/10-bind/4-function-property-after-bind/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Function property after bind 6 | 7 | There's a value in the property of a function. Will it change after `bind`? Why, or why not? 8 | 9 | ```js run 10 | function sayHi() { 11 | alert( this.name ); 12 | } 13 | sayHi.test = 5; 14 | 15 | *!* 16 | let bound = sayHi.bind({ 17 | name: "John" 18 | }); 19 | 20 | alert( bound.test ); // what will be the output? why? 21 | */!* 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /1-js/06-advanced-functions/index.md: -------------------------------------------------------------------------------- 1 | # Advanced working with functions 2 | -------------------------------------------------------------------------------- /1-js/07-object-properties/index.md: -------------------------------------------------------------------------------- 1 | # Object properties configuration 2 | 3 | In this section we return to objects and study their properties even more in-depth. 4 | -------------------------------------------------------------------------------- /1-js/08-prototypes/01-prototype-inheritance/1-property-after-delete/solution.md: -------------------------------------------------------------------------------- 1 | 2 | 1. `true`, taken from `rabbit`. 3 | 2. `null`, taken from `animal`. 4 | 3. `undefined`, there's no such property any more. 5 | -------------------------------------------------------------------------------- /1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/solution.md: -------------------------------------------------------------------------------- 1 | **The answer: `rabbit`.** 2 | 3 | That's because `this` is an object before the dot, so `rabbit.eat()` modifies `rabbit`. 4 | 5 | Property lookup and execution are two different things. 6 | 7 | The method `rabbit.eat` is first found in the prototype, then executed with `this=rabbit`. 8 | -------------------------------------------------------------------------------- /1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Where does it write? 6 | 7 | We have `rabbit` inheriting from `animal`. 8 | 9 | If we call `rabbit.eat()`, which object receives the `full` property: `animal` or `rabbit`? 10 | 11 | ```js 12 | let animal = { 13 | eat() { 14 | this.full = true; 15 | } 16 | }; 17 | 18 | let rabbit = { 19 | __proto__: animal 20 | }; 21 | 22 | rabbit.eat(); 23 | ``` 24 | -------------------------------------------------------------------------------- /1-js/08-prototypes/03-native-prototypes/1-defer-to-prototype/solution.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```js run 4 | Function.prototype.defer = function(ms) { 5 | setTimeout(this, ms); 6 | }; 7 | 8 | function f() { 9 | alert("Hello!"); 10 | } 11 | 12 | f.defer(1000); // shows "Hello!" after 1 sec 13 | ``` 14 | -------------------------------------------------------------------------------- /1-js/08-prototypes/03-native-prototypes/1-defer-to-prototype/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Add method "f.defer(ms)" to functions 6 | 7 | Add to the prototype of all functions the method `defer(ms)`, that runs the function after `ms` milliseconds. 8 | 9 | After you do it, such code should work: 10 | 11 | ```js 12 | function f() { 13 | alert("Hello!"); 14 | } 15 | 16 | f.defer(1000); // shows "Hello!" after 1 second 17 | ``` 18 | -------------------------------------------------------------------------------- /1-js/08-prototypes/03-native-prototypes/console_dir_array.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/08-prototypes/03-native-prototypes/console_dir_array.png -------------------------------------------------------------------------------- /1-js/08-prototypes/index.md: -------------------------------------------------------------------------------- 1 | # Prototypes, inheritance 2 | -------------------------------------------------------------------------------- /1-js/09-classes/01-class/1-rewrite-to-class/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/09-classes/01-class/1-rewrite-to-class/solution.md -------------------------------------------------------------------------------- /1-js/09-classes/01-class/1-rewrite-to-class/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Rewrite to class 6 | 7 | The `Clock` class (see the sandbox) is written in functional style. Rewrite it in the "class" syntax. 8 | 9 | P.S. The clock ticks in the console, open it to see. 10 | -------------------------------------------------------------------------------- /1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.md: -------------------------------------------------------------------------------- 1 | [js src="solution.view/extended-clock.js"] 2 | -------------------------------------------------------------------------------- /1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js: -------------------------------------------------------------------------------- 1 | class ExtendedClock extends Clock { 2 | constructor(options) { 3 | super(options); 4 | let { precision = 1000 } = options; 5 | this.precision = precision; 6 | } 7 | 8 | start() { 9 | this.render(); 10 | this.timer = setInterval(() => this.render(), this.precision); 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | -------------------------------------------------------------------------------- /1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 22 | -------------------------------------------------------------------------------- /1-js/09-classes/04-private-protected-properties-methods/coffee-inside.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/09-classes/04-private-protected-properties-methods/coffee-inside.jpg -------------------------------------------------------------------------------- /1-js/09-classes/04-private-protected-properties-methods/coffee.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/09-classes/04-private-protected-properties-methods/coffee.jpg -------------------------------------------------------------------------------- /1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md: -------------------------------------------------------------------------------- 1 | Yeah, looks strange indeed. 2 | 3 | But `instanceof` does not care about the function, but rather about its `prototype`, that it matches against the prototype chain. 4 | 5 | And here `a.__proto__ == B.prototype`, so `instanceof` returns `true`. 6 | 7 | So, by the logic of `instanceof`, the `prototype` actually defines the type, not the constructor function. 8 | -------------------------------------------------------------------------------- /1-js/09-classes/06-instanceof/1-strange-instanceof/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Strange instanceof 6 | 7 | In the code below, why does `instanceof` return `true`? We can easily see that `a` is not created by `B()`. 8 | 9 | ```js run 10 | function A() {} 11 | function B() {} 12 | 13 | A.prototype = B.prototype = {}; 14 | 15 | let a = new A(); 16 | 17 | *!* 18 | alert( a instanceof B ); // true 19 | */!* 20 | ``` 21 | -------------------------------------------------------------------------------- /1-js/09-classes/index.md: -------------------------------------------------------------------------------- 1 | # Classes 2 | -------------------------------------------------------------------------------- /1-js/10-error-handling/2-custom-errors/1-format-error/solution.md: -------------------------------------------------------------------------------- 1 | ```js run untrusted 2 | class FormatError extends SyntaxError { 3 | constructor(message) { 4 | super(message); 5 | this.name = this.constructor.name; 6 | } 7 | } 8 | 9 | let err = new FormatError("formatting error"); 10 | 11 | alert( err.message ); // formatting error 12 | alert( err.name ); // FormatError 13 | alert( err.stack ); // stack 14 | 15 | alert( err instanceof SyntaxError ); // true 16 | ``` 17 | -------------------------------------------------------------------------------- /1-js/10-error-handling/index.md: -------------------------------------------------------------------------------- 1 | # Error handling 2 | -------------------------------------------------------------------------------- /1-js/11-async/01-callbacks/one.js: -------------------------------------------------------------------------------- 1 | function one() { 2 | alert(1); 3 | } 4 | -------------------------------------------------------------------------------- /1-js/11-async/02-promise-basics/01-re-resolve/solution.md: -------------------------------------------------------------------------------- 1 | The output is: `1`. 2 | 3 | The second call to `resolve` is ignored, because only the first call of `reject/resolve` is taken into account. Further calls are ignored. 4 | -------------------------------------------------------------------------------- /1-js/11-async/02-promise-basics/01-re-resolve/task.md: -------------------------------------------------------------------------------- 1 | 2 | # Re-resolve a promise? 3 | 4 | 5 | What's the output of the code below? 6 | 7 | ```js 8 | let promise = new Promise(function(resolve, reject) { 9 | resolve(1); 10 | 11 | setTimeout(() => resolve(2), 1000); 12 | }); 13 | 14 | promise.then(alert); 15 | ``` 16 | -------------------------------------------------------------------------------- /1-js/11-async/02-promise-basics/02-delay-promise/solution.md: -------------------------------------------------------------------------------- 1 | ```js run 2 | function delay(ms) { 3 | return new Promise(resolve => setTimeout(resolve, ms)); 4 | } 5 | 6 | delay(3000).then(() => alert('runs after 3 seconds')); 7 | ``` 8 | 9 | Please note that in this task `resolve` is called without arguments. We don't return any value from `delay`, just ensure the delay. 10 | -------------------------------------------------------------------------------- /1-js/11-async/02-promise-basics/02-delay-promise/task.md: -------------------------------------------------------------------------------- 1 | 2 | # Delay with a promise 3 | 4 | The built-in function `setTimeout` uses callbacks. Create a promise-based alternative. 5 | 6 | The function `delay(ms)` should return a promise. That promise should resolve after `ms` milliseconds, so that we can add `.then` to it, like this: 7 | 8 | ```js 9 | function delay(ms) { 10 | // your code 11 | } 12 | 13 | delay(3000).then(() => alert('runs after 3 seconds')); 14 | ``` 15 | -------------------------------------------------------------------------------- /1-js/11-async/02-promise-basics/03-animate-circle-promise/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/11-async/02-promise-basics/03-animate-circle-promise/solution.md -------------------------------------------------------------------------------- /1-js/11-async/02-promise-basics/03-animate-circle-promise/task.md: -------------------------------------------------------------------------------- 1 | 2 | # Animated circle with promise 3 | 4 | Rewrite the `showCircle` function in the solution of the task so that it returns a promise instead of accepting a callback. 5 | 6 | The new usage: 7 | 8 | ```js 9 | showCircle(150, 150, 100).then(div => { 10 | div.classList.add('message-ball'); 11 | div.append("Hello, world!"); 12 | }); 13 | ``` 14 | 15 | Take the solution of the task as the base. 16 | -------------------------------------------------------------------------------- /1-js/11-async/02-promise-basics/head.html: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /1-js/11-async/03-promise-chaining/01-then-vs-catch/task.md: -------------------------------------------------------------------------------- 1 | # Promise: then versus catch 2 | 3 | Are these code fragments equal? In other words, do they behave the same way in any circumstances, for any handler functions? 4 | 5 | ```js 6 | promise.then(f1).catch(f2); 7 | ``` 8 | 9 | Versus: 10 | 11 | ```js 12 | promise.then(f1, f2); 13 | ``` 14 | -------------------------------------------------------------------------------- /1-js/11-async/03-promise-chaining/getMessage.js: -------------------------------------------------------------------------------- 1 | function getMessage() { 2 | return "Hello, world!"; 3 | } 4 | -------------------------------------------------------------------------------- /1-js/11-async/03-promise-chaining/one.js: -------------------------------------------------------------------------------- 1 | function one() { 2 | alert(1); 3 | } 4 | -------------------------------------------------------------------------------- /1-js/11-async/03-promise-chaining/three.js: -------------------------------------------------------------------------------- 1 | function three() { 2 | alert(3); 3 | } 4 | -------------------------------------------------------------------------------- /1-js/11-async/03-promise-chaining/two.js: -------------------------------------------------------------------------------- 1 | function two() { 2 | alert(2); 3 | } 4 | -------------------------------------------------------------------------------- /1-js/11-async/03-promise-chaining/user.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iliakan", 3 | "isAdmin": true 4 | } 5 | -------------------------------------------------------------------------------- /1-js/11-async/04-promise-error-handling/01-error-async/solution.md: -------------------------------------------------------------------------------- 1 | The answer is: **no, it won't**: 2 | 3 | ```js run 4 | new Promise(function(resolve, reject) { 5 | setTimeout(() => { 6 | throw new Error("Whoops!"); 7 | }, 1000); 8 | }).catch(alert); 9 | ``` 10 | 11 | As said in the chapter, there's an "implicit `try..catch`" around the function code. So all synchronous errors are handled. 12 | 13 | But here the error is generated not while the executor is running, but later. So the promise can't handle it. 14 | -------------------------------------------------------------------------------- /1-js/11-async/04-promise-error-handling/01-error-async/task.md: -------------------------------------------------------------------------------- 1 | # Error in setTimeout 2 | 3 | What do you think? Will the `.catch` trigger? Explain your answer. 4 | 5 | ```js 6 | new Promise(function(resolve, reject) { 7 | setTimeout(() => { 8 | throw new Error("Whoops!"); 9 | }, 1000); 10 | }).catch(alert); 11 | ``` 12 | -------------------------------------------------------------------------------- /1-js/11-async/04-promise-error-handling/getMessage.js: -------------------------------------------------------------------------------- 1 | function getMessage() { 2 | return "Hello, world!"; 3 | } 4 | -------------------------------------------------------------------------------- /1-js/11-async/04-promise-error-handling/one.js: -------------------------------------------------------------------------------- 1 | function one() { 2 | alert(1); 3 | } 4 | -------------------------------------------------------------------------------- /1-js/11-async/04-promise-error-handling/three.js: -------------------------------------------------------------------------------- 1 | function three() { 2 | alert(3); 3 | } 4 | -------------------------------------------------------------------------------- /1-js/11-async/04-promise-error-handling/two.js: -------------------------------------------------------------------------------- 1 | function two() { 2 | alert(2); 3 | } 4 | -------------------------------------------------------------------------------- /1-js/11-async/04-promise-error-handling/user.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iliakan", 3 | "isAdmin": true 4 | } 5 | -------------------------------------------------------------------------------- /1-js/11-async/05-promise-api/head.html: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /1-js/11-async/05-promise-api/iliakan.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iliakan", 3 | "isAdmin": true 4 | } 5 | -------------------------------------------------------------------------------- /1-js/11-async/05-promise-api/one.js: -------------------------------------------------------------------------------- 1 | function one() { 2 | alert(1); 3 | } 4 | -------------------------------------------------------------------------------- /1-js/11-async/05-promise-api/two.js: -------------------------------------------------------------------------------- 1 | function two() { 2 | alert(2); 3 | } 4 | -------------------------------------------------------------------------------- /1-js/11-async/08-async-await/03-async-from-regular/solution.md: -------------------------------------------------------------------------------- 1 | 2 | That's the case when knowing how it works inside is helpful. 3 | 4 | Just treat `async` call as promise and attach `.then` to it: 5 | ```js run 6 | async function wait() { 7 | await new Promise(resolve => setTimeout(resolve, 1000)); 8 | 9 | return 10; 10 | } 11 | 12 | function f() { 13 | // shows 10 after 1 second 14 | *!* 15 | wait().then(result => alert(result)); 16 | */!* 17 | } 18 | 19 | f(); 20 | ``` 21 | -------------------------------------------------------------------------------- /1-js/11-async/08-async-await/head.html: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /1-js/11-async/index.md: -------------------------------------------------------------------------------- 1 | 2 | # Promises, async/await 3 | -------------------------------------------------------------------------------- /1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/_js.view/solution.js: -------------------------------------------------------------------------------- 1 | function* pseudoRandom(seed) { 2 | let value = seed; 3 | 4 | while(true) { 5 | value = value * 16807 % 2147483647 6 | yield value; 7 | } 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /1-js/12-generators-iterators/index.md: -------------------------------------------------------------------------------- 1 | 2 | # Generators, advanced iteration 3 | -------------------------------------------------------------------------------- /1-js/13-modules/01-modules-intro/say.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /1-js/13-modules/01-modules-intro/say.view/say.js: -------------------------------------------------------------------------------- 1 | export function sayHi(user) { 2 | return `Hello, ${user}!`; 3 | } 4 | -------------------------------------------------------------------------------- /1-js/13-modules/01-modules-intro/scopes-working.view/hello.js: -------------------------------------------------------------------------------- 1 | import {user} from './user.js'; 2 | 3 | document.body.innerHTML = user; // John 4 | -------------------------------------------------------------------------------- /1-js/13-modules/01-modules-intro/scopes-working.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /1-js/13-modules/01-modules-intro/scopes-working.view/user.js: -------------------------------------------------------------------------------- 1 | export let user = "John"; 2 | -------------------------------------------------------------------------------- /1-js/13-modules/01-modules-intro/scopes.view/hello.js: -------------------------------------------------------------------------------- 1 | alert(user); // no such variable (each module has independent variables) 2 | -------------------------------------------------------------------------------- /1-js/13-modules/01-modules-intro/scopes.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /1-js/13-modules/01-modules-intro/scopes.view/user.js: -------------------------------------------------------------------------------- 1 | let user = "John"; 2 | -------------------------------------------------------------------------------- /1-js/13-modules/03-modules-dynamic-imports/say.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | -------------------------------------------------------------------------------- /1-js/13-modules/03-modules-dynamic-imports/say.view/say.js: -------------------------------------------------------------------------------- 1 | export function hi() { 2 | alert(`Hello`); 3 | } 4 | 5 | export function bye() { 6 | alert(`Bye`); 7 | } 8 | 9 | export default function() { 10 | alert("Module loaded (export default)!"); 11 | } 12 | -------------------------------------------------------------------------------- /1-js/13-modules/index.md: -------------------------------------------------------------------------------- 1 | 2 | # Modules 3 | -------------------------------------------------------------------------------- /1-js/99-js-misc/01-proxy/02-array-negative/solution.md: -------------------------------------------------------------------------------- 1 | 2 | ```js run 3 | let array = [1, 2, 3]; 4 | 5 | array = new Proxy(array, { 6 | get(target, prop, receiver) { 7 | if (prop < 0) { 8 | // even if we access it like arr[1] 9 | // prop is a string, so need to convert it to number 10 | prop = +prop + target.length; 11 | } 12 | return Reflect.get(target, prop, receiver); 13 | } 14 | }); 15 | 16 | 17 | alert(array[-1]); // 3 18 | alert(array[-2]); // 2 19 | ``` 20 | -------------------------------------------------------------------------------- /1-js/99-js-misc/02-eval/1-eval-calculator/solution.md: -------------------------------------------------------------------------------- 1 | Let's use `eval` to calculate the maths expression: 2 | 3 | ```js demo run 4 | let expr = prompt("Type an arithmetic expression?", '2*3+2'); 5 | 6 | alert( eval(expr) ); 7 | ``` 8 | 9 | The user can input any text or code though. 10 | 11 | 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. 12 | -------------------------------------------------------------------------------- /1-js/99-js-misc/02-eval/1-eval-calculator/task.md: -------------------------------------------------------------------------------- 1 | importance: 4 2 | 3 | --- 4 | 5 | # Eval-calculator 6 | 7 | Create a calculator that prompts for an arithmetic expression and returns its result. 8 | 9 | There's no need to check the expression for correctness in this task. Just evaluate and return the result. 10 | 11 | [demo] 12 | -------------------------------------------------------------------------------- /1-js/99-js-misc/04-reference-type/2-check-syntax/task.md: -------------------------------------------------------------------------------- 1 | importance: 2 2 | 3 | --- 4 | 5 | # Syntax check 6 | 7 | What is the result of this code? 8 | 9 | 10 | ```js no-beautify 11 | let user = { 12 | name: "John", 13 | go: function() { alert(this.name) } 14 | } 15 | 16 | (user.go)() 17 | ``` 18 | 19 | P.S. There's a pitfall :) 20 | -------------------------------------------------------------------------------- /1-js/99-js-misc/07-weakref-finalizationregistry/google-chrome-developer-tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/99-js-misc/07-weakref-finalizationregistry/google-chrome-developer-tools.png -------------------------------------------------------------------------------- /1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-01.png -------------------------------------------------------------------------------- /1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-02.png -------------------------------------------------------------------------------- /1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-03.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-03.gif -------------------------------------------------------------------------------- /1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-04.jpg -------------------------------------------------------------------------------- /1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-05.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-05.gif -------------------------------------------------------------------------------- /1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-06.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-06.jpg -------------------------------------------------------------------------------- /1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-07.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-07.gif -------------------------------------------------------------------------------- /1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-08.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-08.jpg -------------------------------------------------------------------------------- /1-js/99-js-misc/index.md: -------------------------------------------------------------------------------- 1 | 2 | # Miscellaneous 3 | -------------------------------------------------------------------------------- /1-js/index.md: -------------------------------------------------------------------------------- 1 | # The JavaScript language 2 | 3 | Here we learn JavaScript, starting from scratch and go on to advanced concepts like OOP. 4 | 5 | We concentrate on the language itself here, with the minimum of environment-specific notes. 6 | 7 | -------------------------------------------------------------------------------- /2-ui/1-document/02-dom-nodes/elk.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The truth about elk. 5 |
    6 |
  1. An elk is a smart
  2. 7 | 8 |
  3. ...and cunning animal!
  4. 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /2-ui/1-document/02-dom-nodes/head.html: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /2-ui/1-document/03-dom-navigation/1-dom-children/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # DOM children 6 | 7 | Look at this page: 8 | 9 | ```html 10 | 11 | 12 |
Users:
13 |
    14 |
  • John
  • 15 |
  • Pete
  • 16 |
17 | 18 | 19 | ``` 20 | 21 | For each of the following, give at least one way of how to access them: 22 | - The `
` DOM node? 23 | - The `
    ` DOM node? 24 | - The second `
  • ` (with Pete)? 25 | -------------------------------------------------------------------------------- /2-ui/1-document/03-dom-navigation/3-navigation-links-which-null/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # The sibling question 6 | 7 | If `elem` -- is an arbitrary DOM element node... 8 | 9 | - Is it true that `elem.lastChild.nextSibling` is always `null`? 10 | - Is it true that `elem.children[0].previousSibling` is always `null` ? 11 | -------------------------------------------------------------------------------- /2-ui/1-document/03-dom-navigation/4-select-diagonal-cells/solution.md: -------------------------------------------------------------------------------- 1 | We'll be using `rows` and `cells` properties to access diagonal table cells. 2 | -------------------------------------------------------------------------------- /2-ui/1-document/03-dom-navigation/4-select-diagonal-cells/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Select all diagonal cells 6 | 7 | Write the code to paint all diagonal table cells in red. 8 | 9 | You'll need to get all diagonal `` from the `` and paint them using the code: 10 | 11 | ```js 12 | // td should be the reference to the table cell 13 | td.style.backgroundColor = 'red'; 14 | ``` 15 | 16 | The result should be: 17 | 18 | [iframe src="solution" height=180] 19 | -------------------------------------------------------------------------------- /2-ui/1-document/03-dom-navigation/head.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /2-ui/1-document/05-basic-dom-node-properties/2-lastchild-nodetype-inline/solution.md: -------------------------------------------------------------------------------- 1 | There's a catch here. 2 | 3 | At the time of ` 14 | 15 | 16 | 17 | ``` 18 | -------------------------------------------------------------------------------- /2-ui/1-document/05-basic-dom-node-properties/2-lastchild-nodetype-inline/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # What's in the nodeType? 6 | 7 | What does the script show? 8 | 9 | ```html 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | ``` 20 | -------------------------------------------------------------------------------- /2-ui/1-document/05-basic-dom-node-properties/2-tree-info/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Count descendants 6 | 7 | There's a tree structured as nested `ul/li`. 8 | 9 | Write the code that for each `
  • ` shows: 10 | 11 | 1. What's the text inside it (without the subtree) 12 | 2. The number of nested `
  • ` -- all descendants, including the deeply nested ones. 13 | 14 | [demo src="solution"] 15 | -------------------------------------------------------------------------------- /2-ui/1-document/05-basic-dom-node-properties/3-tag-in-comment/task.md: -------------------------------------------------------------------------------- 1 | importance: 3 2 | 3 | --- 4 | 5 | # Tag in comment 6 | 7 | What does this code show? 8 | 9 | ```html 10 | 17 | ``` 18 | -------------------------------------------------------------------------------- /2-ui/1-document/05-basic-dom-node-properties/4-where-document-in-hierarchy/task.md: -------------------------------------------------------------------------------- 1 | importance: 4 2 | 3 | --- 4 | 5 | # Where's the "document" in the hierarchy? 6 | 7 | Which class does the `document` belong to? 8 | 9 | What's its place in the DOM hierarchy? 10 | 11 | Does it inherit from `Node` or `Element`, or maybe `HTMLElement`? 12 | -------------------------------------------------------------------------------- /2-ui/1-document/06-dom-attributes-and-properties/1-get-user-attribute/solution.md: -------------------------------------------------------------------------------- 1 | 2 | ```html run height=100 3 | 4 | 5 | 6 | 7 |
    Choose the genre
    8 | 9 | 18 | 19 | 20 | ``` 21 | -------------------------------------------------------------------------------- /2-ui/1-document/06-dom-attributes-and-properties/1-get-user-attribute/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Get the attribute 6 | 7 | Write the code to select the element with `data-widget-name` attribute from the document and to read its value. 8 | 9 | ```html run 10 | 11 | 12 | 13 | 14 |
    Choose the genre
    15 | 16 | 19 | 20 | 21 | ``` 22 | -------------------------------------------------------------------------------- /2-ui/1-document/07-modifying-document/1-createtextnode-vs-innerhtml/solution.md: -------------------------------------------------------------------------------- 1 | Answer: **1 and 3**. 2 | 3 | Both commands result in adding the `text` "as text" into the `elem`. 4 | 5 | Here's an example: 6 | 7 | ```html run height=80 8 |
    9 |
    10 |
    11 | 18 | ``` 19 | -------------------------------------------------------------------------------- /2-ui/1-document/07-modifying-document/1-createtextnode-vs-innerhtml/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # createTextNode vs innerHTML vs textContent 6 | 7 | We have an empty DOM element `elem` and a string `text`. 8 | 9 | Which of these 3 commands will do exactly the same? 10 | 11 | 1. `elem.append(document.createTextNode(text))` 12 | 2. `elem.innerHTML = text` 13 | 3. `elem.textContent = text` 14 | -------------------------------------------------------------------------------- /2-ui/1-document/07-modifying-document/10-clock-setinterval/source.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /2-ui/1-document/07-modifying-document/10-clock-setinterval/task.md: -------------------------------------------------------------------------------- 1 | importance: 4 2 | 3 | --- 4 | 5 | # Colored clock with setInterval 6 | 7 | Create a colored clock like here: 8 | 9 | [iframe src="solution" height=60] 10 | 11 | Use HTML/CSS for the styling, JavaScript only updates time in elements. 12 | -------------------------------------------------------------------------------- /2-ui/1-document/07-modifying-document/11-append-to-list/solution.md: -------------------------------------------------------------------------------- 1 | 2 | When we need to insert a piece of HTML somewhere, `insertAdjacentHTML` is the best fit. 3 | 4 | The solution: 5 | 6 | ```js 7 | one.insertAdjacentHTML('afterend', '
  • 2
  • 3
  • '); 8 | ``` 9 | -------------------------------------------------------------------------------- /2-ui/1-document/07-modifying-document/11-append-to-list/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Insert the HTML in the list 6 | 7 | Write the code to insert `
  • 2
  • 3
  • ` between two `
  • ` here: 8 | 9 | ```html 10 |
      11 |
    • 1
    • 12 |
    • 4
    • 13 |
    14 | ``` 15 | -------------------------------------------------------------------------------- /2-ui/1-document/07-modifying-document/4-clear-elem/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Clear the element 6 | 7 | Create a function `clear(elem)` that removes everything from the element. 8 | 9 | ```html run height=60 10 |
      11 |
    1. Hello
    2. 12 |
    3. World
    4. 13 |
    14 | 15 | 20 | ``` 21 | -------------------------------------------------------------------------------- /2-ui/1-document/07-modifying-document/6-create-list/solution.md: -------------------------------------------------------------------------------- 1 | Please note the usage of `textContent` to assign the `
  • ` content. 2 | -------------------------------------------------------------------------------- /2-ui/1-document/07-modifying-document/7-create-object-tree/solution.md: -------------------------------------------------------------------------------- 1 | The easiest way to walk the object is to use recursion. 2 | 3 | 1. [The solution with innerHTML](sandbox:innerhtml). 4 | 2. [The solution with DOM](sandbox:build-tree-dom). 5 | -------------------------------------------------------------------------------- /2-ui/1-document/07-modifying-document/8-tree-count/solution.md: -------------------------------------------------------------------------------- 1 | To append text to each `
  • ` we can alter the text node `data`. 2 | -------------------------------------------------------------------------------- /2-ui/1-document/07-modifying-document/8-tree-count/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Show descendants in a tree 6 | 7 | There's a tree organized as nested `ul/li`. 8 | 9 | Write the code that adds to each `
  • ` the number of its descendants. Skip leaves (nodes without children). 10 | 11 | The result: 12 | 13 | [iframe border=1 src="solution"] 14 | -------------------------------------------------------------------------------- /2-ui/1-document/08-styles-and-classes/2-create-notification/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/2-ui/1-document/08-styles-and-classes/2-create-notification/solution.md -------------------------------------------------------------------------------- /2-ui/1-document/08-styles-and-classes/2-create-notification/solution.view/index.css: -------------------------------------------------------------------------------- 1 | .notification { 2 | position: fixed; 3 | z-index: 1000; 4 | padding: 5px; 5 | border: 1px solid black; 6 | font-size: 20px; 7 | background: white; 8 | text-align: center; 9 | } 10 | 11 | .welcome { 12 | background: #b80000; 13 | color: yellow; 14 | } 15 | -------------------------------------------------------------------------------- /2-ui/1-document/08-styles-and-classes/2-create-notification/source.view/index.css: -------------------------------------------------------------------------------- 1 | .notification { 2 | position: fixed; 3 | z-index: 1000; 4 | padding: 5px; 5 | border: 1px solid black; 6 | font-size: 20px; 7 | background: white; 8 | text-align: center; 9 | } 10 | 11 | .welcome { 12 | background: #b80000; 13 | color: yellow; 14 | } 15 | -------------------------------------------------------------------------------- /2-ui/1-document/09-size-and-scroll/1-get-scroll-height-bottom/solution.md: -------------------------------------------------------------------------------- 1 | The solution is: 2 | 3 | ```js 4 | let scrollBottom = elem.scrollHeight - elem.scrollTop - elem.clientHeight; 5 | ``` 6 | 7 | In other words: (full height) minus (scrolled out top part) minus (visible part) -- that's exactly the scrolled out bottom part. 8 | -------------------------------------------------------------------------------- /2-ui/1-document/09-size-and-scroll/1-get-scroll-height-bottom/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # What's the scroll from the bottom? 6 | 7 | The `elem.scrollTop` property is the size of the scrolled out part from the top. How to get the size of the bottom scroll (let's call it `scrollBottom`)? 8 | 9 | Write the code that works for an arbitrary `elem`. 10 | 11 | P.S. Please check your code: if there's no scroll or the element is fully scrolled down, then it should return `0`. 12 | -------------------------------------------------------------------------------- /2-ui/1-document/09-size-and-scroll/2-scrollbar-width/task.md: -------------------------------------------------------------------------------- 1 | importance: 3 2 | 3 | --- 4 | 5 | # What is the scrollbar width? 6 | 7 | Write the code that returns the width of a standard scrollbar. 8 | 9 | For Windows it usually varies between `12px` and `20px`. If the browser doesn't reserve any space for it (the scrollbar is half-translucent over the text, also happens), then it may be `0px`. 10 | 11 | P.S. The code should work for any HTML document, do not depend on its content. 12 | -------------------------------------------------------------------------------- /2-ui/1-document/09-size-and-scroll/6-width-vs-clientwidth/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # The difference: CSS width versus clientWidth 6 | 7 | What's the difference between `getComputedStyle(elem).width` and `elem.clientWidth`? 8 | 9 | Give at least 3 differences. The more the better. 10 | -------------------------------------------------------------------------------- /2-ui/1-document/11-coordinates/2-position-at/solution.md: -------------------------------------------------------------------------------- 1 | In this task we only need to accurately calculate the coordinates. See the code for details. 2 | 3 | Please note: the elements must be in the document to read `offsetHeight` and other properties. 4 | A hidden (`display:none`) or out of the document element has no size. 5 | -------------------------------------------------------------------------------- /2-ui/1-document/11-coordinates/3-position-at-absolute/solution.md: -------------------------------------------------------------------------------- 1 | The solution is actually pretty simple: 2 | 3 | - Use `position:absolute` in CSS instead of `position:fixed` for `.note`. 4 | - Use the function [getCoords()](info:coordinates#getCoords) from the chapter to get document-relative coordinates. 5 | -------------------------------------------------------------------------------- /2-ui/1-document/11-coordinates/3-position-at-absolute/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Show a note near the element (absolute) 6 | 7 | Modify the solution of the [previous task](info:task/position-at) so that the note uses `position:absolute` instead of `position:fixed`. 8 | 9 | That will prevent its "runaway" from the element when the page scrolls. 10 | 11 | Take the solution of that task as a starting point. To test the scroll, add the style ``. 12 | -------------------------------------------------------------------------------- /2-ui/1-document/11-coordinates/4-position-inside-absolute/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/2-ui/1-document/11-coordinates/4-position-inside-absolute/solution.md -------------------------------------------------------------------------------- /2-ui/1-document/index.md: -------------------------------------------------------------------------------- 1 | # Document 2 | 3 | Here we'll learn to manipulate a web-page using JavaScript. 4 | -------------------------------------------------------------------------------- /2-ui/2-events/01-introduction-browser-events/01-hide-other/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/2-ui/2-events/01-introduction-browser-events/01-hide-other/solution.md -------------------------------------------------------------------------------- /2-ui/2-events/01-introduction-browser-events/01-hide-other/source.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
    Text
    13 | 14 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /2-ui/2-events/01-introduction-browser-events/01-hide-other/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Hide on click 6 | 7 | Add JavaScript to the `button` to make `
    ` disappear when we click it. 8 | 9 | The demo: 10 | 11 | [iframe border=1 src="solution" height=80] 12 | -------------------------------------------------------------------------------- /2-ui/2-events/01-introduction-browser-events/02-hide-self-onclick/solution.md: -------------------------------------------------------------------------------- 1 | Can use `this` in the handler to reference "the element itself" here: 2 | 3 | ```html run height=50 4 | 5 | ``` 6 | -------------------------------------------------------------------------------- /2-ui/2-events/01-introduction-browser-events/02-hide-self-onclick/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Hide self 6 | 7 | Create a button that hides itself on click. 8 | 9 | ```online 10 | Like this: 11 | 12 | ``` 13 | -------------------------------------------------------------------------------- /2-ui/2-events/01-introduction-browser-events/03-which-handlers-run/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Which handlers run? 6 | 7 | There's a button in the variable. There are no handlers on it. 8 | 9 | Which handlers run on click after the following code? Which alerts show up? 10 | 11 | ```js no-beautify 12 | button.addEventListener("click", () => alert("1")); 13 | 14 | button.removeEventListener("click", () => alert("1")); 15 | 16 | button.onclick = () => alert(2); 17 | ``` 18 | -------------------------------------------------------------------------------- /2-ui/2-events/01-introduction-browser-events/05-sliding-menu/source.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ▶ ▼ Sweeties (click me)! 9 |
      10 |
    • Cake
    • 11 |
    • Donut
    • 12 |
    • Honey
    • 13 |
    14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /2-ui/2-events/01-introduction-browser-events/05-sliding-menu/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Create a sliding menu 6 | 7 | Create a menu that opens/collapses on click: 8 | 9 | [iframe border=1 height=100 src="solution"] 10 | 11 | P.S. HTML/CSS of the source document is to be modified. 12 | -------------------------------------------------------------------------------- /2-ui/2-events/01-introduction-browser-events/06-hide-message/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Add a closing button 6 | 7 | There's a list of messages. 8 | 9 | Use JavaScript to add a closing button to the right-upper corner of each message. 10 | 11 | The result should look like this: 12 | 13 | [iframe src="solution" height=450] 14 | -------------------------------------------------------------------------------- /2-ui/2-events/01-introduction-browser-events/07-carousel/task.md: -------------------------------------------------------------------------------- 1 | importance: 4 2 | 3 | --- 4 | 5 | # Carousel 6 | 7 | Create a "carousel" -- a ribbon of images that can be scrolled by clicking on arrows. 8 | 9 | [iframe height=200 src="solution"] 10 | 11 | Later we can add more features to it: infinite scrolling, dynamic loading etc. 12 | 13 | P.S. For this task HTML/CSS structure is actually 90% of the solution. 14 | -------------------------------------------------------------------------------- /2-ui/2-events/02-bubbling-and-capturing/both.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
    FORM 12 |
    DIV 13 |

    P

    14 |
    15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /2-ui/2-events/02-bubbling-and-capturing/both.view/script.js: -------------------------------------------------------------------------------- 1 | let elems = document.querySelectorAll('form,div,p'); 2 | 3 | for (let i = 0; i < elems.length; i++) { 4 | elems[i].addEventListener("click", highlightThis, true); 5 | elems[i].addEventListener("click", highlightThis, false); 6 | } 7 | 8 | function highlightThis() { 9 | this.style.backgroundColor = 'yellow'; 10 | alert(this.tagName); 11 | this.style.backgroundColor = ''; 12 | } -------------------------------------------------------------------------------- /2-ui/2-events/02-bubbling-and-capturing/bubble-target.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | A click shows both event.target and this to compare: 11 | 12 |
    FORM 13 |
    DIV 14 |

    P

    15 |
    16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /2-ui/2-events/02-bubbling-and-capturing/bubble-target.view/script.js: -------------------------------------------------------------------------------- 1 | 2 | form.onclick = function(event) { 3 | event.target.style.backgroundColor = 'yellow'; 4 | 5 | // chrome needs some time to paint yellow 6 | setTimeout(() => { 7 | alert("target = " + event.target.tagName + ", this=" + this.tagName); 8 | event.target.style.backgroundColor = '' 9 | }, 0); 10 | }; 11 | -------------------------------------------------------------------------------- /2-ui/2-events/02-bubbling-and-capturing/capture.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
    FORM 8 |
    DIV 9 |

    P

    10 |
    11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /2-ui/2-events/02-bubbling-and-capturing/capture.view/script.js: -------------------------------------------------------------------------------- 1 | let elems = document.querySelectorAll('form,div,p'); 2 | 3 | for (let i = 0; i < elems.length; i++) { 4 | elems[i].addEventListener("click", highlightThis, true); 5 | } 6 | 7 | function highlightThis() { 8 | this.style.backgroundColor = 'yellow'; 9 | alert(this.tagName); 10 | this.style.backgroundColor = ''; 11 | } -------------------------------------------------------------------------------- /2-ui/2-events/03-event-delegation/1-hide-message-delegate/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/2-ui/2-events/03-event-delegation/1-hide-message-delegate/solution.md -------------------------------------------------------------------------------- /2-ui/2-events/03-event-delegation/1-hide-message-delegate/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Hide messages with delegation 6 | 7 | There's a list of messages with removal buttons `[x]`. Make the buttons work. 8 | 9 | Like this: 10 | 11 | [iframe src="solution" height=420] 12 | 13 | P.S. Should be only one event listener on the container, use event delegation. 14 | -------------------------------------------------------------------------------- /2-ui/2-events/03-event-delegation/2-sliding-tree/solution.md: -------------------------------------------------------------------------------- 1 | The solution has two parts. 2 | 3 | 1. Wrap every tree node title into ``. Then we can CSS-style them on `:hover` and handle clicks exactly on text, because `` width is exactly the text width (unlike without it). 4 | 2. Set a handler to the `tree` root node and handle clicks on that `` titles. 5 | -------------------------------------------------------------------------------- /2-ui/2-events/03-event-delegation/2-sliding-tree/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Tree menu 6 | 7 | Create a tree that shows/hides node children on click: 8 | 9 | [iframe border=1 src="solution"] 10 | 11 | Requirements: 12 | 13 | - Only one event handler (use delegation) 14 | - A click outside the node title (on an empty space) should not do anything. 15 | -------------------------------------------------------------------------------- /2-ui/2-events/03-event-delegation/3-sortable-table/solution.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /2-ui/2-events/03-event-delegation/4-behavior-tooltip/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/2-ui/2-events/03-event-delegation/4-behavior-tooltip/solution.md -------------------------------------------------------------------------------- /2-ui/2-events/04-default-browser-action/3-image-gallery/solution.md: -------------------------------------------------------------------------------- 1 | The solution is to assign the handler to the container and track clicks. If a click is on the `` link, then change `src` of `#largeImg` to the `href` of the thumbnail. 2 | -------------------------------------------------------------------------------- /2-ui/2-events/04-default-browser-action/3-image-gallery/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Image gallery 6 | 7 | Create an image gallery where the main image changes by the click on a thumbnail. 8 | 9 | Like this: 10 | 11 | [iframe src="solution" height=600] 12 | 13 | P.S. Use event delegation. 14 | -------------------------------------------------------------------------------- /2-ui/2-events/04-default-browser-action/menu.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /2-ui/2-events/04-default-browser-action/menu.view/menu.js: -------------------------------------------------------------------------------- 1 | menu.onclick = function(event) { 2 | if (event.target.nodeName != 'A') return; 3 | 4 | let href = event.target.getAttribute('href'); 5 | alert(href); 6 | 7 | return false; // prevent url change 8 | }; 9 | -------------------------------------------------------------------------------- /2-ui/2-events/index.md: -------------------------------------------------------------------------------- 1 | # Introduction to Events 2 | 3 | An introduction to browser events, event properties and handling patterns. 4 | -------------------------------------------------------------------------------- /2-ui/3-event-details/1-mouse-events-basics/01-selectable-list/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/2-ui/3-event-details/1-mouse-events-basics/01-selectable-list/solution.md -------------------------------------------------------------------------------- /2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/1-behavior-nested-tooltip/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/1-behavior-nested-tooltip/solution.md -------------------------------------------------------------------------------- /2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseleave-table.view/script.js: -------------------------------------------------------------------------------- 1 | table.onmouseenter = table.onmouseleave = log; 2 | 3 | function log(event) { 4 | text.value += event.type + ' [target: ' + event.target.tagName + ']\n'; 5 | text.scrollTop = text.scrollHeight; 6 | } -------------------------------------------------------------------------------- /2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseleave.view/script.js: -------------------------------------------------------------------------------- 1 | function mouselog(event) { 2 | let d = new Date(); 3 | text.value += `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()} | ${event.type} [target: ${event.target.id}]\n`.replace(/(:|^)(\d\D)/, '$10$2'); 4 | text.scrollTop = text.scrollHeight; 5 | } 6 | -------------------------------------------------------------------------------- /2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseleave.view/style.css: -------------------------------------------------------------------------------- 1 | #parent { 2 | background: #99C0C3; 3 | width: 160px; 4 | height: 120px; 5 | position: relative; 6 | } 7 | 8 | #child { 9 | background: #FFDE99; 10 | width: 50%; 11 | height: 50%; 12 | position: absolute; 13 | left: 50%; 14 | top: 50%; 15 | transform: translate(-50%, -50%); 16 | } 17 | 18 | textarea { 19 | height: 140px; 20 | width: 300px; 21 | display: block; 22 | } 23 | -------------------------------------------------------------------------------- /2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseoverout-child.view/script.js: -------------------------------------------------------------------------------- 1 | function mouselog(event) { 2 | let d = new Date(); 3 | text.value += `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()} | ${event.type} [target: ${event.target.id}]\n`.replace(/(:|^)(\d\D)/, '$10$2'); 4 | text.scrollTop = text.scrollHeight; 5 | } 6 | -------------------------------------------------------------------------------- /2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseoverout-child.view/style.css: -------------------------------------------------------------------------------- 1 | #parent { 2 | background: #99C0C3; 3 | width: 160px; 4 | height: 120px; 5 | position: relative; 6 | } 7 | 8 | #child { 9 | background: #FFDE99; 10 | width: 50%; 11 | height: 50%; 12 | position: absolute; 13 | left: 50%; 14 | top: 50%; 15 | transform: translate(-50%, -50%); 16 | } 17 | 18 | textarea { 19 | height: 140px; 20 | width: 300px; 21 | display: block; 22 | } 23 | -------------------------------------------------------------------------------- /2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseoverout-fast.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
    parent 12 |
    child
    13 |
    14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseoverout-fast.view/style.css: -------------------------------------------------------------------------------- 1 | #parent { 2 | background: #99C0C3; 3 | width: 160px; 4 | height: 120px; 5 | position: relative; 6 | } 7 | 8 | #child { 9 | background: #FFDE99; 10 | width: 50%; 11 | height: 50%; 12 | position: absolute; 13 | left: 50%; 14 | top: 50%; 15 | transform: translate(-50%, -50%); 16 | } 17 | 18 | textarea { 19 | height: 140px; 20 | width: 300px; 21 | display: block; 22 | } 23 | -------------------------------------------------------------------------------- /2-ui/3-event-details/4-mouse-drag-and-drop/1-slider/solution.md: -------------------------------------------------------------------------------- 1 | As we can see from HTML/CSS, the slider is a `
    ` with a colored background, that contains a runner -- another `
    ` with `position:relative`. 2 | 3 | To position the runner we use `position:relative`, to provide the coordinates relative to its parent, here it's more convenient here than `position:absolute`. 4 | 5 | Then we implement horizontal-only Drag'n'Drop with limitation by width. 6 | -------------------------------------------------------------------------------- /2-ui/3-event-details/4-mouse-drag-and-drop/1-slider/solution.view/style.css: -------------------------------------------------------------------------------- 1 | .slider { 2 | border-radius: 5px; 3 | background: #E0E0E0; 4 | background: linear-gradient(left top, #E0E0E0, #EEEEEE); 5 | width: 310px; 6 | height: 15px; 7 | margin: 5px; 8 | } 9 | 10 | .thumb { 11 | width: 10px; 12 | height: 25px; 13 | border-radius: 3px; 14 | position: relative; 15 | left: 10px; 16 | top: -5px; 17 | background: blue; 18 | cursor: pointer; 19 | } 20 | -------------------------------------------------------------------------------- /2-ui/3-event-details/4-mouse-drag-and-drop/1-slider/source.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
    12 |
    13 |
    14 | 15 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /2-ui/3-event-details/4-mouse-drag-and-drop/1-slider/source.view/style.css: -------------------------------------------------------------------------------- 1 | .slider { 2 | border-radius: 5px; 3 | background: #E0E0E0; 4 | background: linear-gradient(left top, #E0E0E0, #EEEEEE); 5 | width: 310px; 6 | height: 15px; 7 | margin: 5px; 8 | } 9 | 10 | .thumb { 11 | width: 10px; 12 | height: 25px; 13 | border-radius: 3px; 14 | position: relative; 15 | left: 10px; 16 | top: -5px; 17 | background: blue; 18 | cursor: pointer; 19 | } 20 | -------------------------------------------------------------------------------- /2-ui/3-event-details/4-mouse-drag-and-drop/1-slider/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Slider 6 | 7 | Create a slider: 8 | 9 | [iframe src="solution" height=60 border=1] 10 | 11 | Drag the blue thumb with the mouse and move it. 12 | 13 | Important details: 14 | 15 | - When the mouse button is pressed, during the dragging the mouse may go over or below the slider. The slider will still work (convenient for the user). 16 | - If the mouse moves very fast to the left or to the right, the thumb should stop exactly at the edge. 17 | -------------------------------------------------------------------------------- /2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.md: -------------------------------------------------------------------------------- 1 | To drag the element we can use `position:fixed`, it makes coordinates easier to manage. At the end we should switch it back to `position:absolute` to lay the element into the document. 2 | 3 | When coordinates are at window top/bottom, we use `window.scrollTo` to scroll it. 4 | 5 | More details in the code, in comments. 6 | -------------------------------------------------------------------------------- /2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/source.view/soccer.js: -------------------------------------------------------------------------------- 1 | // Your code 2 | -------------------------------------------------------------------------------- /2-ui/3-event-details/4-mouse-drag-and-drop/ball4.view/style.css: -------------------------------------------------------------------------------- 1 | 2 | #gate { 3 | cursor: pointer; 4 | margin-bottom: 100px; 5 | width: 83px; 6 | height: 46px; 7 | } 8 | 9 | #ball { 10 | cursor: pointer; 11 | width: 40px; 12 | height: 40px; 13 | } 14 | -------------------------------------------------------------------------------- /2-ui/3-event-details/6-pointer-events/slider-html.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
    5 |
    6 |
    7 | -------------------------------------------------------------------------------- /2-ui/3-event-details/6-pointer-events/slider-html.view/style.css: -------------------------------------------------------------------------------- 1 | .slider { 2 | border-radius: 5px; 3 | background: #E0E0E0; 4 | background: linear-gradient(left top, #E0E0E0, #EEEEEE); 5 | width: 310px; 6 | height: 15px; 7 | margin: 5px; 8 | } 9 | 10 | .thumb { 11 | width: 10px; 12 | height: 25px; 13 | border-radius: 3px; 14 | position: relative; 15 | left: 10px; 16 | top: -5px; 17 | background: blue; 18 | cursor: pointer; 19 | } 20 | -------------------------------------------------------------------------------- /2-ui/3-event-details/6-pointer-events/slider.view/style.css: -------------------------------------------------------------------------------- 1 | .slider { 2 | border-radius: 5px; 3 | background: #E0E0E0; 4 | background: linear-gradient(left top, #E0E0E0, #EEEEEE); 5 | width: 310px; 6 | height: 15px; 7 | margin: 5px; 8 | } 9 | 10 | .thumb { 11 | touch-action: none; 12 | width: 10px; 13 | height: 25px; 14 | border-radius: 3px; 15 | position: relative; 16 | left: 10px; 17 | top: -5px; 18 | background: blue; 19 | cursor: pointer; 20 | } 21 | -------------------------------------------------------------------------------- /2-ui/3-event-details/7-keyboard-events/2-check-sync-keydown/solution.md: -------------------------------------------------------------------------------- 1 | 2 | We should use two handlers: `document.onkeydown` and `document.onkeyup`. 3 | 4 | Let's create a set `pressed = new Set()` to keep currently pressed keys. 5 | 6 | The first handler adds to it, while the second one removes from it. Every time on `keydown` we check if we have enough keys pressed, and run the function if it is so. 7 | -------------------------------------------------------------------------------- /2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/style.css: -------------------------------------------------------------------------------- 1 | #kinput { 2 | font-size: 150%; 3 | box-sizing: border-box; 4 | width: 95%; 5 | } 6 | 7 | #area { 8 | width: 95%; 9 | box-sizing: border-box; 10 | height: 250px; 11 | border: 1px solid black; 12 | display: block; 13 | } 14 | 15 | form label { 16 | display: inline; 17 | white-space: nowrap; 18 | } -------------------------------------------------------------------------------- /2-ui/3-event-details/8-onscroll/1-endless-page/source.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

    Scroll me

    10 | 11 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /2-ui/3-event-details/8-onscroll/2-updown-button/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/2-ui/3-event-details/8-onscroll/2-updown-button/solution.md -------------------------------------------------------------------------------- /2-ui/3-event-details/index.md: -------------------------------------------------------------------------------- 1 | # UI Events 2 | 3 | Here we cover most important user interface events and how to work with them. 4 | -------------------------------------------------------------------------------- /2-ui/4-forms-controls/2-focus-blur/3-editable-div/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/2-ui/4-forms-controls/2-focus-blur/3-editable-div/solution.md -------------------------------------------------------------------------------- /2-ui/4-forms-controls/2-focus-blur/3-editable-div/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Editable div 6 | 7 | Create a `
    ` that turns into ` 3 |
    4 | 5 | 11 | -------------------------------------------------------------------------------- /6-data-storage/02-localstorage/1-form-autosave/source.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /6-data-storage/02-localstorage/1-form-autosave/task.md: -------------------------------------------------------------------------------- 1 | 2 | # Autosave a form field 3 | 4 | Create a `textarea` field that "autosaves" its value on every change. 5 | 6 | So, if the user accidentally closes the page, and opens it again, he'll find his unfinished input at place. 7 | 8 | Like this: 9 | 10 | [iframe src="solution" height=120] 11 | -------------------------------------------------------------------------------- /6-data-storage/02-localstorage/sessionstorage.view/iframe.html: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /6-data-storage/02-localstorage/sessionstorage.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /6-data-storage/index.md: -------------------------------------------------------------------------------- 1 | 2 | # Storing data in the browser 3 | -------------------------------------------------------------------------------- /7-animation/1-bezier-curve/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/7-animation/1-bezier-curve/pause.png -------------------------------------------------------------------------------- /7-animation/1-bezier-curve/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/7-animation/1-bezier-curve/play.png -------------------------------------------------------------------------------- /7-animation/2-css-animations/1-animate-logo-css/solution.md: -------------------------------------------------------------------------------- 1 | 2 | CSS to animate both `width` and `height`: 3 | ```css 4 | /* original class */ 5 | 6 | #flyjet { 7 | transition: all 3s; 8 | } 9 | 10 | /* JS adds .growing */ 11 | #flyjet.growing { 12 | width: 400px; 13 | height: 240px; 14 | } 15 | ``` 16 | 17 | Please note that `transitionend` triggers two times -- once for every property. So if we don't perform an additional check then the message would show up 2 times. 18 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/1-animate-logo-css/source.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/1-animate-logo-css/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Animate a plane (CSS) 6 | 7 | Show the animation like on the picture below (click the plane): 8 | 9 | [iframe src="solution" height=300] 10 | 11 | - The picture grows on click from `40x24px` to `400x240px` (10 times larger). 12 | - The animation takes 3 seconds. 13 | - At the end output: "Done!". 14 | - During the animation process, there may be more clicks on the plane. They shouldn't "break" anything. 15 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/2-animate-logo-bezier-css/solution.md: -------------------------------------------------------------------------------- 1 | We need to choose the right Bezier curve for that animation. It should have `y>1` somewhere for the plane to "jump out". 2 | 3 | For instance, we can take both control points with `y>1`, like: `cubic-bezier(0.25, 1.5, 0.75, 1.5)`. 4 | 5 | The graph: 6 | 7 | ![](bezier-up.svg) 8 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/2-animate-logo-bezier-css/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Animate the flying plane (CSS) 6 | 7 | Modify the solution of the previous task to make the plane grow more than its original size 400x240px (jump out), and then return to that size. 8 | 9 | Here's how it should look (click on the plane): 10 | 11 | [iframe src="solution" height=350] 12 | 13 | Take the solution of the previous task as the source. 14 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/3-animate-circle/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/7-animation/2-css-animations/3-animate-circle/solution.md -------------------------------------------------------------------------------- /7-animation/2-css-animations/4-animate-circle-callback/solution.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/7-animation/2-css-animations/4-animate-circle-callback/solution.md -------------------------------------------------------------------------------- /7-animation/2-css-animations/boat.view/style.css: -------------------------------------------------------------------------------- 1 | #boat { 2 | margin-left: 0; 3 | cursor: pointer; 4 | transition: margin-left 3s ease-in-out; 5 | } 6 | 7 | /* flipping the picture with CSS */ 8 | .back { 9 | transform: scaleX(-1); 10 | filter: fliph; 11 | } 12 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/digits-negative-delay.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Click below to animate: 12 |
    0123456789
    13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/digits-negative-delay.view/script.js: -------------------------------------------------------------------------------- 1 | stripe.onclick = function() { 2 | let sec = new Date().getSeconds() % 10; 3 | stripe.style.transitionDelay = '-' + sec + 's'; 4 | stripe.classList.add('animate'); 5 | }; -------------------------------------------------------------------------------- /7-animation/2-css-animations/digits-negative-delay.view/style.css: -------------------------------------------------------------------------------- 1 | #digit { 2 | width: .5em; 3 | overflow: hidden; 4 | font: 32px monospace; 5 | cursor: pointer; 6 | } 7 | 8 | #stripe { 9 | display: inline-block 10 | } 11 | 12 | #stripe.animate { 13 | transform: translate(-90%); 14 | transition-property: transform; 15 | transition-duration: 9s; 16 | transition-timing-function: linear; 17 | } 18 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/digits.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Click below to animate: 12 | 13 |
    0123456789
    14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/digits.view/script.js: -------------------------------------------------------------------------------- 1 | stripe.onclick = function() { 2 | stripe.classList.add('animate'); 3 | }; -------------------------------------------------------------------------------- /7-animation/2-css-animations/digits.view/style.css: -------------------------------------------------------------------------------- 1 | #digit { 2 | width: .5em; 3 | overflow: hidden; 4 | font: 32px monospace; 5 | cursor: pointer; 6 | } 7 | 8 | #stripe { 9 | display: inline-block 10 | } 11 | 12 | #stripe.animate { 13 | transform: translate(-90%); 14 | transition-property: transform; 15 | transition-duration: 9s; 16 | transition-timing-function: linear; 17 | } 18 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/step-end.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Click below to animate: 12 | 13 |
    0123456789
    14 | 15 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/step-end.view/style.css: -------------------------------------------------------------------------------- 1 | #digit { 2 | width: .5em; 3 | overflow: hidden; 4 | font: 32px monospace; 5 | cursor: pointer; 6 | } 7 | 8 | #stripe { 9 | display: inline-block 10 | } 11 | 12 | #stripe.animate { 13 | transform: translate(-90%); 14 | transition-property: transform; 15 | transition-duration: 9s; 16 | transition-timing-function: steps(9, end); 17 | } 18 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/step-list.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
    0123456789
    12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/step-list.view/style.css: -------------------------------------------------------------------------------- 1 | #digit { 2 | border: 1px solid red; 3 | width: 1.2em; 4 | } 5 | 6 | #stripe { 7 | display: inline-block; 8 | font: 32px monospace; 9 | } 10 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/step.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Click below to animate: 12 | 13 |
    0123456789
    14 | 15 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/step.view/style.css: -------------------------------------------------------------------------------- 1 | #digit { 2 | width: .5em; 3 | overflow: hidden; 4 | font: 32px monospace; 5 | cursor: pointer; 6 | } 7 | 8 | #stripe { 9 | display: inline-block 10 | } 11 | 12 | #stripe.animate { 13 | transform: translate(-90%); 14 | transition-property: transform; 15 | transition-duration: 9s; 16 | transition-timing-function: steps(9, start); 17 | } 18 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/train-linear.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/train-linear.view/style.css: -------------------------------------------------------------------------------- 1 | .train { 2 | position: relative; 3 | cursor: pointer; 4 | width: 177px; 5 | height: 160px; 6 | left: 0; 7 | transition: left 5s cubic-bezier(0, 0, 1, 1); 8 | } -------------------------------------------------------------------------------- /7-animation/2-css-animations/train-over.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/train-over.view/style.css: -------------------------------------------------------------------------------- 1 | .train { 2 | position: relative; 3 | cursor: pointer; 4 | width: 177px; 5 | height: 160px; 6 | left: 100px; 7 | transition: left 5s cubic-bezier(.5, -1, .5, 2); 8 | } -------------------------------------------------------------------------------- /7-animation/2-css-animations/train.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /7-animation/2-css-animations/train.view/style.css: -------------------------------------------------------------------------------- 1 | .train { 2 | position: relative; 3 | cursor: pointer; 4 | width: 177px; 5 | height: 160px; 6 | left: 0px; 7 | transition: left 5s cubic-bezier(0.0, 0.5, 0.5, 1.0); 8 | } -------------------------------------------------------------------------------- /7-animation/3-js-animation/1-animate-ball/solution.view/style.css: -------------------------------------------------------------------------------- 1 | #field { 2 | height: 200px; 3 | border-bottom: 3px black groove; 4 | position: relative; 5 | } 6 | 7 | #ball { 8 | position: absolute; 9 | cursor: pointer; 10 | } -------------------------------------------------------------------------------- /7-animation/3-js-animation/1-animate-ball/source.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
    13 | 14 |
    15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /7-animation/3-js-animation/1-animate-ball/source.view/style.css: -------------------------------------------------------------------------------- 1 | #field { 2 | height: 200px; 3 | border-bottom: 3px black groove; 4 | position: relative; 5 | } 6 | 7 | #ball { 8 | position: absolute; 9 | cursor: pointer; 10 | } -------------------------------------------------------------------------------- /7-animation/3-js-animation/1-animate-ball/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Animate the bouncing ball 6 | 7 | Make a bouncing ball. Click to see how it should look: 8 | 9 | [iframe height=250 src="solution"] 10 | -------------------------------------------------------------------------------- /7-animation/3-js-animation/2-animate-ball-hops/solution.view/style.css: -------------------------------------------------------------------------------- 1 | #field { 2 | height: 200px; 3 | border-bottom: 3px black groove; 4 | position: relative; 5 | } 6 | 7 | #ball { 8 | position: absolute; 9 | cursor: pointer; 10 | } -------------------------------------------------------------------------------- /7-animation/3-js-animation/2-animate-ball-hops/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # Animate the ball bouncing to the right 6 | 7 | Make the ball bounce to the right. Like this: 8 | 9 | [iframe height=250 src="solution"] 10 | 11 | Write the animation code. The distance to the left is `100px`. 12 | 13 | Take the solution of the previous task as the source. 14 | -------------------------------------------------------------------------------- /7-animation/3-js-animation/back.view/style.css: -------------------------------------------------------------------------------- 1 | #brick { 2 | width: 40px; 3 | height: 20px; 4 | background: #EE6B47; 5 | position: relative; 6 | cursor: pointer; 7 | } 8 | 9 | #path { 10 | outline: 1px solid #E8C48E; 11 | width: 540px; 12 | height: 20px; 13 | } -------------------------------------------------------------------------------- /7-animation/3-js-animation/bounce-easeinout.view/style.css: -------------------------------------------------------------------------------- 1 | #brick { 2 | width: 40px; 3 | height: 20px; 4 | background: #EE6B47; 5 | position: relative; 6 | cursor: pointer; 7 | } 8 | 9 | #path { 10 | outline: 1px solid #E8C48E; 11 | width: 540px; 12 | height: 20px; 13 | } -------------------------------------------------------------------------------- /7-animation/3-js-animation/bounce-easeout.view/style.css: -------------------------------------------------------------------------------- 1 | #brick { 2 | width: 40px; 3 | height: 20px; 4 | background: #EE6B47; 5 | position: relative; 6 | cursor: pointer; 7 | } 8 | 9 | #path { 10 | outline: 1px solid #E8C48E; 11 | width: 540px; 12 | height: 20px; 13 | } -------------------------------------------------------------------------------- /7-animation/3-js-animation/bounce.view/style.css: -------------------------------------------------------------------------------- 1 | #brick { 2 | width: 40px; 3 | height: 20px; 4 | background: #EE6B47; 5 | position: relative; 6 | cursor: pointer; 7 | } 8 | 9 | #path { 10 | outline: 1px solid #E8C48E; 11 | width: 540px; 12 | height: 20px; 13 | } -------------------------------------------------------------------------------- /7-animation/3-js-animation/circ.view/style.css: -------------------------------------------------------------------------------- 1 | #brick { 2 | width: 40px; 3 | height: 20px; 4 | background: #EE6B47; 5 | position: relative; 6 | cursor: pointer; 7 | } 8 | 9 | #path { 10 | outline: 1px solid #E8C48E; 11 | width: 540px; 12 | height: 20px; 13 | } -------------------------------------------------------------------------------- /7-animation/3-js-animation/elastic.view/style.css: -------------------------------------------------------------------------------- 1 | #brick { 2 | width: 40px; 3 | height: 20px; 4 | background: #EE6B47; 5 | position: relative; 6 | cursor: pointer; 7 | } 8 | 9 | #path { 10 | outline: 1px solid #E8C48E; 11 | width: 540px; 12 | height: 20px; 13 | } -------------------------------------------------------------------------------- /7-animation/3-js-animation/quad.view/style.css: -------------------------------------------------------------------------------- 1 | #brick { 2 | width: 40px; 3 | height: 20px; 4 | background: #EE6B47; 5 | position: relative; 6 | cursor: pointer; 7 | } 8 | 9 | #path { 10 | outline: 1px solid #E8C48E; 11 | width: 540px; 12 | height: 20px; 13 | } -------------------------------------------------------------------------------- /7-animation/3-js-animation/quint.view/style.css: -------------------------------------------------------------------------------- 1 | #brick { 2 | width: 40px; 3 | height: 20px; 4 | background: #EE6B47; 5 | position: relative; 6 | cursor: pointer; 7 | } 8 | 9 | #path { 10 | outline: 1px solid #E8C48E; 11 | width: 540px; 12 | height: 20px; 13 | } -------------------------------------------------------------------------------- /7-animation/3-js-animation/text.view/style.css: -------------------------------------------------------------------------------- 1 | textarea { 2 | display: block; 3 | border: 1px solid #BBB; 4 | color: #444; 5 | font-size: 110%; 6 | } 7 | 8 | button { 9 | margin-top: 10px; 10 | } -------------------------------------------------------------------------------- /7-animation/3-js-animation/width.view/animate.js: -------------------------------------------------------------------------------- 1 | function animate({duration, draw, timing}) { 2 | 3 | let start = performance.now(); 4 | 5 | requestAnimationFrame(function animate(time) { 6 | let timeFraction = (time - start) / duration; 7 | if (timeFraction > 1) timeFraction = 1; 8 | 9 | let progress = timing(timeFraction) 10 | 11 | draw(progress); 12 | 13 | if (timeFraction < 1) { 14 | requestAnimationFrame(animate); 15 | } 16 | 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /7-animation/index.md: -------------------------------------------------------------------------------- 1 | # Animation 2 | 3 | CSS and JavaScript animations. 4 | -------------------------------------------------------------------------------- /8-web-components/1-webcomponents-intro/satellite-expanded.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/8-web-components/1-webcomponents-intro/satellite-expanded.jpg -------------------------------------------------------------------------------- /8-web-components/1-webcomponents-intro/satellite-expanded@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/8-web-components/1-webcomponents-intro/satellite-expanded@2x.jpg -------------------------------------------------------------------------------- /8-web-components/1-webcomponents-intro/satellite.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/8-web-components/1-webcomponents-intro/satellite.jpg -------------------------------------------------------------------------------- /8-web-components/1-webcomponents-intro/satellite@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/8-web-components/1-webcomponents-intro/satellite@2x.jpg -------------------------------------------------------------------------------- /8-web-components/2-custom-elements/1-live-timer/solution.md: -------------------------------------------------------------------------------- 1 | 2 | Please note: 3 | 1. We clear `setInterval` timer when the element is removed from the document. That's important, otherwise it continues ticking even if not needed any more. And the browser can't clear the memory from this element and referenced by it. 4 | 2. We can access current date as `elem.date` property. All class methods and properties are naturally element methods and properties. 5 | -------------------------------------------------------------------------------- /8-web-components/2-custom-elements/1-live-timer/solution.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /8-web-components/2-custom-elements/1-live-timer/source.view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /8-web-components/2-custom-elements/1-live-timer/source.view/live-timer.js: -------------------------------------------------------------------------------- 1 | class LiveTimer extends HTMLElement { 2 | 3 | /* your code here */ 4 | 5 | } 6 | 7 | customElements.define("live-timer", LiveTimer); 8 | -------------------------------------------------------------------------------- /8-web-components/3-shadow-dom/shadow-dom-range.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/8-web-components/3-shadow-dom/shadow-dom-range.png -------------------------------------------------------------------------------- /8-web-components/3-shadow-dom/shadow-dom-range@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/8-web-components/3-shadow-dom/shadow-dom-range@2x.png -------------------------------------------------------------------------------- /8-web-components/3-shadow-dom/shadow-dom-say-hello.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/8-web-components/3-shadow-dom/shadow-dom-say-hello.png -------------------------------------------------------------------------------- /8-web-components/3-shadow-dom/shadow-dom-say-hello@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/javascript-tutorial/en.javascript.info/540d753e90789205fc6e75c502f68382c87dea9b/8-web-components/3-shadow-dom/shadow-dom-say-hello@2x.png -------------------------------------------------------------------------------- /8-web-components/index.md: -------------------------------------------------------------------------------- 1 | # Web components 2 | 3 | Web components is a set of standards to make self-contained components: custom HTML-elements with their own properties and methods, encapsulated DOM and styles. 4 | -------------------------------------------------------------------------------- /9-regular-expressions/04-regexp-anchors/1-start-end/solution.md: -------------------------------------------------------------------------------- 1 | An empty string is the only match: it starts and immediately finishes. 2 | 3 | The task once again demonstrates that anchors are not characters, but tests. 4 | 5 | The string is empty `""`. The engine first matches the `pattern:^` (input start), yes it's there, and then immediately the end `pattern:$`, it's here too. So there's a match. 6 | -------------------------------------------------------------------------------- /9-regular-expressions/04-regexp-anchors/1-start-end/task.md: -------------------------------------------------------------------------------- 1 | # Regexp ^$ 2 | 3 | Which string matches the pattern `pattern:^$`? 4 | -------------------------------------------------------------------------------- /9-regular-expressions/06-regexp-boundary/1-find-time-hh-mm/solution.md: -------------------------------------------------------------------------------- 1 | 2 | The answer: `pattern:\b\d\d:\d\d\b`. 3 | 4 | ```js run 5 | alert( "Breakfast at 09:00 in the room 123:456.".match( /\b\d\d:\d\d\b/ ) ); // 09:00 6 | ``` 7 | -------------------------------------------------------------------------------- /9-regular-expressions/06-regexp-boundary/1-find-time-hh-mm/task.md: -------------------------------------------------------------------------------- 1 | # Find the time 2 | 3 | The time has a format: `hours:minutes`. Both hours and minutes has two digits, like `09:00`. 4 | 5 | Make a regexp to find time in the string: `subject:Breakfast at 09:00 in the room 123:456.` 6 | 7 | P.S. In this task there's no need to check time correctness yet, so `25:99` can also be a valid result. 8 | 9 | P.P.S. The regexp shouldn't match `123:456`. 10 | -------------------------------------------------------------------------------- /9-regular-expressions/08-regexp-character-sets-and-ranges/1-find-range-1/task.md: -------------------------------------------------------------------------------- 1 | # Java[^script] 2 | 3 | We have a regexp `pattern:/Java[^script]/`. 4 | 5 | Does it match anything in the string `subject:Java`? In the string `subject:JavaScript`? 6 | -------------------------------------------------------------------------------- /9-regular-expressions/08-regexp-character-sets-and-ranges/2-find-time-2-formats/solution.md: -------------------------------------------------------------------------------- 1 | Answer: `pattern:\d\d[-:]\d\d`. 2 | 3 | ```js run 4 | let regexp = /\d\d[-:]\d\d/g; 5 | alert( "Breakfast at 09:00. Dinner at 21-30".match(regexp) ); // 09:00, 21-30 6 | ``` 7 | 8 | Please note that the dash `pattern:'-'` has a special meaning in square brackets, but only between other characters, not when it's in the beginning or at the end, so we don't need to escape it. 9 | -------------------------------------------------------------------------------- /9-regular-expressions/09-regexp-quantifiers/1-find-text-manydots/solution.md: -------------------------------------------------------------------------------- 1 | 2 | Solution: 3 | 4 | ```js run 5 | let regexp = /\.{3,}/g; 6 | alert( "Hello!... How goes?.....".match(regexp) ); // ..., ..... 7 | ``` 8 | 9 | Please note that the dot is a special character, so we have to escape it and insert as `\.`. 10 | -------------------------------------------------------------------------------- /9-regular-expressions/09-regexp-quantifiers/1-find-text-manydots/task.md: -------------------------------------------------------------------------------- 1 | importance: 5 2 | 3 | --- 4 | 5 | # How to find an ellipsis "..." ? 6 | 7 | Create a regexp to find ellipsis: 3 (or more?) dots in a row. 8 | 9 | Check it: 10 | 11 | ```js 12 | let regexp = /your regexp/g; 13 | alert( "Hello!... How goes?.....".match(regexp) ); // ..., ..... 14 | ``` 15 | -------------------------------------------------------------------------------- /9-regular-expressions/10-regexp-greedy-and-lazy/1-lazy-greedy/solution.md: -------------------------------------------------------------------------------- 1 | 2 | The result is: `match:123 4`. 3 | 4 | First the lazy `pattern:\d+?` tries to take as little digits as it can, but it has to reach the space, so it takes `match:123`. 5 | 6 | Then the second `\d+?` takes only one digit, because that's enough. 7 | -------------------------------------------------------------------------------- /9-regular-expressions/10-regexp-greedy-and-lazy/1-lazy-greedy/task.md: -------------------------------------------------------------------------------- 1 | # A match for /d+? d+?/ 2 | 3 | What's the match here? 4 | 5 | ```js 6 | alert( "123 456".match(/\d+? \d+?/g) ); // ? 7 | ``` 8 | -------------------------------------------------------------------------------- /9-regular-expressions/10-regexp-greedy-and-lazy/3-find-html-comments/task.md: -------------------------------------------------------------------------------- 1 | # Find HTML comments 2 | 3 | Find all HTML comments in the text: 4 | 5 | ```js 6 | let regexp = /your regexp/g; 7 | 8 | let str = `... .. .. 10 | `; 11 | 12 | alert( str.match(regexp) ); // '', '' 13 | ``` 14 | -------------------------------------------------------------------------------- /9-regular-expressions/10-regexp-greedy-and-lazy/4-find-html-tags-greedy-lazy/solution.md: -------------------------------------------------------------------------------- 1 | 2 | The solution is `pattern:<[^<>]+>`. 3 | 4 | ```js run 5 | let regexp = /<[^<>]+>/g; 6 | 7 | let str = '<> '; 8 | 9 | alert( str.match(regexp) ); // '', '', '' 10 | ``` 11 | -------------------------------------------------------------------------------- /9-regular-expressions/11-regexp-groups/03-find-decimal-numbers/solution.md: -------------------------------------------------------------------------------- 1 | A positive number with an optional decimal part is: `pattern:\d+(\.\d+)?`. 2 | 3 | Let's add the optional `pattern:-` in the beginning: 4 | 5 | ```js run 6 | let regexp = /-?\d+(\.\d+)?/g; 7 | 8 | let str = "-1.5 0 2 -123.4."; 9 | 10 | alert( str.match(regexp) ); // -1.5, 0, 2, -123.4 11 | ``` 12 | -------------------------------------------------------------------------------- /9-regular-expressions/11-regexp-groups/03-find-decimal-numbers/task.md: -------------------------------------------------------------------------------- 1 | # Find all numbers 2 | 3 | Write a regexp that looks for all decimal numbers including integer ones, with the floating point and negative ones. 4 | 5 | An example of use: 6 | 7 | ```js 8 | let regexp = /your regexp/g; 9 | 10 | let str = "-1.5 0 2 -123.4."; 11 | 12 | alert( str.match(regexp) ); // -1.5, 0, 2, -123.4 13 | ``` 14 | -------------------------------------------------------------------------------- /9-regular-expressions/13-regexp-alternation/01-find-programming-language/task.md: -------------------------------------------------------------------------------- 1 | # Find programming languages 2 | 3 | There are many programming languages, for instance Java, JavaScript, PHP, C, C++. 4 | 5 | Create a regexp that finds them in the string `subject:Java JavaScript PHP C++ C`: 6 | 7 | ```js 8 | let regexp = /your regexp/g; 9 | 10 | alert("Java JavaScript PHP C++ C".match(regexp)); // Java JavaScript PHP C++ C 11 | ``` 12 | -------------------------------------------------------------------------------- /9-regular-expressions/13-regexp-alternation/04-match-exact-tag/task.md: -------------------------------------------------------------------------------- 1 | # Find the full tag 2 | 3 | Write a regexp to find the tag ``. It should match the full tag: it may have no attributes `