├── .gitattributes
├── .github
└── PULL_REQUEST_TEMPLATE.md
├── .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.png
│ │ ├── chrome@2x.png
│ │ ├── 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
│ │ ├── 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
│ └── 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
├── 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 |
--------------------------------------------------------------------------------
/.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 | 本页面的脚本中有一个错误。
11 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/1-js/01-getting-started/4-devtools/chrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javascript-tutorial/zh.javascript.info/e41b584cd6b44d001d8ead96e9005f60d9f06dca/1-js/01-getting-started/4-devtools/chrome.png
--------------------------------------------------------------------------------
/1-js/01-getting-started/4-devtools/chrome@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javascript-tutorial/zh.javascript.info/e41b584cd6b44d001d8ead96e9005f60d9f06dca/1-js/01-getting-started/4-devtools/chrome@2x.png
--------------------------------------------------------------------------------
/1-js/01-getting-started/4-devtools/safari.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javascript-tutorial/zh.javascript.info/e41b584cd6b44d001d8ead96e9005f60d9f06dca/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/zh.javascript.info/e41b584cd6b44d001d8ead96e9005f60d9f06dca/1-js/01-getting-started/4-devtools/safari@2x.png
--------------------------------------------------------------------------------
/1-js/01-getting-started/index.md:
--------------------------------------------------------------------------------
1 | # 简介
2 |
3 | 介绍 JavaScript 语言及其开发环境。
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 | # 显示一个提示语
6 |
7 | 创建一个页面,然后显示一个消息 “I'm JavaScript!”。
8 |
9 | 在沙箱中或者在你的硬盘上做这件事都无所谓,只要确保它能运行起来。
10 |
11 | [demo src="solution"]
12 |
--------------------------------------------------------------------------------
/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 | HTML 代码:
2 |
3 | [html src="index.html"]
4 |
5 | 同一个文件夹中的 `alert.js` 文件:
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 | # 使用外部的脚本显示一个提示语
6 |
7 | 打开前一个任务 的答案。将脚本的内容提取到一个外部的 `alert.js` 文件中,放置在相同的文件夹中。
8 |
9 | 打开页面,确保它能够工作。
10 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/04-variables/1-hello-variables/solution.md:
--------------------------------------------------------------------------------
1 | 下面的代码,每一行都对应着任务列表中的对应项。
2 |
3 | ```js run
4 | let admin, name; // 一次声明两个变量。
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 | # 使用变量
6 |
7 | 1. 声明两个变量:`admin` 和 `name`。
8 | 2. 将值 `"John"` 赋给 `name`。
9 | 3. 从 `name` 变量中拷贝其值给 `admin`。
10 | 4. 使用 `alert` 显示 `admin` 的值(必须输出 "John")。
11 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/04-variables/2-declare-variables/solution.md:
--------------------------------------------------------------------------------
1 | ## 代表我们星球的变量
2 |
3 | 这很简单:
4 |
5 | ```js
6 | let ourPlanetName = "Earth";
7 | ```
8 |
9 | 注意,我们也可以用一个更简短的名字 `planet`,但这样可能并不能表达清楚它指的是哪个星球。再啰嗦一点也挺好的。至少让这个变量别太长就行。
10 |
11 | ## 网站当前访问者的名字
12 |
13 | ```js
14 | let currentUserName = "John";
15 | ```
16 |
17 | 同样,如果我们的确知道用户就是当前的用户的话,我们可以使用更短的变量名 `userName`。
18 |
19 | 现代编辑器的自动补全可以让长变量名变得容易编写。不要浪费这个特性。一个名字中包含三个词挺好的。
20 |
21 | 如果你的编辑器没有合适的自动补全功能,换 [一个新的吧](/code-editors)。
22 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/04-variables/2-declare-variables/task.md:
--------------------------------------------------------------------------------
1 | importance: 3
2 |
3 | ---
4 |
5 | # 给出正确的名字
6 |
7 | 1. 使用我们的星球的名字创建一个变量。你会怎么命名这个变量?
8 | 2. 创建一个变量来存储当前浏览者的名字。你会怎么命名这个变量?
9 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/04-variables/3-uppercast-constant/solution.md:
--------------------------------------------------------------------------------
1 | 我们通常用大写字母表示“硬编码(hard-coded)”的常量。或者,换句话说就是,当值在执行之前或在被写入代码的时候,我们就知道值是什么了。
2 |
3 | 在这个代码中 `birthday` 确实是这样的。因此我们可以使用大写。
4 |
5 | 在对照组中,`age` 是在程序运行时计算出的。今天我们有一个年龄,一年以后我们就会有另一个。它在某种意义上不会随着代码的执行而改变。但与 `birthday` 相比,它还是有一定的可变性:它是计算出来的,因此我们应该使用小写。
6 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/05-types/1-string-quotes/solution.md:
--------------------------------------------------------------------------------
1 |
2 | 反引号将包装在 `${...}` 中的表达式嵌入到了字符串。
3 |
4 | ```js run
5 | let name = "Ilya";
6 |
7 | // 表达式为数字 1
8 | alert( `hello ${1}` ); // hello 1
9 |
10 | // 表达式是一个字符串 "name"
11 | alert( `hello ${"name"}` ); // hello name
12 |
13 | // 表达式是一个变量,嵌入进去了。
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 | # 字符串的反引号
6 |
7 | 下面的脚本会输出什么?
8 |
9 | ```js
10 | let name = "Ilya";
11 |
12 | alert( `hello ${1}` ); // ?
13 |
14 | alert( `hello ${"name"}` ); // ?
15 |
16 | alert( `hello ${name}` ); // ?
17 | ```
18 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/solution.md:
--------------------------------------------------------------------------------
1 | JavaScript 代码:
2 |
3 | ```js demo run
4 | let name = prompt("What is your name?", "");
5 | alert(name);
6 | ```
7 |
8 | 整个页面的代码:
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 | # 创建一个简单的页面
6 |
7 | 创建一个要求用户输入 `name`,并通过浏览器窗口对键入的内容进行输出的 web 页面。
8 |
9 | [demo]
10 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/08-operators/1-increment-order/solution.md:
--------------------------------------------------------------------------------
1 |
2 | 答案如下:
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,前置运算符返回最新值
13 | alert( b++ ); // 1,后置运算符返回旧值
14 |
15 | alert( a ); // 2,自增一次
16 | alert( b ); // 2,自增一次
17 | ```
18 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/08-operators/1-increment-order/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 后置运算符和前置运算符
6 |
7 | 以下代码中变量 `a`、`b`、`c`、`d` 的最终值分别是多少?
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 | 答案如下:
2 |
3 | - `a = 4`(乘以 2)
4 | - `x = 5`(相当于计算 1 + 4)
5 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/08-operators/2-assignment-result/task.md:
--------------------------------------------------------------------------------
1 | importance: 3
2 |
3 | ---
4 |
5 | # 赋值结果
6 |
7 | 下面这段代码运行完成后,代码中的 `a` 和 `x` 的值是多少?
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 | # 类型转换
6 |
7 | 下面这些表达式的结果是什么?
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 | 好好思考一下,把它们写下来然后和答案比较一下。
27 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/08-operators/4-fix-prompt/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 修正加法
6 |
7 | 这里有一段代码,要求用户输入两个数字并显示它们的总和。
8 |
9 | 它的运行结果不正确。下面例子中的输出是 `12`(对于默认的 prompt 的值)。
10 |
11 | 为什么会这样?修正它。结果应该是 `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 | # 值的比较
6 |
7 | 以下表达式的执行结果是?
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 | **是的,它会**
2 |
3 | 任何非空字符串(`"0"` 不是空字符串)的逻辑值都是 `true`。
4 |
5 | 我们可以执行下面的代码来进行验证:
6 |
7 | ```js run
8 | if ("0") {
9 | alert( 'Hello' );
10 | }
11 | ```
12 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/10-ifelse/1-if-zero-string/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # if(值为 0 的字符串)
6 |
7 | `alert` 弹窗会出来吗?
8 |
9 | ```js
10 | if ("0") {
11 | alert( 'Hello' );
12 | }
13 | ```
14 |
--------------------------------------------------------------------------------
/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 | # JavaScript 的名字
6 |
7 | 使用 `if..else` 结构,实现提问 "What's the “official” name of JavaScript?" 的代码。
8 |
9 | 如果访问者输入了 "ECMAScript",输出就提示 "Right!",否则 —— 输出:"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 | # 显示符号
6 |
7 | 使用 `if..else` 语句,编写代码实现通过 `prompt` 获取一个数字并用 `alert` 显示结果:
8 |
9 | - 如果这个数字大于 0,就显示 `1`,
10 | - 如果这个数字小于 0,就显示 `-1`,
11 | - 如果这个数字等于 0,就显示 `0`。
12 |
13 | 在这个任务中,我们假设输入永远是一个数字。
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 | # 使用 '?' 重写 'if' 语句
6 |
7 | 使用条件运算符 `'?'` 重写下面的 `if` 语句:
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/10-ifelse/6-rewrite-if-else-question/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 使用 '?' 重写 'if..else' 语句
6 |
7 | 使用多个三元运算符 `'?'` 重写下面的 `if..else` 语句。
8 |
9 | 为了增强代码可读性,建议将代码分成多行。
10 |
11 | ```js
12 | let message;
13 |
14 | if (login == 'Employee') {
15 | message = 'Hello';
16 | } else if (login == 'Director') {
17 | message = 'Greetings';
18 | } else if (login == '') {
19 | message = 'No login';
20 | } else {
21 | message = '';
22 | }
23 | ```
24 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/solution.md:
--------------------------------------------------------------------------------
1 | 结果是 `2`,这是第一个真值。
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 | # 或运算的结果是什么?
6 |
7 | 如下代码将会输出什么?
8 |
9 | ```js
10 | alert( null || 2 || undefined );
11 | ```
12 |
13 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md:
--------------------------------------------------------------------------------
1 | 答案:首先是 `1`,然后是 `2`。
2 |
3 | ```js run
4 | alert( alert(1) || 2 || alert(3) );
5 | ```
6 |
7 | 对 `alert` 的调用没有返回值。或者说返回的是 `undefined`。
8 |
9 | 1. 第一个或运算 `||` 对它的左值 `alert(1)` 进行了计算。这就显示了第一条信息 `1`。
10 | 2. 函数 `alert` 返回了 `undefined`,所以或运算继续检查第二个操作数以寻找真值。
11 | 3. 第二个操作数 `2` 是真值,所以执行就中断了。`2` 被返回,并且被外层的 alert 显示。
12 |
13 | 这里不会显示 `3`,因为运算没有抵达 `alert(3)`。
14 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/11-logical-operators/2-alert-or/task.md:
--------------------------------------------------------------------------------
1 | importance: 3
2 |
3 | ---
4 |
5 | # 或运算和 alert 的结果是什么?
6 |
7 | 下面的代码将会输出什么?
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 | 答案:`null`,因为它是列表中第一个假值。
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 | # 与操作的结果是什么?
6 |
7 | 下面这段代码将会显示什么?
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 | 答案:`1`,然后 `undefined`。
2 |
3 | ```js run
4 | alert( alert(1) && alert(2) );
5 | ```
6 |
7 | 调用 `alert` 返回了 `undefined`(它只展示消息,所以没有有意义的返回值)。
8 |
9 | 因此,`&&` 计算了它左边的操作数(显示 `1`),然后立即停止了,因为 `undefined` 是一个假值。`&&` 就是寻找假值然后返回它,所以运算结束。
10 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/11-logical-operators/4-alert-and/task.md:
--------------------------------------------------------------------------------
1 | importance: 3
2 |
3 | ---
4 |
5 | # 与运算连接的 alert 的结果是什么?
6 |
7 | 这段代码将会显示什么?
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 | 答案:`3`。
2 |
3 | ```js run
4 | alert( null || 2 && 3 || 4 );
5 | ```
6 |
7 | 与运算 `&&` 的优先级比 `||` 高,所以它第一个被执行。
8 |
9 | 结果是 `2 && 3 = 3`,所以表达式变成了:
10 |
11 | ```
12 | null || 3 || 4
13 | ```
14 |
15 | 现在的结果就是第一个真值:`3`。
16 |
17 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/11-logical-operators/5-alert-and-or/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 或运算、与运算、或运算串联的结果
6 |
7 | 结果将会是什么?
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 | # 检查值是否位于范围区间内
6 |
7 | 写一个 `if` 条件句来检查 `age` 是否位于 `14` 到 `90` 的闭区间。
8 |
9 | “闭区间”意味着,`age` 的值可以取 `14` 或 `90`。
10 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/11-logical-operators/7-check-if-out-range/solution.md:
--------------------------------------------------------------------------------
1 | 第一个表达式:
2 |
3 | ```js
4 | if (!(age >= 14 && age <= 90))
5 | ```
6 |
7 | 第二个表达式:
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 | # 检查值是否位于范围之外
6 |
7 | 写一个 `if` 条件句,检查 `age` 是否不位于 `14` 到 `90` 的闭区间。
8 |
9 | 创建两个表达式:第一个用非运算 `!`,第二个不用。
10 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/11-logical-operators/8-if-question/solution.md:
--------------------------------------------------------------------------------
1 | 答案:第一个和第三个将会被执行。
2 |
3 | 详解:
4 |
5 | ```js run
6 | // 执行。
7 | // -1 || 0 的结果为 -1,真值
8 | if (-1 || 0) alert( 'first' );
9 |
10 | // 不执行。
11 | // -1 && 0 = 0,假值
12 | if (-1 && 0) alert( 'second' );
13 |
14 | // 执行
15 | // && 运算的优先级比 || 高
16 | // 所以 -1 && 1 先执行,给出如下运算链:
17 | // null || -1 && 1 -> null || 1 -> 1
18 | if (null || -1 && 1) alert( 'third' );
19 | ```
20 |
21 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/11-logical-operators/8-if-question/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 一个关于 "if" 的问题
6 |
7 | 下面哪一个 `alert` 将会被执行?
8 |
9 | `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/solution.md:
--------------------------------------------------------------------------------
1 | 答案是:`1`。
2 |
3 | ```js run
4 | let i = 3;
5 |
6 | while (i) {
7 | alert( i-- );
8 | }
9 | ```
10 |
11 | 每次循环迭代都将 `i` 减 `1`。当检查到 `i = 0` 时,`while(i)` 循环停止。
12 |
13 | 因此,此循环执行的步骤如下(“循环展开”):
14 |
15 | ```js
16 | let i = 3;
17 |
18 | alert(i--); // 显示 3,i 减至 2
19 |
20 | alert(i--) // 显示 2,i 减至 1
21 |
22 | alert(i--) // 显示 1,i 减至 0
23 |
24 | // 完成,while(i) 检查循环条件并停止循环
25 | ```
26 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/13-while-for/1-loop-last-value/task.md:
--------------------------------------------------------------------------------
1 | importance: 3
2 |
3 | ---
4 |
5 | # 最后一次循环的值
6 |
7 | 此代码最后一次 alert 值是多少?为什么?
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 | # while 循环显示哪些值?
6 |
7 | 对于每次循环,写出你认为会显示的值,然后与答案进行比较。
8 |
9 | 以下两个循环的 `alert` 值是否相同?
10 |
11 | 1. 前缀形式 `++i`:
12 |
13 | ```js
14 | let i = 0;
15 | while (++i < 5) alert( i );
16 | ```
17 | 2. 后缀形式 `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/solution.md:
--------------------------------------------------------------------------------
1 | **答案:在这两种情况下都是从 `0` 到 `4`。**
2 |
3 | ```js run
4 | for (let i = 0; i < 5; ++i) alert( i );
5 |
6 | for (let i = 0; i < 5; i++) alert( i );
7 | ```
8 |
9 | 这可以很容易地从 `for` 算法中推导出:
10 |
11 | 1. 在一切开始之前执行 `i = 0`。
12 | 2. 检查 `i < 5` 条件
13 | 3. 如果 `true` —— 执行循环体并 `alert(i)`,然后进行 `i++`
14 |
15 | 递增 `i++` 与检查条件(2)分开。这只是另一种写法。
16 |
17 | 在这没使用返回的递增值,因此 `i++` 和 `++i`之间没有区别。
18 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/13-while-for/3-which-value-for/task.md:
--------------------------------------------------------------------------------
1 | importance: 4
2 |
3 | ---
4 |
5 | # "for" 循环显示哪些值?
6 |
7 | 对于每次循环,写下它将显示的值。然后与答案进行比较。
8 |
9 | 两次循环 `alert` 值是否相同?
10 |
11 | 1. 后缀形式:
12 |
13 | ```js
14 | for (let i = 0; i < 5; i++) alert( i );
15 | ```
16 | 2. 前缀形式:
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 | 我们使用 "modulo" 运算符 `%` 来获取余数,并检查奇偶性。
12 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/13-while-for/4-for-even/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 使用 for 循环输出偶数
6 |
7 | 使用 `for` 循环输出从 `2` 到 `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 | # 用 "while" 替换 "for"
6 |
7 | 重写代码,在保证不改变其行为的情况下,将 `for` 循环更改为 `while`(输出应保持不变)。
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/13-while-for/6-repeat-until-correct/solution.md:
--------------------------------------------------------------------------------
1 |
2 | ```js run demo
3 | let num;
4 |
5 | do {
6 | num = prompt("Enter a number greater than 100?", 0);
7 | } while (num <= 100 && num);
8 | ```
9 |
10 | 两个检查都为真时,继续执行 `do..while` 循环:
11 |
12 | 1. 检查 `num <= 100` —— 即输入值仍然不大于 `100`。
13 | 2. 当 `num` 为 `null` 或空字符串时,`&& num` 的结果为 false。那么 `while` 循环也会停止。
14 |
15 | P.S. 如果 `num` 为 `null`,那么 `num <= 100` 为 `true`。因此用户单击取消,如果没有第二次检查,循环就不会停止。两次检查都是必须的。
16 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/13-while-for/6-repeat-until-correct/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 | ---
3 |
4 | # 重复输入,直到正确为止
5 |
6 | 编写一个提示用户输入大于 `100` 的数字的循环。如果用户输入其他数值 —— 请他重新输入。
7 |
8 | 循环一直在请求一个数字,直到用户输入了一个大于 `100` 的数字、取消输入或输入了一个空行为止。
9 |
10 | 在这我们假设用户只会输入数字。在本题目中,不需要对非数值输入进行特殊处理。
11 |
12 | [demo]
13 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/13-while-for/7-list-primes/task.md:
--------------------------------------------------------------------------------
1 | importance: 3
2 |
3 | ---
4 |
5 | # 输出素数(prime)
6 |
7 | 大于 `1` 且不能被除了 `1` 和它本身以外的任何数整除的整数叫做[素数](https://en.wikipedia.org/wiki/Prime_number)。
8 |
9 | 换句话说,`n > 1` 且不能被 `1` 和 `n` 以外的任何数整除的整数,被称为素数。
10 |
11 | 例如,`5` 是素数,因为它不能被 `2`、`3` 和 `4` 整除,会产生余数。
12 |
13 | **写一个可以输出 `2` 到 `n` 之间的所有素数的代码。**
14 |
15 | 当 `n = 10`,结果输出 `2、3、5、7`。
16 |
17 | P.S. 代码应适用于任何 `n`,而不是对任何固定值进行硬性调整。
18 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/14-switch/2-rewrite-if-switch/task.md:
--------------------------------------------------------------------------------
1 | importance: 4
2 |
3 | ---
4 |
5 | # 将 "if" 结构重写为 "switch" 结构
6 |
7 | 用 `switch` 重写以下代码:
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 | 没有区别。
2 |
3 | 在这两种情况下,`return confirm('父母允许吗?')` 均只会在 `if` 条件为假时执行。
4 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/solution.md:
--------------------------------------------------------------------------------
1 | 使用问号运算符 `'?'`:
2 |
3 | ```js
4 | function checkAge(age) {
5 | return (age > 18) ? true : confirm('Did parents allow you?');
6 | }
7 | ```
8 |
9 | 使用或运算符 `||`(最短的变体):
10 |
11 | ```js
12 | function checkAge(age) {
13 | return (age > 18) || confirm('Did parents allow you?');
14 | }
15 | ```
16 |
17 | 请注意此处不需要 `age > 18` 左右的括号。写上括号是为了提高可读性。
18 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/15-function-basics/3-min/solution.md:
--------------------------------------------------------------------------------
1 | 使用 `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 | 使用问号运算符 `'?'` 的解决方案:
14 |
15 | ```js
16 | function min(a, b) {
17 | return a < b ? a : b;
18 | }
19 | ```
20 |
21 | P.S. 在 `a == b` 的情况下,返回什么都无关紧要。
22 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/15-function-basics/3-min/task.md:
--------------------------------------------------------------------------------
1 | importance: 1
2 |
3 | ---
4 |
5 | # 函数 min(a, b)
6 |
7 | 写一个返回数字 `a` 和 `b` 中较小的那个数字的函数 `min(a,b)`。
8 |
9 | 例如:
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/15-function-basics/4-pow/task.md:
--------------------------------------------------------------------------------
1 | importance: 4
2 |
3 | ---
4 |
5 | # 函数 pow(x,n)
6 |
7 | 写一个函数 `pow(x,n)`,返回 `x` 的 `n` 次方。换句话说,将 `x` 与自身相乘 `n` 次,返回最终结果。
8 |
9 | ```js
10 | pow(3, 2) = 3 * 3 = 9
11 | pow(3, 3) = 3 * 3 * 3 = 27
12 | pow(1, 100) = 1 * 1 * ...*1 = 1
13 | ```
14 |
15 | 创建一个 web 页面,提示输入 `x` 和 `n`,然后返回 `pow(x,n)` 的运算结果。
16 |
17 | [demo]
18 |
19 | P.S. 在这个任务中,函数应该只支持自然数 `n`:从 `1` 开始的整数。
20 |
--------------------------------------------------------------------------------
/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 | 是不是看起来精简多了?
18 |
--------------------------------------------------------------------------------
/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/task.md:
--------------------------------------------------------------------------------
1 |
2 | # 用箭头函数重写
3 |
4 | 用箭头函数重写下面的函数表达式:
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 基础知识
2 |
3 | 让我们来一起学习 JavaScript 脚本构建的基础知识。
4 |
--------------------------------------------------------------------------------
/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 | # 测试代码中有什么错误?
6 |
7 | 下面这个 `pow` 的测试代码有什么错误?
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 | 附:从语法上来说这些测试代码是正确且通过的。
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-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 | # 代码质量
2 |
3 | 本章介绍了我们将在开发中进一步使用的编码实践。
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 | # 你好,对象
6 |
7 | 按下面的要求写代码,一条对应一行代码:
8 |
9 | 1. 创建一个空的对象 `user`。
10 | 2. 为这个对象增加一个属性,键是 `name`,值是 `John`。
11 | 3. 再增加一个属性,键是 `surname`,值是 `Smith`。
12 | 4. 把键为 `name` 的属性的值改成 `Pete`。
13 | 5. 删除这个对象中键为 `name` 的属性。
14 |
--------------------------------------------------------------------------------
/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 | // 如果进到循环里面,说明有属性。
4 | return false;
5 | }
6 | return true;
7 | }
--------------------------------------------------------------------------------
/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 | 只需要遍历这个对象,如果对象存在任何属性则 `return false`。
2 |
--------------------------------------------------------------------------------
/1-js/04-object-basics/01-object/3-is-empty/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 检查空对象
6 |
7 | 写一个 `isEmpty(obj)` 函数,当对象没有属性的时候返回 `true`,否则返回 `false`。
8 |
9 | 应该像这样:
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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/1-js/04-object-basics/01-object/5-sum-object/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 对象属性求和
6 |
7 | 我们有一个保存着团队成员工资的对象:
8 |
9 | ```js
10 | let salaries = {
11 | John: 100,
12 | Ann: 160,
13 | Pete: 130
14 | }
15 | ```
16 |
17 | 写一段代码求出我们的工资总和,将计算结果保存到变量 `sum`。从所给的信息来看,结果应该是 `390`。
18 |
19 | 如果 `salaries` 是一个空对象,那结果就为 `0`。
20 |
--------------------------------------------------------------------------------
/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 | /* 你的代码 */
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/zh.javascript.info/e41b584cd6b44d001d8ead96e9005f60d9f06dca/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 | # 在对象字面量中使用 "this"
6 |
7 | 这里 `makeUser` 函数返回了一个对象。
8 |
9 | 访问 `ref` 的结果是什么?为什么?
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 ); // 结果是什么?
22 | ```
23 |
--------------------------------------------------------------------------------
/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/7-calculator/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 创建一个计算器
6 |
7 | 创建一个有三个方法的 `calculator` 对象:
8 |
9 | - `read()` 提示输入两个值,并将其保存为对象属性,属性名分别为 `a` 和 `b`。
10 | - `sum()` 返回保存的值的和。
11 | - `mul()` 将保存的值相乘并返回计算结果。
12 |
13 | ```js
14 | let calculator = {
15 | // ……你的代码……
16 | };
17 |
18 | calculator.read();
19 | alert( calculator.sum() );
20 | alert( calculator.mul() );
21 | ```
22 |
23 | [demo]
24 |
--------------------------------------------------------------------------------
/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 | 是的,这是可以的。
2 |
3 | 如果一个函数返回一个对象,那么 `new` 返回那个对象而不是 `this`。
4 |
5 | 所以它们可以,例如,返回相同的外部定义的对象 `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 | # 两个函数 —— 一个对象
6 |
7 | 是否可以创建像 `new A() == new B()` 这样的函数 `A` 和 `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 | 如果可以,请提供一个它们的代码示例。
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/2-calculator-constructor/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 创建 new Calculator
6 |
7 | 创建一个构造函数 `Calculator`,它创建的对象中有三个方法:
8 |
9 | - `read()` 使用 `prompt` 请求两个值并把它们记录在对象的属性中。
10 | - `sum()` 返回这些属性的总和。
11 | - `mul()` 返回这些属性的乘积。
12 |
13 | 例如:
14 |
15 | ```js
16 | let calculator = new Calculator();
17 | calculator.read();
18 |
19 | alert( "Sum=" + calculator.sum() );
20 | alert( "Mul=" + calculator.mul() );
21 | ```
22 |
23 | [demo]
24 |
--------------------------------------------------------------------------------
/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 | # Object(对象):基础知识
2 |
--------------------------------------------------------------------------------
/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 我能为字符串添加一个属性吗?
6 |
7 |
8 | 思考下面的代码:
9 |
10 | ```js
11 | let str = "Hello";
12 |
13 | str.test = 5;
14 |
15 | alert(str.test);
16 | ```
17 |
18 | 你怎么想的呢,它会工作吗?会得到什么样的结果?
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 | 注意在 `prompt` 前面的一元加号 `+`。它将立即把值转换成数字。
11 |
12 | 否则,`a` 和 `b` 将会是字符串,它们的总和将是它们的连接,即:`"1" + "2" = "12"`。
13 |
--------------------------------------------------------------------------------
/1-js/05-data-types/02-number/1-sum-interface/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 来自访问者的数字的总和
6 |
7 | 创建一个脚本,提示访问者输入两个数字,然后显示它们的总和。
8 |
9 | [demo]
10 |
11 | P.S. 有一个类型陷阱。
12 |
--------------------------------------------------------------------------------
/1-js/05-data-types/02-number/2-why-rounded-down/task.md:
--------------------------------------------------------------------------------
1 | importance: 4
2 |
3 | ---
4 |
5 | # 为什么 6.35.toFixed(1) == 6.3?
6 |
7 | 根据文档,`Math.round` 和 `toFixed` 都将数字舍入到最接近的数字:`0..4` 会被舍去,而 `5..9` 会进一位。
8 |
9 | 例如:
10 |
11 | ```js run
12 | alert( 1.35.toFixed(1) ); // 1.4
13 | ```
14 |
15 | 在下面这个类似的示例中,为什么 `6.35` 被舍入为 `6.3` 而不是 `6.4`?
16 |
17 | ```js run
18 | alert( 6.35.toFixed(1) ); // 6.3
19 | ```
20 |
21 | 如何以正确的方式来对 `6.35` 进行舍入?
22 |
23 |
--------------------------------------------------------------------------------
/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 | # 重复,直到输入的是一个数字
6 |
7 | 创建一个函数 `readNumber`,它提示输入一个数字,直到访问者输入一个有效的数字为止。
8 |
9 | 结果值必须以数字形式返回。
10 |
11 | 访问者也可以通过输入空行或点击“取消”来停止该过程。在这种情况下,函数应该返回 `null`。
12 |
13 | [demo]
14 |
15 |
--------------------------------------------------------------------------------
/1-js/05-data-types/02-number/4-endless-loop-error/solution.md:
--------------------------------------------------------------------------------
1 | 那是因为 `i` 永远不会等于 `10`。
2 |
3 | 运行下面这段代码来查看 `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 | 它们中没有一个恰好是 `10`。
14 |
15 | 之所以发生这种情况,是因为对 `0.2` 这样的小数时进行加法运算时出现了精度损失。
16 |
17 | 结论:在处理小数时避免相等性检查。
18 |
--------------------------------------------------------------------------------
/1-js/05-data-types/02-number/4-endless-loop-error/task.md:
--------------------------------------------------------------------------------
1 | importance: 4
2 |
3 | ---
4 |
5 | # 一个偶发的无限循环
6 |
7 | 这是一个无限循环。它永远不会结束。为什么?
8 |
9 | ```js
10 | let i = 0;
11 | while (i != 10) {
12 | i += 0.2;
13 | }
14 | ```
15 |
16 |
--------------------------------------------------------------------------------
/1-js/05-data-types/02-number/8-random-min-max/solution.md:
--------------------------------------------------------------------------------
1 | 我们需要将区间 0..1 中的所有值“映射”为范围在 `min` 到 `max` 中的值。
2 |
3 | 这可以分两个阶段完成:
4 |
5 | 1. 如果我们将 0..1 的随机数乘以 `max-min`,则随机数的范围将从 0..1 增加到 `0..max-min`。
6 | 2. 现在,如果我们将随机数与 `min` 相加,则随机数的范围将为 `min` 到 `max`。
7 |
8 | 函数实现:
9 |
10 | ```js run
11 | function random(min, max) {
12 | return min + Math.random() * (max - min);
13 | }
14 |
15 | alert( random(1, 5) );
16 | alert( random(1, 5) );
17 | alert( random(1, 5) );
18 | ```
19 |
20 |
--------------------------------------------------------------------------------
/1-js/05-data-types/02-number/8-random-min-max/task.md:
--------------------------------------------------------------------------------
1 | importance: 2
2 |
3 | ---
4 |
5 | # 从 min 到 max 的随机数
6 |
7 | 内建函数 `Math.random()` 会创建一个在 `0` 到 `1` 之间(不包括 `1`)的随机数。
8 |
9 | 编写一个 `random(min, max)` 函数,用以生成一个在 `min` 到 `max` 之间的随机浮点数(不包括 `max`))。
10 |
11 | 运行示例:
12 |
13 | ```js
14 | alert( random(1, 5) ); // 1.2345623452
15 | alert( random(1, 5) ); // 3.7894332423
16 | alert( random(1, 5) ); // 4.3435234525
17 | ```
18 |
--------------------------------------------------------------------------------
/1-js/05-data-types/02-number/9-random-int-min-max/task.md:
--------------------------------------------------------------------------------
1 | importance: 2
2 |
3 | ---
4 |
5 | # 从 min 到 max 的随机整数
6 |
7 | 创建一个函数 `randomInteger(min, max)`,该函数会生成一个范围在 `min` 到 `max` 中的随机整数,包括 `min` 和 `max`。
8 |
9 | 在 `min..max` 范围中的所有数字的出现概率必须相同。
10 |
11 |
12 | 运行示例:
13 |
14 | ```js
15 | alert( randomInteger(1, 5) ); // 1
16 | alert( randomInteger(1, 5) ); // 3
17 | alert( randomInteger(1, 5) ); // 5
18 | ```
19 |
20 | 你可以使用 [上一个任务](info:task/random-min-max) 的解决方案作为基础。
21 |
--------------------------------------------------------------------------------
/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 | # 首字母大写
6 |
7 | 写一个函数 `ucFirst(str)`,并返回首字母大写的字符串 `str`,例如:
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 | 为了使搜索不区分大小写,我们将字符串改为小写,然后搜索:
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 | # 检查 spam
6 |
7 | 写一个函数 `checkSpam(str)`,如果 `str` 包含 `viagra` 或 `XXX` 就返回 `true`,否则返回 `false`。
8 |
9 | 函数必须不区分大小写:
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/solution.md:
--------------------------------------------------------------------------------
1 | 最大长度必须是 `maxlength`,因此为了给省略号留空间我们需要缩短它。
2 |
3 | 请注意,省略号实际上有一个单独的 Unicode 字符,而不是三个点。
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/3-truncate/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 截断文本
6 |
7 | 创建函数 `truncate(str, maxlength)` 来检查 `str` 的长度,如果超过 `maxlength` —— 应使用 `"…"` 来代替 `str` 的结尾部分,长度仍然等于 `maxlength`。
8 |
9 | 函数的结果应该是截断后的文本(如果需要的话)。
10 |
11 | 例如:
12 |
13 | ```js
14 | truncate("What I'd like to tell on this topic is:", 20) = "What I'd like to te…"
15 |
16 | truncate("Hi everyone!", 20) = "Hi everyone!"
17 | ```
18 |
--------------------------------------------------------------------------------
/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/zh.javascript.info/e41b584cd6b44d001d8ead96e9005f60d9f06dca/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 | # 提取货币
6 |
7 | 我们有以 `"$120"` 这样的格式表示的花销。意味着:先是美元符号,然后才是数值。
8 |
9 | 创建函数 `extractCurrencyValue(str)` 从字符串中提取数值并返回。
10 |
11 | 例如:
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 | 结果是 `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 | 这是因为数组是对象。所以 `shoppingCart` 和 `fruits` 是同一数组的引用。
17 |
18 |
--------------------------------------------------------------------------------
/1-js/05-data-types/04-array/1-item-value/task.md:
--------------------------------------------------------------------------------
1 | importance: 3
2 |
3 | ---
4 |
5 | # 数组被拷贝了吗?
6 |
7 | 下面的代码将会显示什么?
8 |
9 | ```js
10 | let fruits = ["Apples", "Pear", "Orange"];
11 |
12 | // 在“副本”里 push 了一个新的值
13 | let shoppingCart = fruits;
14 | shoppingCart.push("Banana");
15 |
16 | // fruits 里面是什么?
17 | alert( fruits.length ); // ?
18 | ```
19 |
--------------------------------------------------------------------------------
/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/solution.md:
--------------------------------------------------------------------------------
1 | `arr[2]()` 调用从句法来看可以类比于 `obj[method]()`,与 `obj` 对应的是 `arr`,与 `method` 对应的是 `2`。
2 |
3 | 所以调用 `arr[2]` 函数也就是调用对象函数。自然地,它接收 `this` 引用的对象 `arr` 然后输出该数组:
4 |
5 | ```js run
6 | let arr = ["a", "b"];
7 |
8 | arr.push(function() {
9 | alert( this );
10 | })
11 |
12 | arr[2](); // a,b,function(){...}
13 | ```
14 |
15 | 该数组有 3 项:最开始有两个,后来添加进来一个函数。
16 |
--------------------------------------------------------------------------------
/1-js/05-data-types/04-array/3-call-array-this/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 在数组上下文调用
6 |
7 | 结果是什么?为什么?
8 |
9 | ```js
10 | let arr = ["a", "b"];
11 |
12 | arr.push(function() {
13 | alert( this );
14 | });
15 |
16 | arr[2](); // ?
17 | ```
18 |
--------------------------------------------------------------------------------
/1-js/05-data-types/04-array/5-array-input-sum/task.md:
--------------------------------------------------------------------------------
1 | importance: 4
2 |
3 | ---
4 |
5 | # 输入数字求和
6 |
7 | 写出函数 `sumInput()`,要求如下:
8 |
9 | - 使用 `prompt` 向用户索要值,并存在数组中。
10 | - 当用户输入了非数字、空字符串或者点击“取消”按钮的时候,问询结束。
11 | - 计算并返回数组所有项之和。
12 |
13 | P.S. `0` 是有效的数字,不要因为是 0 就停止问询。
14 |
15 | [demo]
16 |
--------------------------------------------------------------------------------
/1-js/05-data-types/05-array-methods/1-camelcase/solution.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javascript-tutorial/zh.javascript.info/e41b584cd6b44d001d8ead96e9005f60d9f06dca/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 | # 数组去重
6 |
7 | `arr` 是一个数组。
8 |
9 | 创建一个函数 `unique(arr)`,返回去除重复元素后的数组 `arr`。
10 |
11 | 例如:
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/zh.javascript.info/e41b584cd6b44d001d8ead96e9005f60d9f06dca/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/solution.md:
--------------------------------------------------------------------------------
1 | ```js run demo
2 | function filterRange(arr, a, b) {
3 | // 在表达式周围添加了括号,以提高可读性
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(匹配的值)
12 |
13 | alert( arr ); // 5,3,8,1(未经改动的数组中的值)
14 | ```
15 |
--------------------------------------------------------------------------------
/1-js/05-data-types/05-array-methods/2-filter-range/task.md:
--------------------------------------------------------------------------------
1 | importance: 4
2 |
3 | ---
4 |
5 | # 过滤范围
6 |
7 | 写一个函数 `filterRange(arr, a, b)`,该函数获取一个数组 `arr`,在其中查找数值大于或等于 `a`,且小于或等于 `b` 的元素,并将结果以数组的形式返回。
8 |
9 | 该函数不应该修改原数组。它应该返回新的数组。
10 |
11 | 例如:
12 |
13 | ```js
14 | let arr = [5, 3, 8, 1];
15 |
16 | let filtered = filterRange(arr, 1, 4);
17 |
18 | alert( filtered ); // 3,1(匹配值)
19 |
20 | alert( arr ); // 5,3,8,1(未修改)
21 | ```
22 |
23 |
--------------------------------------------------------------------------------
/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/3-filter-range-in-place/solution.md:
--------------------------------------------------------------------------------
1 | ```js run demo
2 | function filterRangeInPlace(arr, a, b) {
3 |
4 | for (let i = 0; i < arr.length; i++) {
5 | let val = arr[i];
6 |
7 | // 如果超出范围,则删除
8 | if (val < a || val > b) {
9 | arr.splice(i, 1);
10 | i--;
11 | }
12 | }
13 |
14 | }
15 |
16 | let arr = [5, 3, 8, 1];
17 |
18 | filterRangeInPlace(arr, 1, 4); // 删除 1 到 4 范围之外的值
19 |
20 | alert( arr ); // [3, 1]
21 | ```
22 |
--------------------------------------------------------------------------------
/1-js/05-data-types/05-array-methods/3-filter-range-in-place/task.md:
--------------------------------------------------------------------------------
1 | importance: 4
2 |
3 | ---
4 |
5 | # 原位(in place)过滤范围
6 |
7 | 写一个函数 `filterRangeInPlace(arr, a, b)`,该函数获取一个数组 `arr`,并删除其中介于 `a` 和 `b` 区间以外的所有值。检查:`a ≤ arr[i] ≤ b`。
8 |
9 | 该函数应该只修改数组。它不应该返回任何东西。
10 |
11 | 例如:
12 | ```js
13 | let arr = [5, 3, 8, 1];
14 |
15 | filterRangeInPlace(arr, 1, 4); // 删除了范围在 1 到 4 之外的所有值
16 |
17 | alert( arr ); // [3, 1]
18 | ```
19 |
--------------------------------------------------------------------------------
/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 | # 降序排列
6 |
7 | ```js
8 | let arr = [5, 2, 1, -10, 8];
9 |
10 | // ……你的代码以降序对其进行排序
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 | 我们可以使用 `slice()` 来创建一个副本并对其进行排序:
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 | # 复制和排序数组
6 |
7 | 我们有一个字符串数组 `arr`。我们希望有一个排序过的副本,但保持 `arr` 不变。
8 |
9 | 创建一个函数 `copySorted(arr)` 返回这样一个副本。
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 | - 请注意方法的存储方式。它们只是被添加到 `this.methods` 属性中。
3 | - 所有检测和数字转换都通过 `calculate` 方法完成。将来可能会扩展它以支持更复杂的表达式。
4 |
--------------------------------------------------------------------------------
/1-js/05-data-types/05-array-methods/9-shuffle/task.md:
--------------------------------------------------------------------------------
1 | importance: 3
2 |
3 | ---
4 |
5 | # 随机排列数组
6 |
7 | 编写函数 `shuffle(array)` 来随机排列数组的元素。
8 |
9 | 多次运行 `shuffle` 可能导致元素顺序的不同。例如:
10 |
11 | ```js
12 | let arr = [1, 2, 3];
13 |
14 | shuffle(arr);
15 | // arr = [3, 2, 1]
16 |
17 | shuffle(arr);
18 | // arr = [2, 1, 3]
19 |
20 | shuffle(arr);
21 | // arr = [3, 1, 2]
22 | // ...
23 | ```
24 |
25 | 所有元素顺序应该具有相等的概率。例如,可以将 `[1,2,3]` 重新排序为 `[1,2,3]` 或 `[1,3,2]` 或 `[3,1,2]` 等,每种情况的概率相等。
26 |
--------------------------------------------------------------------------------
/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/zh.javascript.info/e41b584cd6b44d001d8ead96e9005f60d9f06dca/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 | 这是因为 `map.keys()` 返回的是可迭代对象而非数组。
3 |
4 | 我们可以使用方法 `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/07-map-set/03-iterable-keys/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 迭代键
6 |
7 | 我们期望使用 `map.keys()` 得到一个数组,然后使用例如 `.push` 等特定的方法对其进行处理。
8 |
9 | 但是运行不了:
10 |
11 | ```js run
12 | let map = new Map();
13 |
14 | map.set("name", "John");
15 |
16 | let keys = map.keys();
17 |
18 | *!*
19 | // Error: keys.push is not a function
20 | keys.push("more");
21 | */!*
22 | ```
23 |
24 | 为什么?我们应该如何修改代码让 `keys.push` 工作?
25 |
--------------------------------------------------------------------------------
/1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/solution.md:
--------------------------------------------------------------------------------
1 |
2 | 我们可以使用 `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 对象
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/01-sum-salaries/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 属性求和
6 |
7 | 有一个带有任意数量薪水的 `salaries` 对象。
8 |
9 | 编写函数 `sumSalaries(salaries)`,该函数使用 `Object.values` 和 `for..of` 循环返回所有薪水的总和。
10 |
11 | 如果 `salaries` 是空对象,那么结果必须是 `0`。
12 |
13 | 举个例子:
14 |
15 | ```js
16 | let salaries = {
17 | "John": 100,
18 | "Pete": 300,
19 | "Mary": 250
20 | };
21 |
22 | alert( sumSalaries(salaries) ); // 650
23 | ```
24 |
25 |
--------------------------------------------------------------------------------
/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/zh.javascript.info/e41b584cd6b44d001d8ead96e9005f60d9f06dca/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 | # 计算属性数量
6 |
7 | 写一个函数 `count(obj)`,该函数返回对象中的属性的数量:
8 |
9 | ```js
10 | let user = {
11 | name: 'John',
12 | age: 30
13 | };
14 |
15 | alert( count(user) ); // 2
16 | ```
17 |
18 | 试着使代码尽可能简短。
19 |
20 | P.S. 忽略 Symbol 类型属性,只计算“常规”属性。
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 | ```
14 |
--------------------------------------------------------------------------------
/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(let [name, salary] of Object.entries(salaries)) {
7 | if (maxSalary < salary) {
8 | maxSalary = salary;
9 | maxName = name;
10 | }
11 | }
12 |
13 | return maxName;
14 | }
15 |
--------------------------------------------------------------------------------
/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/zh.javascript.info/e41b584cd6b44d001d8ead96e9005f60d9f06dca/1-js/05-data-types/10-destructuring-assignment/6-max-salary/solution.md
--------------------------------------------------------------------------------
/1-js/05-data-types/10-destructuring-assignment/6-max-salary/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 最高薪资
6 |
7 | 这儿有一个 `salaries` 对象:
8 |
9 | ```js
10 | let salaries = {
11 | "John": 100,
12 | "Pete": 300,
13 | "Mary": 250
14 | };
15 | ```
16 |
17 | 新建一个函数 `topSalary(salaries)`,返回收入最高的人的姓名。
18 |
19 | - 如果 `salaries` 是空的,函数应该返回 `null`。
20 | - 如果有多个收入最高的人,返回其中任意一个即可。
21 |
22 | P.S. 使用 `Object.entries` 和解构语法来遍历键/值对。
23 |
--------------------------------------------------------------------------------
/1-js/05-data-types/11-date/1-new-date/solution.md:
--------------------------------------------------------------------------------
1 | `new Date` 构造函数默认使用本地时区。所以唯一需要牢记的就是月份从 0 开始计数。
2 |
3 | 所以二月对应的数值是 1。
4 |
5 | 这是一个以数字作为日期参数的示例:
6 |
7 | ```js run
8 | // new Date(year, month, date, hour, minute, second, millisecond)
9 | let d1 = new Date(2012, 1, 20, 3, 12);
10 | alert( d1 );
11 | ```
12 | 我们还可以从字符串创建日期,像这样:
13 |
14 | ```js run
15 | // new Date(datestring)
16 | let d2 = new Date("2012-02-20T03:12");
17 | alert( d2 );
18 | ```
19 |
--------------------------------------------------------------------------------
/1-js/05-data-types/11-date/1-new-date/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 创建日期
6 |
7 | 创建一个 `Date` 对象,日期是:Feb 20, 2012, 3:12am。时区是当地时区。
8 |
9 | 使用 `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 | `date.getDay()` 方法返回从星期日开始的星期数。
2 |
3 | 我们创建一个关于星期的数组,这样我们就可以通过编号获取正确的日期名称:
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 | # 显示星期数
6 |
7 | 编写一个函数 `getWeekDay(date)` 以短格式来显示一个日期的星期数:'MO','TU','WE','TH','FR','SA','SU'。
8 |
9 | 例如:
10 |
11 | ```js no-beautify
12 | let date = new Date(2012, 0, 3); // 3 Jan 2012
13 | alert( getWeekDay(date) ); // 应该输出 "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:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/1-js/05-data-types/11-date/3-weekday/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 欧洲的星期表示方法
6 |
7 | 欧洲国家的星期计算是从星期一(数字 1)开始的,然后是星期二(数字 2),直到星期日(数字 7)。编写一个函数 `getLocalDay(date)`,并返回日期的欧洲式星期数。
8 |
9 | ```js no-beautify
10 | let date = new Date(2012, 0, 3); // 3 Jan 2012
11 | alert( getLocalDay(date) ); // 星期二,应该显示 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/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 某月的最后一天?
6 |
7 | 写一个函数 `getLastDayOfMonth(year, month)` 返回 month 月的最后一天。有时候是 30,有时是 31,甚至在二月的时候会是 28/29。
8 |
9 | 参数:
10 |
11 | - `year` —— 四位数的年份,比如 2012。
12 | - `month` —— 月份,从 0 到 11。
13 |
14 | 举个例子,`getLastDayOfMonth(2012, 1) = 29`(闰年,二月)
15 |
--------------------------------------------------------------------------------
/1-js/05-data-types/11-date/6-get-seconds-today/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 今天过去了多少秒?
6 |
7 | 写一个函数 `getSecondsToday()`,返回今天已经过去了多少秒?
8 |
9 | 例如:如果现在是 `10:00 am`,并且没有夏令时转换,那么:
10 |
11 | ```js
12 | getSecondsToday() == 36000 // (3600 * 10)
13 | ```
14 |
15 | 该函数应该在任意一天都能正确运行。那意味着,它不应具有“今天”的硬编码值。
16 |
--------------------------------------------------------------------------------
/1-js/05-data-types/11-date/7-get-seconds-to-tomorrow/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 距离明天还有多少秒?
6 |
7 | 写一个函数 `getSecondsToTomorrow()`,返回距离明天的秒数。
8 |
9 | 例如,现在是 `23:00`,那么:
10 |
11 | ```js
12 | getSecondsToTomorrow() == 3600
13 | ```
14 |
15 | P.S. 该函数应该在任意一天都能正确运行。那意味着,它不应具有“今天”的硬编码值。
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 | # 将对象转换为 JSON,然后再转换回来
6 |
7 | 将 `user` 转换为 JSON,然后将其转换回到另一个变量。
8 |
9 | ```js
10 | let user = {
11 | name: "John Smith",
12 | age: 35
13 | };
14 | ```
15 |
--------------------------------------------------------------------------------
/1-js/05-data-types/index.md:
--------------------------------------------------------------------------------
1 | # 数据类型
2 |
3 | 更多的数据结构和更深入的类型研究。
4 |
--------------------------------------------------------------------------------
/1-js/06-advanced-functions/01-recursion/05-output-single-linked-list-reverse/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 反向输出单链表
6 |
7 | 反向输出前一个任务 中的单链表。
8 |
9 | 使用两种解法:循环和递归。
10 |
--------------------------------------------------------------------------------
/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/solution.md:
--------------------------------------------------------------------------------
1 | 答案:**Pete**。
2 |
3 | 函数将从内到外依次在对应的词法环境中寻找目标变量,它使用最新的值。
4 |
5 | 旧变量值不会保存在任何地方。当一个函数想要一个变量时,它会从自己的词法环境或外部词法环境中获取当前值。
6 |
--------------------------------------------------------------------------------
/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 函数会选择最新的内容吗?
6 |
7 | 函数 sayHi 使用外部变量。当函数运行时,将使用哪个值?
8 |
9 | ```js
10 | let name = "John";
11 |
12 | function sayHi() {
13 | alert("Hi, " + name);
14 | }
15 |
16 | name = "Pete";
17 |
18 | sayHi(); // 会显示什么:"John" 还是 "Pete"?
19 | ```
20 |
21 | 这种情况在浏览器和服务器端开发中都很常见。一个函数可能被计划在创建之后一段时间后才执行,例如在用户行为或网络请求之后。
22 |
23 | 因此,问题是:它会接收最新的修改吗?
24 |
--------------------------------------------------------------------------------
/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 | 答案:**Pete**.
2 |
3 | 下方代码中的函数 `work()` 在其被创建的位置通过外部词法环境引用获取 `name`:
4 |
5 | 
6 |
7 | 所以这里的结果是 `"Pete"`。
8 |
9 | 但如果在 `makeWorker()` 中没有 `let name`,那么将继续向外搜索并最终找到全局变量,正如我们可以从上图中看到的那样。在这种情况下,结果将是 `"John"`。
10 |
--------------------------------------------------------------------------------
/1-js/06-advanced-functions/03-closure/3-counter-independent/solution.md:
--------------------------------------------------------------------------------
1 | 答案是:**0,1。**
2 |
3 | 函数 `counter` 和 `counter2` 是通过 `makeCounter` 的不同调用创建的。
4 |
5 | 因此,它们具有独立的外部词法环境,每一个都有自己的 `count`。
6 |
--------------------------------------------------------------------------------
/1-js/06-advanced-functions/03-closure/5-function-in-if/solution.md:
--------------------------------------------------------------------------------
1 | 答案:**error**。
2 |
3 | 函数 `sayHi` 是在 `if` 内声明的,所以它只存在于 `if` 中。外部是没有 `sayHi` 的。
4 |
--------------------------------------------------------------------------------
/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # if 内的函数
6 |
7 | 看看下面这个代码。最后一行代码的执行结果是什么?
8 |
9 | ```js run
10 | let phrase = "Hello";
11 |
12 | if (true) {
13 | let user = "John";
14 |
15 | function sayHi() {
16 | alert(`${phrase}, ${user}`);
17 | }
18 | }
19 |
20 | *!*
21 | sayHi();
22 | */!*
23 | ```
24 |
--------------------------------------------------------------------------------
/1-js/06-advanced-functions/03-closure/6-closure-sum/solution.md:
--------------------------------------------------------------------------------
1 | 为了使第二个括号有效,第一个(括号)必须返回一个函数。
2 |
3 | 就像这样:
4 |
5 | ```js run
6 | function sum(a) {
7 |
8 | return function(b) {
9 | return a + b; // 从外部词法环境获得 "a"
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
6 |
7 | 编写一个像 `sum(a)(b) = a+b` 这样工作的 `sum` 函数。
8 |
9 | 是的,就是这种通过双括号的方式(并不是错误)。
10 |
11 | 举个例子:
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 | # 变量可见吗?
6 |
7 | 下面这段代码的结果会是什么?
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. 这个任务有一个陷阱。解决方案并不明显。
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 | 该解决方案在局部变量中使用 `count`,而进行加法操作的方法是直接写在 `counter` 中的。它们共享同一个外部词法环境,并且可以访问当前的 `count`。
3 |
--------------------------------------------------------------------------------
/1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 为 counter 添加 set 和 decrease 方法
6 |
7 | 修改 `makeCounter()` 代码,使得 counter 可以进行减一和设置值的操作:
8 |
9 | - `counter()` 应该返回下一个数字(与之前的逻辑相同)。
10 | - `counter.set(value)` 应该将 `count` 设置为 `value`。
11 | - `counter.decrease()` 应该把 `count` 减 1。
12 |
13 | 查看沙箱中的代码获取完整使用示例。
14 |
15 | P.S. 你可以使用闭包或者函数属性来保持当前的计数,或者两种都写。
16 |
--------------------------------------------------------------------------------
/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 | # 任意数量的括号求和
6 |
7 | 写一个函数 `sum`,它有这样的功能:
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. 提示:你可能需要创建自定义对象来为你的函数提供基本类型转换。
18 |
--------------------------------------------------------------------------------
/1-js/06-advanced-functions/08-settimeout-setinterval/1-output-numbers-100ms/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 每秒输出一次
6 |
7 | 编写一个函数 `printNumbers(from, to)`,使其每秒输出一个数字,数字从 `from ` 开始,到 `to` 结束。
8 |
9 | 使用以下两种方法来实现。
10 |
11 | 1. 使用 `setInterval`。
12 | 2. 使用嵌套的 `setTimeout`。
13 |
--------------------------------------------------------------------------------
/1-js/06-advanced-functions/08-settimeout-setinterval/4-settimeout-result/solution.md:
--------------------------------------------------------------------------------
1 |
2 | 任何 `setTimeout` 都只会在当前代码执行完毕之后才会执行。
3 |
4 | 所以 `i` 的取值为:`100000000`。
5 |
6 | ```js run
7 | let i = 0;
8 |
9 | setTimeout(() => alert(i), 100); // 100000000
10 |
11 | // 假设这段代码的运行时间 >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 | 由 `spy(f)` 返回的包装器应存储所有参数,然后使用 `f.apply` 转发调用。
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 | 调用 `debounce` 会返回一个包装器。当它被调用时,它会安排一个在给定的 `ms` 之后对原始函数的调用,并取消之前的此类超时。
12 |
--------------------------------------------------------------------------------
/1-js/06-advanced-functions/10-bind/2-write-to-object-after-bind/solution.md:
--------------------------------------------------------------------------------
1 | 答案:`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 | 绑定函数的上下文是硬绑定(hard-fixed)的。没有办法再修改它。
17 |
18 | 所以即使我们执行 `user.g()`,源方法调用时还是 `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 | # 作为方法的绑定函数
6 |
7 | 输出将会是什么?
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 | 答案:**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 | `f.bind(...)` 返回的外来(exotic)[绑定函数](https://tc39.github.io/ecma262/#sec-bound-function-exotic-objects) 对象仅在创建的时候记忆上下文(以及参数,如果提供了的话)。
14 |
15 | 一个函数不能被重绑定(re-bound)。
16 |
--------------------------------------------------------------------------------
/1-js/06-advanced-functions/10-bind/3-second-bind/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 二次 bind
6 |
7 | 我们可以通过额外的绑定改变 `this` 吗?
8 |
9 | 输出将会是什么?
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 | 答案:`undefined`。
2 |
3 | `bind` 的结果是另一个对象。它并没有 `test` 属性。
4 |
5 |
--------------------------------------------------------------------------------
/1-js/06-advanced-functions/10-bind/4-function-property-after-bind/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # bind 后的函数属性
6 |
7 | 函数的属性中有一个值。`bind` 之后它会改变吗?为什么,阐述一下?
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 ); // 输出将会是什么?为什么?
21 | */!*
22 | ```
23 |
24 |
--------------------------------------------------------------------------------
/1-js/06-advanced-functions/10-bind/6-ask-partial/solution.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | 1. 使用包装(wapper)函数,箭头函数很简洁:
4 |
5 | ```js
6 | askPassword(() => user.login(true), () => user.login(false));
7 | ```
8 |
9 | 现在它从外部变量中获得了 `user`,然后以常规方式运行它。
10 |
11 | 2. 或者从 `user.login` 创建一个偏函数,该函数使用 `user` 作为上下文,并具有正确的第一个参数:
12 |
13 |
14 | ```js
15 | askPassword(user.login.bind(user, true), user.login.bind(user, false));
16 | ```
17 |
--------------------------------------------------------------------------------
/1-js/06-advanced-functions/index.md:
--------------------------------------------------------------------------------
1 | # 函数进阶内容
2 |
--------------------------------------------------------------------------------
/1-js/07-object-properties/index.md:
--------------------------------------------------------------------------------
1 | # 对象属性配置
2 |
3 | 在本节中,我们将回到对象,并更深入地研究其属性。
4 |
--------------------------------------------------------------------------------
/1-js/08-prototypes/01-prototype-inheritance/1-property-after-delete/solution.md:
--------------------------------------------------------------------------------
1 |
2 | 1. `true`,来自于 `rabbit`。
3 | 2. `null`,来自于 `animal`。
4 | 3. `undefined`,不再有这样的属性存在。
5 |
--------------------------------------------------------------------------------
/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/solution.md:
--------------------------------------------------------------------------------
1 | **答案:`rabbit`。**
2 |
3 | 这是因为 `this` 是点符号前面的这个对象,因此 `rabbit.eat()` 修改了 `rabbit`。
4 |
5 | 属性查找和执行是两回事儿。
6 |
7 | 首先在原型中找到 `rabbit.eat` 方法,然后在 `this=rabbit` 的情况下执行。
8 |
--------------------------------------------------------------------------------
/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 写在哪里?
6 |
7 | 我们有从 `animal` 中继承的 `rabbit`。
8 |
9 | 如果我们调用 `rabbit.eat()`,哪一个对象会接收到 `full` 属性:`animal` 还是 `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/02-function-prototype/4-new-object-same-constructor/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 使用相同的构造函数创建一个对象
6 |
7 | 想象一下,我们有一个由构造函数创建的对象 `obj` —— 我们不知道使用的是哪个构造函数,但是我们想使用它创建一个新对象。
8 |
9 | 我们可以这样做吗?
10 |
11 | ```js
12 | let obj2 = new obj.constructor();
13 | ```
14 |
15 | 请给出一个可以使这样的代码正常工作的 `obj` 的构造函数的例子。再给出会导致这样的代码无法正确工作的例子。
16 |
--------------------------------------------------------------------------------
/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); // 1 秒后显示 "Hello!"
13 | ```
14 |
--------------------------------------------------------------------------------
/1-js/08-prototypes/03-native-prototypes/1-defer-to-prototype/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 给函数添加一个 "f.defer(ms)" 方法
6 |
7 | 在所有函数的原型中添加 `defer(ms)` 方法,该方法将在 `ms` 毫秒后运行该函数。
8 |
9 | 当你完成添加后,下面的代码应该是可执行的:
10 |
11 | ```js
12 | function f() {
13 | alert("Hello!");
14 | }
15 |
16 | f.defer(1000); // 1 秒后显示 "Hello!"
17 | ```
18 |
--------------------------------------------------------------------------------
/1-js/08-prototypes/03-native-prototypes/2-defer-to-prototype-extended/task.md:
--------------------------------------------------------------------------------
1 | importance: 4
2 |
3 | ---
4 |
5 | # 将装饰器 "defer()" 添加到函数
6 |
7 | 在所有函数的原型中添加 `defer(ms)` 方法,该方法返回一个包装器,将函数调用延迟 `ms` 毫秒。
8 |
9 | 下面是它应该如何执行的例子:
10 |
11 | ```js
12 | function f(a, b) {
13 | alert( a + b );
14 | }
15 |
16 | f.defer(1000)(1, 2); // 1 秒后显示 3
17 | ```
18 |
19 | 请注意,参数应该被传给原始函数。
20 |
--------------------------------------------------------------------------------
/1-js/08-prototypes/03-native-prototypes/console_dir_array.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javascript-tutorial/zh.javascript.info/e41b584cd6b44d001d8ead96e9005f60d9f06dca/1-js/08-prototypes/03-native-prototypes/console_dir_array.png
--------------------------------------------------------------------------------
/1-js/08-prototypes/index.md:
--------------------------------------------------------------------------------
1 | # 原型,继承
2 |
--------------------------------------------------------------------------------
/1-js/09-classes/01-class/1-rewrite-to-class/solution.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javascript-tutorial/zh.javascript.info/e41b584cd6b44d001d8ead96e9005f60d9f06dca/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 | # 重写为 class
6 |
7 | `Clock` 类(请见沙箱)是以函数式编写的。请以 "class" 语法重写它。
8 |
9 | P.S. 时钟在控制台(console)中滴答,打开控制台即可查看。
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/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 扩展 clock
6 |
7 | 我们获得了一个 `Clock` 类。到目前为止,它每秒都会打印一次时间。
8 |
9 |
10 | [js src="source.view/clock.js"]
11 |
12 | 创建一个继承自 `Clock` 的新的类 `ExtendedClock`,并添加参数 `precision` — 每次 "ticks" 之间间隔的毫秒数,默认是 `1000`(1 秒)。
13 |
14 | - 你的代码应该在 `extended-clock.js` 文件里。
15 | - 不要修改原有的 `clock.js`。请扩展它。
16 |
--------------------------------------------------------------------------------
/1-js/09-classes/04-private-protected-properties-methods/coffee-inside.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javascript-tutorial/zh.javascript.info/e41b584cd6b44d001d8ead96e9005f60d9f06dca/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/zh.javascript.info/e41b584cd6b44d001d8ead96e9005f60d9f06dca/1-js/09-classes/04-private-protected-properties-methods/coffee.jpg
--------------------------------------------------------------------------------
/1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md:
--------------------------------------------------------------------------------
1 | 是的,看起来确实很奇怪。
2 |
3 | `instanceof` 并不关心函数,而是关心函数的与原型链匹配的 `prototype`。
4 |
5 | 并且,这里 `a.__proto__ == B.prototype`,所以 `instanceof` 返回 `true`。
6 |
7 | 总之,根据 `instanceof` 的逻辑,真正决定类型的是 `prototype`,而不是构造函数。
8 |
--------------------------------------------------------------------------------
/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 不按套路出牌的 instanceof
6 |
7 | 在下面的代码中,为什么 `instanceof` 会返回 `true`?我们可以明显看到,`a` 并不是通过 `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 | # 类
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 | # 错误处理
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 | 输出为:`1`。
2 |
3 | 第二个对 `resolve` 的调用会被忽略,因为只有第一次对 `reject/resolve` 的调用才会被处理。进一步的调用都会被忽略。
4 |
--------------------------------------------------------------------------------
/1-js/11-async/02-promise-basics/01-re-resolve/task.md:
--------------------------------------------------------------------------------
1 |
2 | # 用 promise 重新解决?
3 |
4 |
5 | 下列这段代码会输出什么?
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 | 请注意,在此任务中 `resolve` 是不带参数调用的。我们不从 `delay` 中返回任何值,只是确保延迟即可。
10 |
--------------------------------------------------------------------------------
/1-js/11-async/02-promise-basics/02-delay-promise/task.md:
--------------------------------------------------------------------------------
1 |
2 | # 基于 promise 的延时
3 |
4 | 内建函数 `setTimeout` 使用了回调函数。请创建一个基于 promise 的替代方案。
5 |
6 | 函数 `delay(ms)` 应该返回一个 promise。这个 promise 应该在 `ms` 毫秒后被 resolve,所以我们可以向其中添加 `.then`,像这样:
7 |
8 | ```js
9 | function delay(ms) {
10 | // 你的代码
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/zh.javascript.info/e41b584cd6b44d001d8ead96e9005f60d9f06dca/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 | # 带有 promise 的圆形动画
3 |
4 | 重写任务 的解决方案中的 `showCircle` 函数,以使其返回一个 promise,而不接受回调。
5 |
6 | 新的用法:
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 | 以任务 的解决方案为基础。
16 |
--------------------------------------------------------------------------------
/1-js/11-async/02-promise-basics/head.html:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/1-js/11-async/03-promise-chaining/01-then-vs-catch/solution.md:
--------------------------------------------------------------------------------
1 | 简要回答就是:**不,它们不相等**:
2 |
3 | 不同之处在于,如果 `f1` 中出现 error,那么在这儿它会被 `.catch` 处理:
4 |
5 | ```js run
6 | promise
7 | .then(f1)
8 | .catch(f2);
9 | ```
10 |
11 | ……在这儿则不会:
12 |
13 | ```js run
14 | promise
15 | .then(f1, f2);
16 | ```
17 |
18 | 这是因为 error 是沿着链传递的,而在第二段代码中,`f1` 下面没有链。
19 |
20 | 换句话说,`.then` 将 result/error 传递给下一个 `.then/.catch`。所以在第一个例子中,在下面有一个 `catch`,而在第二个例子中并没有 `catch`,所以 error 未被处理。
21 |
--------------------------------------------------------------------------------
/1-js/11-async/03-promise-chaining/01-then-vs-catch/task.md:
--------------------------------------------------------------------------------
1 | # Promise:then 对比 catch
2 |
3 | 这两个代码片段是否相等?换句话说,对于任何处理程序(handler),它们在任何情况下的行为都相同吗?
4 |
5 | ```js
6 | promise.then(f1).catch(f2);
7 | ```
8 |
9 | 对比:
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 | 答案是:**不,它不会被触发**:
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 | 正如本章所讲,函数代码周围有个“隐式的 `try..catch`”。所以,所有同步错误都会得到处理。
12 |
13 | 但是这里的错误并不是在 executor 运行时生成的,而是在稍后生成的。因此,promise 无法处理它。
14 |
--------------------------------------------------------------------------------
/1-js/11-async/04-promise-error-handling/01-error-async/task.md:
--------------------------------------------------------------------------------
1 | # setTimeout 中的错误
2 |
3 | 你怎么看?`.catch` 会被触发么?解释你的答案。
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 | 在这种情况下,知道其内部工作原理会很有帮助。
3 |
4 | 只需要把 `async` 调用当作 promise 对待,并在它的后面加上 `.then` 即可:
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 | // 1 秒后显示 10
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 | # Promise,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 | # Generator,高级 iteration
3 |
--------------------------------------------------------------------------------
/1-js/13-modules/01-modules-intro/say.view/index.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/1-js/13-modules/01-modules-intro/say.view/say.js:
--------------------------------------------------------------------------------
1 | export function sayHi(user) {
2 | return `Hello, ${user}!`;
3 | }
4 |
--------------------------------------------------------------------------------
/1-js/13-modules/01-modules-intro/scopes-working.view/hello.js:
--------------------------------------------------------------------------------
1 | import {user} from './user.js';
2 |
3 | document.body.innerHTML = user; // John
4 |
--------------------------------------------------------------------------------
/1-js/13-modules/01-modules-intro/scopes-working.view/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/1-js/13-modules/01-modules-intro/scopes-working.view/user.js:
--------------------------------------------------------------------------------
1 | export let user = "John";
2 |
--------------------------------------------------------------------------------
/1-js/13-modules/01-modules-intro/scopes.view/hello.js:
--------------------------------------------------------------------------------
1 | alert(user); // no such variable (each module has independent variables)
2 |
--------------------------------------------------------------------------------
/1-js/13-modules/01-modules-intro/scopes.view/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/1-js/13-modules/01-modules-intro/scopes.view/user.js:
--------------------------------------------------------------------------------
1 | let user = "John";
2 |
--------------------------------------------------------------------------------
/1-js/13-modules/03-modules-dynamic-imports/say.view/index.html:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
--------------------------------------------------------------------------------
/1-js/13-modules/03-modules-dynamic-imports/say.view/say.js:
--------------------------------------------------------------------------------
1 | export function hi() {
2 | alert(`Hello`);
3 | }
4 |
5 | export function bye() {
6 | alert(`Bye`);
7 | }
8 |
9 | export default function() {
10 | alert("Module loaded (export default)!");
11 | }
12 |
--------------------------------------------------------------------------------
/1-js/13-modules/index.md:
--------------------------------------------------------------------------------
1 | # 模块
2 |
--------------------------------------------------------------------------------
/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 | // 即使我们像 arr[1] 这样访问它
9 | // prop 是一个字符串,所以我们需要将其转换成数字
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 | 让我们使用 `eval` 来计算数学表达式:
2 |
3 | ```js demo run
4 | let expr = prompt("Type an arithmetic expression?", '2*3+2');
5 |
6 | alert( eval(expr) );
7 | ```
8 |
9 | 用户可以输入任意文本或代码。
10 |
11 | 安全起见,并限制其仅进行算术运算,我们可以使用 [正则表达式](info:regular-expressions) 来检查 `expr`,以限制输入的内容只能包含数字和运算符。
12 |
--------------------------------------------------------------------------------
/1-js/99-js-misc/02-eval/1-eval-calculator/task.md:
--------------------------------------------------------------------------------
1 | importance: 4
2 |
3 | ---
4 |
5 | # Eval-计算器
6 |
7 | 创建一个计算器,提示用户输入一个算术表达式,并返回其计算结果。
8 |
9 | 在本题中,你不需要检查表达式是否正确。只需要计算并返回结果。
10 |
11 | [demo]
12 |
--------------------------------------------------------------------------------
/1-js/99-js-misc/04-reference-type/2-check-syntax/task.md:
--------------------------------------------------------------------------------
1 | importance: 2
2 |
3 | ---
4 |
5 | # 检查语法
6 |
7 | 这段代码的结果是什么?
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 | 提示:有一个陷阱哦 :)
20 |
--------------------------------------------------------------------------------
/1-js/99-js-misc/index.md:
--------------------------------------------------------------------------------
1 |
2 | # 杂项
3 |
--------------------------------------------------------------------------------
/1-js/index.md:
--------------------------------------------------------------------------------
1 | # JavaScript 编程语言
2 |
3 | 在这儿我们将从头开始学习 JavaScript,也会学习 OOP 等相关高级概念。
4 |
5 | 本教程专注于语言本身,我们默认使用最小环境。
6 |
--------------------------------------------------------------------------------
/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 子节点
6 |
7 | 对于这个页面:
8 |
9 | ```html
10 |
11 |
12 | Users:
13 |
17 |
18 |
19 | ```
20 |
21 | 对于以下各项,请给出至少一种访问方式:
22 | - `` DOM 节点?
23 | - `
` DOM 节点?
24 | - 第二个 `- ` 节点(即包含 Pete 的节点)?
25 |
--------------------------------------------------------------------------------
/2-ui/1-document/03-dom-navigation/3-navigation-links-which-null/solution.md:
--------------------------------------------------------------------------------
1 | 1. 是的,这是真的。`elem.lastChild` 就是最后一个节点,它没有 `nextSibling`。
2 | 2. 不,这是错的,因为 `elem.children[0]` 是元素中的第一个子元素。但是在它前面可能存在非元素的节点。所以 `previousSibling` 可能是一个文本节点。
3 |
4 | 请注意,对于这两种情况,如果没有子节点,那么就会报错。
5 |
6 | 如果这里没有子节点,那么 `elem.lastChild` 是 `null`,所以我们就访问不到 `elem.lastChild.nextSibling`。并且 `elem.children` 是空的(像一个空数组一样 `[]`)。
7 |
--------------------------------------------------------------------------------
/2-ui/1-document/03-dom-navigation/3-navigation-links-which-null/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 兄弟节点问题
6 |
7 | 如果 `elem` 是任意一个 DOM 元素节点……
8 |
9 | - `elem.lastChild.nextSibling` 值一直都是 `null`,这个判定是不是真的?
10 | - `elem.children[0].previousSibling` 值一直都是 `null`,这个判定是不是真的?
11 |
--------------------------------------------------------------------------------
/2-ui/1-document/03-dom-navigation/4-select-diagonal-cells/solution.md:
--------------------------------------------------------------------------------
1 | 我们将使用 `rows` 和 `cells` 属性来获取表格中的对角单元格。
--------------------------------------------------------------------------------
/2-ui/1-document/03-dom-navigation/4-select-diagonal-cells/task.md:
--------------------------------------------------------------------------------
1 | importance: 5
2 |
3 | ---
4 |
5 | # 选择所有对角单元格
6 |
7 | 编写代码来把表格中的对角单元格都绘制成红色。
8 |
9 | 你需要用代码从 `
` 中获取所有的对角单元格 ``,然后绘制它们:
10 |
11 | ```js
12 | // td 表示的是对单元格的引用
13 | td.style.backgroundColor = 'red';
14 | ```
15 |
16 | 结果应该如下所示:
17 |
18 | [iframe src="solution" height=180]
19 |
--------------------------------------------------------------------------------
/2-ui/1-document/03-dom-navigation/head.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/2-ui/1-document/04-searching-elements-dom/1-find-elements/task.md:
--------------------------------------------------------------------------------
1 | importance: 4
2 |
3 | ---
4 |
5 | # 搜索元素
6 |
7 | 这是带有表格(table)和表单(form)的文档。
8 |
9 | 如何查找?……
10 |
11 | 1. 带有 `id="age-table"` 的表格。
12 | 2. 表格内的所有 `label` 元素(应该有三个)。
13 | 3. 表格中的第一个 `td`(带有 "Age" 字段)。
14 | 4. 带有 `name="search"` 的 `form`。
15 | 5. 表单中的第一个 `input`。
16 | 6. 表单中的最后一个 `input`。
17 |
18 | 在一个单独的窗口中打开 [table.html](table.html) 页面,并对此页面使用浏览器开发者工具。
19 |
--------------------------------------------------------------------------------
/2-ui/1-document/05-basic-dom-node-properties/2-lastchild-nodetype-inline/solution.md:
--------------------------------------------------------------------------------
1 | 这里有一个陷阱。
2 |
3 | 在 `
14 | |