├── .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 | 
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 | 
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 | Click me
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 | An elk is a smart
7 |
8 | ...and cunning animal!
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 |
17 |
18 |
19 | ```
20 |
21 | For each of the following, give at least one way of how to access them:
22 | - The `