Showing preview only (4,540K chars total). Download the full file or copy to clipboard to get everything.
Repository: javascript-tutorial/id.javascript.info
Branch: master
Commit: e594d6760e9f
Files: 1160
Total size: 3.7 MB
Directory structure:
gitextract_3kej2r86/
├── .gitattributes
├── .gitignore
├── 1-js/
│ ├── 01-getting-started/
│ │ ├── 1-intro/
│ │ │ └── article.md
│ │ ├── 2-manuals-specifications/
│ │ │ └── article.md
│ │ ├── 3-code-editors/
│ │ │ └── article.md
│ │ ├── 4-devtools/
│ │ │ ├── article.md
│ │ │ └── bug.html
│ │ └── 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
│ │ ├── 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/
│ │ │ │ │ └── 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/
│ │ │ │ ├── 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
│ │ │ ├── debugging.view/
│ │ │ │ ├── hello.js
│ │ │ │ └── index.html
│ │ │ └── head.html
│ │ ├── 02-coding-style/
│ │ │ ├── 1-style-errors/
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ └── article.md
│ │ ├── 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
│ │ ├── 02-object-copy/
│ │ │ └── article.md
│ │ ├── 03-garbage-collection/
│ │ │ └── article.md
│ │ ├── 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
│ │ │ └── article.md
│ │ ├── 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
│ │ ├── 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
│ │ ├── 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
│ │ └── index.md
│ ├── 06-advanced-functions/
│ │ ├── 01-recursion/
│ │ │ ├── 01-sum-to/
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ ├── 02-factorial/
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ ├── 03-fibonacci-numbers/
│ │ │ │ ├── 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
│ │ ├── 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
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ ├── 2-closure-variable-access/
│ │ │ │ ├── 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
│ │ ├── 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
│ │ ├── 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.view/
│ │ │ │ │ └── index.html
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ ├── 04-throttle/
│ │ │ │ ├── _js.view/
│ │ │ │ │ ├── solution.js
│ │ │ │ │ └── test.js
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ └── article.md
│ │ ├── 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
│ │ ├── 02-function-prototype/
│ │ │ ├── 1-changing-prototype/
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ ├── 4-new-object-same-constructor/
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ └── article.md
│ │ ├── 03-native-prototypes/
│ │ │ ├── 1-defer-to-prototype/
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ ├── 2-defer-to-prototype-extended/
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ └── article.md
│ │ ├── 04-prototype-methods/
│ │ │ ├── 2-dictionary-tostring/
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ ├── 3-compare-calls/
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ └── article.md
│ │ └── index.md
│ ├── 09-classes/
│ │ ├── 01-class/
│ │ │ ├── 1-rewrite-to-class/
│ │ │ │ ├── _js.view/
│ │ │ │ │ ├── solution.js
│ │ │ │ │ └── source.js
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ └── article.md
│ │ ├── 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
│ │ │ └── article.md
│ │ ├── 03-static-properties-methods/
│ │ │ ├── 3-class-extend-object/
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ └── article.md
│ │ ├── 04-private-protected-properties-methods/
│ │ │ └── article.md
│ │ ├── 05-extend-natives/
│ │ │ └── article.md
│ │ ├── 06-instanceof/
│ │ │ ├── 1-strange-instanceof/
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ └── article.md
│ │ ├── 07-mixins/
│ │ │ ├── article.md
│ │ │ └── head.html
│ │ └── index.md
│ ├── 10-error-handling/
│ │ ├── 1-try-catch/
│ │ │ ├── 1-finally-or-code-after/
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ └── article.md
│ │ ├── 2-custom-errors/
│ │ │ ├── 1-format-error/
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ └── article.md
│ │ └── index.md
│ ├── 11-async/
│ │ ├── 01-callbacks/
│ │ │ ├── article.md
│ │ │ └── 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
│ │ ├── 03-promise-chaining/
│ │ │ ├── 01-then-vs-catch/
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ ├── article.md
│ │ │ ├── getMessage.js
│ │ │ ├── head.html
│ │ │ ├── one.js
│ │ │ ├── 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
│ │ │ ├── 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
│ │ ├── 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
│ │ ├── 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
│ │ ├── 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
│ │ └── index.md
│ └── index.md
├── 2-ui/
│ ├── 1-document/
│ │ ├── 01-browser-environment/
│ │ │ └── article.md
│ │ ├── 02-dom-nodes/
│ │ │ ├── article.md
│ │ │ ├── elk.html
│ │ │ └── head.html
│ │ ├── 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
│ │ │ └── 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
│ │ ├── 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
│ │ ├── 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
│ │ │ │ ├── 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.view/
│ │ │ └── index.html
│ │ ├── 10-size-and-scroll-window/
│ │ │ └── article.md
│ │ ├── 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
│ │ │ └── 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/
│ │ │ │ ├── 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/
│ │ │ │ ├── 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
│ │ ├── 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.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
│ │ │ ├── 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/
│ │ │ │ │ ├── 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
│ │ ├── 6-pointer-events/
│ │ │ ├── article.md
│ │ │ ├── ball-2.view/
│ │ │ │ └── index.html
│ │ │ ├── ball.view/
│ │ │ │ └── index.html
│ │ │ ├── multitouch.view/
│ │ │ │ └── index.html
│ │ │ └── slider.view/
│ │ │ ├── index.html
│ │ │ └── style.css
│ │ ├── 7-keyboard-events/
│ │ │ ├── 2-check-sync-keydown/
│ │ │ │ ├── solution.md
│ │ │ │ ├── solution.view/
│ │ │ │ │ └── index.html
│ │ │ │ └── task.md
│ │ │ ├── article.md
│ │ │ └── keyboard-dump.view/
│ │ │ ├── index.html
│ │ │ ├── script.js
│ │ │ └── style.css
│ │ ├── 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
│ │ │ │ ├── source.view/
│ │ │ │ │ └── index.html
│ │ │ │ └── task.md
│ │ │ └── article.md
│ │ └── index.md
│ ├── 4-forms-controls/
│ │ ├── 1-form-elements/
│ │ │ ├── 1-add-select-option/
│ │ │ │ ├── solution.md
│ │ │ │ └── task.md
│ │ │ └── article.md
│ │ ├── 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
│ │ ├── 03-event-loop/
│ │ │ └── article.md
│ │ └── 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
│ │ └── article.md
│ ├── 02-text-decoder/
│ │ └── article.md
│ ├── 03-blob/
│ │ └── article.md
│ ├── 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
│ │ └── post.view/
│ │ └── server.js
│ ├── 02-formdata/
│ │ ├── article.md
│ │ └── post.view/
│ │ └── server.js
│ ├── 03-fetch-progress/
│ │ ├── article.md
│ │ └── 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
│ ├── 06-fetch-api/
│ │ ├── article.md
│ │ └── post.view/
│ │ ├── index.html
│ │ └── server.js
│ ├── 07-url/
│ │ └── article.md
│ ├── 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
│ │ └── longpoll.view/
│ │ ├── browser.js
│ │ ├── index.html
│ │ └── server.js
│ ├── 11-websocket/
│ │ ├── article.md
│ │ ├── chat.view/
│ │ │ ├── index.html
│ │ │ └── server.js
│ │ └── demo.view/
│ │ └── server.js
│ ├── 12-server-sent-events/
│ │ ├── article.md
│ │ └── eventsource.view/
│ │ ├── index.html
│ │ └── server.js
│ └── index.md
├── 6-data-storage/
│ ├── 01-cookie/
│ │ ├── article.md
│ │ └── 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
│ └── index.md
├── 7-animation/
│ ├── 1-bezier-curve/
│ │ └── article.md
│ ├── 2-css-animations/
│ │ ├── 1-animate-logo-css/
│ │ │ ├── solution.md
│ │ │ ├── solution.view/
│ │ │ │ └── index.html
│ │ │ ├── source.view/
│ │ │ │ └── index.html
│ │ │ └── task.md
│ │ ├── 2-animate-logo-bezier-css/
│ │ │ ├── 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
│ │ ├── boat.view/
│ │ │ ├── index.html
│ │ │ └── style.css
│ │ ├── digits-negative-delay.view/
│ │ │ ├── index.html
│ │ │ ├── script.js
│ │ │ └── style.css
│ │ ├── digits.view/
│ │ │ ├── index.html
│ │ │ ├── script.js
│ │ │ └── style.css
│ │ ├── step-end.view/
│ │ │ ├── index.html
│ │ │ └── style.css
│ │ ├── step-list.view/
│ │ │ ├── index.html
│ │ │ └── style.css
│ │ ├── step.view/
│ │ │ ├── index.html
│ │ │ └── style.css
│ │ ├── 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.view/
│ │ │ ├── index.html
│ │ │ └── style.css
│ │ ├── bounce-easeinout.view/
│ │ │ ├── index.html
│ │ │ └── style.css
│ │ ├── bounce-easeout.view/
│ │ │ ├── index.html
│ │ │ └── style.css
│ │ ├── bounce.view/
│ │ │ ├── index.html
│ │ │ └── style.css
│ │ ├── circ.view/
│ │ │ ├── index.html
│ │ │ └── style.css
│ │ ├── elastic.view/
│ │ │ ├── index.html
│ │ │ └── style.css
│ │ ├── move-raf.view/
│ │ │ └── index.html
│ │ ├── move.view/
│ │ │ └── index.html
│ │ ├── quad.view/
│ │ │ ├── index.html
│ │ │ └── style.css
│ │ ├── 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
│ ├── 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
│ ├── 4-template-element/
│ │ └── article.md
│ ├── 5-slots-composition/
│ │ ├── article.md
│ │ └── menu.view/
│ │ └── index.html
│ ├── 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
│ ├── 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
│ ├── 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
│ ├── 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
│ ├── 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
├── glossary.md
├── script/
│ └── clean-unused-png.php
└── todo.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
* text=auto eol=lf
*.svg binary
================================================
FILE: .gitignore
================================================
*.diff
*.err
*.orig
*.log
*.rej
*.swo
*.swp
*.vi
*~
*.sass-cache
# OS or Editor folders
.DS_Store
.idea
.cache
.project
.settings
.tmproj
.nvmrc
sftp-config.json
Thumbs.db
================================================
FILE: 1-js/01-getting-started/1-intro/article.md
================================================
# Pengenalan JavaScript
Mari kita lihat apa yang spesial dari JavaScript, apa saja yang bisa kita buat menggunakan JavaScript, dan teknologi apa yang cocok dengan JavaScript.
## Apa itu JavaScript?
*Javascript" pada awalnya diciptakan untuk "membuat halaman web menjadi hidup".
Program yang ada dalam bahasa ini disebut *script*. Script ini bisa ditulis langsung ke dalam kode HTML dari sebuah web dan berjalan otomatis saat halaman dimuat.
Script tersedia dan dieksekusi sebagai sebuah teks biasa. Script tidak membutuhkan persiapan khusus atau kompilasi untuk dijalankan.
Dalam hal ini, JavaScript sangat berbeda dari bahasa lain yang disebut [Java](https://en.wikipedia.org/wiki/Java_(programming_language)).
```smart header="Kenapa disebut <u>Java</u>Script?"
Saat JavaScript diciptakan, nama awalnya adalah "LiveScript". Namun saat itu Java sudah sangat terkenal, sehingga akhirnya diputuskanlah bahwa memposisikan bahasa baru menjadi "adik" Java dapat membantu.
Seiring waktu, JavaScript tumbuh menjadi bahasa yang sepenuhnya bebas dengan memiliki spesifikasi [ECMAScript](http://en.wikipedia.org/wiki/ECMAScript), dan sekarang JavaScript tak punya hubungan apa-apa dengan Java.
```
Sekarang, JavaScript bisa berjalan tak hanya pada browser, tapi juga di server, atau di perangkat manapun yang memiliki program khusus [JavaScript engine](https://en.wikipedia.org/wiki/JavaScript_engine).
Browser punya engine yang tertanam didalamnya yang disebut "JavaScript virtual machine".
Tiap engine punya *codename*-nya sendiri. Misalnya:
- [V8](https://en.wikipedia.org/wiki/V8_(JavaScript_engine)) -- di Chrome dan Opera.
- [SpiderMonkey](https://en.wikipedia.org/wiki/SpiderMonkey) -- di Firefox.
- ...Ada juga codename lain seperti "Trident" dan "Chakra" untuk versi berbeda dari IE, "ChakraCore" untuk Microsoft Edge, "Nitro" dan "SquirrelFish" untuk Safari, dll.
Istilah di atas sebaiknya diingat karena akan sering digunakan dalam artikel para developer di internet. Kita akan menggunakannya juga. Misalnya, jika "fitur X didukung V8", kemungkinan ia bisa jalan di Chrome dan Opera.
```smart header="Bagaimana engine bekerja?"
Engine sangat rumit. Tapi basicnya mudah.
1. Engine (tertanam jika ia sebuah browser)bisa membaca ("memparsing") script.
2. Lalu ia mengkonversi ("mengkompilasi") script tersebut menjadi bahasa mesin.
3. Dan kemudian kode mesin berjalan, lumayan cepat.
Engine melakukan optimisasi di setiap langkah proses. Dia bahkan memperhatikan script yang telah dikompilasi saat sedang berjalan, menganalisa data yang mengalir di dalam, dan melakukan optimisasi ke kode mesin berdasarkan pengetahuan itu.
```
## Apa yang bisa dilakukan *in-browser JavaScript*?
JavaScript modern merupakan bahasa pemrograman yang "aman". Ia tidak menyebabkan akses tingkat-rendah ke memory atau CPU, karena memang awalnya dibuat untuk browser, yang tentunya tidak membutuhkan hal tersebut.
Kemampuan JavaScript sangat tergantung pada lingkungan tempat ia berjalan. Misalnya, [Node.js](https://wikipedia.org/wiki/Node.js) mendukung function yang memungkingkan JavaScript melakukan baca/tulis file apapun, melakukan permintaan jaringan, dsb.
*In-browser JavaScript* bisa melakukan apapun terkait manipulasi halaman web, interaksi dengan pengguna, dan webserver.
Misalnya, *in-browser JavaScript* mampu:
- Menambah HTML baru ke sebuah halaman, mengganti isinya, memodifikasi gayanya.
- Bereaksi terhadap aktifitas pengguna, berjalan saat mouse diklik, pointer digerakkan, tombol ditekan.
- Mengirim permintaan jaringan ke remote server, mengunduh dan mengunggah file (disebut teknologi [AJAX](https://en.wikipedia.org/wiki/Ajax_(programming)) dan [COMET](https://en.wikipedia.org/wiki/Comet_(programming))).
- Memperoleh and menset cookie, bertanya ke pengunjung, menampilkan pesan.
- Menyimpan data pada client-side ("local storage").
## Apa yang TIDAK BISA dilakukan *in-browser JavaScript*?
Kemampuan JavaScript yang ada di dalam browser terbatas demi keamanan pengguna. Tujuannya supaya mencegah halaman web berbahya mengakses informasi pribadi atau merusak data pengguna.
Contoh keterbatasan tersebut meliputi:
- Javascript didalam sebuah halaman web seharusnya tidak dapat membaca/mengubah file didalam hardisk semaunya.
Browser-browser modern memperbolehkan JavaScript mengakses file, tapi aksesnya dibatasi dan tersedia hanya jika pengguna melakukan hal tertentu, misalnya seperti "menjatuhkan" file ke dalam jendela browser atau memilih file via tag `<input>`.
Ada beberapa cara untuk berinteraksi dengan kamera/mikrofon dan perangkat-perangkat lainnya, namun mereka butuh ijin khusus pengguna. Jadi sebuah halaman yang memiliki JavaScript tidak bisa mengaktifkan web-camera, memantau sekeliling dan mengirim informasinya ke [NSA] secara diam-diam(https://en.wikipedia.org/wiki/National_Security_Agency).
- Tab/jendela yang berbeda umumnya tidak ada hubungan sama sekali. Terkadang jendela yang berbeda bisa saling berhubungan juga, misalnya ketika satu jendela menggunakan JavaScript untuk membuka jendela lainnya. Tapi meski demikian, JavaScript dari suatu halaman tak boleh mengakses halaman lainnya jika mereka berasal dari situs yang berbeda (dari domain, protokol, atau port berbeda).
Ini disebut "Same Origin Policy". Untuk melakukan hal tersebut, *kedua halaman* harus sepakat terhadap adanya pertukaran data dan memiliki kode JavaScript khusus yang melakukan hal tersebut. Kita akan membahasnya nanti dalam tutorial ini.
Pembatasan ini pun demi keselamatan pengguna. Sebuah halaman dari `http://anysite.com` yang dibuka pengguna tidak akan bisa mengakses tab browser lainnya dengan URL `http://gmail.com` dan mencuri informasinya.
- JavaScript bisa dengan mudah berinteraksi secara online ke server di mana halaman berasal. Tapi kemampuannya menerima data dari situs/domain lain dilumpuhkan. Meskipun mampu, ia butuh persetujuan explisit (yang diexpresikan dalam HTTP header) dari sisi remote. Sekali lagi, itu merupakan pembatasan keamanan.

Pembatasan macam ini tidak ada jika JavaScript digunakan di luar browser, misalnya di server. Browser-browser modern juga memperbolehkan plugin/ekstensi yang membutuhkan ijin tambahan.
## Apa yang membuat JavaScript unik?
Paling tidak ada *tiga* hal unik dari JavaScript:
```compare
+ Integrasi penuh dengan HTML/CSS.
+ Hal sederhana diselesaikan dengan sederhana.
+ Dukungan dari mayoritas web browser dan aktif secara default.
```
JavaScript merupakan satu-satunya teknologi browser yang mengkombinasikan ketiga poin di atas.
Itulah yang membuat JavaScript unik. Itulah kenapa JavaScript menjadi alat yang paling sering untuk membuat antarmuka browser.
Katanya, JavaScript juga bisa dipakai untuk membuat aplikasi server, mobile, dsb.
## Bahasa "di atas" JavaScript
Sintaks JavaScript tidak memenuhi kebutuhan setiap orang. Masing-masing orang ingin fitur yang berbeda-beda.
Itu wajar, karena proyek dan persyaratan tiap orang berbeda-beda.
Akhir-akhir ini muncul banyak bahasa baru, yang *ditranspile* (dikonversi) ke JavaScript sebelum dijalankan di browser.
Tools modern membuat transpilasi sangat cepat dan transparan, yang memungkinkan para developer menulis kodenya dalam bahasa lain dan mengautokonversi itu "di balik layar".
Contoh bahasa yang dimaksud:
- [CoffeeScript](http://coffeescript.org/) merupakan "syntactic sugar" dari JavaScript. Dia memperkenalkan syntax yang lebih pendek, memungkingkan kita menulis kode lebih bersih dan lebih presisi. Biasanya, Ruby devs menyukainya.
- [TypeScript](http://www.typescriptlang.org/) berfokus pada penambahan "strict data typing" yang menyederhanakan pengembangan dan dukungan sistem yang komplex. Ia dikembangkan oleh Microsoft.
- [Flow](http://flow.org/) juga menambahkan data typing, tapi dalam cara berbeda. Dikembangkan oleh Facebook.
- [Dart](https://www.dartlang.org/) ialah bahasa mandiri yang punya engine sendiri yang berjalan di lingkungan non-peramban (seperti mobile apps), tapi bisa juga ditranspile ke JavaScript. Dikembangkan oleh Google.
- [Brython](https://brython.info/) adalah transpiler python untuk Javascript yang memperbolehkan untuk menulis kode aplikasi didalam Python murni tanpa Javascript.
- [Kotlin](https://kotlinlang.org/docs/reference/js-overview.html) adalah sebuah bahasa pemograman modern, ringkas dan aman yang dapat ditargetkan untuk browser atau Node.
Masih banyak lagi. Tentunya, jika kita menggunakan salah satu bahasa yang ditranspile tersebut, kita sebaiknya juga paham JavaScript untuk mengerti apa yang mereka lakukan.
## Kesimpulan
- JavaScript awalnya diciptakan sebagai bahasa khusus browser, namun sekarang banyak digunakan di lingkungan lain.
- Sekarang, JavaScript mempunyai posisi unik sebagai bahasa browser paling banyak diadopsi dengan integrasi penuh dengan HTML/CSS.
- Ada banyak bahasa yang "ditranspile" ke JavaScript dan menyediakan fitur tertentu. Disarankan untuk mempelajari mereka juga, minimal sebentar, setelah menguasai JavaScript.
================================================
FILE: 1-js/01-getting-started/2-manuals-specifications/article.md
================================================
# Manual dan spesifikasi
Buku ini adalah _tutorial_. Tujuannya membantu kamu memahami bahasa ini (Javascript) pelan-pelan. Tapi sekali kamu akrab atau familiar dengan dasarnya, kamu juga membutuhkan dari sumber-sumber lain.
## Spesifikasi
[Spesifikasi ECMA-262](https://www.ecma-international.org/publications/standards/Ecma-262.htm) berisi informasi formal, detil, and mendalam tentang JavaScript. Ia mendefisikan bahasa ini.
Tapi karena menjadi formal, ia sulit dipahami di awal. Jadi jika kamu butuh sumber informasi terpercaya tentang detil bahasa, spesifikasi ini tempat yang tepat. Tapi ini bukan untuk penggunaan harian.
Versi spesifikasi baru dirilis tiap tahun. Di antara rilis ini, draft spesifikasi terakhir ada di <https://tc39.es/ecma262/>.
Untuk membaca tentang fitur terkini, termasuk yang "hampir menjadi standar" (disebut "stage 3"), lihat proposalnya di <https://github.com/tc39/proposals>.
Juga, jika kamu dalam pengembangan untuk peramban, maka ada spek lain yang dibahas di [bagian kedua](info:browser-environment) di tutorial ini.
## Manual
- **Referensi JavaScript MDN (Mozilla)** ialah manual dengan informasi dan contoh lain. Di sana bagus untuk mendapat informasi mendalam tentang metode, fungsi bahasa, dll.
Kamu bisa cari di <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference>.
Meski, sering lebih bagus menggunakan pencarian internet. Pakai "MDN [term]" di query, misal <https://google.com/search?q=MDN+parseInt> untuk mencari fungsi `parseInt`.
- **MSDN** – Manual Microsoft dengan banyak informasi, termasuk JavaScript (sering dirujuk sebagai JScript). Jika kamu butuh sesuatu yang spesifik ke Internet Explorer, lebih baik pergi ke: <http://msdn.microsoft.com/>.
Juga, kamu bisa menggunakan pencarian internet dengan frasa seperti "RegExp MSDN" atau "RegExp MSDN jscript".
## Tabel kompatibilitas
JavaScript merupakan bahasa berkembang, fitur baru ditambah secara reguler.
Untuk melihat dukungan mereka pada engine berbasis peramban dan lainnya, lihat:
- <http://caniuse.com> - tabel dukungan per-fitur, misal untuk melihat engine mana yang mendukung fungsi kryptografi modern: <http://caniuse.com/#feat=cryptography>.
- <https://kangax.github.io/compat-table> - tabel dengan fitur dan engine bahasa yang mendukung atau yang tidak mendukung.
Semua sumber ini berguna di pengembangan nyata, karena mereka berisi informasi berharga tentang detil bahasa, dukungan mereka dll.
Silakan ingat mereka (atau laman ini) saat kamu butuh informasi mendalam tentang fitur tertentu.
================================================
FILE: 1-js/01-getting-started/3-code-editors/article.md
================================================
# Editor kode
Editor kode adalah tempat programmer menghabiskan usianya.
Ada dua tipe utama editor kode: IDE dan editor ringan. Kebanyakan orang menggunakan satu tool saja dari setiap tipe.
## IDE
Istilah [IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) (Integrated Development Environment) mengacu kepada editor mumpuni dengan banyak fitur yang biasanya beroperasi di atas "seluruh proyek." Dilihat dari namanya, ia bukan hanya sekedar editor biasa, tapi sebuah "lingkungan pengembangan" berskala besar.
Satu IDE meload proyek (yang bisa berupa banyak file), memungkingkan navigasi antar file, menyediakan autocompletion berdasarkan seluruh proyek (tak hanya file terbuka), dan berintegrasi dengan sistem manajemen versi (seperti [git](https://git-scm.com/)), lingkungan pengujian, dan hal-hal "level proyek" lainnya.
Jika kamu belum memilih satu IDE, pertimbangkan opsi-opsi berikut:
- [Visual Studio Code](https://code.visualstudio.com/) (lintas-platform, gratis).
- [WebStorm](http://www.jetbrains.com/webstorm/) (lintas-platform, berbayar).
Untuk Windows, ada juga "Visual Studio", jangan dipusingkan dengan "Visual Studio Code." "Visual Studio" merupakan editor khusus Windows yang keren dan berbayar, sangat cocok untuk platform .NET. Ia bagus juga untuk JavaScript. Lalu ada juga versi gratisnya [Visual Studio Community](https://www.visualstudio.com/vs/community/).
Banyak IDE berbayar, tapi punya masa percobaan. Biasanya harganya tak seberapa dibanding gaji pengembang berkualitas, jadi pilihlah yang terbaik untukmu.
## Editor ringan
"Editor ringan" tak semumpuni IDE, tapi mereka cepat, elegan, dan simpel.
Mereka digunakan terutama untuk membuka dan mengedit file secara instan.
Perbedaan utama antara "editor ringan" dan "IDE" adalah IDE bekerja pada level proyek, jadi IDE meload banyak data di awal, menganalisa struktur proyek jika dibutuhkan dan lain sebagainya. Editor ringan jauh lebih cepat jika kita cuma membutuhkan hanya satu file.
Pada praktiknya, editor ringan bisa punya banyak plugin termasuk syntax analyzers dan autocompleters level direktori, jadi tak ada batasan ketat antara editor ringan dan IDE.
Opsi-opsi berikut patut anda perhatikan:
- [Atom](https://atom.io/) (lintas-platform, gratis).
- [Visual Studio Code](https://code.visualstudio.com/) (lintas-platform, gratis).
- [Sublime Text](http://www.sublimetext.com) (lintas-platform, shareware).
- [Notepad++](https://notepad-plus-plus.org/) (Windows, gratis).
- [Vim](http://www.vim.org/) dan [Emacs](https://www.gnu.org/software/emacs/) sangat keren juga jika kamu tahu cara pakainya.
## Jangan berdebat
Daftar editor di atas merupakan barang yang sudah biasa saya atau teman-teman saya para pengembang profesional gunakan selama ini dengan gembira.
Ada banyak editor bagus lainnya di dunia kita yang besar ini. Silakan pilih satu yang paling kamu suka.
Pilihan editor, sama seperti tool lainnya, bersifat individual dan tergantung pada proyek, kebiasaan, dan preferensi personal.
================================================
FILE: 1-js/01-getting-started/4-devtools/article.md
================================================
# Konsol pengembang
Yang namanya kode selalu rentan error. Mudah sekali bagimu bikin error... Benar kan? Kamu *tidak akan pernah* luput dari error, itu karena kamu manusia, bukan [robot](https://en.wikipedia.org/wiki/Bender_(Futurama)).
Tapi di dalam peramban, error tidak terlihat ke pengguna secara default. Jadi, kalau ada yang salah di script, itu tidak kelihatan mata kita dan kita sudah memperbaiki itu.
Supaya bisa melihat error dan memperoleh informasi berfaedah lainnya dari script, "tools pengembang" ditanamkan di dalam peramban.
Kebanyakan pengembang memakai Chrome atau Firefox untuk pengembangan karena tools pengembangan yang mereka punya paling mantap. Peramban lain punya juga koq, ada with special features, but are usually playing "catch-up" to Chrome or Firefox. So most developers have a "favorite" browser and switch to others if a problem is browser-specific.
Tools pengembang mengandung banyak manfaat; mereka punya banyak fitur. Untuk memulainya, kita akan belajar cara membuka mereka, mencari error, dan menjalankan perintah JavaScript.
## Google Chrome
Buka laman [bug.html](bug.html).
Ada satu error di dalam kode JavaScript di situ. Ia tersembunyi dari mata pengunjung biasa, mari kita buka tools pengembang untuk melihatnya.
Tekan `key:F12` atau, kalau kamu pakai Mac, tekan `key:Cmd+Opt+J`.
Tools pengembang akan terbuka pada Console tab secara default.
Nanti tampilannya seperti ini:

Tampilan persisnya tools pengembang tergantung versi Chrome kamu. Ia berubah dari masa ke masa tapi tetap serupa.
- Di sini kita bisa melihat pesan error berwarna merah. Di sini, scriptnya mengandung perintah asing "lalala".
- Di kanan, ada link yang bisa diklik ke sumber `bug.html:12` dengan nomor baris di mana error itu muncul.
Di bawah pesan error, ada simbol `>` berwarna biru. Ia menandakan "command line" di mana kita bisa mengetik perintah JavaScript. Tekan `key:Enter` untuk menjalankannya.
Sekarang kita bisa melihat error, dan itu sudah cukup untuk permulaan. Kita nanti akan kembali ke tools pengembang dan mengcover debugging lebih dalam di bab <info:debugging-chrome>.
```smart header="Multi-line input"
Usually, when we put a line of code into the console, and then press `key:Enter`, it executes.
To insert multiple lines, press `key:Shift+Enter`. This way one can enter long fragments of JavaScript code.
```
## Firefox, Edge, dan lainnya
Banyak peramban lain memakai `key:F12` untuk membuka tools pengembang.
Look & feel mereka hampir mirip. Sekali kamu tahu cara memakainya (kamu bisa mulai dengan Chrome), kamu bisa dengan mudah ganti dari satu ke yang lain.
## Safari
Safari (peramban Mac, tidak didukung Windows/Linux) agak sedikit spesial di sini. Kita harus mengaktifkan "Develop menu" terlebih dulu.
Buka Preferences dan pergi ke "Advanced" pane. Di sana ada checkbox di sebelah bawah:

Sekarang `key:Cmd+Opt+C` bisa mentoggle konsol. Lalu, menu "Develop" muncul pada menu item di atas. Ia punya banyak perintah dan opsi.
## Kesimpulan
- Tools pengembang memungkinkan kita melihat error, menjalankan perintah, memeriksa variabel, dan sebagainya.
- Mereka bisa dibuka dengan `key:F12` untuk kebanyakan peramban di Windows. Chrome di Mac dengan `key:Cmd+Opt+J`, Safari `key:Cmd+Opt+C` (harus diaktifkan terlebih dulu).
Kini kita sudah menyiapkan lingkungannya. Di seksi berikutnya, kita akan terjun ke JavaScript.
================================================
FILE: 1-js/01-getting-started/4-devtools/bug.html
================================================
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
There is an error in the script on this page.
<script>
lalala
</script>
</body>
</html>
================================================
FILE: 1-js/01-getting-started/index.md
================================================
# Pengenalan
Tentang bahasa JavaScript dan lingkungan pengembangannya.
================================================
FILE: 1-js/02-first-steps/01-hello-world/1-hello-alert/index.html
================================================
<!DOCTYPE html>
<html>
<body>
<script>
alert( "I'm JavaScript!" );
</script>
</body>
</html>
================================================
FILE: 1-js/02-first-steps/01-hello-world/1-hello-alert/solution.md
================================================
[html src="index.html"]
================================================
FILE: 1-js/02-first-steps/01-hello-world/1-hello-alert/solution.view/index.html
================================================
<!DOCTYPE html>
<html>
<body>
<script>
alert( "I'm JavaScript!" );
</script>
</body>
</html>
================================================
FILE: 1-js/02-first-steps/01-hello-world/1-hello-alert/task.md
================================================
nilai penting: 5
---
# Tampilkan alert
Buat laman yang menampilkan pesan "I'm JavaScript!".
Lakukan dalam sandbox, atau di hard drive kamu, tak masalah, pastikan bisa berjalan.
[demo src="solution"]
================================================
FILE: 1-js/02-first-steps/01-hello-world/2-hello-alert-ext/alert.js
================================================
alert("I'm JavaScript!");
================================================
FILE: 1-js/02-first-steps/01-hello-world/2-hello-alert-ext/index.html
================================================
<!DOCTYPE html>
<html>
<body>
<script src="alert.js"></script>
</body>
</html>
================================================
FILE: 1-js/02-first-steps/01-hello-world/2-hello-alert-ext/solution.md
================================================
Kode HTML:
[html src="index.html"]
Untuk file `alert.js` di dalam folder yang sama:
[js src="alert.js"]
================================================
FILE: 1-js/02-first-steps/01-hello-world/2-hello-alert-ext/task.md
================================================
nilai penting: 5
---
# Tampilkan alert dengan script external
Ambil solusi dari tugas sebelumnya <info:task/hello-alert>. Modifikasi itu dengan mengextrak konten script ke file external `alert.js`, yang berada di dalam folder yang sama.
Buka lamannya, pastikan alertnya bekerja.
================================================
FILE: 1-js/02-first-steps/01-hello-world/article.md
================================================
# Hello, world!
Bagian dari tutorial ini ialah tentang inti JavaScript itu sendiri.
Tapi kita butuh lingkungan kerja untuk menjalankan scripts kita dan, karena buku ini online, peramban adalah pilihan yang baik. Kita akan menjaga supaya jumlah perintah yang spesifik peramban (seperti `alert`) seminimum mungkin sehingga kamu tak boros waktu di situ jika kamu berencana untuk fokus ke lingkungan lain (seperti Node.js). Kita akan fokus ke JavaScript di peramban dalam [bagian selanjutnya](/ui) dari tutorial ini.
Jadi pertama, kita lihat bagaimana kita menyisipkan script ke laman web. Untuk lingkungan (seperti Node.js), kamu bisa mengeksekusi script itu dengan perintah seperti `"node my.js"`.
## Tag "script"
Program JavaScript bisa disisipkan ke dalam bagian mana saja dari dokumen HTML dengan bantuan tag `<script>`.
Contoh:
```html run height=100
<!DOCTYPE HTML>
<html>
<body>
<p>Kode ini ditulis sebelum skrip...</p>
*!*
<script>
alert( 'Hello, world!' );
</script>
*/!*
<p>...Kode ini ditulis setelah skrip.</p>
</body>
</html>
```
```online
Kamu bisa menjalankan contohnya dengan mengklik tombol "Play" di sebelah ujung kanan-atas dari box di atas.
```
Tag `<script>` mengandung kode JavaScript yang otomatis dieksekusi ketika peramban memproses tag.
## Markup modern
Tag `<script>` punya beberapa attribut yang jarang dipakai akhir-akhir ini tapi masih bisa ditemukan dalam kode lama:
Atribut `type`: <code><script <u>type</u>=...></code>
: Standar HTML lawas, HTML4, mengharuskan script memiliki `type`. Biasanya `type="text/javascript"`. Sekarang sudah tak diperlukan. Selain itu, standar HTML modern, HTML5, mengubah total makna atribut ini. Sekarang, ia bisa digunakan untuk modul JavaScript. Tapi itu topik berat, kita akan membahas modul di bagian lain dari tutorial ini.
Atribut `language`: <code><script <u>language</u>=...></code>
: Atribut ini untuk menampilkan bahasa script. Atribut ini tak lagi dibutuhkan karena JavaScript adalah bahasa default. Tak usah menggunakan itu lagi.
Komen sebelum dan setelah script.
: Di dalam buku dan panduan jadul, kamu mungkin menemukan komen di dalam tag `<script>`, seperti ini:
```html no-beautify
<script type="text/javascript"><!--
...
//--></script>
```
Trik ini tak lagi dipakai di JavaScript modern. Komen ini menyembunyikan kode JavaScript dari peramban tua yang tak tahu cara memproses tag `<script>`. Oleh karena peramban yang dirilis 15 tahun terakhir tak punya masalah terkait ini, komen macam ini bisa membantumu mengidentifikasi kode yang sangat jadul.
## Script External
Jika kita punya banyak kode JavaScript, kita bisa menaruhnya di dalam file berbeda.
File script ditempel ke HTML dengan atribut `src`:
```html
<script src="/path/to/script.js"></script>
```
Di sini, `/path/to/script.js` adalah jalur absolut ke file script dari root sitius. Kamu juga bisa menyediakan jalur relatif dari laman ini. Misalnya, `src="script.js"` berarti file `"script.js"` dalam folder saat ini.
Kamu bisa memasang URL penuh juga. Misalnya:
```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
```
Untuk menempelkan beberapa script, gunakan tag berlapis:
```html
<script src="/js/script1.js"></script>
<script src="/js/script2.js"></script>
…
```
```smart
Aturannya, cuma script paling simpel yang ditaruh di dalam HTML. Script lebih rumit ditaruh di file terpisah.
Keuntungan file terpisah ialah peramban akan mengunduhnya dan menyimpannya di [cache](https://en.wikipedia.org/wiki/Web_cache)-nya.
Laman lain yang merujuk ke script yang sama akan mengambilnya dari cache ketimbang mengunduhnya, jadi sebenarnya file hanya diunduh sekali saja.
Itu mengurangi trafik dan membuat laman jadi lebih cepat.
```
````warn header="Jika `src` diset, konten script diabaikan."
Tag `<script>` tunggal tak bisa punya atribut `src` dan kode di dalamnya bersamaan.
Ini tak akan berjalan:
```html
<script *!*src*/!*="file.js">
alert(1); // konten diabaikan karena 'src' telah di set
</script>
```
Kita harus memilih antara `<script src="…">` external atau `<script>` external.
Contoh di atas bisa dipecah menjadi dua script:
```html
<script src="file.js"></script>
<script>
alert(1);
</script>
```
````
## Kesimpulan
- Kita bisa menggunakan tag `<script>` untuk menambah kode JavaScript ke laman.
- Atribut `type` dan `language` tak wajib.
- Script di file external bisa disisipkan dengan `<script src="path/to/script.js"></script>`.
Masih banyak lagi yang harus dipelajari tentang script peramban dan interaksi mereka dengan laman web. Tapi harap diingat bahwa bagian ini dari tutorial ini dikhususkan hanya ke bahasa JavaScript, jadi kita tak akan membahas implementasi Javascript yang spesifik peramban. Kita akan menggunakan peramban hanya sebagai alat untuk menjalankan JavaScript, yang nyaman untuk bacaan online.
================================================
FILE: 1-js/02-first-steps/02-structure/article.md
================================================
# Struktur kode
Hal pertama yang kita akan pelajari ialah membangun blok kode.
## Pernyataan
Pernyataan ialah konsep dan perintah syntax yang mejalankan aksi.
Kita sudah melihat satu pernyataan, `alert('Hello, world!')`, yang menampilkan pesan "Hello, world!".
Kita bisa memiliki sebanyak apapun pernyataan dalam kode kita. Pernyataan bisa dipisah menggunakan titik koma.
Misalnya, di sini kita memecah "Hello World" menjadi dua alert:
```js run no-beautify
alert('Hello'); alert('World');
```
Biasanya, pernyataan ditulis dalam baris terpisah supaya kode lebih mudah dibaca:
```js run no-beautify
alert('Hello');
alert('World');
```
## Titik koma [#semicolon]
Titik koma bisa dibuang dalam banyak kasus jika ada jeda baris.
Ini juga akan berjalan:
```js run no-beautify
alert('Hello')
alert('World')
```
Di sini, JavaScript menginterpretasi jeda baris sebagai titik koma "implisit". Ini disebut [penyisipan titik koma otomatis](https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion).
**Dalam banyak kasus, sebuah garis baru mengimplikasikan titik koma. Tapi "dalam banyak kasus" tak "selalu" begitu!**
Ada kasus ketika garis baru tidak berarti titik koma. Misalnya:
```js run no-beautify
alert(3 +
1
+ 2);
```
Output dari kode itu adalah `6` karena JavaScript tak menyisipkan titik koma di sini. Sudah jelas sekali bahwa barisnya selesai dengan tanda plus `"+"`, sehingga itu menjadi "expresi tak lengkap", jadi tak butuh titik koma. Dan dalam hal ini memang seperti itu.
**Tapi ada situasi di mana JavaScript "gagal" mengasumsi titik koma di mana itu benar-benar dibutuhkan.**
Galat yang muncul pada kasus ini agak sulit dicari dan dibetulkan.
````smart header="Contoh galat"
Jika kamu penasaran untuk melihat contoh konkrit dari galat ini, cek kode ini:
```js run
alert("Hello");
[1, 2].forEach(alert);
```
Untuk sekarang tak usah memikirkan makna kurung siku `[]` dan `forEach`. Kita akan mempelajari mereka nanti. Untuk sekarang, ingat hasil kode tersebut: yaitu `1` lalu `2`.
Sekarang, ayo kita tambahkan `alert` sebelum kodenya *tanpa* diikuti titik koma:
```js run no-beautify
alert("Hello")
[1, 2].forEach(alert);
```
Sekarang jika kita menjalankan kodenya, hanya `alert` pertama yang tampil dan kemudian galat!
Tapi semua akan baik-baik saja jika kita menambahkan titik koma setelah `alert`:
```js run
alert("All fine now");
If we run this code, only the first `Hello` shows (and there's an error, you may need to open the console to see it). There are no numbers any more.
Sekarang kita punya pesan "All fine now" diikuti dengan `1` dan `2`.
Galat muncul pada varian tanpa titik koma karena JavaScript tak mengasumsikan titik koma sebelum kurung siku `[...]`.
Jadi, karena titik koma tidak otomatis disisipkan, kode di contoh pertama diperlakukan sebagai pernyataan tunggal. Inilah cara engine melihatnya:
```js run no-beautify
alert("Hello")[1, 2].forEach(alert);
```
Tapi itu harus jadi dua pernyataan terpisah, bukan satu. Penyatuan macam ini salah pada kasus ini, makanya galat. Ini bisa terjadi dalam situasi lain.
````
Kami sarankan menaruh titik koma di antara pernyataan meski mereka dipisahkan garis baru. Ini aturan yang diterima secara luas oleh komunitas. Harap diingat sekali lagi bahwa -- *bisa saja* menanggalkan titik koma di banyak kesempatan. Tapi akan lebih aman -- terutama untuk pemula -- untuk menggunakan mereka.
## Komentar [#komentar pada sebuah kode]
Seiring waktu berjalan, program menjadi lebih rumit. Dan dibutuhkan *komen* yang menjelaskan kode apa itu dan kenapa.
Komen bisa ditaruh di mana saja dari script. Dan tidak berpengaruh ke eksekusi karena engine mengabaikan mereka.
**Satu-baris komen bermula dengan dua karakter slash `//`.**
Sisa barisnya adalah komen. Ia bisa memenuhi satu baris sendiri atau mengikuti pernyataan.
Seperti di sini:
```js run
// Komen ini menghuni satu baris sendiri
alert('Hello');
alert('World'); // Komen ini mengikuti pernyataan
```
**Komen multiline bermula dengan garis miring dan bintang <code>/*</code> dan berakhir dengan bintang dan garis miring <code>*/</code>.**
Seperti ini:
```js run
/* Contoh dengan dua pesan.
Ini komen multiline.
*/
alert('Hello');
alert('World');
```
Konten komen diabaikan, jadi jika menaruh kode di dalam <code>/* ... */</code>, ia tidak akan dieksekusi.
Kadang sangat berguna jika kita bisa menonaktifkan sementara sebagian kode:
```js run
/* Mengkomen kode
alert('Hello');
*/
alert('World');
```
```smart header="Gunakan hotkey!"
Di banyak editor, sebaris kode bisa dikomen dengan menekan hotkey `key:Ctrl+/` untuk komen baris-tunggal dan sesuatu macam `key:Ctrl+Shift+/` -- untuk komen multibaris (pilih sepotong kode dan tekan hotkeynya). Untuk Mac, coba `key:Cmd` ketimbang `key:Ctrl`.
```
````warn header="Komen bersarang tidak didukung!"
Tidak boleh ada `/*...*/` di dalam `/*...*/` yang lain.
Kode begini akan berakhir galat:
```js run no-beautify
/*
/* komen bersarang ?!? */
*/
alert( 'World' );
```
````
Silakan, jangan ragu mengkomen.
Komen meningkatkan kode footprint garis besar, tapi itu bukan masalah sama sekali. Ada banyak tools yang meminifikasi kode sebelum dipublikasi ke production server. Mereka menghapus komen, jadi mereka tidak tampil di script yang berjalan. Selain itu, komen tidak punya efek negatif pada production sama sekali.
Di akhir tutorial ini akan ada bab <info:code-quality> yang juga menerangkan cara menulis komen yang lebih baik.
================================================
FILE: 1-js/02-first-steps/03-strict-mode/article.md
================================================
# The modern mode, "use strict"
Selama ini, JavaScript tumbuh tanpa isu kompatibilitas. Fitur baru ditambahkan tanpa mengubah fungsionalitas yang sudah ada.
Keuntungannya adalah kode yang sudah ada tidak rusak. Tapi jeleknya adalah satu keputusan salah atau cacat yang dibuat oleh pembuat JavaScript akan menetap selamanya.
Inilah yang terjadi hingga tahun 2009 ketika ECMAScript 5 (ES5) muncul. Fitur baru ditambah dan beberapa kode yang ada diubah. Supaya kode lama tetap berjalan, kebanyakan modifikasi seperti ini secara default mati. Kamu harus mengaktifkan mereka secara explisit menggunakan directive special: `"use strict"`.
## "use strict"
Directive tersebut mirip string: `"use strict"` atau `'use strict'`. Jika itu diletakkan paling atas dari script, seluruh script akan bekerja secara "modern".
Misalnya:
```js
"use strict";
// this code works the modern way
...
```
Kita akan mempelajari fungsi (cara mengelompokkan perintah) segera. Melihat ke depan, ingatlah bahwa `"use strict"` bisa ditaruh di bagian awal fungsi. Itu membuat strict mode aktif hanya di dalam fungsi itu. Tapi biasanya, orang memakai itu untuk seluruh script.
````warn header="Yakinkan bahwa \"use strict\" berada paling atas"
Pastikan `"use strict"` berada paling atas dari script kamu, kalau tidak strict mode tidak akan aktif.
Strict mode tidak aktif di sini:
```js no-strict
alert("some code");
// "use strict" di sini diabaikan--dia harus berada paling atas
"use strict";
// strict mode tidak aktif
```
Hanya komen yang muncul di atas `"use strict"`.
````
```warn header="Tidak ada cara untuk membatalkan `use strict`"
Tak ada directive seperti `"no use strict"` yang merevert engine ke kelakuan lama.
Sekali kita masuk strict mode, tak ada jalan kembali.
```
## Konsol pengembang
Ketika kamu menggunakan konsol pengembang [developer console](info:devtools) untuk menjalankan kode, perlu diingat pada dasarnya konsol pengembang tidak menggunakan `use strict`.
Kadang, ketika menggunakan `use strict`, kamu akan mendapat hasil yang salah.
Jadi, bagaimana seharusnya mengunakan `use strict` didalam konsol?
Pertama, kamu bisa menekan tombol `key:Shift+Enter` untuk memasukan beberapa baris kode dan masukan `use strict` di paling atas, seperti ini:
```js
'use strict'; <Shift+Enter untuk baris baru>
// ...Kodemu
<Tekan enter untuk menjalankan>
```
Ini bekerja pada kebanyakan peramban, seperti Firefox dan Chrome.
Jika tidak berjalan, seperti di browser lama, ada sebuah cara untuk memastikan penggunaan `use strict`. Masukan kodenya kedalam sebuah pembungkus:
```js
(function() {
'use strict';
// ...Kode lainnya disini...
})()
```
## Haruskah kita menggunakan "use strict"?
Pertanyaannya sudah cukup jelas, tapi ternyata tidak.
Seseorang bisa saja merekomendasikan memulai skrip dengan menggunakan `"use strict"`...Tapi apakah kamu tahu apa keren?
Javascript modern mendukung kelas atau *classes* dan modul atau *modules* - struktur bahasa tingkat tinggi (kita akan belajar nanti), yang dapat mengaktifkan `use strict` secara otomatis. Jadi kita tidak perlu untuk menambahkan instruksi `"use strict"`, jika kita menggunakannya.
**Jadi, untuk sekarang `"use strict";` adalah hal yang perlu ada di awal dari skrip kamu. Nanti, ketika seluruh kodemu telah menggunakan kelas dan modul, kamu bisa menghilangkannya**
Untuk sekarang, kita harus mengetahui tentang `use strict` secara dasar.
Di bagian selanjutnya, selagi kita belajar tentang fitur jadi Javascript, kita akan melihat beberapa perbedaan diantara *strict mode* dan mode lama. Beruntungnya, tidak dapat terdapat banyak perbedaan dan sebenarnya keduanya sangat bermanfaat.
Seluruh contoh di tutorial ini menggunakan *strict mode* kecuali (sangat jarang) dituliskan sebaliknya.
================================================
FILE: 1-js/02-first-steps/04-variables/1-hello-variables/solution.md
================================================
Dalam kode di bawah, tiap baris berkorespondensi ke item di dalam daftar tugas.
```js run
let admin, name; // bisa mendeklarasikan dua variabel sekaligus
name = "John";
admin = name;
alert( admin ); // "John"
```
================================================
FILE: 1-js/02-first-steps/04-variables/1-hello-variables/task.md
================================================
nilai penting: 2
---
# Bekerja dengan variabel
1. Deklarasikan dua variabel: `admin` and `name`.
2. Assign nilai `"John"` ke `name`.
3. Kopi nilai dari `name` ke `admin`.
4. Tampilkan nilai `admin` menggunakan `alert` (harus beroutput "John").
================================================
FILE: 1-js/02-first-steps/04-variables/2-declare-variables/solution.md
================================================
## Variabel untuk planet kita
Itu simpel:
```js
let ourPlanetName = "Earth";
```
Ingat, kita bisa menggunakan nama lebih pendek `planet`, tapi itu tak akan jelas planet apa. Bagus jika lebih panjang dan deskriptif. Minimal hingga variabel isNotTooLong.
## Nama pengunjung saat ini
```js
let currentUserName = "John";
```
Lagi, kita bisa memperpendek jadi `userName` jika kita tahu pasti user saat ini.
Editor modern dan autocomplete membuat nama variabel panjang mudah ditulis. Jangan pelit terhadap mereka. Nama yang mengandung 3 kata di dalamnya itu bagus.
Dan jika editormu tidak punya autocompletion yang layak, carilah [editor yang baru](/code-editors).
================================================
FILE: 1-js/02-first-steps/04-variables/2-declare-variables/task.md
================================================
nilai penting: 3
---
# Memberikan nama yang tepat
1. Buat variabel dengan nama planet kita. Bagaimana kamu akan menamainya?
2. Buat variabel untuk menyimpan nama pengunjung saat ini ke website. Bagaimana kamu menamainya?
================================================
FILE: 1-js/02-first-steps/04-variables/3-uppercast-constant/solution.md
================================================
Kita umumnya menggunakan case yang layak untuk konstan yang "dihard-code". Atau, dengan kata lain, ketika nilainya diketahui sebelum eksekusi dan langsung ditulis ke dalam kode.
Di dalam kode, `birthday` memang seperti itu. Jadi kita bisa menggunakan kapital besar untuknya.
Sebaliknya, `age` dievaluasi saat run-time. Hari ini kita punya satu umur, setahun kemudian kita akan punya umur yang berbeda. Ia termasuk konstan yang takkan berubah melalui eksekusi kode. Tapi ia agak "sedikit bukan konstan" ketimbang `birthday`: ia dihitung, jadi sebaiknya kita menggunakan huruf kecil untuk itu.
================================================
FILE: 1-js/02-first-steps/04-variables/3-uppercast-constant/task.md
================================================
nilai penting: 4
---
# Const huruf kapital?
Cek kode berikut:
```js
const birthday = '18.04.1982';
const age = someCode(birthday);
```
Di sini kita punya konstan tanggal `birthday` dan `age` dikalkulasi dari `birthday` dengan batuan beberapa kode (tidak tersedia yang pendek-pendek, dan karena detail tidak masalah di sini).
Apakah tepat menggunakan huruf kapital untuk `birthday`? Untuk `age`? Atau bahkan untuk keduanya?
```js
const BIRTHDAY = '18.04.1982'; // buat huruf kapital?
const AGE = someCode(BIRTHDAY); // buat huruf kapital?
```
================================================
FILE: 1-js/02-first-steps/04-variables/article.md
================================================
# Variabel
Seringnya, aplikasi JavaScript butuh kerja dengan informasi. Di sini ada dua contoh:
1. Toko online -- informasinya mungkin berisi barang-barang yang dijual dan kereta belanja.
2. Aplikasi chat -- informasinya mungkin berisi user, pesan, dan banyak lagi.
Variabel digunakan untuk menyimpan informasi ini.
## Variabel
[Variabel](https://en.wikipedia.org/wiki/Variable_(computer_science)) ialah "simpanan bernama" untuk data. Kita bisa memakainya untuk menyimpan barang, pengunjung, dan data lain.
Untuk membuat variabel di JavaScript, gunakan katakunci `let`.
Pernyataan di bawah membuat (dengan kata lain: *declares* or *defines*) variabel dengan nama "message":
```js
let message;
```
Kini, kita bisa menaruh beberapa data ke dalamnya dengan menggunakan operator penetapan `=`:
```js
let message;
*!*
message = 'Hello'; // simpan string
*/!*
```
String ini kini disimpan ke area memori yang terasosiasi dengan variabel. Kita bisa mengakses itu menggunakan nama variabel:
```js run
let message;
message = 'Hello!';
*!*
alert(message); // tampilkan isi variabel
*/!*
```
Supaya ringkas, kita bisa mengkombinasi deklarasi variabel dan penetapan ke baris tunggal:
```js run
let message = 'Hello!'; // definisikan variabel dan tetapkan nilai
alert(message); // Hello!
```
Kita juga bisa mendeklarasi variabel ganda dalam satu baris:
```js no-beautify
let user = 'John', age = 25, message = 'Hello';
```
Kelihatannya pendek, tapi itu tidak disarankan. Demi kemudahan dibaca, tolong gunakan bari tunggal per variabel.
Varian multibaris agak panjang, tapi lebih mudah dibaca:
```js
let user = 'John';
let age = 25;
let message = 'Hello';
```
Beberapa orang juga mendefinisi variabel ganda dalam gaya multibaris ini:
```js no-beautify
let user = 'John',
age = 25,
message = 'Hello';
```
...Atau bahkan dalam gaya "comma-first":
```js no-beautify
let user = 'John'
, age = 25
, message = 'Hello';
```
Secara teknis, semua varian ini melakukan hal yang sama. Jadi, cuma masaleh selera personal dan estetika saja.
````smart header="`var` ketimbang `let`"
Di script jadul, kamu mungkin juga menemukan katakunci lain: `var` ketimbang `let`:
```js
*!*var*/!* message = 'Hello';
```
Katakunci `var` *hampir* sama dengan `let`. Gunanya untuk mendeklarasi variabel, tapi caranya agak sedikit beda, "jadul".
Ada perbedaan halus antara `let` dan `var`, tapi itu tak masalah buat kita sekarang ini. Kita akan mengcover mereka lebih detil di bab <info:var>.
````
## Analogy kehidupan nyata
Kita bisa dengan mudah memahami konsep "variabel" jika kita membayangkannya sebagai "box" untuk data, dengan stiker nama yang unik.
Misalnya, variabel `message` bisa dibayangkan sebagai box berlabel `"message"` dengan nilai `"Hello!"` di dalamnya:

Kita bisa menaruh nilai apapun di dalam box.
Kita juga bisa mengubahnya sebanyak yang kita mau:
```js run
let message;
message = 'Hello!';
message = 'World!'; // value changed
alert(message);
```
Ketika nilainya berubah, data lama dihapus dari variabel:

Kita juga bisa mendeklarasi dua variabel dan mengkopi data dari satu ke yang lainnya.
```js run
let hello = 'Hello world!';
let message;
*!*
// mengkopi 'Hello world' dari hello ke message
message = hello;
*/!*
// sekarang dua variabel punya data yang sama
alert(hello); // Hello world!
alert(message); // Hello world!
```
````warn header="Mendeklarasikan variabel dua kali akan menciptakan error"
Sebuah variabel seharusnya di deklarasikan hanya sekali.
Mendeklarasikan variabel berkali kali akan menciptakan error:
```js run
let message = "This";
// repeated 'let' leads to an error
// deklarasi 'let' berulang akan mengembalikan sebuah error
let message = "That"; // SyntaxError: 'message' has already been declared
```
Jadi, kita harus mendeklarasikan variabel sekali dan menggunakan variabel tersebut tanpa menggunakan 'let'.
````
```smart header="Bahasa fungsional"
Ini sangat menarik untuk diperhatikan bahwa ada bahasa pemrograman [fungsional](https://en.wikipedia.org/wiki/Functional_programming), seperti [Scala](http://www.scala-lang.org/) atau [Erlang](http://www.erlang.org/) yang melarang merubah nilai dari variabel.
Di dalam bahasa macam ini, sekali nilai disimpan "dalam box", ia akan di sana selamanya. Jika kita harus menyimpan sesuatu yang lain, bahasa tersebut memaksa kita membuat box baru (mendeklarasi variabel baru). Kita tak bisa menggunakan ulang yang lama.
Meski kelihatan sedikit aneh saat pandangan pertama, bahasa-bahasa ini ternyata mumpuni untuk pengembangan yang serius. Lebih dari itu, ada area seperti komputasi paralel di mana keterbatasan ini memberikan keuntungan tertentu. Disarankan mempelajari bahasa macam ini (meski jika kamu tak berencana menggunakannya segera) untuk meningkatkan wawasan.
```
## Penamaan variabel [#variable-naming]
Ada dua keterbatasan pada nama variabel di JavaScript:
1. Nama hanya boleh mengandung huruf, digit, atau simbol seperti `$` and `_`.
2. Karakter pertama tidak boleh digit.
Contoh nama valid:
```js
let userName;
let test123;
```
Ketika namanya mengandung kata ganda, [camelCase](https://en.wikipedia.org/wiki/CamelCase) umum digunakan: kata demi kata digabung, setiap kata kecuali yang pertama dimulai dengan huruf kapital: `myVeryLongName`.
Yang menarik ialah -- tanda dollar `'$'` dan underscore `'_'` juga bisa digunakan dalam nama. Mereka simbol reguler, hanya seperti huruf, tanpa makna yang spesial.
Nama-nama ini valid:
```js run untrusted
let $ = 1; // declared a variable with the name "$"
let _ = 2; // and now a variable with the name "_"
alert($ + _); // 3
```
Contoh nama variabel yang tidak valid:
```js no-beautify
let 1a; // cannot start with a digit
let my-name; // hyphens '-' aren't allowed in the name
```
```smart header="Case berpengaruh"
Variabel dengan nama `apple` dan `AppLE` adalah dua variabel yang berbeda.
```
````smart header="Huruf non-Latin diperbolehkan, namun tak direkomendasikan"
Boleh menggunakan bahasa apapun, termasuk huruf cyrillic atau bahkan hieroglyphs, seperti ini:
```js
let имя = '...';
let 我 = '...';
```
Secara teknis, tak ada error di sini, nama-nama begitu boleh digunakan, tapi ada tradisi internasional untuk menggunakan bahasa Inggris dalam nama variabel. Meski jika kita menulis script kecil, kemungkinan variabelnya akan digunakan terus-menerus. Dan juga orang-orang dari negara lain mungkin harus membaca beberapa kali.
````
````warn header="Nama-nama yang dikecualikan"
Ada [daftar kata yang dikecualikan](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords), yang tidak bisa digunakan sebagai nama variabel karena mereka digunakan oleh bahasa Javascript sendiri.
Misalnya: `let`, `class`, `return`, dan `function` dikecualikan.
Kode di bawah menghasilkan galat syntax:
```js run no-beautify
let let = 5; // tak bisa menamai variable "let", galat!
let return = 5; // juga tak bisa menamainya "return", galat!
```
````
````warn header="Assignment tanpa `use strict`"
Normalnya, kita harus mendefinisi variabel sebelum memakainya. Tapi dulu, secara teknis boleh membuat variabel hanya dengan penetapan nilai tanpa menggunakan `let`. Ini masih berjalan jika kita tak menaruh `use strict` di script kita untuk mengelola kompatibilitas dengan script jadul.
```js run no-strict
// note: tak ada "use strict" di contoh ini
num = 5; // variabel "num" dibuat jika ia tak ada
alert(num); // 5
```
Ini kebiasaan buruk dan akan mengakibatkan galat dalam mode ketat:
```js
"use strict";
*!*
num = 5; // galat: num tak terdefinisi
*/!*
```
````
## Konstan
Untuk mendeklarasi variabel konstan (tak berubah), gunakan `const` ketimbang `let`:
```js
const myBirthday = '18.04.1982';
```
Variabel yang dideklarasi menggunakan `const` disebut "konstan". Mereka tak bisa diubah. Jika kamu mencoba mengubahnya maka ia menghasilkan galat:
```js run
const myBirthday = '18.04.1982';
myBirthday = '01.01.2001'; // error, tak bisa menetapkan-ulang konstan!
```
Ketika programmer yakin bahwa variabel tak akan berubah, mereka bisa mendeklarasikan `const` untuk menjamin hal itu dan memberitahu semua orang.
### Konstan huruf-besar
Ada kebiasaan umum untuk menggunakan konstan sebagai alias untuk nilai yang sulit dihafal yang akan diketahui sebelum dieksekusi.
Konstan macam ini dinamai dengan huruf kapital dan underscore.
Misalnya, mari kita buat konstan untuk warna dalam sesuatu yang disebut format "web" (hexadecimal):
```js run
const COLOR_RED = "#F00";
const COLOR_GREEN = "#0F0";
const COLOR_BLUE = "#00F";
const COLOR_ORANGE = "#FF7F00";
// ...ketika kita harus memilih warna
let color = COLOR_ORANGE;
alert(color); // #FF7F00
```
Keuntungan:
- `COLOR_ORANGE` lebih mudah diingat ketimbang `"#FF7F00"`.
- Lebih rentan salah penulisan `"#FF7F00"` ketimbang `COLOR_ORANGE`.
- Ketika membaca code, `COLOR_ORANGE` lebih berarti daripada `#FF7F00`.
Kapan kita sebaiknya menggunakan kapital untuk konstan dan kapan itu dinamai dengan normal? Ayo kita perjelas.
Menjadi "konstan" hanya berarti jika nilai variable tak pernah berubah. Tapi ada konstan yang diketahui sebelum eksekusi (seperti nilai hexadecimal untuk merah) dan ada konstan yang *dikalkulasi* dalam run-time, selama eksekusi, tapi tak berubah setelah penetapan inisial mereka.
Misalnya:
```js
const pageLoadTime = /* waktu yang dibutuhkan laman web untuk meload */;
```
Nilai `pageLoadTime` tidak diketahui sebelum laman diload, jadi itu dinamai dengan normal. Tapi ia masih konstan karena ia tak berubah setelah penetapan.
Dengan kata lain, konstan berhuruf kapital hanya digunakan sebagai alias untuk nilai yang "dihard-code".
## Namai dengan benar
Berbicara tentang variabel, ada satu hal yang sangat penting.
Nama variabel sebaiknya punya arti yang bersih dan jelas, yang menjelaskan data yang ia simpan.
Penamaan variabel adalah salah satu keahlian yang penting dan rumit dalam pemrograman. Pandangan sekilas pada nama variabel bisa menyingkap kode yang ditulis oleh pengembang pemula versus pengembang berpengalaman.
Di proyek nyata, kebanyakan waktu dihabiskan untuk modifikasi dan mengextend code base ketimbang menulis sesuatu yang benar-benar baru dari awal. Ketika kita kembali ke beberapa kode setelah melakukan sesuatu yang lain untuk sementara, akan lebih mudah menemukan informasi yang labelnya tepat. Atau, dengan kata lain, ketika variabel punya nama yang baik.
Tolong renungkan tentang nama yang baik untuk variabel sebelum mendeklarasinya. Itu baik untukmu.
Beberapa aturan yang baik untuk ditiru:
- Gunakan nama yang manusiawi seperti `userName` atau `shoppingCart`.
- Jauhi singkatan atau nama pendek seperti `a`, `b`, `c`, kecuali jika kamu benar-benar tau apa yang kamu lakukan.
- Buat nama sedeskriptif dan sejelas mungkin. Contoh nama yang jelek ialah `data` dan `value`. Nama semacam ini tidak punya makna dan hanya OK untuk menggunakannya jika data atau nilai variabel yang mengacu kontex kodenya luar biasa jelas.
- Sepakat dalam hal-hal yang ada di dalam timmu dan pikiranmu. Jika pengunjung situs disebut "user" maka kita sebaiknya menamai variabel terkait `currentUser` atau `newUser` ketimbang `currentVisitor` atau `newManInTown`.
Kedengaran simpel kan? Jelas saja, tapi membuat nama variabel descriptif dan jelas pada praktiknya tidak mudah. Coba lakukan.
```smart header="Daur ulang atau buat baru?"
Dan catatan terakhirnya. Ada juga programmer malas yang, ketimbang mendeklarasi variabel baru, cenderung menggunakan variabel yang sudah ada.
Hasilnya, variabel mereka seperti box yang orang-orang lempar tanpa menganti stikernya. Apa yang ada di dalam boxnya? Siapa yang tahu? Kita harus mengeceknya dengan seksama.
Programmer macam ini pelit terhadap satu deklarasi variabel namun boros sepuluh kali saat debugging.
Variabel extra itu baik, tidak jahat.
JavaScript minifier dan peramban modern mengoptimisasi kode dengan cukup baik, sehingga ia tak akan mengakibatkan isu performa. Menggunakan variabel yang berbeda untuk nilai yang berbeda bahkan bisa membantu engine mengoptimisasi kodemu.
```
## Kesimpulan
Kita bisa mendeklarasi variabel untuk menyimpan data menggunakan katakunci `var`, `let`, atau `const`.
- `let` -- adalah deklarasi variabel modern.
- `var` -- adalah deklarasi variabel jadul. Normalnya kita tak menggunakannya sama sekali, tapi kita akan mengcover perbedaan halus dari `let` di bab <info:var>, hanya jika kamu membutuhkannya.
- `const` -- seperti `let`, tapi nilai variabelnya tak bisa diubah.
Variabel sebaiknya diberi nama yang memudahkan kita untuk memahami apa isinya.
================================================
FILE: 1-js/02-first-steps/05-types/1-string-quotes/solution.md
================================================
Backtick mengembed expresi di dalam `${...}` ke dalam string.
```js run
let name = "Ilya";
// expresinya ialah angka 1
alert( `hello ${1}` ); // hello 1
// expresinya ialah nama string
alert( `hello ${"name"}` ); // hello name
// expresinya ialah variabel, embed dia
alert( `hello ${name}` ); // hello Ilya
```
================================================
FILE: 1-js/02-first-steps/05-types/1-string-quotes/task.md
================================================
nilai penting: 5
---
# Petik string
Apa output dari script ini?
```js
let name = "Ilya";
alert( `hello ${1}` ); // ?
alert( `hello ${"name"}` ); // ?
alert( `hello ${name}` ); // ?
```
================================================
FILE: 1-js/02-first-steps/05-types/article.md
================================================
# Tipe data
Dalam Javascript terdapat beberapa tipe data yang dapat digunakan, sebuah *string* atau sebuah *number*
Terdapat delapan tipe data dasar dalam Javascript. Disini, kita akan mempelajarinya dan di bagian selanjutnya kita akan mempelajarinya secara detail.
Kita bisa menggunakan tipe apa saja didalam sebuah variabel. Contoh, Untuk sesaat sebuah variabel bisa saja memiliki tipe data *string* dan selanjutnya variabel tersebut menyimpan *number*:
```js
// Tidak ada error
let message = "hello";
message = 123456;
```
Bahasa pemrograman yang mendukung hal semacam ini, seperti Javascript, disebut dengan "dynamically typed", berarti terdapat tipe data, akan tetapi variabel tidak terikat pada tipe data apapun.
## Number
```js
let n = 123;
n = 12.345;
```
Tipe *number* merepresentasikan angka baik integer maupun floating point.
Ada banyak operasi untuk angka, misal perkalian `*`, pembagian `/`, penambahan `+`, pengurangan `-`, dan lainnya.
Selain angka reguler, ada yang disebut "nilai numerik spesial" yang juga bagian dari tipe data ini: `Infinity`, `-Infinity` dan `NaN`.
- `Infinity` mewakili [Infinity](https://en.wikipedia.org/wiki/Infinity) matematis ∞. Ia merupakan nilai spesial yang lebih besar dari angka apapun.
Kita bisa mendapatkannya sebagai hasil dari pembagian oleh nol:
```js run
alert( 1 / 0 ); // Infinity
```
Atau langsung referensikan saja dia:
```js run
alert( Infinity ); // Infinity
```
- `NaN` mewakili error komputasional. Ia merupakan hasil operasi matematis yang salah atau tak-terdefinisi, misalnya:
```js run
alert( "not a number" / 2 ); // NaN, pembagian macam ini keliru
```
`NaN` itu lengket. Operasi lanjutan apapun pada `NaN` menghasilkan `NaN`:
```js run
alert( "not a number" / 2 + 5 ); // NaN
```
Jadi, jika ada `NaN` di manapun di expresi matematika, ia mempropagasi hasil keseluruhan.
```smart header="Operasi matematika itu aman"
Melakukan matematika itu "aman" dalam JavaScript. Kita bisa melakukan apapun: pembagian dengan nol, memperlakukan string non-numerik sebagai angka, dll.
Script ini takkan pernah stop dengan fatal error ("die"). Paling buruk, kita akan mendapat `NaN` sebagai hasilnya.
```
Nilai numerik spesial formalnya merupakan bagian dari tipe "number". Tentu saja mereka bukan angka dalam pandangan umum dari kata ini.
Kita akan melihat lebih tentang cara bekerja dengan angka di bab <info:number>.
## BigInt [#bigint-type]
Didalam Javascript, tipe data "number" tidak bisa mengandung nilai lebih dari <code>(2<sup>53</sup>-1)</code> (sama dengan `9007199254740991`) atau kurang dari <code>-(2<sup>53</sup>-1)</code>. Itu adalah batasan teknik yang dibuat.
Untuk kebanyakan kebutuhan sebenarnya sudah cukup, dan terkadang kita membutuhkan nilai yang lebih besar, contohnya untuk kriptografy atau perhitungan waktu microsecond.
Tipe data `BigInt` lalu ditambahkan kedalam Javascript untuk menampilkan nilai *integer* yang sangat panjang.
Tipe data `BigInt` dibuat dengan menambahkan `n` diakhir dari nilai sebuah *integer*.
```js
// arti dari "n" pada akhir menandakan bahwa contoh dibawah adalah sebuah `BigInt`
const bigInt = 1234567890123456789012345678901234567890n;
```
Sebenarnya `BigInt` jarang dibutuhkan, kita tidak akan mempelajarinya disini, tetapi akan dipisahkan didalam bagian <info:bigint>. Baca saja saat kamu membutuhkan nilai *integer* yang sangat panjang.
```smart header="Masalah Kompabilitas"
Sekarang `BigInt` sudah didukung oleh Firefox/Chrome/Edge, tapi tidak didalam Safari/Internet Explorer.
You can check [*MDN* BigInt compatibility table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility) to know which versions of a browser are supported.
## String
String di JavaScript harus dikelilingi petik.
```js
let str = "Hello";
let str2 = 'Single quotes are ok too';
let phrase = `can embed another ${str}`;
```
Di JavaScript, ada 3 tipe petik.
1. Petik ganda: `"Hello"`.
2. Petik tunggal: `'Hello'`.
3. Backtick: <code>`Hello`</code>.
Petik tunggal dan ganda merupakan petik "simpel". Tak ada perbedaan antara mereka di JavaScript.
Backtick merupakan petik "fungsional lanjutan". Mereka memungkinkan kita mengembed variabel dan expresi ke dalam string dengan membungkus mereka dalam `${…}`, misalnya:
```js run
let name = "John";
// mengembed satu variabel
alert( `Hello, *!*${name}*/!*!` ); // Hello, John!
// mengembed expresi
alert( `the result is *!*${1 + 2}*/!*` ); // hasilnya 3
```
Expresi di dalam `${…}` dievaluasi dan hasilnya menjadi bagian dari string. Kita bisa menaruh apapun di sana: variabel seperti `name` atau expresi aritmatika seperti `1 + 2` atau sesuatu yang lebih rumit.
Tolong diingat bahwa ini hanya bisa dilakukan dalam backtick. Petik lain tidak punya fungsionalitas pengembedan!
```js run
alert( "the result is ${1 + 2}" ); // hasilnya ${1 + 2} (petik ganda tak akan berpengaruh)
```
Kita akan mengcover string lebih dalam di bab <info:string>.
```smart header="Tidak ada tipe *character*."
Dalam beberapa bahasa, ada tipe "character" spesial untuk karakter tunggal. Misalnya, di bahasa C dan di Java adalah `char`.
Di JavaScript, tak ada tipe semacam itu. Cuma ada satu tipe: `string`. String bisa berisi satu karakter atau lebih.
```
## Boolean (tipe logika)
Tipe boolean cuma punya dua nilai: `true` dan `false`.
Tipe ini umumnya digunakan untuk menyimpan niai ya/tidak: `true` artinya "ya, betul", dan `false` artinya "tidak, salah".
Misalnya:
```js
let nameFieldChecked = true; // ya, field nama dicek
let ageFieldChecked = false; // tidak, field usia tak dicek
```
Nilai boolean juga datang dari perbandingan:
```js run
let isGreater = 4 > 1;
alert( isGreater ); // benar (hasil perbandingan yaitu "ya")
```
Kita akan mengcover boolean lebih dalam di bab <info:logical-operators>.
## Nilai "null"
Nilai `null` spesial bukan bagian dari tipe apapun yang dijelaskan di atas.
Ia membentuk tipe terpisah miliknya sendiri yang cuma berisi nilai `null`:
```js
let age = null;
```
Di JavaScript, `null` tidak "mereferensi ke objek yang tak ada" atau "null pointer" seperti beberapa bahasa lain.
Ia cuma nilai spesial yang mewakili "hampa", "kosong" atau "nilai tak-diketahui".
Kode diatas mengatakan bahwa `age` tidak diketahui.
## Nilai "undefined"
Nilai spesial `undefined` juga berbeda lagi. Ia punya tipe miliknya sendiri, sama seperti `null`.
Arti `undefined` ialah "nilai yang tak ditetapkan".
Jika variabel dideklarasi, namun tak ditetapkan, maka nilainya `undefined`:
```js run
let age;
alert(age); // menampilkan "undefined"
```
Secara teknis, kita bisa secara jelas menetapkan `undefined` kedalam sebuah variabel:
```js run
let age = 100;
// mengubah nilai menjadi undefined
age = undefined;
alert(age); // "undefined"
```
...Tapi kita tidak menyarankan itu. Normalnya, kita gunakan `null` untuk menetapkan nilai "kosong" atau "tak-diketahui" ke variabel, dan kita gunakan `undefined` untuk pengecekan seperti melihat apakah nilai dari variabel telah ditetapkan.
## Objek dan Simbol
Tipe `object` itu special.
Seluruh tipe data lainnya disebut "primitive" karena hanya bisa mengandung satu buah nilai (entah itu sebuah string ataupun number atau lainnya). Sebaliknnya, object digunakan untuk menyimpan koleksi dari data dan entitas lainnya.
Objek itu penting, objek membutuhkan perlakuan yang spesial. Kita akan pelajari objek lebih lanjut di bagian <info:object>, setelah kita pelajari lebih lanjut tentang tipe data primitif.
Tipe `symbol` digunakan untuk menciptakan identifier unik untuk sebuah objek. Untuk kelengkapan kita akan menyebutkannya disini, tetapi akan ditunda hingga kita tahu tentang objek
## Operator typeof [#type-typeof]
Operator `typeof` mengembalikan tipe argumen. Berguna ketika kita ingin memproses nilai dari tipe berbeda secara berbeda atau cuma ingin mengecek sekilas.
Ia mendukung dua bentuk syntax:
1. Sebagai operator: `typeof x`.
2. Sebagai fungsi: `typeof(x)`.
Dengan kata lain, ia berjalan dengan atau tanpa kurung. Hasilnya sama saja.
Panggilan ke `typeof x` mengembalikan string dengan nama tipenya:
```js
typeof undefined // "undefined"
typeof 0 // "number"
typeof 10n // "bigint"
typeof true // "boolean"
typeof "foo" // "string"
typeof Symbol("id") // "symbol"
*!*
typeof Math // "object" (1)
*/!*
*!*
typeof null // "object" (2)
*/!*
*!*
typeof alert // "function" (3)
*/!*
```
Tiga baris terakhir mungkin butuh penjelasan tambahan:
1. `Math` ialah objek built-in yang menyediakan operasi matematik. Kita akan belajar itu di bab <info:number>. Di sini, ia cuma sekedar contoh dari objek.
2. Hasil `typeof null` yaitu `"object"`. Itu salah. Ia merupakan error yang terkenal resmi dalam `typeof`, yang dijaga untuk kompatibilitas. Tentu saja, `null` bukanlah objek. Ia merupakan nilai spesial dengan tipe terpisah miliknya sendiri. Jadi, lagi, ini merupakan error dalam bahasa.
3. Hasil dari `typeof alert` yaitu `"function"`, karena `alert` merupakan fungsi. Kita akan belajar fungsi di bab berikutnya di mana kita juga akan melihat bahwa tak ada tipe "fungsi" spesial di JavaScript. Fungsi merupakan bagian dari tipe objek. Tapi `typeof` memperlakukan mereka secara berbeda, yang mengembalikan `"fungsi"`. Itu tak sepenuhnya benar, tapi sangat nyaman pada praktiknya.
## Kesimpulan
Ada 7 tipe data dasar dalam JavaScript.
- `number` untuk nomor dengan bentuk apapun: integer ataupun nilai yang memiliki nilai desimal, batas dari integer adalah ±2<sup>53</sup>.
- `bigint` untuk nomor integer yang sangat panjang.
- `string` untuk string. Sebuah string mungkin memiliki 0 atau lebih karakter, tidak ada tipe data untuk string yang memiliki panjang 1 karakter.
- `boolean` untuk `true`/`false`.
- `null` untuk nilai yang tidak diketahui -- sebuah tipe data mandiri yang memiliki satu nilai yaitu `null`.
- `undefined` untuk nilai yang tidak ada atau tidak diberikan nilai -- sebuah tipe data mandiri yang memiliki satu nilai yaitu `null`.
- `object` untuk struktur data yang lebih rumit.
- `symbol` untuk identifier atau pengenal yang unik.
Operator `typeof` memungkinkan kita melihat tipe mana yang disimpan dalam variable.
- Dua form: `typeof x` atau `typeof(x)`.
- Mengembalikan string dengan nama tipe, seperti `"string"`.
- Untuk `null` mengembalikan `"object"` -- ada error dalam bahasa, yang sebenarnya bukan objek.
Di bab berikutnya, kita akan fokus pada nilai primitive dan sekali kita familiar dengan mereka, kita akan lanjut ke objek.
================================================
FILE: 1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/solution.md
================================================
Kode JavaScript:
```js demo run
let name = prompt("Siapakah nama Anda?", "");
alert(name);
```
Laman penuh:
```html
<!DOCTYPE html>
<html>
<body>
<script>
'use strict';
let name = prompt("Siapakah nama Anda?", "");
alert(name);
</script>
</body>
</html>
```
================================================
FILE: 1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/task.md
================================================
nilai penting: 4
---
# Laman simpel
Buat laman web yang meminta nama dan menampilkannya.
[demo]
================================================
FILE: 1-js/02-first-steps/06-alert-prompt-confirm/article.md
================================================
# Interaksi: alert, prompt, confirm
sebagaimana kita akan menggunakan peramban sebagai lingkungan percobaan kode, ayo kita lihat beberapa fungsi untuk berinteraksi dengan pengguna: `alert`, `prompt` dan `confirm`.
## alert
Untuk yang satu ini kita sudah pernah melihatnya. Ini akan menampilkan pesan dan menunggu pengguna untuk menekan tombol "OK".
Contoh:
```js run
alert("Hello");
```
Mini-window dengan pesan ini disebut *modal window*. Kata "modal" artinya pengunjung tak bisa berinteraksi dengan apapun di laman, menekan tombol lain, dll. hingga mereka selesai berurusan dengan window ini. Dalam hal ini -- hingga mereka menekan "OK".
## prompt
Fungsi `prompt` menerima dua argumen:
```js no-beautify
result = prompt(title, [default]);
```
Ia menampilkan modal window dengan pesan teks, input field untuk pengunjung, dan tombol OK/CANCEL.
`title`
: Teks untuk ditampilkan ke pengunjung.
`default`
: Parameter kedua opsional, nilai inisial untuk input field.
```smart header="Kurung siku didalam sintaks `[...]`"
Kurung siku di sintaks `default` di kode sintaks di atas menandakan bahwa parameter itu bersifat opsional, tidak benar-benar dibutuhkan.
```
Pengunjung halaman bisa mengetik sesuatu didalam kotak prompt dan menekan tombol OK. Lalu kita akan mendapatkan teksnya didalam `result`. Atau pengunjung halaman bisa membatalkan kotak promp dengan menekan *Cancel* atau menekan `key:Esc` pada *keyboard*, lalu kita akan mendapatkan `null` sebagai `result`.
Panggilan ke `prompt` mengembalikan teks dari input field atau `null` jika input dibatalkan.
Misalnya:
```js run
let age = prompt('Berapakah umut anda?', 100);
alert(`Umur Anda ${age} tahun`); // Umur Anda 100 tahun!
```
```warn header="In IE: selalu isikan nilai `default`"
Parameter kedua ini opsional, tapi jika kita tidak menyuplai, Internet Explorer akan menyisipkan teks `"undefined"` ke dalam prompt.
Jalan kode ini di Internet Explorer untuk melihat:
```js run
let test = prompt("Test");
```
Jadi, supaya prompt terlihat bagus di IE, sebaiknya sediakan argumen kedua:
```js run
let test = prompt("Test", ''); // <-- for IE
```
## confirm
Syntaxnya:
```js
result = confirm(question);
```
Fungsi `confirm` menampilkan modal window dengan `pertanyaan` dan dua tombol: OK dan Cancel.
Hasilnya `true` jika OK ditekan dan `false` jika tidak.
Misalnya:
```js run
let isBoss = confirm("Are you the boss?");
alert( isBoss ); // true jika OK ditekan
```
## Kesimpulan
Kita membahas 3 fungsi spesifik peramban untuk berinteraksi dengan pengunjung:
`alert`
: menampilkan pesan.
`prompt`
: menampilkan pesan yang minta input teks pengguna. Ia mengembalikan teks atau, jika Cancel atau `key:Esc` diklik, `null`.
`confirm`
: menampilkan pesan dan menunggu pengguna menekan "OK" atau "Cancel". Ia mengembalikan `true` untuk OK dan `false` untuk Cancel/`key:Esc`.
Semua metode ini ialah modal: mereka menyela exekusi script dan tak membolehkan pengunjung berinteraksi dengan apapun di laman hingga window ditutup.
Ada dua batasan yang dibagikan semua metode di atas:
1. Lokasi tepat modal window ditentukan oleh peramban. Biasanya, di tengah.
2. Tampilan tepat window juga tergantung peramban. Kita tak bisa modifikasi ini.
Itulah harga untuk kesederhanaan. Ada banyak cara menampilkan window lebih manis dan kaya akan interaksi dengan pengguna, tapi jika "bells and whistles" tak jadi masalah, metode ini baik-baik saja.
================================================
FILE: 1-js/02-first-steps/07-type-conversions/article.md
================================================
# Konversi Tipe
Seringkali, operator dan fungsi otomatis mengkonversi nilai yang diberikan ke mereka ke tipe yang sesuai.
Misalnya, `alert` otomatis mengkonversi nilai apapun ke string untuk menampilkannya. Operasi mathematika mengkonversi nilai ke angka.
Ada juga kasus di mana kita harus explisit mengkonversi nilai ke tipe yang diharapkan.
```smart header="Belum bicara objek dulu"
Di bab ini, kita takkan mengcover objek. Daripada itu, kita akan belajar primitives dulu.
Lalu, setelah kita belajar tentang objek, kita akan lihat cara konversi objek bekerja di bab <info:object-toprimitive>.
```
## Konversi String
Konversi string terjadi ketika kita butuh bentuk string dari nilai.
Misalnya, `alert(value)` menampilkan nilai.
Kita juga bisa memanggil fungsi `String(value)` untuk mengkonversi nilai string:
```js run
let value = true;
alert(typeof value); // boolean
*!*
value = String(value); // sekarang nilainya string "true"
alert(typeof value); // string
*/!*
```
Konversi string kebanyakan jelas. `false` menjadi `"false"`, `null` menjadi `"null"`, dll.
## Konversi Numerik
Konversi numerik terjadi otomatis dalam fungsi dan expresi matematis.
Misalnya, ketika pembagian `/` dilakukan ke non-angka:
```js run
alert( "6" / "2" ); // 3, string dikonversi ke angka
```
Kita bisa gunakan fungsi `Number(value)` untuk explisit mengkonversi `value` ke angka:
```js run
let str = "123";
alert(typeof str); // string
let num = Number(str); // menjadi angka 123
alert(typeof num); // angka
```
Konversi explisit biasanya dibutuhkan ketika kita membaca nilai dari sumber berbasis string seperti form teks namun mengharapkan angka untuk dienter.
Jika stringnya angka tak valid, hasilnya konversi macam ini ialah `NaN`. Misalnya:
```js run
let age = Number("an arbitrary string instead of a number");
alert(age); // NaN, konversi gagal
```
Aturan konversi numerik:
| Value | Becomes... |
|-------|-------------|
|`undefined`|`NaN`|
|`null`|`0`|
|<code>true dan false</code> | `1` and `0` |
| `string` | Whitespaces dari awal dan akhir dibuang. Jika string sisanya kosong, hasilnya `0`. Sebaliknya, angkanya "dibaca" dari stringnya. Error memberikan `NaN`. |
Misalnya:
```js run
alert( Number(" 123 ") ); // 123
alert( Number("123z") ); // NaN (error membaca angka pada "z")
alert( Number(true) ); // 1
alert( Number(false) ); // 0
```
Tolong diingat bahwa kelakuan `null` dan `undefined` berbeda di sini: `null` menjadi nol namun `undefined` menjadi `NaN`.
Hampir semua operasi matematik melakukan konversi semacam ini, yang akan kita lihat di bab berikutnya.
## Konversi Boolean
Konversi boolean ialah yang paling simpel.
Ini terjadi dalam operasi logika (nanti kita akan menemui tes kondisi dan hal mirp lainnya) tapi bisa juga berjalan explisit dengan panggilan ke `Boolean(value)`.
Aturan konversi:
- Nilai yang secara intuitif "kosong", seperti `0`, string kosong, `null`, `undefined`, dan `NaN`, menjadi `false`.
- Nilai lainnya menjadi `true`.
Misalnya:
```js run
alert( Boolean(1) ); // true
alert( Boolean(0) ); // false
alert( Boolean("hello") ); // true
alert( Boolean("") ); // false
```
````warn header="Please note: the string with zero `\"0\"` is `true`"
Some languages (namely PHP) treat `"0"` as `false`. But in JavaScript, a non-empty string is always `true`.
```js run
alert( Boolean("0") ); // true
alert( Boolean(" ") ); // spaces, also true (any non-empty string is true)
```
````
## Kesimpulan
Tiga tipe konversi yang paling digunakan ialah ke string, ke angka, dan ke boolean.
**`Konversi String`** -- Terjadi ketika kita mengoutput sesuatu. Bisa berjalan dengan `String(value)`. Konversi ke string biasanya untuk nilai primitif.
**`Konversi Numerik`** -- Terjadi di operasi matematika. Bisa berjalan dengan `Number(value)`.
Konversinya mengikuti aturan ini:
| Value | Becomes... |
|-------|-------------|
|`undefined`|`NaN`|
|`null`|`0`|
|<code>true / false</code> | `1 / 0` |
| `string` | Stringnya dibaca "apa adanya", whitespace dari kedua sisi diabaikan. String kosong menjadi `0`. Error memberikan `NaN`. |
**`Konversi Boolean`** -- Terjadi di operasi logika. Bisa berjalan dengan `Boolean(value)`.
Ikuti aturan ini:
| Value | Becomes... |
|-------|-------------|
|`0`, `null`, `undefined`, `NaN`, `""` |`false`|
|nilai lain apapun| `true` |
Kebanyakan aturan ini mudah dipahami dan diingat. Pengecualian penting di mana orang biasanya membuat kesalahan yaitu:
- `undefined` ialah `NaN` sebagai angka, buka `0`.
- `"0"` dan string yang cuma-spasi seperti `" "` ialah true sebagai boolean.
Objek tidak dicover di sini. Kita akan kembali ke mereka nanti di bab <info:object-toprimitive> yang khusus exclusif untuk objeck setelah kita belajar hal-hal lebih dasar tentang JavaScript.
================================================
FILE: 1-js/02-first-steps/08-operators/1-increment-order/solution.md
================================================
Jawabannya adalah:
- `a = 2`
- `b = 2`
- `c = 2`
- `d = 1`
```js run no-beautify
let a = 1, b = 1;
alert( ++a ); // 2, bentuk prefix mengembalikan nilainya
alert( b++ ); // 1, bentuk postfix mengembalikan nilai lamanya
alert( a ); // 2, diinkremen sekali
alert( b ); // 2, diinkremen sekali
```
================================================
FILE: 1-js/02-first-steps/08-operators/1-increment-order/task.md
================================================
nilai penting: 5
---
# Bentuk postfix dan prefix
Berapa nilai final dari semua variabel `a`, `b`, `c` dan `d` setelah kode berikut?
```js
let a = 1, b = 1;
let c = ++a; // ?
let d = b++; // ?
```
================================================
FILE: 1-js/02-first-steps/08-operators/2-assignment-result/solution.md
================================================
Jawabannya adalah:
- `a = 4` (dikali 2)
- `x = 5` (dikalkulasi sebagai 1 + 4)
================================================
FILE: 1-js/02-first-steps/08-operators/2-assignment-result/task.md
================================================
nilai penting: 3
---
# Hasil penetapan
Berapa nilai dari `a` dan `x` setelah kode berikut?
```js
let a = 2;
let x = 1 + (a *= 2);
```
================================================
FILE: 1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md
================================================
```js no-beautify
"" + 1 + 0 = "10" // (1)
"" - 1 + 0 = -1 // (2)
true + false = 1
6 / "3" = 2
"2" * "3" = 6
4 + 5 + "px" = "9px"
"$" + 4 + 5 = "$45"
"4" - 2 = 2
"4px" - 2 = NaN
" -9 " + 5 = " -9 5" // (3)
" -9 " - 5 = -14 // (4)
null + 1 = 1 // (5)
undefined + 1 = NaN // (6)
" \t \n" - 2 = -2 // (7)
```
1. Penambahan dengan string `"" + 1` mengkonversi `1` ke string: `"" + 1 = "1"`, dan kita punya `"1" + 0`, aturan yang sama berlaku.
2. Pengurangan `-` (seperti kebanyakan operasi matematika) cuma berjalan dengan angka, ia mengkonversi string kosong `""` ke `0`.
3. Penambahan dengan string mengappend angka `5` ke string.
4. Pengurangan selalu mengkonversi ke angka, jadi ia membuat `" -9 "` menjadi angka `-9` (mengabaikan spasi sekitarnya).
5. `null` menjadi `0` setelah konversi numerik.
6. `undefined` menjadi `NaN` setelah konversi numerik.
7. Karakter spasi, ialah string yang depan dan belakangnya ditrim ketika string dikonversi ke angka. Berikut seluruh string berisi karakter spasi, seperti `\t`, `\n` dan spasi "reguler" di antaranya. Jadi, serupa dengan string kosong, ia menjadi `0`.
================================================
FILE: 1-js/02-first-steps/08-operators/3-primitive-conversions-questions/task.md
================================================
nilai penting: 5
---
# Konversi tipe
Apa hasil dari expresi ini?
```js no-beautify
"" + 1 + 0
"" - 1 + 0
true + false
6 / "3"
"2" * "3"
4 + 5 + "px"
"$" + 4 + 5
"4" - 2
"4px" - 2
" -9 " + 5
" -9 " - 5
null + 1
undefined + 1
" \t \n" - 2
```
Pikirkan dengan baik, tulis dan bandingkan dengan jawaban.
================================================
FILE: 1-js/02-first-steps/08-operators/4-fix-prompt/solution.md
================================================
Alasannya adalah karena kotak *prompt* mengembalikan inputan dari user sebagai string.
Jadi nilai dari masing-masing variabel adalah `"1"` dan `"2"`.
```js run
let a = "1"; // prompt("Angka pertama?", 1);
let b = "2"; // prompt("Angka kedua?", 2);
alert(a + b); // 12
```
Apa yang kita harus lakukan untuk mengubah string menjadi angka sebelum `+`, gunakan `Number()` atau menambahkannya dengan `+`.
Contoh, tepat sebelum `prompt`:
```js run
let a = +prompt("Angka pertama?", 1);
let b = +prompt("Angka kedua?", 2);
alert(a + b); // 3
```
Atau didalam `alert`:
```js run
let a = prompt("Angka pertama?", 1);
let b = prompt("Angka kedua?", 2);
alert(+a + +b); // 3
```
Menggunakan *unary* dan *binary* `+` dicontoh kode terakhir terlihat lucu, kan?
================================================
FILE: 1-js/02-first-steps/08-operators/4-fix-prompt/task.md
================================================
nilai penting: 5
---
# Benarkan penambahan
Ini adalah kode yang menanyakan pengguna untuk memasukan dua angka dan menampilkan jumlahnya.
Kodenya tidak berjalan dengan semestinya. Keluaran dari contoh kode dibawah adalah `12` (nilai dimasukan secara default didalam kotak prompt).
Kenapa? Benarkan. Hasilnya haruslah `3`.
```js run
let a = prompt("Angka pertama?", 1);
let b = prompt("Angka kedua?", 2);
alert(a + b); // 12
```
================================================
FILE: 1-js/02-first-steps/08-operators/article.md
================================================
# Operator dasar, maths
Kita tahu banyak operator dari sekolah. Mereka adalah penambahan `+`, perkalian `*`, pengurangan `-`, dll.
Didalam bagian ini, kita akan memulai dengan menggunakan operator sederhana, lalu kita akan fokus pada aspek khusus Javascript, yang tidak dipelajari pada aritmatika di sekolah.
## Istilah: "unary", "binary", "operand"
Sebelum kita lanjut, mari pahami dulu terminologi umum.
- *Operand* -- untuk apa operator diaplikasikan. Misalnya, dalam perkalian `5 * 2` ada dua operand: operand kiri `5` dan operand kanan `2`. Kadang, orang memanggil ini "argumen" ketimbang "operand".
- Operator disebut *unary* jika ia punya operand tunggal. Misalnya, negasi unary `-` membalikkan tanda dari angka:
```js run
let x = 1;
*!*
x = -x;
*/!*
alert( x ); // -1, negasi unary diaplikasikan
```
- Operator disebut *binary* jika ia punya dua operand. Minus yang sama juga berada dalam bentuk binary:
```js run no-beautify
let x = 1, y = 3;
alert( y - x ); // 2, minus binary mengurangi nilai
```
Formalnya, di contoh di atas kita punya dua operator berbeda yang berbagi simbol yang sama: operator negasi, operator unary yang membalik tanda, dan operator pengurangan, operator biner yang mengurangi angka satu dengan lainnya.
## Maths
Operasi matematika dibawah telah didukung didalam Javascript:
- Penambahan `+`,
- Pengurangan `-`,
- Perkalian `*`,
- Pembagian `/`,
- Sisa Bagi `%`,
- Eksponensial `**`.
Keempat operasi pertama sudah cukup jelas, sementara `%` dan `**` membutuhkan lebih banyak kata-kata untuk dijelaskan.
### Sisa bagi %
Operator sisa bagi `%` sebagaimana kelihatannya, tidak berhubungan dengan persen.
Hasil dari `a % b` adalah [nilai sisa](https://en.wikipedia.org/wiki/Remainder) dai pembagian antara `a` oleh `b`.
Contoh
```js run
alert( 5 % 2 ); // 1, sisa dari pembagian antara 5 dibagi 2
alert( 8 % 3 ); // 2, sisa dari pembagian antara 8 dibagi 3
```
### Eksponensial **
Operator eksponensial `a ** b` mengkalikan `a` dengan nilai itu sendiri sebanyak `b` kali.
Dalam matematika sekolah, kita menuliskannya sebagai<sup>b</sup>.
alert( 2 ** 2 ); // 2² = 4
alert( 2 ** 3 ); // 2³ = 8
alert( 2 ** 4 ); // 2⁴ = 16
```
Sama seperti dalam matematika, operator eksponensial juga didefinisikan untuk bilangan non-bilangan bulat.
Misalnya, akar kuadrat adalah eksponensial dengan :
```js run
alert( 4 ** (1/2) ); // 2 (pangkat 1/2 sama dengan akar kuadrat)
alert( 8 ** (1/3) ); // 2 (pangkat 1/3 sama dengan akar kubik)
```
## Penambahan string dengan +
Ayo kita bertemu dengan fitur dari operator Javascript yang berada diatas aritmatika di sekolah.
Biasanya, operator plus `+` menambah angka.
Tapi, jika binary `+` diaplikasikan ke string, ia menggabungkan (konkatenasi) mereka:
```js
let s = "my" + "string";
alert(s); // mystring
```
Ingat bahwa jika salah satu operand berupa string, maka yang satunya dikonversi ke string juga.
Misalnya:
```js run
alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"
```
Lihat, tak masalah operand manapun yang berupa string. Aturannya simpel: jika salah satu operand adalah string, maka yang satunya dikonversi ke string juga.
Namun, ingat bahwa operasi berjalan dari kiri ke kanan. Jika ada dua angka diikuti string, angka akan ditambah sebelum dikonversi ke string:
Ini adalah contoh yang lebih rumit:
```js run
alert(2 + 2 + '1' ); // "41" dan bukan "221"
```
Disini, operator bekerja secara bergantian. Pertama `+` menambahkan dua angka, jadi akan menghasilkan `4`, lalu selanjutnya `+` menambahkan string `1` kedalamnya, jadi akan menjadi seperti `4 + '1' = 41`.
```js run
alert('1' + 2 + 2); // "122" dan bukan "14"
```
disini, bilangan pertama adalah string, kompiler memperlakukan dua bilangan lainnya sebagai string juga. Bilangan `2` ditambahkan dengan `1`, jadi `'1' + 2 = "12"` dan `"12" + 2 = "122"`.
Operator `+` hanyalah satu-satunya operator yang mendukung penggunaan string dengan cara semacan itu. Operator aritmatika lainnya hanya bekerja dengan angka dan selalu mengubah operannya menjadi angka.
Ini adalah contoh untuk pengurangan dan pembagian:
```js run
alert( 6 - '2' ); // 4, mengubah '2' menjadi angka
alert( '6' / '2' ); // 3, mengubah keduanya menjadi angka
```
## Konversi angka, unary +
Plus `+` ada dalam dua bentuk: bentuk binary yang kita gunakan di atas dan bentuk unary.
Plus unary atau, dalam kata lain, operator plus `+` diaplikasikan ke nilai tunggal, tak berefek apapun ke angka. Tapi jika operand bukan angka, plus unary dikonversi ke dalam angka.
Misalnya:
```js run
// Tak ada efek ke angka
let x = 1;
alert( +x ); // 1
let y = -2;
alert( +y ); // -2
*!*
// Mengkonversi non-angka
alert( +true ); // 1
alert( +"" ); // 0
*/!*
```
Sebenarnya ia melakukan hal yang sama seperti `Number(...)`, tapi lebih pendek.
Kebutuhan mengkonversi string ke angka sangat sering meningkat. Misalnya, jika kita memperoleh nilai dari kolom di form HTML, mereka biasanya string. Bagaimana jika kita ingin menjumlahkan mereka?
Plus binary akan menambah mereka sebagai string:
```js run
let apples = "2";
let oranges = "3";
alert( apples + oranges ); // "23", plus binary mengkonkatenasi string
```
Jika kita ingin memperlakukan mereka sebagai angka, kita harus mengkonversi, lalu menjumlahkan mereka:
```js run
let apples = "2";
let oranges = "3";
*!*
// kedua nilai dikonversi ke angka sebelum plus binary
alert( +apples + +oranges ); // 5
*/!*
// varian lebih panjang
// alert( Number(apples) + Number(oranges) ); // 5
```
Dari sisi pandang matematikawan, melimpahnya plus terlihat aneh. Tapi dari sisi pandang programmer, tak ada yang spesial: plus unary diaplikasikan dahulu, lalu mengkonversi string ke angka, dan lalu binary plus menjumlahkan mereka.
Kenapa plus unary diaplikasi ke nilai sebelum binarynya? Seperti yang kita lihat, itu karena *peresedensi lebih tinggi* mereka.
## Presedensi operator
Jika expresi punya lebih dari satu operator, urutan eksekusi ditentukan oleh *presedensi* mereka, atau dengan kata lain, urutan prioritas default operator.
Dari sekolah, kita semua tahu bahwa perkalian dalam expresi `1 + 2 * 2` harus dihitung sebelum penambahan. Itulah arti dari presedensi. Perkalian disebut memiliki *presedensi lebih tinggi* dari penambahan.
Tanda kurung mengesampingkan presedensi apapun, jadi jika kita tak puas dengan urutan default, kita bisa gunakan mereka untuk mengubahnya. Misalnya: tulis `(1 + 2) * 2`.
Ada banyak operator di JavaScript. Tiap operator punya nomor presedensi masing-masing. Nomor yang lebih besar dieksekusi terlebih dahulu. Jika presedensinya sama, urutan eksekusinya dari kiri ke kanan.
Di sini adalah extrak dari [tabel presedensi](https://developer.mozilla.org/en/JavaScript/Reference/operators/operator_precedence) (kamu tak usah mengingat ini, tapi catat bahwa operator unary lebih tinggi dari binary terkait):
| Presedensi | Nama | Tanda |
|------------|------|------|
| ... | ... | ... |
| 17 | plus unary | `+` |
| 17 | negasi unary | `-` |
| 16 | akar pangkat | `**` |
| 15 | perkalian | `*` |
| 15 | pembagian | `/` |
| 13 | penambahan | `+` |
| 13 | pengurangan | `-` |
| ... | ... | ... |
| 3 | penetapan | `=` |
| ... | ... | ... |
Seperti yang kita lihat, "plus unary" punya prioritas `17` yang lebih tinggi dari `13` "penambahan" (plus binary). Itulah kenapa, dalam expresi `"+apples + +oranges"`, plus unary bekerja sebelum penambahan.
## Penetapan
Mari ingat bahwa penetapan `=` juga merupakan operator. Ia terdaftar di tabel presedensi dengan prioritas sangat rendah `3`.
Itulah kenapa, ketika kita tetapkan variabel, seperti `x = 2 * 2 + 1`, kalkulasinya dilakukan pertama dan kemudian `=` dievaluasi, menyimpan hasilnya dalam in `x`.
```js
let x = 2 * 2 + 1;
alert( x ); // 5
```
### Assignment = mengembalikan nilai
Fakta dari `=` menjadi sebuah operator, bukanlah sebuah hal yang "fantastis" konstruksi dari bahasa memiliki implikasi yang menarik.
Kebanyakan operator di Javascript mengembalikan sebuah nilai. Sudah jelas untuk `+` dan `-`, tetapi berlaku juga untuk `=`.
Panggilan `x = value` menulis `value` ke dalam `x` *dan mengembalikannya*.
Ini adalah demo yang menggunakan penetapan sebagai bagian dari expresi yang rumit:
```js run
let a = 1;
let b = 2;
*!*
let c = 3 - (a = b + 1);
*/!*
alert( a ); // 3
alert( c ); // 0
```
Di contoh di atas, hasil dari expresi `(a = b + 1)` ialah nilai yang ditetapkan ke `a` (yaitu `3`). Ia kemudian digunakan untuk evaluasi berikutnya.
Kodenya lucu, kan? kita harus mengerti bagaimana itu bekerja, karena terkadang kita melihat hal itu didalam library Javascript.
Dan juga, tolong jangan tulis kode seperti itu. Trik semacam itu tidak akan membuat kode menjadi jelas dan mudah dibaca.
### Chaining assignments / Assignments berantai
Fitur menarik lainnya adalah kemampuan untuk melakukan assignments berantai:
```js run
let a, b, c;
*!*
a = b = c = 2 + 2;
*/!*
alert( a ); // 4
alert( b ); // 4
alert( c ); // 4
```
Assignments berantai mengevaluasi dari kanan ke kiri. Pertama, dari ekspresi paling kanan `2 + 2` di evaluasi terlebih dahulu dan dimasukan kedalam variabel disebelah kiri: `c`, `b` dan `a`. Dan diakhir, seluruh variabel saling membagi satu nilai.
Sekali lagi, untuk tujuan kode yang mudak dibaca akan lebih baik untuk membagi kode kedalam beberapa baris:
```js
c = 2 + 2;
b = c;
a = c;
```
Ini akan mudah untuk dibaca, terutama jika melihatnya secara sekilas.
## Mengubah variabel secara langsung
Kita terkadang membutuhkan sebuah operator untuk sebuah variabel dan menyimpan hasil baru didalam variabel yang sama
Contoh:
```js
let n = 2;
n = n + 5;
n = n * 2;
```
Notasi ini bisa diperpendek dengan menggunakan operator `+=` dan `*=`:
```js run
let n = 2;
n += 5; // sekarang n = 7 (sama dengan n = n + 5)
n *= 2; // sekarang n = 14 (sama dengan n = n * 2)
alert( n ); // 14
```
Operator dari "ubah-dan-simpan" atau bisa disebut mengubah variabel secara langsung hadir pada setiap aritmatik dan operator bitwise: `/=`, `-=`, etc.
Operator semacam itu memiliki hak dengan tingkat yang sama dengan assignment yang biasa, jadi mereka akan berjalan setelah kalkulasi lainnya selesai:
```js run
let n = 2;
n *= 3 + 5;
alert( n ); // 16 (bagian paling kanan dievaluasi terlebih dahulu, sama seperti n *= 8)
```
## Inkremen/dekremen
<!-- Tak bisa menggunakan "--/++" di judul, karena built-in parse mengubahnya menjadi sebuah "dash"/- -->
Menaikkan atau menurunkan satu angka ialah salah satu operasi numerik paling umum.
Jadi, ada operator spesial untuk itu:
- **Inkremen** `++` menaikkan variabel sebanyak 1:
```js run no-beautify
let counter = 2;
counter++; // cara kerjanya sama dengan counter = counter + 1, tapi lebih pendek
alert( counter ); // 3
```
- **Decrement** `--` menurunkan variabel sebanyak 1:
```js run no-beautify
let counter = 2;
counter--; // cara kerjanya sama dengan counter = counter - 1,tapi lebih pendek
alert( counter ); // 1
```
```warn
Inkremen/dekremen cuma bisa diaplikasikan ke variabel. Mencoba menggunakan itu pada nilai seperti `5++` akan menghasilkan galat.
```
Operator `++` dan `--` bisa ditaruh sebelum atau setelah variabel.
- Ketika operatornya ditaruh setelah variabel, ia ada dalam "bentuk postfix": `counter++`.
- "Bentuk prefix" ialah ketika operatornya ditaruh sebelum variabel: `++counter`.
Kedua pernyataan ini melakukan hal yang sama: menambah `counter` sebanyak `1`.
Apakah ada perbedaan? Ya, tapi kita cuma bisa melihatnya jika kita menggunakan nilai kembalian `++/--`.
Mari kita klarifikasi. Seperti yang kita tahu, semua operator mengembalikan nilai. Inkremen/dekremen bukan pengecualian. Bentuk prefix mengembalikan nilai baru sedangkan bentuk postfix mengembalikan nilai lama (sebelum inkremen/dekremen).
Untuk melihat perbedaannya, berikut misalnya:
```js run
let counter = 1;
let a = ++counter; // (*)
alert(a); // *!*2*/!*
```
Dalam baris `(*)`, bentuk *prefix*`++counter` menginkremen `counter` dan mengembalikan nilai baru, `2`. Jadi, `alert` menampilkan `2`.
Sekarang, mari kita gunakan bentuk postfix:
```js run
let counter = 1;
let a = counter++; // (*) ganti ++counter ke counter++
alert(a); // *!*1*/!*
```
Dalam baris `(*)`, bentuk *postfix* `counter++` juga menginkremen `counter` tapi mengembalikan nilai *lama* (sebelum inkremen). Jadi, `alert` menampilkan `1`.
Ringkasnya:
- Jika hasil dari inkremen/dekremen tak digunakan, tak ada bedanya bentuk mana yang dipakai:
```js run
let counter = 0;
counter++;
++counter;
alert( counter ); // 2, kedua counter diatas melakukan hal yang serupa.
```
- Jika kita ingin menaikkan nilai *dan* langsung memakai hasil dari operator, kita butuh bentuk prefix:
```js run
let counter = 0;
alert( ++counter ); // 1
```
- Jika kita ingin menginkremen suatu nilai tanpa memakai nilai sebelumnya, kita butuh bentuk postfix:
```js run
let counter = 0;
alert( counter++ ); // 0
```
````smart header="Inkremen/dekremen di antara operator lainnya"
Operator `++/--` bisa juga digunakan di dalam expresi. Presedensi mereka lebih tinggi dari kebanyakan operasi aritmatika lainnya.
Misalnya:
```js run
let counter = 1;
alert( 2 * ++counter ); // 4
```
Bandingkan dengan:
```js run
let counter = 1;
alert( 2 * counter++ ); // 2, karena counter++ mengembalikan nilai "lama"
```
Meski secara teknis OK, notasi macam ini biasanya membuat kode kurang dapat dibaca. Satu baris melakukan banyak hal -- tak baik.
Sambil membaca kode, dan melihatnya secara sekilas kita bisa saja melewatkan kode seperti `counter++` dan tidak akan jelas bahwa nilai variabel telah bertambah.
Jadi direkomendasikan menuliskan kode dengan gaya "satu baris -- satu aksi":
```js run
let counter = 1;
alert( 2 * counter );
counter++;
```
````
## Operator bitwise
Operator bitwise memperlakukan argumen sebagai angka integer 32-bit dan bekerja pada level representasi biner mereka.
Operator ini bukan spesifik JavaScript. Mereka didukung di banyak bahasa pemrograman.
Daftar operator:
- AND ( `&` )
- OR ( `|` )
- XOR ( `^` )
- NOT ( `~` )
- LEFT SHIFT ( `<<` )
- RIGHT SHIFT ( `>>` )
- ZERO-FILL RIGHT SHIFT ( `>>>` )
Operator seperti diatas sangat jarang digunakan, ketika kita membutuhkan untuk memainkan angka di level paling rendah (bitwise). Kita tidak akan membutuhkan operator seperti ini dalam waktu dekat, sebagaimana dalam pengembangan web penggunaan operator seperti itu lebih sedikit, tetapi di area yang spesial, seperti kriptographi, operator seperti itu sangan dibutuhkan. Kamu bisa membaca artikel [Bitwise Operators](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators) di MDN ketika kamu membutuhkannya.
## Koma
Operator koma `,` ialah satu dari banyak operator paling langka dan tak biasa. Kadang, ia digunakan untuk menulis kode lebih pendek, jadi kita harus tahu itu untuk memahami apa yang terjadi.
Operator koma memperbolehkan untuk mengevaluasi beberapa expresi, membagi mereka dengan koma `,`. Each of them is evaluated but only the result of the last one is returned.
Misalnya:
```js run
*!*
let a = (1 + 2, 3 + 4);
*/!*
alert( a ); // 7 (hasil dari 3 + 4)
```
Di sini, expresi pertama `1 + 2` dievaluasi dan hasilnya dibuang. Lalu, `3 + 4` dievaluasi dan dikembalikan sebagai hasilnya.
```smart header="Koma punya presedensi sangat kecil"
Harap ingat bahwa operator koma punya presedensi sangat kecil, lebih kecil dari `=`, jadi tanda kurung penting dalam contoh di atas.
Tanpa mereka: `a = 1 + 2, 3 + 4` mengevaluasi `+` terlebih dahulu, menjumlahkan mereka menjadi `a = 3, 7`, lalu operator penetapan `=` menetapkan `a = 3`, dan sisanya diabaikan. Ini seperti `(a = 1 + 2), 3 + 4`.
```
Kenapa kita butuh operator yang membuang semuanya kecuali expresi terakhir?
Kadang, orang memakai itu dalam konstruksi rumit untuk menaruh beberapa aksi dalam satu baris.
Misalnya:
```js
// tiga operasi dalam satu baris
for (*!*a = 1, b = 3, c = a * b*/!*; a < 10; a++) {
...
}
```
Trik macam ini dipakai di banyak framework JavaScript. Itulah kenapa kita membahas mereka. Tapi, biasanya, mereka tak membuat kode mudah dibaca sehingga kita sebaiknya pikir-pikir dulu sebelum menggunakan mereka.
================================================
FILE: 1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md
================================================
```js no-beautify
5 > 4 → true
"apple" > "pineapple" → false
"2" > "12" → true
undefined == null → true
undefined === null → false
null == "\n0\n" → false
null === +"\n0\n" → false
```
Beberapa alasan:
1. Sudah jelas, true.
2. Pembandingan kamus, jadi false. `"a"` lebih kecil dari `"p"`.
3. Lagi, pembandingan kamus, karakter pertama `"2"` lebih besar dari karakter pertama `"1"`.
4. Nilai `null` dan `undefined` selalu bernilai sama.
5. Equalitas ketat memang ketat. Tipe berbeda dari kedua sisi menghasilkan false.
6. Serupa dengan `(4)`, `null` hanya sama dengan `undefined`.
7. Equalitas ketat dari tipe berbeda.
================================================
FILE: 1-js/02-first-steps/09-comparison/1-comparison-questions/task.md
================================================
nilai penting: 5
---
# Pembandingan
Apa hasil dari expresi ini?
```js no-beautify
5 > 4
"apple" > "pineapple"
"2" > "12"
undefined == null
undefined === null
null == "\n0\n"
null === +"\n0\n"
```
================================================
FILE: 1-js/02-first-steps/09-comparison/article.md
================================================
# Perbandingan
Kita tahu beberapa operator pembanding dari matematika.
Didalam Javascript operator-operator itu ditulis seperi ini:
- Lebih besar/kurang dari: <code>a > b</code>, <code>a < b</code>.
- Lebih besar/kurang dari atau sama: <code>a >= b</code>, <code>a <= b</code>.
- Sama dengan: `a == b`, perhatikan tanda dua `=` digunakan untuk test persamaan, jika menggunakan satu `=` seperti `a = b` itu adalah sebuah asignment atau memasukan nilai kedalam variabel.
- Tidak sama dengan: Didalam matematika notasinya seperti <code>≠</code>, tetapi didalam Javascript ditulis seperti <code>a != b</code>.
Didalam artikel ini kita akan belajar lebih lanjut tentang perbedaan tipe dari perbandingan, bagaimana cara Javascript membuatnya, termasuk sifat-sifat penting.
Diakhir nanti kamu akan menemukan hal yang bagus untuk menghindari masalah yang berhubungan dengan "kebiasaan Javascript".
## Boolean ialah hasilnya
Semua operator pembanding mengembalikan nilai boolean:
- `true` -- berarti "ya", "betul" atau "fakta".
- `false` -- berarti "tidak", "salah" atau "bukan fakta".
Misalnya:
```js run
alert( 2 > 1 ); // true (benar)
alert( 2 == 1 ); // false (salah)
alert( 2 != 1 ); // true (benar)
```
Hasil perbandingan bisa ditetapkan ke variabel, sama seperti nilainya:
```js run
let result = 5 > 4; // tetapkan hasil perbandingan
alert( result ); // true
```
## Perbandingan string
Untuk melihat apakah satu string lebih besar dari yang lain, JavaScript menggunakan yang disebut "kamus" atau urutan "lexicografik".
Dengan keta lain, string diperbandingkan huruf-demi-huruf.
Misalnya:
```js run
alert( 'Z' > 'A' ); // true
alert( 'Glow' > 'Glee' ); // true
alert( 'Bee' > 'Be' ); // true
```
algoritma untuk membandingkan dua string sederhana:
1. Bandingkan karakter pertama dari kedua string.
2. Jika karakter pertama dari string pertama lebih besar (atau lebih kecil) dari string kedua, maka string pertama lebih besar (atau lebih kecil) dari string kedua. Kita selesai.
3. Sebaliknya, jika karakter pertama kedua string sama, bandingkan karakter kedua dengan cara sama.
4. Ulangi sampai string berakhir.
5. Jika kedua string berakhir pada panjang yang sama, maka mereka sama. Sebaliknya, string lebih panjang yang lebih besar.
Pada contoh di atas, pembandingan `'Z' > 'A'` menghasilkan pada langkah pertama sedangkan string `"Glow"` dan `"Glee"` dibandingkan karakter-demi-karakter:
1. `G` sama dengan `G`.
2. `l` sama dengan `l`.
3. `o` lebih besar dari `e`. Berhenti di sini. String pertama lebih besar.
```smart header="Bukan dictionary riil, tapi urutan Unicode"
Algoritma pembangingan yang diberikan di atas secara kasar equivalen dengan yang digunakan dalam kamus atau buku telpon, tapi tak sepenuhnya sama.
Misalnya, case diperhitungkan. Huruf besar `"A"` tak sama dengan huruf kecil `"a"`. Yang mana yang lebih besar? Huruf kecil `"a"`. Kenapa? Karena karakter huruf kecil punya index lebih besar dalam tabel encoding internal yang dipakai JavaScript (Unicode). Kita akan kembali ke detil spesifik dan konsekuensinya dalam bab <info:string>.
```
## Pembandingan dari tipe yang berbeda
Ketika membandingkan nilai dari tipe yang berbeda, JavaScript mengkonversi nilai tersebut ke angka.
Misalnya:
```js run
alert( '2' > 1 ); // true, string '2' menjadi angka 2
alert( '01' == 1 ); // true, string '01' menjadi angka 1
```
Untuk nilai boolean, `true` menjadi `1` dan `false` menjadi `0`.
Misalnya:
```js run
alert( true == 1 ); // true
alert( false == 0 ); // true
```
````smart header="Konsekuensi lucu"
Memungkinkan juga bahwa pada saat yang sama:
- Dua nilai equal.
- Satu dari mereka `true` sebagai boolean dan satunya lagi `false` sebagai boolean.
Misalnya:
```js run
let a = 0;
alert( Boolean(a) ); // false
let b = "0";
alert( Boolean(b) ); // true
alert(a == b); // true!
```
Dari cara pandang JavaScript', hasil ini terbilang normal. Pengecekan equalitas mengkonversi nilai menggunakan konversi numerik (jadi `"0"` menjadi `0`), sedangkan konversi explisit `Boolean` menggunakan set aturan yang lain.
````
## Equalitas ketat
Pengecekan equalitas reguler `==` punya satu problem. Ia tak bisa membedakan `0` dari `false`:
```js run
alert( 0 == false ); // true
```
Hal yang sama terjadi pada string kosong:
```js run
alert( '' == false ); // true
```
Ini terjadi karena operand dari tipe yang berbeda dikonversi ke angka oleh operator equalitas `==`. String kosong, sama seperti `false`, menjadi nol.
Apa yang dilakukan jika kita ingin membedakan `0` dari `false`?
**Operator equalitas ketat `===` mengecek equalitas tanpa konversi tipe.**
Dengan kata lain, jika `a` dan `b` tipenya berbeda, maka `a === b` segera menghasilkan `false` tanpa konversi apapun terhadap mereka.
Mari kita coba:
```js run
alert( 0 === false ); // false, karena tipenya berbeda
```
Ada juga operator "non-equalitas ketat" `!==` yang analog dengan `!=`.
Operator equalitas ketat sedikit lebih panjang untuk ditulis, tapi lebih memperlihatkan apa yang terjadi dan meninggalkan ruang lebih kecil untuk galat.
## Pembandingan dengan null dan undefined
Ada sikap non-intuitif ketika `null` atau `undefined` diperbandingkan dengan nilai lain.
Untuk pengecekan equalitas ketat `===`
: Nilai ini berbeda, karena setiap dari mereka tipenya berbeda.
```js run
alert( null === undefined ); // false
```
Untuk pengecekan non-ketat `==`
: Ada aturan spesial. Kedyanya merupakan "pasangan manis": mereka sama (karena `==`), tapi tidak dengan nilai lain manapun.
```js run
alert( null == undefined ); // true
```
Untuk pembandingan matematika dan lainnya `< > <= >=`
: `null/undefined` dikonversi ke angka: `null` menjadi `0`, sedangkan `undefined` menjadi `NaN`.
Sekarang mari kita lihat beberapa hal lucu yang terjadi ketika kita menerapkan aturan ini. Dan, yang lebih penting, bagaimana supaya tidak jatuh ke dalam perangkap ini.
### Hasil aneh: null vs 0
Mari kita bandingkan `null` dengan nol:
```js run
alert( null > 0 ); // (1) false
alert( null == 0 ); // (2) false
alert( null >= 0 ); // (3) *!*true*/!*
```
Secara matematik, ini aneh. Hasil terakhir menyatakan bahwa "`null` lebih besar atau sama dengan nol", seharusnya salah satu dari pembandingan di atasnya `true`, tapi nyatanya malah tidak.
Alasannya ialah pengecekan equalitas `==` dan pembandingan `> < >= <=` bekerja secara berbeda. Pembandingan mengkonversi `null` ke angka `0`. Itulah kenapa (3) `null >= 0` true dan (1) `null > 0` false.
Di sisi lain, pengecekan equalitas `==` untuk `undefined` and `null` dijelaskan bahwa, tanpa konversi apapun, mereka sama dengan satu sama lain dan tidak sama dengan nilai lain manapun. Itulah kenapa (2) `null == 0` is false.
### Uundefined yang tak bisa diperbandingkan
Nilai `undefined` sebainya tak diperbandingkan dengan nilai lain:
```js run
alert( undefined > 0 ); // false (1)
alert( undefined < 0 ); // false (2)
alert( undefined == 0 ); // false (3)
```
Kenapa ia tak suka sekali dengan nol? Selalu false!
Kita dapatkan hasil ini karena:
- Pembandingan `(1)` dan `(2)` menghasilkan `false` karena `undefined` dikonversi ke `NaN` dan `NaN` merupakan numerik spesial yang mengembalikan `false` untuk semua pembandingan.
- Pengecekan equalitas `(3)` mengembalikan `false` karena `undefined` hanya sama dengan `null` dan tidak dengan nilai lain manapun.
### Hindari problem
Kenapa kita menggunakan contoh ini? Haruskah kita ingat semua keanehan ini? Tidak juga. Sebenarnya, hal tricky macam ini akan menjadi akrab seiring waktu, tapi ada cara solid untuk menghindari masalah dengan mereka:
Perlakukan pembandingan manapun dengan `undefined/null` kecuali equalitas ketat `===` dengan hati-hati.
Jangan gunakan pembandingan `>= > < <=` dengan variabel yang bisa jadi `null/undefined`, kecuali kamu paham apa yang kamu lakukan. Jika variabel bisa punya nilai ini, cek mereka secara terpisah.
## Kesimpulan
- Operator pembandingan menghasilkan nilai boolean.
- String dibandingkan huruf-demi-huruf dalam urutan "kamus".
- Ketika nilai dari tipe berbeda diperbandingkan, mereka dikonversi ke angka (kecuali pengecekan equalitas ketat).
- Nilai `null` dan `undefined` sama dengan `==` satu sama lain dan tidak sama dengan nilai lain manapun.
- Waspada ketika menggunakan pembandingan seperti `>` atau `<` dengan variabel yang kadang bisa jadi `null/undefined`. Pengecekan secara terpisah `null/undefined` merupakan ide yang bagus.
================================================
FILE: 1-js/02-first-steps/10-ifelse/1-if-zero-string/solution.md
================================================
**Ya, tentu saja.**
Setiap string kecuali yang kosong (ingat bahwa `" 0 "` tidak kosong) menjadi `true` dalam konteks logika boolean.
Kita dapat mengeksekusi dan mengecek kode di bawah ini :
```js run
if ("0") {
alert( 'Hello' );
}
```
================================================
FILE: 1-js/02-first-steps/10-ifelse/1-if-zero-string/task.md
================================================
Nilai penting: 5
---
# if (string berisi angka nol)
Apakah `alert` akan dieksekusi?
```js
if ("0") {
alert( 'Hello' );
}
```
================================================
FILE: 1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2/index.html
================================================
<!DOCTYPE html>
<html>
<body>
<script>
'use strict';
let value = prompt('Apakah nama "official" dari Javascript?', '');
if (value == 'ECMAScript') {
alert('Benar sekali!');
} else {
alert("Kamu tidak tahu? ECMAScript!");
}
</script>
</body>
</html>
================================================
FILE: 1-js/02-first-steps/10-ifelse/2-check-standard/solution.md
================================================
[html run src="ifelse_task2/index.html"]
================================================
FILE: 1-js/02-first-steps/10-ifelse/2-check-standard/task.md
================================================
Nilai penting: 2
---
# Nama JavaScript
Dengan menggunakan konstruksi `if..else`, tulis kode yang menanyakan: 'Apa nama "official" JavaScript?'
Jika pengunjung memasukkan "ECMAScript", maka tunjukkan output "Benar!", Jika tidak - tunjukkan output: "Tidak tahu? ECMAScript!"

[demo src="ifelse_task2"]
================================================
FILE: 1-js/02-first-steps/10-ifelse/3-sign/if_sign/index.html
================================================
<!DOCTYPE html>
<html>
<body>
<script>
'use strict';
let value = prompt('Tuliskan sebuah angka', 0);
if (value > 0) {
alert(1);
} else if (value < 0) {
alert(-1);
} else {
alert(0);
}
</script>
</body>
</html>
================================================
FILE: 1-js/02-first-steps/10-ifelse/3-sign/solution.md
================================================
```js run
let value = prompt('Masukan sebuah angka', 0);
if (value > 0) {
alert( 1 );
} else if (value < 0) {
alert( -1 );
} else {
alert( 0 );
}
```
================================================
FILE: 1-js/02-first-steps/10-ifelse/3-sign/task.md
================================================
Nilai penting: 2
---
# Tunjukkan tandanya
Dengan menggunakan `if..else`, tulis kode yang mendapatkan nomor melalui` prompt` dan kemudian tampilkan nomornya dengen menggunakan `alert`:
- `1`, jika nilainya lebih besar dari nol,
- `-1`, jika kurang dari nol,
- `0`, jika sama dengan nol.
Dalam tugas ini kita mengasumsikan bahwa input selalu berupa angka.
[demo src="if_sign"]
================================================
FILE: 1-js/02-first-steps/10-ifelse/5-rewrite-if-question/solution.md
================================================
```js
let result = (a + b < 4) ? 'Kurang' : 'Lebih';
```
================================================
FILE: 1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md
================================================
Nilai penting: 5
---
# Tulis ulang 'if' menggunakan '?'
Tulis ulang `if` menggunakan operator kondisional `'?'`:
```js
let result;
if (a + b < 4) {
result = 'Kurang';
} else {
result = 'Lebih';
}
```
================================================
FILE: 1-js/02-first-steps/10-ifelse/6-rewrite-if-else-question/solution.md
================================================
```js
let message = (login == 'Karyawan') ? 'Hallo' :
(login == 'Direksi') ? 'Salam Hangat!' :
(login == '') ? 'Belum Login' :
'';
```
================================================
FILE: 1-js/02-first-steps/10-ifelse/6-rewrite-if-else-question/task.md
================================================
Nilai penting: 5
---
# Tulis ulang 'if..else' menjadi '?'
Tulis ulang `if..else` menggunakan beberapa operator ternary` '?' `.
Agar mudah dibaca, disarankan untuk membagi kode menjadi beberapa baris.
```js
let message;
if (login == 'Karyawan') {
message = 'Hallo';
} else if (login == 'Direksi') {
message = 'Salam Hangat!';
} else if (login == '') {
message = 'Belum Login';
} else {
message = '';
}
```
================================================
FILE: 1-js/02-first-steps/10-ifelse/article.md
================================================
# Kondisi bercabang: if, '?'
Terkadang, kita perlu melakukan tindakan berbeda berdasarkan kondisi yang berbeda.
Untuk melakukan itu, kita dapat menggunakan pernyataan `if` dan operator kondisional `?`, yang juga merupakan "question mark" operator (operator tanda tanya).
## Pernyataan "if"
Pernyataan `if` mengevaluasi suatu kondisi dan, jika hasil kondisi itu `true`, maka blok kode di dalam `if` akan diexekusi.
Sebagai contoh:
```js run
let tahun = prompt('Ditahun berapa spesifikasi ECMAScript-2015 dipublikasikan?', '');
*!*
if (tahun == 2015) alert( 'Kamu Benar!' );
*/!*
```
Pada contoh di atas, persyaratannya adalah pemeriksaan kesetaraan sederhana (`tahun == 2015`), tetapi pada kode lain, bisa menjadi jauh lebih kompleks.
Jika kita ingin menjalankan lebih dari satu pernyataan di dalam suatu kondisional blok kode, kita harus membungkus blok kode kita di dalam kurung kurawal {} :
```js
if (tahun == 2015) {
alert( "Kamu Benar!" );
alert( "Kamu Memang Pintar!" );
}
```
Disarankan untuk membungkus blok kode Anda dengan kurung kurawal `{}` setiap kali Anda menggunakan pernyataan `if`, bahkan jika hanya ada satu pernyataan di dalam suatu blok kode. Hal ini agar kode anda mudah dibaca oleh anda di masa depan,dan tentu saja oleh orang lain.
## Konversi Boolean
Pernyataan `if (…)` mengevaluasi ekspresi dalam tanda kurung dan mengubah hasilnya menjadi boolean.
Mari kita mengingat kembali aturan konversi dari bab <info:type-conversions>:
- Angka `0`, string kosong `""`, `null`, `undefined`, dan `NaN` semuanya menjadi salah (`false`). Oleh sebab itu,mereka disebut nilai-nilai "falsy" (palsu/salah)
- Nilai-nilai yang lain menjadi benar (`true`), sehingga kadang mereka disebut "truthy" (benar)
Jadi, kode dalam kondisi ini tidak akan pernah berjalan:
```js
if (0) { // 0 adalah falsy
...
}
```
... dan di dalam kondisi ini - selalu akan berjalan:
```js
if (1) { // 1 adalah truthy
...
}
```
Kamu juga dapat memberikan nilai boolean yang telah dievaluasi ke `if`, seperti ini::
```js
let kondisi = (tahun == 2015); // mengevaluasi nilai apakah *true* atau *false*
if (kondisi) {
...
}
```
## Klausa "else"
Pernyataan `if` dapat berisi blok opsional "else" opsional. Block "else" dijalankan ketika semua kondisi di atas blok "else" salah (false) semua.
Contohnya:
```js run
let tahun = prompt('Ditahun berapa spesifikasi ECMAScript-2015 dipublikasikan?'', '');
if (tahun == 2015) {
alert( 'Jawaban kamu benar!' );
} else {
alert( 'Hah, kok jawaban kamu salah?' ); // nilai lainnya selain 2015
}
```
## Pernyataan kondisional lebih dari satu: "else if"
Terkadang, kita ingin menguji beberapa kondisi yang berbeda-beda Klausa `else if` memungkinkan kita melakukan itu.
Sebagai contoh:
```js run
let tahun = prompt('Ditahun berapa spesifikasi ECMAScript-2015 dipublikasikan?', '');
if (tahun < 2015) {
alert( 'Terlalu dini...' );
} else if (tahun > 2015) {
alert( 'Terlalu akhir' );
} else {
alert( 'Tepat sekali!' );
}
```
Pada kode di atas, pertama JavaScript mengecek ekspresi `tahun < 2015`. Jika itu salah, maka masuk ke kondisi selanjutnya `tahun > 2015`. Jika itu juga salah, pernyataan di dalam blok "else" akan dijalankan,yang merupakan sebuah alert
Blok `else if`bisa digunakan berkali-kali. Pernyataan final `else` hanya opsional.
## Operator Kondisional '?'
Terkadang, kita perlu memberi nilai ke suatu variabel tergantung pada suatu kondisi.
Contohnya:
```js run no-beautify
let accessAllowed;
let umur = prompt('Berapakah umur kamu?', '');
*!*
if (umur > 18) {
accessAllowed = true;
} else {
accessAllowed = false;
}
*/!*
alert(accessAllowed);
```
Operator "question mark" (tanda tanya) memungkinkan kita melakukan kode di atas dengan cara yang lebih singkat dan sederhana.
Operator tersebut direpresentasikan oleh tanda tanya `?`. Nama lain dari operator ini adalah "ternary", karena operator ini memiliki tiga operan (ternary bahasa Indonesia adalah "terdiri dari 3 bagian"). Ini sebenarnya satu-satunya operator dalam JavaScript yang memiliki 3 operan.
Sintaksnya adalah:
```js
let result = condition ? value1 : value2;
```
Di kode di atas, `condition` dievaluasi: jika itu benar maka value1 akan dikembalikan, jika tidak - value2 yang akan dikembalikan.
Contohnya:
```js
let accessAllowed = (age > 18) ? true : false;
```
Secara teknis, kita dapat menghilangkan tanda kurung di sekitar `age > 18` . Operator tanda tanya memiliki prioritas rendah, sehingga hanya akan dijalankan setelah perbandingan `>` .
Contoh di bawah ini akan melakukan hal yang sama seperti kode sebelumnya:
```js
// perbandingan operator "age > 18" dieksekusi pertama kali
// (tidak perlu dibungkus dengan kurung)
let accessAllowed = age > 18 ? true : false;
```
Tetapi tanda kurung membuat kode lebih mudah dibaca, jadi kami sarankan untuk tetap menggunakannya di kode-kode anda.
````smart
Pada contoh di atas, Anda dapat menghindari pengunaan operator tanda tanya karena perbandingan itu sendiri menghasilkan `true/false`:
```js
// the same
let accessAllowed = age > 18;
```
````
## Multiple '?'
Rangkaian operator tanda tanya `?` dapat mengembalikan nilai yang tergantung pada lebih dari satu kondisi.
Contohnya:
```js run
let age = prompt('age?', 18);
let message = (age < 3) ? 'Hi, baby!' :
(age < 18) ? 'Hello!' :
(age < 100) ? 'Greetings!' :
'What an unusual age!';
alert( message );
```
Mungkin sulit pada awalnya untuk memahami apa yang terjadi. Tetapi setelah melihat lebih dekat, kita dapat melihat bahwa itu hanya serangkaian tes biasa:
1. Tanda tanya pertama memeriksa apakah `age < 3`.
2. Jika benar -- `'Hi, baby!'` akan dikembalikan. Jika tidak, kode akan melanjutkan ke ekspresi setelah titik dua '":"', memeriksa apakah `age < 18`.
3. Jika itu benar -- `'Hello!'` akan dikembalikan. . Jika tidak, kode akan melanjutkan ke ekspresi setelah titik dua berikutnya '":"', memeriksa `age < 100`.
4. Jika itu benar -- `'Greetings!'` akan dikembalikan. Jika tidak, kode akan melanjutkan ke ekspresi setelah titik dua terakhir '":"', dan akhirnya akan mengembalikan `'What an unusual age!'`.
Kode bawah ini memperlihatkan apabila menggunakan `if..else` untuk kode di atas:
```js
if (age < 3) {
message = 'Hi, baby!';
} else if (age < 18) {
message = 'Hello!';
} else if (age < 100) {
message = 'Greetings!';
} else {
message = 'What an unusual age!';
}
```
## Penggunaan '?' yang non-tradisional
Terkadang tanda tanya `?` digunakan sebagai pengganti `if`:
```js run no-beautify
let company = prompt('Which company created JavaScript?', '');
*!*
(company == 'Netscape') ?
alert('Right!') : alert('Wrong.');
*/!*
```
Bergantung pada kondisional `company == 'Netscape' , ekspresi pertama atau kedua setelah `?` akan dieksekusi dan menunjukkan sebuah "alert".
Kita tidak memberikan nilai hasil ke suatu variable di sini. Sebagai gantinya, kita mengeksekusi kode yang berbeda tergantung pada kondisinya.
**Tidak disarankan memakai operator tanda tanya dengan cara ini.**
Notasinya memang lebih pendek daripada apabila menggunakan pernyataan `if` , yang mungkin menarik bagi beberapa programmer, tetapi hal ini membuat kode anda lebih susah dibaca.
Berikut adalah kode yang sama menggunakan `if` untuk perbandingan:
```js run no-beautify
let company = prompt('Which company created JavaScript?', '');
*!*
if (company == 'Netscape') {
alert('Right!');
} else {
alert('Wrong.');
}
*/!*
```
Mata kita memindai kode secara vertikal. Blok kode yang terdiri dari beberapa baris akan lebih mudah dipahami daripada suatu set instruksi horizontal yang panjang.
Tujuan operator tanda tanya `?` adalah mengembalikan satu nilai atau nilai yang lainnya tergantung pada kondisinya. Mohon untuk gunakan operator tanda tanya hanya untuk fungsi tersebut. Gunakan `if ketika Anda perlu menjalankan berbagai cabang kode yang berbeda-beda
================================================
FILE: 1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/solution.md
================================================
Jawabannya `2`, itu nilai truthy pertama.
```js run
alert( null || 2 || undefined );
```
================================================
FILE: 1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/task.md
================================================
nilai penting: 5
---
# Apa hasil dari OR?
Apakah keluaran dari kode dibawah?
```js
alert( null || 2 || undefined );
```
================================================
FILE: 1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md
================================================
Jawabannya: pertama `1`, lalu `2`.
```js run
alert( alert(1) || 2 || alert(3) );
```
Panggilan `alert` tak mengembalikan nilai. Atau, dengan kata lain, ia mengembalikan `undefined`.
1. Pertama OR `||` mengevaluasi operand kiri `alert(1)`. Ia menampilkan pesan pertama dengan `1`.
2. `alert` mengembalikan `undefined`, jadi OR jalan ke operand kedua mencari nilai truthy.
3. Operand kedua `2` truthy, jadi eksekusinya disela, `2` dikembalikan dan ditampilkan oleh alert terluar.
Tak akan ada `3`, karena evaluasinya tidak mencapai `alert(3)`.
================================================
FILE: 1-js/02-first-steps/11-logical-operators/2-alert-or/task.md
================================================
niai penting: 3
---
# Apa hasil dari alert yang di-OR-kan?
Apa output kode di bawah?
```js
alert( alert(1) || 2 || alert(3) );
```
================================================
FILE: 1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md
================================================
Jawabannya: `null`, karena `null` adalah nilai falsy pertama yang ada di daftar.
```js run
alert( 1 && null && 2 );
```
================================================
FILE: 1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/task.md
================================================
nilai penting: 5
---
# Apa hasil AND?
Kode ini akan menampilkan apa?
```js
alert( 1 && null && 2 );
```
================================================
FILE: 1-js/02-first-steps/11-logical-operators/4-alert-and/solution.md
================================================
Jawabannya: `1`, dan kemudian `undefined`.
```js run
alert( alert(1) && alert(2) );
```
Panggilan `alert` mengembalikan `undefined` (ia cuma menampilkan pesan, jadi tak ada kembalian berarti).
Karena itu, `&&` mengevaluasi operand kiri (output `1`), dan langsung berhenti, karena `undefined` adalah nilai falsy.
Dan `&&` mencari nilai falsy dan mengembalikannya, jadi begitulah.
================================================
FILE: 1-js/02-first-steps/11-logical-operators/4-alert-and/task.md
================================================
nilai penting: 3
---
# Apa hasil dari alert yang di-AND-kan?
Kode ini akan menampilkan apa?
```js
alert( alert(1) && alert(2) );
```
================================================
FILE: 1-js/02-first-steps/11-logical-operators/5-alert-and-or/solution.md
================================================
Jawabannya: `3`.
```js run
alert( null || 2 && 3 || 4 );
```
Presedensi AND `&&` lebih tinggi dari `||`, jadi ia jalan pertama.
Hasil dari `2 && 3 = 3`, jadi expresinya menjadi:
```
null || 3 || 4
```
Sekarang hasilnya jadi nilai truthy pertama: `3`.
================================================
FILE: 1-js/02-first-steps/11-logical-operators/5-alert-and-or/task.md
================================================
nilai penting: 5
---
# Hasil dari OR AND OR
Hasilnya akan jadi apa?
```js
alert( null || 2 && 3 || 4 );
```
================================================
FILE: 1-js/02-first-steps/11-logical-operators/6-check-if-in-range/solution.md
================================================
```js
if (age >= 14 && age <= 90)
```
================================================
FILE: 1-js/02-first-steps/11-logical-operators/6-check-if-in-range/task.md
================================================
nilai penting: 3
---
# Cek kisaran antara
Tulis satu kondisi "if" untuk mengecek bahwa `age` ada di antara `14` dan `90` secara inklusif.
"Secara inklusif" artinya bahwa `age` bisa mencapai `14` atau `90`.
================================================
FILE: 1-js/02-first-steps/11-logical-operators/7-check-if-out-range/solution.md
================================================
Varian pertama:
```js
if (!(age >= 14 && age <= 90))
```
Varian kedua:
```js
if (age < 14 || age > 90)
```
================================================
FILE: 1-js/02-first-steps/11-logical-operators/7-check-if-out-range/task.md
================================================
nilai penting: 3
---
# Cek kisaran luar
Tulis satu kondisi `if` untuk mengecek bahwa `age` BUKAN di antara 14 dan 90 secara inklusif.
Buat dua varian: pertama menggunakan NOT `!`, kedua -- tanpaanya.
================================================
FILE: 1-js/02-first-steps/11-logical-operators/8-if-question/solution.md
================================================
Jawabannya: pertama dan ketiga akan diexekusi.
Detil:
```js run
// Berjalan.
// Hasil dari -1 || 0 = -1, truthy
if (-1 || 0) alert( 'first' );
// Tidak berjalan
// -1 && 0 = 0, falsy
if (-1 && 0) alert( 'second' );
// Eksekusi
// Operator && mempunyai hak yang lebih tinggi daripada ||
// jadi -1 && 1 dieksekusi pertama, dan memberikan rentetan:
// null || -1 && 1 -> null || 1 -> 1
if (null || -1 && 1) alert( 'third' );
```
================================================
FILE: 1-js/02-first-steps/11-logical-operators/8-if-question/task.md
================================================
nilai penting: 5
---
# Pertanyaan tentang "if"
Mana dari `alert` berikut yang akan diexekusi?
Hasil expresinya akan jadi seperti apa di dalam `if(...)`?
```js
if (-1 || 0) alert( 'first' );
if (-1 && 0) alert( 'second' );
if (null || -1 && 1) alert( 'third' );
```
================================================
FILE: 1-js/02-first-steps/11-logical-operators/9-check-login/solution.md
================================================
```js run demo
let userName = prompt("Who's there?", '');
if (userName === 'Admin') {
let pass = prompt('Password?', '');
if (pass === 'TheMaster') {
alert( 'Welcome!' );
} else if (pass === '' || pass === null) {
alert( 'Canceled' );
} else {
alert( 'Wrong password' );
}
} else if (userName === '' || userName === null) {
alert( 'Canceled' );
} else {
alert( "I don't know you" );
}
```
Perhatikan indent vertkal di dalam blok `if`. Mereka secara teknis tak dibutuhkan, tapi membuat kode lebih mudah dibaca.
================================================
FILE: 1-js/02-first-steps/11-logical-operators/9-check-login/task.md
================================================
nilai penting: 3
---
# Cek login
Tulis kode yang meminta login dengan `prompt`.
Jika pengunjung menekan `"Admin"`, maka `prompt` untuk katasandi, jika inputannya beruba baris kosong atau `key:Esc` -- tampilkan "Canceled.", jika string lain -- maka tampilkan "I don't know you".
Katasandinya dicek sebagai berikut:
- Jika ia sama dengan "TheMaster", maka tampilkan "Welcome!",
- String lain -- tampilkan "Wrong password",
- Untuk string kosong atau batal input, tampilkan "Canceled."
Skemanya:

Silakan gunakan blok `if` bersarang. Abaikan kemudahan-baca seluruh kode.
Petunjuk: mengoper inputan kosong ke prompt mengembalikan string kosong `''`. Menekan `key:ESC` saat prompt mengembalikan `null`.
[demo]
================================================
FILE: 1-js/02-first-steps/11-logical-operators/article.md
================================================
# Operator logika
Ada tiga operator logika di JavaScript: `||` (OR), `&&` (AND), `!` (NOT).
Meski mereka dipanggil "logika", mereka bisa diaplikasikan ke nilai tipe apapun, bukan cuma boolean. Hasil mereka bisa juga tipe apapun.
Mari kita lihat detilnya.
## || (OR)
Operator "OR" diwakili dengan dua simbol garis vertical:
```js
result = a || b;
```
Di pemrograman klasik, logika OR gunanya cuma untuk memanipulasi nilai boolean. Jika argumennya ada yang `true`, ia mengembalikan `true`, tapi jika tidak, maka ia mengembalikan `false`.
Di JavaScript, operator ini agak tricky dan lebih kuat. Tapi pertama-tama, ayo kita lihat apa yang terjadi pada nilai boolean.
Ada empat kemungkinan kombinasi logika:
```js run
alert( true || true ); // true
alert( false || true ); // true
alert( true || false ); // true
alert( false || false ); // false
```
Seperti yang kita lihat, hasilnya selalu `true` kecuali jika kedua operand sama-sama `false`.
Jika operand bukan boolean, ia dikonversi ke boolean untuk evaluasi.
Misalnya, angka `1` diperlakukan sebagai `true`, angka `0` sebagai `false`:
```js run
if (1 || 0) { // bekerja seperti if( true || false )
alert( 'truthy!' );
}
```
Seringkali, OR `||` digunakan di pernyataan `if` untuk menguji apakah ada satu kondisi *manapun* yang `true`.
Misalnya:
```js run
let hour = 9;
*!*
if (hour < 10 || hour > 18) {
*/!*
alert( 'The office is closed.' );
}
```
Kita bisa menyampaikan kondisi lebih:
```js run
let hour = 12;
let isWeekend = true;
if (hour < 10 || hour > 18 || isWeekend) {
alert( 'The office is closed.' ); // akhir minggu
}
```
## OR "||" mencari nilai benar pertama [#or-finds-the-first-truthy-value]
Logika di atas memang klasik. Sekarang, mari bawa fitur "extra" JavaScript.
Algoritma luas bekerja seperti berikut.
Untuk nilai yang diORkan:
```js
result = value1 || value2 || value3;
```
Operator OR `||` melakukan hal berikut:
- Mengevaluasi operand dari kiri ke kanan.
- Untuk tiap operand, konversikan ia ke boolean. Jika hasilnya `true`, stop dan mengembalikan nilai original dari operand.
- Jika semua operand telah dievaluasi (misal semuanya `false`), mengembalikan operand terakhir.
Nilai dikembalikan di bentuk originalnya, tanpa konversi.
Dengan kata lain, rantai OR `"||"` mengembalikan nilai truthy pertama atau yang terakhir jika tak ada nilai benar.
Misalnya:
```js run
alert( 1 || 0 ); // 1 (1 truthy)
alert( true || 'no matter what' ); // (true ialah truthy)
alert( null || 1 ); // 1 (1 ialah nilai truthy pertama)
alert( null || 0 || 1 ); // 1 (nilai truthy pertama)
alert( undefined || null || 0 ); // 0 (semua falsy, mengembalikan nilai terakhir)
```
Hal ini menjadikan penggunaan yang menarik dibanding "OR booleanpure, classical, boolean-only OR".
1. **Dapatkan nilai truthy dari daftar variabel atau expresi.**
Untuk contoh, kita punya variabel `firstName`, `lastName` dan `nickName`, semuanya bersifat opsional.
Kita gunakan OR `||` untuk memilih satu-satunya yang memiliki data dan menampilkannya (atau `anonymous` jika belum ada yang ditentukan atau di set):
```js run
let firstName = "";
let lastName = "";
let nickName = "SuperCoder";
*!*
alert( firstName || lastName || nickName || "Anonymous"); // SuperCoder
*/!*
```
Jika semua variabel bernilai falsy, `Anonymous` akan muncul.
2. **Evaluasi Short-circuit.**
Fitur lainnya dari operator OR `||` adalah evaluasi "short-circuit".
Itu berarti bahwa `||` memproses argumennya sampai nilai pertama bersifat truthy tercapai, lalu nilainya dikembalikan langsung, bahkan tanpa menyentuh argumen lainnya.
Pentingnya dari fitur ini menjadi jelas jika sebuah operan bukan hanya sebuah nilai, tapi sebuah ekspresi yang melakukan aksi, seperti assignment sebuah variabel atau sebuah pemanggilan fungsi.
Didalam contoh dibawah, hanya pesan kedua yang di jalankan:
```js run no-beautify
*!*true*/!* || alert("not printed");
*!*false*/!* || alert("printed");
```
Di baris pertama, operator OR `||` langsung berhenti mengevaluasi karena nilai pertama bersifat `true`, jadi `alert`nya tidak berjalan.
Terkadang, orang-orang menggunakan fitur ini untuk mengeksekusi perintah hanya jika kondisi di paling kiri bersifat falsy.
## && (AND)
Operator AND diwakili dua ampersand `&&`:
```js
result = a && b;
```
Dalam pemrograman klasik, AND mengembalikan `true` jika kedua operand sama-sama truthy dan `false` jika sebaliknya:
```js run
alert( true && true ); // true
alert( false && true ); // false
alert( true && false ); // false
alert( false && false ); // false
```
Contoh dengan `if`:
```js run
let hour = 12;
let minute = 30;
if (hour == 12 && minute == 30) {
alert( 'The time is 12:30' );
}
```
Sama seperti OR, nilai apapun boleh menjadi operand dari AND:
```js run
if (1 && 0) { // dievaluasi sebagai true && false
alert( "won't work, because the result is falsy" );
}
```
## AND "&&" mencari nilai falsy pertama
Misal ada beberapa nilai di-AND-kan:
```js
result = value1 && value2 && value3;
```
Yang dilakukan operator AND `&&` adalah sebagai berikut:
- Mengevaluasi operand dari kiri ke kanan.
- Untuk tiap operand, konversi ia ke boolean. Jika hasilnya `false`, stop dan kembalikan nilai original operand tersebut.
- Jika semua operand dievaluasi (i.e. semua truthy), mengembalikan operand terakhir.
Dengan kata lain, AND mengembalikan nilai falsy pertama atau nilai terakhir jika tak ketemu satupun nilai falsy.
Aturan di atas mirip dengan OR. Bedanya ialah AND mengembalikan niai *falsy* pertama sedangkan OR mengembalikan nilai *truthy* pertama.
Misalnya:
```js run
// jika operand pertama truthy,
// AND mengembalikan operand kedua:
alert( 1 && 0 ); // 0
alert( 1 && 5 ); // 5
// jika operand pertama falsy,
// AND mengembalikan itu. Operand kedua diabaikan
alert( null && 5 ); // null
alert( 0 && "no matter what" ); // 0
```
Kita juga bisa mengoper beberapa nilai dalam satu barus. Lihat bagaimana nilai falsy pertama dikembalikan:
```js run
alert( 1 && 2 && null && 3 ); // null
```
Ketika semua nilai truthy, nilai terakhir dikembalikan:
```js run
alert( 1 && 2 && 3 ); // 3, the last one
```
````smart header="Precedence of AND `&&` is higher than OR `||`"
Presedensi operator AND `&&` lebih tinggi dari OR `||`.
Jadi kode `a && b || c && d` esensinya sama dengan jika expresi `&&` dibungkus tanda kurung: `(a && b) || (c && d)`.
````
````warn header="Jangan ganti `if` dengan || atau &&"
Terkadang, orang-orang menggunakan operator AND `&&` untuk "memperpendek instruksi `if`".
Misalnya:
```js run
let x = 1;
(x > 0) && alert( 'Greater than zero!' );
```
Aksi di bagian kanan `&&` akan diexekusi hanya jika evaluasinya mencapai itu. Yaitu, hanya jika `(x > 0)` true.
Jadi pada dasarnya kita punya analogi untuk:
```js run
let x = 1;
if (x > 0) alert( 'Greater than zero!' );
```
Walaupun, versi dengan `&&` muncul lebih pendek, `if` menjadi jelas dan sedikit lebih mudah dibaca. Jadi kita merekomendasikan menggunakannya untuk setiap kebutuhan: gunakan `if` jika kita ingin if dan gunakan `&&` jika kita ingin AND.
````
## ! (NOT)
Operator boolean NOT diwakili dengan tanda exklamasi `!`.
Syntaxnya cukup simpel:
```js
result = !value;
```
Operator ini menerima argumen tunggal dan menjalankan hal berikut:
1. Mengkonversi operand ke tipe boolean: `true/false`.
2. Mengembalikan nilai kebalikan.
Misalnya:
```js run
alert( !true ); // false
alert( !0 ); // true
```
NOT ganda `!!` kadang dipakai untuk mengkonversi nilai ke tipe boolean:
```js run
alert( !!"non-empty string" ); // true
alert( !!null ); // false
```
Yaitu, NOT pertama mengkonversi nilai ke boolean dan mengembalikan kebalikannya, dan NOT kedua membaliknya lagi. Ujungnya, kita punya konversi nilai-ke-boolean biasa.
Ada sedikit cara rewel untuk melakukan hal serupa -- fungsi `Boolean` built-in:
```js run
alert( Boolean("non-empty string") ); // true
alert( Boolean(null) ); // false
```
Presedensi NOT `!` paling tinggi dari semua operator logika, jadi ia selalu jalan pertama, sebelum `&&` or `||`.
================================================
FILE: 1-js/02-first-steps/12-nullish-coalescing-operator/article.md
================================================
# Operator penggabungan nullish '??'
[browser terbaru="baru"]
Operator penggabungan nullish ditulis sebagai dua tanda tanya `??`.
Karena memperlakukan `null` dan `undefined` sama, kita akan menggunakan istilah khusus di sini, di artikel ini. Kami akan mengatakan bahwa ekspresi adalah "didefinisikan" ketika itu bukan `null` atau `undefined`.
Hasil dari `a?? b` adalah:
- jika `a` didefinisikan, maka `a`,
- jika `a` tidak didefinisikan, maka `b`.
Dengan kata lain, `??` mengembalikan argumen pertama jika bukan `null/undefined`. Kalau tidak, yang kedua.
Operator penggabungan nullish bukanlah sesuatu yang benar-benar baru. Ini hanya sintaks yang bagus untuk mendapatkan nilai "didefinisikan" pertama dari keduanya.
Kita dapat menulis ulang `result = a ?? b` menggunakan operator yang sudah kita kenal, seperti ini:
```js
result = (a !== null && a !== undefined) ? a : b;
```
Sekarang harus benar-benar jelas apa yang dilakukan `??`. Mari kita lihat di mana itu membantu.
Kasus penggunaan umum untuk `??` adalah memberikan nilai default untuk variabel yang berpotensi tidak terdefinisi.
Misalnya, di sini kami menampilkan `pengguna` jika didefinisikan, jika tidak `Anonim`:
```js dijalankan
biarkan pengguna;
alert(pengguna ?? "Anonim"); // Anonim (pengguna tidak ditentukan)
```
Berikut ini contoh dengan `pengguna` ditetapkan ke sebuah nama:
```js dijalankan
biarkan pengguna = "John";
alert(pengguna ?? "Anonim"); // John (ditentukan pengguna)
```
Kita juga dapat menggunakan urutan `??` untuk memilih nilai pertama dari daftar yang bukan `null/undefined`.
Katakanlah kita memiliki data pengguna dalam variabel `FirstName`, `lastName` atau `nickName`. Semuanya mungkin tidak ditentukan, jika pengguna memutuskan untuk tidak memasukkan nilai.
Kami ingin menampilkan nama pengguna menggunakan salah satu variabel ini, atau menampilkan "Anonim" jika semuanya tidak ditentukan.
Mari kita gunakan operator `??` untuk itu:
```js dijalankan
biarkan namadepan = null;
biarkan namabelakang = null;
biarkan nickName = "Supercoder";
// menunjukkan nilai yang ditentukan pertama:
*!*
alert(FirstName ?? LastName ?? nickName ?? "Anonim"); // kode super
*/!*
```
## Perbandingan dengan ||
Operator OR `||` dapat digunakan dengan cara yang sama seperti `??`, seperti yang dijelaskan di [bab sebelumnya](info:logical-operators#or-finds-the-first-truthy-value).
Misalnya, pada kode di atas kita dapat mengganti `??` dengan `||` dan tetap mendapatkan hasil yang sama:
```js dijalankan
biarkan namadepan = null;
biarkan namabelakang = null;
biarkan nickName = "Supercoder";
// menunjukkan nilai kebenaran pertama:
*!*
alert(Namadepan || Nama Belakang || Nama Panggilan || "Anonim"); // kode super
*/!*
```
Secara historis, operator OR `||` ada terlebih dahulu. Itu ada sejak awal JavaScript, jadi pengembang menggunakannya untuk tujuan seperti itu untuk waktu yang lama.
Di sisi lain, operator penggabungan nullish `??` baru saja ditambahkan ke JavaScript, dan alasannya adalah karena orang-orang tidak terlalu senang dengan `||`.
Perbedaan penting di antara mereka adalah bahwa:
- `||` mengembalikan nilai *truth* pertama.
- `??` mengembalikan nilai *yang ditentukan* pertama.
Dengan kata lain, `||` tidak membedakan antara `false`, `0`, string kosong `""` dan `null/undefined`. Semuanya sama -- nilai yang salah. Jika salah satu dari ini adalah argumen pertama dari `||`, maka kita akan mendapatkan argumen kedua sebagai hasilnya.
Namun dalam praktiknya, kita mungkin ingin menggunakan nilai default hanya jika variabelnya `null/undefined`. Artinya, ketika nilainya benar-benar tidak diketahui/tidak disetel.
Misalnya, pertimbangkan ini:
```js dijalankan
misalkan tinggi = 0;
waspada(tinggi || 100); // 100
waspada (tinggi ?? 100); // 0
```
- `tinggi || 100` memeriksa `height` sebagai nilai yang salah, dan itu adalah `0`, memang salah.
- jadi hasil dari `||` adalah argumen kedua, `100`.
- `tinggi ?? 100` memeriksa `height` sebagai `null/undefined`, dan bukan,
- jadi hasilnya adalah `height` "sebagaimana adanya", yaitu `0`.
Dalam praktiknya, ketinggian nol seringkali merupakan nilai yang valid, yang tidak boleh diganti dengan default. Jadi `??` melakukan hal yang benar.
## Prioritas
Prioritas operator `??` hampir sama dengan `||`, hanya sedikit lebih rendah. Ini sama dengan `5` di [tabel MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table), sedangkan `||` adalah `6` .
Artinya, seperti halnya `||`, operator penggabungan nullish `??` dievaluasi sebelum `=` dan `?`, tetapi setelah sebagian besar operasi lain, seperti `+`, `*`.
Jadi, jika kita ingin memilih nilai dengan `??` dalam ekspresi dengan operator lain, pertimbangkan untuk menambahkan tanda kurung:
```js dijalankan
biarkan tinggi = nol;
biarkan lebar = nol;
// penting: gunakan tanda kurung
biarkan luas = (tinggi ?? 100) * (lebar ?? 50);
waspada (daerah); // 5000
```
Jika tidak, jika kita menghilangkan tanda kurung, maka karena `*` memiliki prioritas yang lebih tinggi daripada `??`, tanda kurung akan dieksekusi terlebih dahulu, sehingga menghasilkan hasil yang salah.
```js
// tanpa tanda kurung
misal luas = tinggi?? 100 * lebar ?? 50;
// ...berfungsi sama seperti ini (mungkin bukan yang kita inginkan):
misal luas = tinggi?? (100 * lebar) ?? 50;
```
### Menggunakan ?? dengan && atau ||
Karena alasan keamanan, JavaScript melarang penggunaan `??` bersama dengan operator `&&` dan `||`, kecuali jika prioritas secara eksplisit ditentukan dengan tanda kurung.
Kode di bawah ini memicu kesalahan sintaks:
```js dijalankan
misalkan x = 1 && 2 ?? 3; // Kesalahan sintaks
```
Batasan ini tentu masih bisa diperdebatkan, hal itu ditambahkan ke spesifikasi bahasa dengan tujuan untuk menghindari kesalahan pemrograman, ketika orang mulai beralih dari `||` ke `??`.
Gunakan tanda kurung eksplisit untuk mengatasinya:
```js dijalankan
*!*
misalkan x = (1 && 2) ?? 3; // Bekerja
*/!*
waspada(x); // 2
```
## Ringkasan
- Operator penggabungan nullish `??` menyediakan cara singkat untuk memilih nilai "ditentukan" pertama dari daftar.
Ini digunakan untuk menetapkan nilai default ke variabel:
```js
// atur tinggi=100, jika tinggi nol atau tidak terdefinisi
tinggi = tinggi?? 100;
```
- Operator `??` memiliki prioritas yang sangat rendah, hanya sedikit lebih tinggi dari `?` dan `=`, jadi pertimbangkan untuk menambahkan tanda kurung saat menggunakannya dalam ekspresi.
- Dilarang menggunakannya dengan `||` atau `&&` tanpa tanda kurung eksplisit.
================================================
FILE: 1-js/02-first-steps/13-while-for/1-loop-last-value/solution.md
================================================
Jawabannya: `1`.
```js run
let i = 3;
while (i) {
alert( i-- );
}
```
Setiap pengulangan mengurangi `i` dengan `1`. pengecekan `while(i)` menghentikan perulangan ketika `i = 0`.
Oleh karena itu, langkah-langkah perulangan membentuk urutan sebagai berikut ("loop unrolled"):
```js
let i = 3;
alert(i--); // menampilkan 3, mengurangi i menjadi 2
alert(i--) // menampilkan 2, mengurangi i menjadi 1
alert(i--) // menampilkan 1, mengurangi i menjadi 0
// selesai, pengecekan while(i) menghentikan pengulangan
```
================================================
FILE: 1-js/02-first-steps/13-while-for/1-loop-last-value/task.md
================================================
importance: 3
---
# Nilai terakhir perulangan
Apa nilai terakhir yang diperingatkan oleh kode ini? Mengapa?
```js
let i = 3;
while (i) {
alert( i-- );
}
```
================================================
FILE: 1-js/02-first-steps/13-while-for/2-which-value-while/solution.md
================================================
Tugas mendemonstrasikan bagaimana bentuk postfix/prefix dapat menyebabkan hasil yang berbeda ketika digunakan dalam perbandingan
1. **Dari 1 ke 4**
```js run
let i = 0;
while (++i < 5) alert( i );
```
nilai pertama adalah `i = 1`, karena `++i` menambah terlebih dahulu `i` dan mengembalikan nilai baru. Jadi perbandingan pertama adalah `1 < 5` dan `alert` menampilkan `1`.
lalu diikuti `2, 3, 4…` -- nilainya muncul satu per satu. Perbandingan selalu menggunakan nilai yang ditambah, karna ada `++` sebelum variabel.
Akhirnya, `i = 4` bertambah menjadi `5`, perbandingan `while(5 < 5)` gagal, dan pengulangan berhenti. Jadi `5` tidak ditampilkan.
2. **Dari 1 ke 5**
```js run
let i = 0;
while (i++ < 5) alert( i );
```
Lagi, nilai pertama adalah `i = 1`. bentuk postfix dari `i++` menambah `i` dan kemudian mengembalikan nilai yang *lama*, jadi perbandingan `i++ < 5` akan menggunakan `i = 0` (berbeda dengan `++i < 5`).
Namun panggilan `alert` terpisah. ini adalah pernyataan lain yang berjalan setelah pertambahan dan perbandingan. Jadi ini mendapatkan nilai yang saat ini `i = 1`.
Lalu diikuti `2, 3, 4…`
Mari berhenti di `i = 4`. bentuk prefix `++i` akan menaikannya dan menggunakan `5` di perbandingan. Tapi disini kita mempunyai bentuk postfix `i++`. jadi ini menambah `i` menjadi `5`, namun mengembalikan nilai yang lama. Karna perbandingan yang sebenarnya adalah `while(4 < 5)` -- benar, dan kontrol berlanjut ke `alert`.
Nilai `i = 5` adalah yang terkahir, karena pada langkah berikutnya `while(5 < 5)` adalah salah.
================================================
FILE: 1-js/02-first-steps/13-while-for/2-which-value-while/task.md
================================================
importance: 4
---
# Nilai mana yang ditampilkan perulangan while?
Untuk setiap iterasi, tulis nilai mana yang dikeluarkan dan bandingkan dengan solusinya.
Kedua perulangan `alert` nilai yang sama, atau tidak?
1. Bentuk prefix `++i`:
```js
let i = 0;
while (++i < 5) alert( i );
```
2. Bentuk postfix `i++`
```js
let i = 0;
while (i++ < 5) alert( i );
```
================================================
FILE: 1-js/02-first-steps/13-while-for/3-which-value-for/solution.md
================================================
**Jawabanya: dari `0` ke `4` pada kedua kasus.**
```js run
for (let i = 0; i < 5; ++i) alert( i );
for (let i = 0; i < 5; i++) alert( i );
```
Itu dapat dengan mudah dikurangkan dari algoritma `for`:
1. Jalankan sekali `i = 0` sebelum apapun (begin).
2. Cek kondisinya `i < 5`
3. Jika `true` -- jalankan loop body `alert(i)`, dan kemudian `i++`
pertambahan `i++` terpisah dari pengecekan kondisi (2). itu hanya pernyataan lain.
Nilai yang dikembalikan oleh pertambahan tidak digunakan disini, jadi tidak ada bedanya antara `i++` dan `++i`.
================================================
FILE: 1-js/02-first-steps/13-while-for/3-which-value-for/task.md
================================================
importance: 4
---
# Nilai mana yang ditampilkan oleh perulangan "for" ?
Untuk setiap perulangan tulis nilai mana yang akan ditampilkan. lalu bandingkan dengan jawabanya
Kedua perulangan `alert` nilai yang sama atau tidak?
1. Bentuk postfix:
```js
for (let i = 0; i < 5; i++) alert( i );
```
2. Bentuk prefix:
```js
for (let i = 0; i < 5; ++i) alert( i );
```
================================================
FILE: 1-js/02-first-steps/13-while-for/4-for-even/solution.md
================================================
```js run demo
for (let i = 2; i <= 10; i++) {
if (i % 2 == 0) {
alert( i );
}
}
```
Kita menggunakan operator "modulo" `%` untuk mendapatkan nilai sisa dan untuk mengecek kegenapan disini.
================================================
FILE: 1-js/02-first-steps/13-while-for/4-for-even/task.md
================================================
importance: 5
---
# Menghasilkan angka genap di perulangan
Gunakan perulangan `for` untuk menghasilkan angka genap dari `2`sampai `10`.
[demo]
================================================
FILE: 1-js/02-first-steps/13-while-for/5-replace-for-while/solution.md
================================================
```js run
let i = 0;
while (i < 3) {
alert( `number ${i}!` );
i++;
}
```
================================================
FILE: 1-js/02-first-steps/13-while-for/5-replace-for-while/task.md
================================================
importance: 5
---
# Ganti "for" dengan "while"
Tulis ulang kode ubah perulangan `for` ke `while` tanpa mengubah perilakunya (hasilnya harus tetap sama).
```js run
for (let i = 0; i < 3; i++) {
alert( `number ${i}!` );
}
```
================================================
FILE: 1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md
================================================
```js run demo
let num;
do {
num = prompt("Masukan angka lebih dari 100?", 0);
} while (num <= 100 && num);
```
Perulangan `do..while` diulangi selagi kedua cek itu bernilai benar:
1. Pengecekan untuk `num <= 100` -- itu adalah, nilai yang dimasukan masih tidak lebih besar dari `100`.
2. Pengecekan `&& num` adalah salah ketika `num` adalah `null` atau sebuah string kosong. kemudian perulangan `while` berhenti juga.
P.S. Jika `num` adalah `null` lalu `num <= 100` adalah `true`, jadi tanpa pengecekan kedua, perulangan tidak akan berhenti jika pengguna mengeclick CANCEL. Kedua pengecekan dibutuhkan.
================================================
FILE: 1-js/02-first-steps/13-while-for/6-repeat-until-correct/task.md
================================================
importance: 5
---
# Ulangi sampai inputnya benar
Tulis sebuah perulangan yang meminta angka lebih dari `100`. Jika pendatang memasukan angka lainnya -- tanya mereka untuk menginput kembali.
Perulangan harus menanyakan untuk sebuah angka sampai pengunjung memasukan angka lebih dari `100` atau membatalkan input/memasukan sebuah baris kosong.
Disini kita dapat menganggap bahwa pengunjung hanya menginput angka. Tidak perlu menerapkan penanganan spesial untuk input non-numerik di tugas ini.
[demo]
================================================
FILE: 1-js/02-first-steps/13-while-for/7-list-primes/solution.md
================================================
Ada banyak algoritma untuk tugas ini.
Mari gunakan perulangan bersarang:
```js
For each i in the interval {
cek if i has a divisor from 1..i
if yes => the value is not a prime
if no => the value is a prime, show it
}
```
Kode menggunakan label:
```js run
let n = 10;
nextPrime:
for (let i = 2; i <= n; i++) { // untuk setiap i...
for (let j = 2; j < i; j++) { // mencari pembagi..
if (i % j == 0) continue nextPrime; // bukan prima, pergi ke i berikutnya
}
alert( i ); // prima
}
```
Ada banyak ruang untuk mengoptimalkannya. Misalnya, kita dapat mencari pembagi dari `2` ke akar kuadrat dari `i`. Tapi bagaimanapun, jika kita ingin sangat efisien untuk interval besar, kita perlu mengubah pendekatan dan mengandalkan matematika lanjutan dan algotima rumit seperti [Quadratic sieve](https://en.wikipedia.org/wiki/Quadratic_sieve), [General number field sieve](https://en.wikipedia.org/wiki/General_number_field_sieve) dsb.
================================================
FILE: 1-js/02-first-steps/13-while-for/7-list-primes/task.md
================================================
importance: 3
---
# Menghasilkan bilangan prima
Angka integer lebih dari `1` disebut [bilangan prima](https://en.wikipedia.org/wiki/Prime_number) jika itu tidak bisa dibagi tanpa sisa oleh siapapun kecuali `1` dan bilangan itu sendiri.
Dengan kata lain, `n > 1` adalah prima jika tidak dapat dibagi secara merata oleh apapun kecuali `1` dan `n`.
Contohnya, `5` adalah prima, karna tidak bisa dibagi tanpa sisa oleh `2`, `3` dan `4`.
**Tulis kode yang menghasilkan bilangan prima dalam interval dari `2` sampai `n`.**
Untuk `n = 10` hasilnya akan `2,3,5,7`.
P.S. Kode harus bekerja untuk segala `n`, tidak disetel untuk nilai tetap apapun.
================================================
FILE: 1-js/02-first-steps/13-while-for/article.md
================================================
# Perulangan: while dan for
Kita sering perlu untuk mengulangi tindakan.
Contohnya, Mengeluarkan barang dari sebuah daftar satu per satu atau hanya menjalankan kode yang sama untuk setiap nomor dari 1 hingga 10.
*Perulangan* adalah sebuah cara untuk mengulangi kode yang sama beberapa kali.
## Perulangan "while"
Perulangan `while` memiliki sintaks sebagai berikut:
```js
while (kondisi) {
// kode
// disebut "badan perulangan"
}
```
Ketika `kondisi` bernilai truthy, `kode` dari badan perulangan dijalankan.
Contohnya, perulangan di bawah mengeluarkan `i` selagi `i < 3`:
```js run
let i = 0;
while (i < 3) { // menampilkan 0, lalu 1, lalu 2
alert( i );
i++;
}
```
Eksekusi tunggal dari badan perulangan disebut *sebuah pengulangan*. Perulangan pada contoh diatas membuat tiga kali pengulangan.
Jika `i++` hilang dari contoh di atas, perulangan akan mengulangi (dalam teori) secara terus-menerus. Pada praktiknya, browser menyediakan cara untuk menghentikan perulangan, dan pada sisi server JavaScript, kita dapat mematikan prosesnya.
Ekspresi atau variable apapun bisa menjadi sebuah kondisi perulangan, tidak hanya perbandingan: kondisi terevalusasi dan terkonversi menjadi boolean oleh `while`.
Contohnya, cara cepat untuk menulis `while (i != 0)` adalah `while (i)`:
```js run
let i = 3;
*!*
while (i) { // ketika i menjadi 0, kondisi bernilai salah, dan perulangan berhenti
*/!*
alert( i );
i--;
}
```
````smart header="Kurung kurawal tidak dibutuhkan untuk badan baris tunggal"
Jika badan perulangan mempunyai sebuah pernyataan tunggal, kita dapat menghilangkan kurung kurawal `{…}`:
```js run
let i = 3;
*!*
while (i) alert(i--);
*/!*
```
````
## Perulangan "do..while"
Pengecekan kondisi dapat dipindahkan *di bawah* badan perulangan menggunakan `do..while` sintaks:
```js
do {
// badan perulangan
} while (condition);
```
Perulangan akan mengeksekusi badan terlebih dahulu, lalu memeriksa kondisi, dan, selagi itu bernilai truthy, jalankan itu lagi dan lagi.
Contohnya:
```js run
let i = 0;
do {
alert( i );
i++;
} while (i < 3);
```
Format penulisan ini hanya digunakan ketika kamu ingin badan dari perulangan tereksekusi **setidaknya sekali** Terlepas dari kondisi menjadi bernilai benar. Biasanya, format lain yang dipilih: `while(…) {…}`.
## Perulangan "for"
Perulangan `for` lebih complex, tapi merupakan perulangan yang paling umum digunakan.
Itu terlihat seperti ini:
```js
for (awal; kondisi; langkah) {
// ... badan perulangan ...
}
```
Mari belajar makna dari bagian ini dari contoh. Perulangan dibawah menjalankan `alert(i)` untuk `i` dari `0` sampai dengan (tapi tidak termasuk) `3`:
```js run
for (let i = 0; i < 3; i++) { // menampilkan 0, lalu 1, lalu 2
alert(i);
}
```
Mari bahas pernyataan `for` bagian demi bagian:
| bagian | | |
|-------|----------|----------------------------------------------------------------------------|
| begin | `i = 0` | Jalankan sekali masuk ke loop. |
| condition | `i < 3`| Cek sebelum tiap iterasi loop. Jika salah, loop berhenti. |
| body | `alert(i)`| Jalankan lagi dan lagi selama kondisi bernilai truthy. |
| step | `i++` | Exekusi setelah badan di tiap iterasi. |
Cara kerja algoritma perulangan umum seperti ini:
```
Jalankan begin
→ (jika condition → jalankan body dan jalankan step)
→ (jika condition → jalankan body dan jalankan step)
→ (jika condition → jalankan body dan jalankan step)
→ ...
```
Dikatakan, `begin` diexekusi sekali, kemudian ia beriterasi: setelah tiap `condition` dites, `body` dan `step` diexekusi.
Jika kamu baru pada perulangan, ini bisa membantumu kembali ke contoh dan mereproduksi bagamana ini berjalan selangkah demi selangkah pada sebuah selembar kertas.
Inilah yang sebenarnya terjadi pada kasus kita:
```js
// for (let i = 0; i < 3; i++) alert(i)
// jalankan awal
let i = 0
// jika kondisi → jalankan badan dan jalankan langkah
if (i < 3) { alert(i); i++ }
// jika kondisi → jalankan badan dan jalankan langkah
if (i < 3) { alert(i); i++ }
// jika kondisi → jalankan badan dan jalankan langkah
if (i < 3) { alert(i); i++ }
// ...selesai, karena sekarang i == 3
```
````smart header="Deklarasi varibel sebaris"
Disini, "penghitung" variabel `i` dideklarasikan di dalam perulangan. Ini disebut deklarasi variabel "sebaris". variabel ini hanya akan terlihat di dalam perulangan.
```js run
for (*!*let*/!* i = 0; i < 3; i++) {
alert(i); // 0, 1, 2
}
alert(i); // error, tidak ada variabel
```
Daripada mendefinisikan sebuah variabel, kita dapat menggunakan yang sudah ada:
```js run
let i = 0;
for (i = 0; i < 3; i++) { // gunakan variabel yang sudah ada
alert(i); // 0, 1, 2
}
alert(i); // 3, terlihat, karena dideklarasikan diluar dari perulangan
```
````
### Melewatkan bagian
Bagian apapun dari `for` dapat dilewati.
Contoh, kita dapat menghilangkan `awal` jika kita tidak butuh untuk melakukan apapun pada awal perulangan.
Seperti ini:
```js run
let i = 0; // kita punya i yang sudah dideklarasikan dan telah ditetapkan
for (; i < 3; i++) { // tidak butuh "awal"
alert( i ); // 0, 1, 2
}
```
Kita juga bisa menghilangkan bagian `langkah`:
```js run
let i = 0;
for (; i < 3;) {
alert( i++ );
}
```
Ini membuat perulangan sama dengan `while (i < 3)`.
Kita sebenarnya dapat menghilangkan semuanya, membuat sebuah perulangan tak terhingga:
```js
for (;;) {
// ulangi tanpa batas
}
```
Tolong dicatat bahwa dua `for` titik koma `;` harus ada, jika tidak, akan ada sintaks error.
## Menghentikan perulangan
Biasanya, sebuah perulangan keluar ketika kondisinya menjadi bernilai salah.
Tapi kita dapat memaksanya keluar pada waktu apapun menggunakan perintah spesial `break`.
Contohnya, perulangan dibawah menanyakan pengguna untuk serangkaian angka, "hentikan" ketika tidak ada angka yang dimasukan:
```js run
let sum = 0;
while (true) {
let value = +prompt("Masukan sebuah angka", '');
*!*
if (!value) break; // (*)
*/!*
sum += value;
}
alert( 'Sum: ' + sum );
```
Perintah `break` teraktivasi pada baris `(*)` jika pengguna memasukan baris kosong atau membatalkan input. itu akan langsung berhenti, melewati kontrol ke baris pertama setelah perulangan. yang bernama, `alert`.
Kombinasi "perulangan tak terhingga + `break` sesuai kebutuhan" bagus untuk situasi dimana sebuah kondisi perulangan harus diperiksa tidak di awal atau akhir dari perulangan, tapi di pertengahan atau bahkan di beberapa tempat tubuhnya.
## Lanjutkan ke perulangan berikutnya [#lanjutkan]
Perintah `continue` adalah "versi ringan" dari `break`. Ini tidak mengentikan keseluruhan perulangan. sebagai gantinya, ini menghentikan perulangan saat ini dan memaksa perulangan untuk memulai yang baru (jika kondisi diperbolehkan).
Kita dapat menggunakan ini jika kita selesai dengan perulangan saat ini dan ingin pindah ke yang berikutnya.
Perulangan dibawah menggunakan `continue` untuk hanya menampilkan nilai ganjil:
```js run no-beautify
for (let i = 0; i < 10; i++) {
// jika benar, lewati bagian badan perulangan yang tersisa
*!*if (i % 2 == 0) continue;*/!*
alert(i); // 1, then 3, 5, 7, 9
}
```
Untuk nilai genap dari `i`, perintah `continue` mengentikan menjalankan badan dan melewati kontrol ke perulangan `for` berikutnya (dengan nomor berikutnya). jadi `alert` hanya terpanggil untuk nilai ganjil.
````smart header="Perintah `continue` membantu mengurangi penyarangan"
Sebuah perulangan yang menampilkan nilai ganjil dapat terlihat seperti ini:
```js run
for (let i = 0; i < 10; i++) {
if (i % 2) {
alert( i );
}
}
```
Dari sudut pandang teknis, ini identik dengan contoh diatas. Tentunya, kita dapat membungkus kode dalam sebuah blok `if` daripada menggunakan `continue`.
Tapi sebagai efeknya, hal ini akan menciptakan kode lebih dalam satu tingkat (pemanggilan `alert` didalam kurung kurawal). Jika kode didalam `if` lebih panjang beberapa baris, hal itu akan membuat tingkat keterbacaan kode menjadi berkurang.
````
````warn header="Tidak ada `break/continue` ke sisi kanan '?'"
Harap perhatikan bahwa sintaks yang membangun yang bukan ekspresi tidak dapat digunakan dengan operator ternary `?`. Khususnya, perintah seperti `break/continue` tidak diperbolehkan.
Misalnya, jika kita mengambil kode ini:
```js
if (i > 5) {
alert(i);
} else {
continue;
}
```
...dan tulis ulang menggunakan sebuah tanda tanya:
```js no-beautify
(i > 5) ? alert(i) : *!*continue*/!*; // continue tidak diperbolehkan disini
```
...ia berhenti jalan: ada galat syntax:
Ini hanya alasan lain untuk tidak menggunakan operator tanda tanya `?` daripada `if`.
````
## Label untuk break/continue
Terkadang kita perlu keluar dari beberapa perulangan bersarang sekaligus.
Misalnya, dalam kode di bawah kita lakukan perulangan terhadap `i` dan `j`, meminta koordinat `(i, j)` dari `(0,0)` ke`(3,3)`:
```js run no-beautify
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let input = prompt(`Nilai pada koordinasi (${i},${j})`, '');
// bagaimana jika saya ingin keluar dari sini ke Done (dibawah)?
}
}
alert('Done!');
```
Kita butuh cara untuk menghentikan proses jika pengguna membatalkan input.
`break` biasa setelah `input` hanya akan menghentikan perulangan dalam. Itu tidak cukup--label, datang untuk menyelamatkan!
Label adalah sebuah pengidentifikasi dengan sebuah titik dua sebelum perulangan:
```js
labelName: for (...) {
...
}
```
Pernyataan `break <labelName>` di dalam loop di bawah menghentikan pada label:
```js run no-beautify
*!*outer:*/!* for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let input = prompt(`Value at coords (${i},${j})`, '');
// jika sebuah string kosong atau terbatalkan, lalu hentikan kedua perulangan
if (!input) *!*break outer*/!*; // (*)
// lakukan sesuatu dengan nilai...
}
}
alert('Done!');
```
Pada kode diatas, `break outer` melihat keatas untuk label bernama `outer` dan menghentikan perulangan itu.
Jadi kontrol pergi langsung dari `(*)` ke `alert('Done!')`.
Kita juga dapat memindah label ke sebuah baris terpisah:
```js no-beautify
outer:
for (let i = 0; i < 3; i++) { ... }
```
Perintah `continue` dapat juga digunakan dengan sebuah label. pada kasus ini, eksekusi kode berpindah ke perulangan label berikutnya.
````warn header="Label tidak mengizinkan \"lompat\" ke manapun"
Label tidak mengizinkan kita untuk lompat ke sembarang tempat dalam kode.
Misalnya, mustahil melakukan ini:
```js
break label; // tidak lompak ke label di bawah
label: for (...)
```
Direktif `break` harus berada di dalam blok kode. Secara teknis, setiap blok kode berlabel akan dilakukan, contoh.:
```js
label: {
// ...
break label; // berjalan
// ...
}
```
...Meskipun, 99,9% dari waktu `break` yang digunakan adalah loop dalam, seperti yang telah kita lihat pada contoh di atas.
`continue` hanya dimungkinkan dari dalam loop.
````
## Ringkasan
Kita membahas 3 jenis perulangan:
- `while` -- Kondisi diperiksa sebelum setiap perulangan.
- `do..while` -- Kondisi diperiksa setelah setiap perulangan.
- `for (;;)` -- Kondisi diperiksa sebelum setiap perulangan, pengaturan tambahan tersedia.
Untuk membuat sebuah perulangan "tak terhinggaa", biasanya konstruksi `while(true)` digunakan. Demikian sebuah perulangan, seperti yang lainnya, dapat berhenti dengan perintah `break`.
Jika kita tidak ingin melakukan apapun di perulangan saat ini dan ingin meneruskan ke yang berikutnya, kita dapat menggunakan perintah `continue`.
`break/continue` mendukung label sebelum perulangan. Label adalah satu-satunya cara untuk `break/continue` menghindari loop bersarang untuk pergi ke luar
================================================
FILE: 1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/solution.md
================================================
Supaya fungsionalitas `switch` persis sama, `if` harus memakai pembandingan ketat `'==='`.
Tapi untuk string yang diberikan, `'=='` sederhana cukup bekerja juga.
```js no-beautify
if(browser == 'Edge') {
alert("You've got the Edge!");
} else if (browser == 'Chrome'
|| browser == 'Firefox'
|| browser == 'Safari'
|| browser == 'Opera') {
alert( 'Okay we support these browsers too' );
} else {
alert( 'We hope that this page looks ok!' );
}
```
Tolong ingat: konstruksi `browser == 'Chrome' || browser == 'Firefox' …` dipecah menjadi beberapa baris untuk kemudahan keterbacaan.
Tapi konstruksi `switch` masih lebih bersih dan lebih deskriptif.
================================================
FILE: 1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/task.md
================================================
nilai penting: 5
---
# Tulis kembali "switch" menjadi "if"
Tulis kode menggunakan `if..else` yang akan berkorespon dengan `switch` berikut:
```js
switch (browser) {
case 'Edge':
alert( "You've got the Edge!" );
break;
case 'Chrome':
case 'Firefox':
case 'Safari':
case 'Opera':
alert( 'Okay we support these browsers too' );
break;
default:
alert( 'We hope that this page looks ok!' );
}
```
================================================
FILE: 1-js/02-first-steps/14-switch/2-rewrite-if-switch/solution.md
================================================
Dua cek pertama berubah ke `case`. Cek ketiga dipecah menjadi dua case:
```js run
let a = +prompt('a?', '');
switch (a) {
case 0:
alert( 0 );
break;
case 1:
alert( 1 );
break;
case 2:
case 3:
alert( '2,3' );
*!*
break;
*/!*
}
```
Tolong ingat: `break` di paling bawah tidak wajib. Tapi kita taruh itu supaya kodenya future-proof.
Di masa depan, ada kans bahwa kita ingin menambah `case` lebih, misalnya `case 4`. Dan jika kita lupa menambah break sebelum itu, di akhir `case 3`, akan ada error. Jadi itu lebih ke semacam asuransi diri.
================================================
FILE: 1-js/02-first-steps/14-switch/2-rewrite-if-switch/task.md
================================================
nilai penting: 4
---
# Tulis kembali "if" ke dalam "switch"
Tulis ulang kode berikut menggunakan pernyataan `switch` tunggal:
```js run
let a = +prompt('a?', '');
if (a == 0) {
alert( 0 );
}
if (a == 1) {
alert( 1 );
}
if (a == 2 || a == 3) {
alert( '2,3' );
}
```
================================================
FILE: 1-js/02-first-steps/14-switch/article.md
================================================
# Pernyataan "switch"
Pernyataan `switch` bisa mengganti pengecekan ganda `if`.
Ia memberi cara lebih deskriptif untuk membandingkan nilai dengan varian ganda.
## Syntax
`switch` punya satu atau lebih blok `case` dan satu default opsional.
Rupanya seperti ini:
```js no-beautify
switch(x) {
case 'value1': // if (x === 'value1')
...
[break]
case 'value2': // if (x === 'value2')
...
[break]
default:
...
[break]
}
```
- Nilai `x` dicek ekaulitasnya secara ketat dengan nilaid dari `case` pertama (yaitu, `value1`) lalu ke kedua (`value2`) dan seterusnya.
- Jika ekualitas ditemukan, `switch` mulai mengexekusi kode mulai dari `case` yang berkorespondensi, hingga `break` terdekat (atau hingga akhir `switch`).
- Jika tak ada case yang cocok maka kode `default` diexekusi (jika ada).
## Contoh
Contoh `switch` (kode yang dieksekusi dihighlight):
```js run
let a = 2 + 2;
switch (a) {
case 3:
alert( 'Too small' );
break;
*!*
case 4:
alert( 'Exactly!' );
break;
*/!*
case 5:
alert( 'Too big' );
break;
default:
alert( "I don't know such values" );
}
```
Di sini `switch` mulai membandingkan `a` dari varian `case` pertama yang bernilai `3`. Kecocokan gagal.
Lalu `4`. Ada kecocokan, jadi exekusi mulai dari `case 4` hingga `break` terdekat.
**Jika tak ada `break` maka exekusi lanjut dengan `case` berikutnya tanpa pengecekan.**
Contoh tanpa `break`:
```js run
let a = 2 + 2;
switch (a) {
case 3:
alert( 'Too small' );
*!*
case 4:
alert( 'Exactly!' );
case 5:
alert( 'Too big' );
default:
alert( "I don't know such values" );
*/!*
}
```
Di contoh di atas kita akan lihat exekusi sekuensial dari tiga `alert`:
```js
alert( 'Exactly!' );
alert( 'Too big' );
alert( "I don't know such values" );
```
````smart header="Expresi apapun bisa berupa argumen `switch/case`"
Baik `switch` maupun `case` membolehkan sembarang expresi.
Misalnya:
```js run
let a = "1";
let b = 0;
switch (+a) {
*!*
case b + 1:
alert("this runs, because +a is 1, exactly equals b+1");
break;
*/!*
default:
alert("this doesn't run");
}
```
Di sini `+a` memberikan `1`, yang dibandingkan dengan `b + 1` ndalam `case`, and the corresponding code is executed.
````
## Pengelompokan "case"
Beberapa varian `case` yang berbagi kode yang sama bisa dikelompokkan.
Misalnya, jika kita ingin kode yang sama berjalan untuk `case 3` dan `case 5`:
```js run no-beautify
let a = 3;
switch (a) {
case 4:
alert('Right!');
break;
*!*
case 3: // (*) grouped two cases
case 5:
alert('Wrong!');
alert("Why don't you take a math class?");
break;
*/!*
default:
alert('The result is strange. Really.');
}
```
Sekarang baik `3` maupun `5` menampilkan pesan yang sama.
Kemampuan "mengelompokkan" case adalah efek samping dari bagaimana `switch/case` bekerja tanpa `break`. Di sini exekusi dari `case 3` mulai dari baris `(*)` dan tembus ke `case 5`, karena tidak ada `break`.
## Tipe berpengaruh
Mari kita tekankan bahwa pengecekan ekualitas selalu ketat. Nilainya harus bertipe sama supaya cocok.
Misalnya, mari kita pertimbangkan kode ini:
```js run
let arg = prompt("Enter a value?");
switch (arg) {
case '0':
case '1':
alert( 'One or zero' );
break;
case '2':
alert( 'Two' );
break;
case 3:
alert( 'Never executes!' );
break;
default:
alert( 'An unknown value' );
}
```
1. Untuk `0`, `1`, `alert` pertama berjalan.
2. Untuk `2` `alert` kedua berjalan.
3. Tapi untuk `3`, hasil dari `prompt` ialah string `"3"`, yang berbeda secara ketat `===` dengan angka `3`. Jadi kita punya kode mati di `case 3`! Varian `default` akan diexekusi.
================================================
FILE: 1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md
================================================
Tidak ada perbedaan.
================================================
FILE: 1-js/02-first-steps/15-function-basics/1-if-else-required/task.md
================================================
nilai penting: 4
---
# Apakah "else" dibutuhkan ?
Fungsi berikut mengembalikan nilai `true` jika parameter `age` lebih besar daripada `18`.
Jika tidak, fungsi tersebut akan meminta konfirmasi dan mengembalikan nilainya:
```js
function checkAge(age) {
if (age > 18) {
return true;
*!*
} else {
// ...
return confirm('Did parents allow you?');
}
*/!*
}
```
akankah fungsi bekerja berbeda jika `else` dibuang ?
```js
function checkAge(age) {
if (age > 18) {
return true;
}
*!*
// ...
return confirm('Did parents allow you?');
*/!*
}
```
apakah ada perbedaan pada tingkah laku dari kedua variasi ?
================================================
FILE: 1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/solution.md
================================================
Menggunakan tanda tanya operator `'?'`:
```js
function checkAge(age) {
return (age > 18) ? true : confirm('Did parents allow you?');
}
```
Using OR `||` (the shortest variant):
Menggunakan OR `||` (variasi yang terpendek):
```js
function checkAge(age) {
return (age > 18) || confirm('Did parents allow you?');
}
```
Catatan bahwa tanda kurung sekitar `age > 18` tidak dibutuhkan disini. Mereka ada hanya untuk lebih enak dibaca.
================================================
FILE: 1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/task.md
================================================
nilai penting: 4
---
# Tulis ulang fungsi menggunakan '?' atau '||'
Fungsi berikut mengembalikan nilai `true` jika parameter `age` lebih besar daripada `18`.
Jika tidak, fungsi akan meminta sebuah konfirmasi dan mengembalikan nilainya.
```js
function checkAge(age) {
if (age > 18) {
return true;
} else {
return confirm('Did parents allow you?');
}
}
```
Tulis ulang fungsi, untuk melakukan dengan sama, tetapi tanpa `if`, dalam satu baris.
Buatlah dua variasi dari `checkAge`:
1. Menggunakan sebuah tanda tanya operator `?`
2. Mengguunakan OR `||`
================================================
FILE: 1-js/02-first-steps/15-function-basics/3-min/solution.md
================================================
Solusi menggunakan `if`:
```js
function min(a, b) {
if (a < b) {
return a;
} else {
return b;
}
}
```
Solusi menggunakan tanda tanya operator `'?'`:
```js
function min(a, b) {
return a < b ? a : b;
}
```
P.S. Pada kasus persamaan `a == b` tidak menjadi penting apa yang dikembalikan
================================================
FILE: 1-js/02-first-steps/15-function-basics/3-min/task.md
================================================
nilai penting: 1
---
# Fungsi min(a,b)
Tulis sebuah fungsi `min(a,b)` yang mengembalikan nilai paling terkecil dari dua angka `a` dan `b`.
Sebagai gambaran:
```js
min(2, 5) == 2
min(3, -1) == -1
min(1, 1) == 1
```
================================================
FILE: 1-js/02-first-steps/15-function-basics/4-pow/solution.md
================================================
```js menjalankan demo
function pow(x, n) {
let result = x;
for (let i = 1; i < n; i++) {
result *= x;
}
return result;
}
let x = prompt("x?", '');
let n = prompt("n?", '');
if (n < 1) {
alert(`Power ${n} is not supported, use a positive integer`);
} else {
alert( pow(x, n) );
}
```
================================================
FILE: 1-js/02-first-steps/15-function-basics/4-pow/task.md
================================================
nilai penting: 4
---
# Fungsi pow(X,n)
Tulis sebuah fungsi `pow(x,n)` yang mengembalikkan nilai `x` pada pangkat `n`. Atau, dengan kata lain, kalikan `x` dengan dirinya sendiri sebanyak `n` kali dan mengembalikan hasilnya.
```js
pow(3, 2) = 3 * 3 = 9
pow(3, 3) = 3 * 3 * 3 = 27
pow(1, 100) = 1 * 1 * ...* 1 = 1
```
Buatlah sebuah halaman website yang meminta untuk nilai `x` dan `n`, dan tampilkan hasilnya pada `pow(x,n)`.
[demo]
P.S. pada tugas ini, fungsi seharusnya mendukung hanya nilai bilangan natural dari `n`: bilangan integer mulai dari `1`.
================================================
FILE: 1-js/02-first-steps/15-function-basics/article.md
================================================
# Fungsi
Sering kali, kita harus melakukan tindakan yang sama pada skrip di banyak tempat
Sebagai contoh, kita mengharuskan untuk menampilkan pesan yang terlihat indah ketika pengunjung melakukan log in, log out dan mungkin di tempat lain.
Fungsi adalah program utama yang membentuk "struktur bangunan". Mereka memungkinkan kode untuk dipanggil sebanyak mungkin tanpa harus mengetik berulang-ulang.
Kita telah melihat contoh dari fungsi built-in, seperti `alert(message)`, `prompt(message, default)` dan `confirm(question)`.
## Deklarasi Fungsi
Untuk membuat fungsi, kita dapat menggunakan *deklarasi fungsi*.
Itu terlihat seperti ini:
```js
function showMessage() {
alert( 'Hello everyone!' );
}
```
Katakunci `fungsi` ditulis duluan, lalu *nama fungsinya*, kemudian daftar semua *parameter* antara tanda kurung () (pada contoh di atas, tanda kurung kosong) dan bagian terakhir adalah fungsi kode, yang juga disebut sebagai "badan fungsi", antara kurung kurawal {}.
```js
function name(parameter1, parameter2, ... parameterN) {
...body...
}
```
Fungsi baru kita dapat disebut dengan nama: `showMessage()`.
Sebagai contoh:
```js run
function showMessage() {
alert( 'Hello everyone!' );
}
*!*
showMessage();
showMessage();
*/!*
```
Pemanggilan fungsi `showMessage()` mengeksekusi fungsi kode. Disini kita akan melihat pesan keluaran sebanyak dua kali.
Contoh ini secara jelas memaparkan satu fungsi utama dari penggunaan fungsi: untuk menghindari duplikasi kode.
Jika kita ingin mengubah pesan atau bagaimana pesan itu ingin ditampilkan, itu cukup untuk mengubah kode di satu tempat: yaitu fungsi yang menampilkannya.
## Variabel lokal
Variabel yang diumumkan dalam fungsi hanya akan terlihat di dalam fungsi tersebut.
Misalnya:
```js run
function showMessage() {
*!*
let message = "Hello, I'm JavaScript!"; // variabel lokal
*/!*
alert( message );
}
showMessage(); // Halo, saya adalah JavaScript!
alert( message ); // <-- Error! Variabel terlihat secara lokal menurut fungsi
```
## Variabel luar
Suatu fungsi juga dapat mengakses variabel luar, sebagai contoh:
```js run no-beautify
let *!*userName*/!* = 'John';
function showMessage() {
let message = 'Hello, ' + *!*userName*/!*;
alert(message);
}
showMessage(); // Halo, John
```
Fungsi memiliki hak akses penuh kepada variabel luar fungsi. Juga variabel tersebut dapat diubah.
Sebagai contoh:
```js run
let *!*userName*/!* = 'John';
function showMessage() {
*!*userName*/!* = "Bob"; // (1) changed the outer variable
let message = 'Hello, ' + *!*userName*/!*;
alert(message);
}
alert( userName ); // *!*John*/!* sebelum pemanggilan fungsi
showMessage();
alert( userName ); // *!*Bob*/!*, nilai dimodifikasi oleh fungsi
```
Variabel luar hanya dapat digunakan jika tidak ada variabel lokal yang menggunakan.
Jika terdapat variabel yang memiliki nama identik yang dideklarasikan di dalam fungsi, lalu variabel luar akan *tertumpukkan*. Sebagai gambaran, pada kode di bawah, fungsi menggunakan variabel lokal bernama `userName`. Variabel luar akan terabaikan:
```js run
let userName = 'John';
function showMessage() {
*!*
let userName = "Bob"; // deklarasikan lokal variabel
*/!*
let message = 'Hello, ' + userName; // *!*Bob*/!*
alert(message);
}
// fungsi akan membuat dan menggunakan userName dirinya sendiri
showMessage();
alert( userName ); // *!*John*/!*, tidak berubah, fungsi tidak dapat mengakses variabel luar
```
```smart header="Global variables"
Variabel yang dideklarasikan di luar dari fungsi, seperti variabel luar `userName` pada kode di atas, disebut sebagai *global*.
Variabel global terlihat dari semua fungsi (terkecuali jika ditumpukkan oleh variabel lokal).
Ini menjadi suatu cara yang baik untuk mengurangi penggunaan variabel global. Kode yang modern hanya memiliki sedikit bahkan tidak ada variabel global. Kebanyakan variabel dideklarasikan dan digunakan di dalam fungsi masing-masing. Kadang-kadang, mereka dapat digunakan untuk menyimpan data setingkat projek.
```
## Parameters
Kita dapat meloloskan data yang begitu acak kepada fungsi sebagai parameter (disebut juga sebagai *fungsi argumen*).
Pada contoh di bawah, fungsi memiliki dua paramter: `from` dan `text`.
```js run
function showMessage(*!*from, text*/!*) { // parameters: from, text
alert(from + ': ' + text);
}
*!*
showMessage('Ann', 'Hello!'); // Ann: Hallo! (*)
showMessage('Ann', "What's up?"); // Ann: Ada apa? (**)
*/!*
```
Ketika fungsi dipanggil pada penanda `(*)` dan `(**)`, nilai yang diberikan dipindahkan ke variabel lokal `from` dan `text`. Lalu fungsi menggunakan nilai-nilai tersebut.
Ini terdapat satu lagi contoh: kita memiliki variabel `from` dan memindahkannya ke fungsi. Dengan catatan: fungsi akan mengubah `from`, tapi perubahan ini tidak akan terlihat di luar fungsi, karena sebuah fungsi akan selalu mendapatkan salinan nilai:
```js run
function showMessage(from, text) {
*!*
from = '*' + from + '*'; // membuat "from" terlihat lebih indah
*/!*
alert( from + ': ' + text );
}
let from = "Ann";
showMessage(from, "Hello"); // *Ann*: Hallo
// Nilai dari "from" adalah sama, fungsi melakukan perubahan pada variabel lokal
alert( from ); // Ann
```
Ketika sebuah nilai dilewatkan sebagai parameter fungsi, itu juga disebut *argumen*.
Dengan kata lain, untuk meluruskan istilah-istilah ini:
- Parameter adalah variabel yang tercantum di dalam tanda kurung dalam deklarasi fungsi (ini adalah istilah waktu deklarasi)
- Argumen adalah nilai yang diteruskan ke fungsi saat dipanggil (ini adalah istilah waktu panggilan).
Kami mendeklarasikan fungsi yang mencantumkan parameternya, lalu memanggilnya lewat argumen.
Dalam contoh di atas, seseorang mungkin mengatakan: "fungsi `sayMessage` dideklarasikan dengan dua parameter, kemudian dipanggil dengan dua argumen: `from` dan `"Hello"`".
## Nilai default
Jika suatu fungsi dipanggil, tetapi argumen tidak diberikan, maka nilai yang sesuai menjadi `tidak terdefinisi`.
Sebagai gambaran, fungsi yang telah tersebut di atas `showMessage(from, text)` dapat dipanggil dengan argumen tunggal:
```js
showMessage("Ann");
```
Itu tidak terjadi kesalahan. Malah pemanggilan tersebut akan menghasilkan `"Ann: undefined"`. Tidak ada argumen untuk parameter `text`, jadi ini diasumsikan bahwa `text === undefined`.
Jika kita ingin menggunakan suatu `text` "default" pada kasus ini, lalu kita dapat menentukannya setelah `=`:
```js run
function showMessage(from, *!*text = "no text given"*/!*) {
alert( from + ": " + text );
}
showMessage("Ann"); // Ann: tidak diberikan teks
```
Sekarang, jika parameter `text` tidak ditentukan, parameter tersebut akan mengambil nilai `"no text give"`
Disini `"no text give"` adalah string, tapi ia bisa menjadi suatu expresi nilai lebih kompleks, yang hanya dievaluasi dan ditetapkan jika tak ada nilai pada parameter. Jadi, ini juga mungkin ditetapkan:
```js run
function showMessage(from, text = anotherFunction()) {
// anotherFunction() hanya akan mengeksekusi jika tidak adanya teks
// hasilnya menjjadi nilai pada teks
}
```
```smart header="Evaluasi parameter default"
Di Javascript, parameter default dievaluasi tiap kali fungsi dipanggil tanpa parameter.
Pada contoh di atas, `anotherFunction()` dipanggil tiap kali `showMessage()` dipanggil tanpa parameter `text`.
Di sisi lain, itu dipanggil secara independen setiap kali `teks` hilang.
```
### Alternatif nilai default parameter
Terkadang akan dapat dimengerti untuk memberikan nilai default untuk variabel bukan didalam deklarasi fungsi, tapi di tahap selanjutnya, didalam proses eksekusinya.
Untuk memeriksa parameter yang tidak ada, kita bisa membandingkannya dengan `undefined`:
```js run
function showMessage(text) {
// ...
*!*
if (text === undefined) { // if the parameter is missing
text = 'empty message';
}
*/!*
alert(text);
}
showMessage(); // empty message
```
...Atau kita bisa menggunakan operator `||`:
```js
// jika teks parameter tidak ada atau "", set variabel ke 'empty'
function showMessage(text) {
// if text is undefined or otherwise falsy, set it to 'empty'
text = text || 'empty';
...
}
```
Javascript yang modern mendukung [nullish coalescing operator/operator penggabung nullish](info:nullish-coalescing-operator) `??`, akan lebih baik jika nilai falsy, seperti `0`, dianggap biasa:
```js run
// jika tidak ada parameter "count", tampilkan "unknown"
function showCount(count) {
// if count is undefined or null, show "unknown"
alert(count ?? "unknown");
}
showCount(0); // 0
showCount(null); // unknown
showCount(); // unknown
```
## Mengembalikan nilai
Fungsi dapat mengembalikan nilai kepada kode pemanggil sebagai hasil akhir.
Contoh yang paling sederhana adalah fungsi yang menjumlahkan dua nilai:
```js run no-beautify
function sum(a, b) {
*!*return*/!* a + b;
}
let result = sum(1, 2);
alert( result ); // 3
```
Penulisan kata `return` dapat ditulis dimana saja pada fungsi. Ketika proses eksekusi kode mencapai kata tersebut, proses eksekusi akan berhenti, dan nilai akan dikembalikan kepada kode pemanggil (yang ditentukan pada variabel `result` di atas).
Dapat dimungkinkan kehadiran banyak kata `return` pada suatu fungsi tunggal. Misalnya:
```js run
function checkAge(age) {
if (age >= 18) {
*!*
return true;
*/!*
} else {
*!*
return confirm('Do you have permission from your parents?');
*/!*
}
}
let age = prompt('How old are you?', 18);
if ( checkAge(age) ) {
alert( 'Access granted' );
} else {
alert( 'Access denied' );
}
```
Sangat dimungkinkan menggunakan kata `return` tanpa nilai. Hal ini akan menyebabkan fungsi untuk langsung keluar.
Misalnya:
```js
function showMovie(age) {
if ( !checkAge(age) ) {
*!*
return;
*/!*
}
alert( "Showing you the movie" ); // (*)
// ...
}
```
Pada contoh kode di atas, jika `checkAge(age)` mengembalikan nilai `false`, maka `showMovie` tidak akan memproses `alert`.
````smart header="Jika fungsi tidak mengembalikan nilai, hal ini sama saja dengan mengembalikan nilai `undefined`"
```js run
function doNothing() { /* kosong */ }
alert( doNothing() === undefined ); // true
```
`return` kosong tanpa nilai memiliki nilai yang sama dengan `return undefined`:
```js run
function doNothing() {
return;
}
alert( doNothing() === undefined ); // true
```
````
````warn header="Jangan tambahkan baris baru diantara `return` dan nilainya"
Untuk ekspresi yang lebih panjang pada penggunaan `return`, ini mungkin akan menciptakan suatu penulisan yang singkat untuk menuliskannya pada baris yang berbeda, seperti contoh berikut:
```js
return
(some + long + expression + or + whatever * f(a) + f(b))
```
Hal ini tidak akan berhasil karena Javascript akan menganggap tanda titik koma setelah kata `return`. Hal ini juga akan berlangsung sama dengan contoh berikut:
```js
return*!*;*/!*
(some + long + expression + or + whatever * f(a) + f(b))
```
Jadi, ia efektif menjadi kembalian kosong.
Jika kita ingin expresi kembalian membungkus beberapa baris, kita mesti mulai di baris yang sama dengan `return`. Atau minimal taruh tanda kurung pembuka di sana seperti ini:
```js
return (
some + long + expression
+ or +
whatever * f(a) + f(b)
)
```
Dan ia akan berjalan seperti harapan kita.
````
## Menamakan fungsi [#penamaan fungsi]
Fungsi adalah tindakan. Sehingga nama fungsi mencerminkan kata kerja. Ia harus ringkas, sebisa mungkin harus akurat dan menjelaskan fungsi apa yang dikerjakan, sehingga ketika seseorang yang membaca kode tersebut mendapatkan penjelasan atau indikasi fungsi apa tersebut.
Sudah menjadi khalayak umum bahwa untuk membuat fungsi harus dibarengi dengan awalan verbal yang secara tidak langsung menjelaskan tindakannya.
Sebagai gambaran, fungsi yang dimulai dengan kata `"show"` biasanya melakukan tindakan menunjukkan sesuatu.
Fungsi yang dimulai dengan...
- `"get"` -- mengembalikan suatu nilai,
- `"calc"` -- menghitungkan sesuatu,
- `"create"` -- membuat sesuatu,
- `"check"` -- melakukan pengecekkan dan mengembalikan nilai boolean, dst.
Contoh dari nama yang diberikan di atas:
```js no-beautify
showMessage(..) // menampilkan pesan
getAge(..) // mengembalikan nilai umur (bagaimanapun mengembalikkan umur)
calcSum(..) // menghitung penjumlahan dan mengembalikan hasilnya
createForm(..) // membuat formulir (dan biasanya mengembalikan nilai)
checkPermission(..) // pengecekkan terhadap ijin, mengembalikan true/false
```
Dengan awalan yang tertera, secara sekilas pada nama fungsi memberikan pemahaman tindakan apa yang dilakukan dan nilai apa yang dikembalikan.
```smart header="Satu fungsi -- Satu aksi"
Fungsi sebaiknya mengerjakan apa yang telah ditulis pada namanya, tidak lebih.
Dua tindakan independen biasanya berasal dari dua fungsi, walaupun mereka dipanggil secara bersamaan (pada kasus ini, kita mampu membuat fuungsi ketiga yang memanggil keduanya).
Sedikit contoh yang mematahkan aturan ini:
- `getAge` -- akan menjadi buruk jika menunjukkan `alert` yang menunjukkan umur (seharusnya hanya get).
- `createForm` -- akan menjadi buruk jika fungsi tersebut mengubah dokumen, menambahkan formulir pada dokumen tersebut (seharusnya hanya membentuk dokumen dan mengembalikannya).
- `checkPermission` -- akan menjadi buruk jika fungsi tersebut menampilkan pesan `akses diberikan/ditolak` (seharusnya hanya melakukan pengecekkan dan mengembalikkan nilainya).
Pada contoh-contoh ini diasumsikan arti-arti umum pada kata awalan. Kamu dan tim kamu memiliki kehendak bebas untuk menentukan arti lainnya, tapi biasanya penentuan arti tersebut tidaklah jauh berbeda. Pada contoh lain, kamu seharusnya memiliki pemahaman yang kuat dari arti kata awalan yang digunakan, kata awalan apa yang dapat digunakan pada fungsi dan tidak dapat diguunakan. Semua kata awalan fungsi harus mengikuti aturan tertentu. Dan tim seharusnya dapat saling memberikan pemahaman satu sama lain.
```
```smart header="Ultrashort function names"
Fungsi yang *digunakan secara sering* kadang-kadang memiliki nama yang sangat pendek.
Sebagai contoh, framework [jQuary](http://jquary.com) mendefinisikan fungsi dengan simbol `$`. Library [Lodash](https://lodash.com) memiliki fungsi inti yang dinamakan dengan `_`.
Hal-hal tersebut adalah pengecualian. Secara umum, nama fungsi sebaiknya ringkas dan menjelaskan maksudnya.
```
## Fungsi == komen
Fungsi seharusnya memiliki nama yang pendek dan hanya melakukan satu tindakan. Jika tindakan tersebut mengerjakan hal yang cukup kompleks, mungkin sebaiknya fungsi tersebut dibagi menjadi fungsi yang lebih sederhana. Kadang-kadang, mengikuti aturan ini tidaklah mudah, tetapi tentu adalah hal yang baik.
Fungsi yang terpisah bukan hanya mudah untuk diuji coba dan debug -- kehadirannya sangat baik untuk diberikan komentar!
Sebagai gambaran, bandingkan dua fungsi `showPrimes(n)` di bawah. Setiap satu dari keluarannya [bilangan prima](https://en.wikipedia.org/wiki/Prime_number) mencapai hingga `n`.
Variasi pertama menggunakan label:
```js
function showPrimes(n) {
nextPrime: for (let i = 2; i < n; i++) {
for (let j = 2; j < i; j++) {
if (i % j == 0) continue nextPrime;
}
alert( i ); // bilangan prima
}
}
```
Pada variasi yang kedua mengguunakan fungsi tambahan `isPrime(n)` untuk dilakukan uji coba keutamaannya:
```js
function showPrimes(n) {
for (let i = 2; i < n; i++) {
*!*if (!isPrime(i)) continue;*/!*
alert(i); // bilangan prima
}
}
function isPrime(n) {
for (let i = 2; i < n; i++) {
if ( n % i == 0) return false;
}
return true;
}
```
Pada variasi yang kedua lebih mudah untuk dipahami, benarkan ? Malah daripada potongan kode yang kita lihat pada tindakan (`isPrime`). Kadang-kadang, orang-orang merujuk kepada penulisan kode yang *menjelaskan dirinya*.
Jadi, fungsi dapat dibuat walaupun kita tidak terlalu sering menggunakannya. Mereka membuat kode lebih terstruktur dan lebih mudah untuk dibaca.
## Kesimpulan
Deklarasi fungsi terlihat seperti ini:
```js
function name(parameters, delimited, by, comma) {
/* code */
}
```
- Nilai yang diberikan kepada fungi sebagai parameter dipindahkan ke variabel lokal.
- Fungsi mungkin dapat diakses dengan variabel luar. Tetapi fungsi tersebut hanya dapat bekerja melalui internal fungsi keluar. Kode di luar daripada fungsi bersangkutan tidak dapat melihat variabel lokal.
- Fungsi dapat mengembalikan suatu nilai. Jika tidak demikian, maka akan mengembalikan nilai `undefined`.
Untuk membuat kode yang bersih dan mudah untuk dipahami, sangat dianjurkan untuk menggunakan variabel lokal dan parameter pada fungsi, tidak mengguunakan variabel luar / variabel global.
Akan menjadi hal yang mudah untuk dipahami pada fungsi yang mendapatkan parameter, yang bekerja dengan parameter tersebut dan mengembalikan nilainya daripada fuungsi yang tidak memilki parameter, tetapi melakukan modifikasi terhadap variabel luar akan memiliki efek samping.
Penamaan fungsi:
- Nama seharusnya ditulis dengan jelas dan mendeskripsikan apa yang dikerjakan. Ketika kita melihat fungsi dipanggil pada kode, penamaan yang baik secara langsuung akan memberikan kita pemahaman apa yang dikerjakan dan nilai apa yang dikembalikan.
- Fungsi adalah tindakan, sehingga nama fungsi biasanya kata kerja (verbal).
- Banyak nama-nama awalan fungsi seperti `create`, `show`, `get`, `check` dan lainnya. Gunakan awalan tersebut untuk memberikan kata kunci apa yang dikerjakan oleh fungsi.
Fungsi adalah bagaikan fondasi bangunan dari skrip. Sekarang, kita telah mempelajari dasarnya, sehingga sekarang kita dapat memumlai untuk membuat dan menggunakannya. Tapi hal itu baru permulaan dari awal perjalanan. Kita akan kembali menggunakan mereka berulang kali, secara terus-menerus menggunakan secara mendalam hingga fitur yang lebih kompleks.
================================================
FILE: 1-js/02-first-steps/16-function-expressions/article.md
================================================
# Expresi fungsi
Di JavaScript, fungsi bukan "struktur bahasa magis", melaikan satu bentuk nilai spesial.
Syntax yang kita gunakan sebelumnya disebut *Deklarasi Fungsi*:
```js
function sayHi() {
alert( "Hello" );
}
```
Ada syntax lain untuk membuat fungsi yang disebut *Expresi Fungsi*.
Rupanya seperti ini:
```js
let sayHi = function() {
alert( "Hello" );
};
```
Di sini, fungsi dibuat dan diisi variabel secara explisit, seperti nilai lain manapun. Tak peduli bagaimana fungsi didefinisi, ia hanya suatu nilai yang disimpan dalam variabel `sayHi`.
Arti dari sampel kode ini sama: "buatlah fungs dan taruhlah di dalam variabel `sayHi`".
Kita bahkan bisa mencetak nilai itu menggunakan `alert`:
```js run
function sayHi() {
alert( "Hello" );
}
*!*
alert( sayHi ); // menampilkan kode fungsi
*/!*
```
Tolong ingat bahwa baris terakhir tidak menjalankan fungsi, karena tak ada tanda kurung setelah `sayHi`. Ada bahasa pemrograman di mana satu penyebutan nama fungsi menyebabkan exekusi fungsi, tapi JavaScript tak seperti itu.
Di JavaScript, fungsi adalah nilai, jadi kita bisa menghadapinya sebagai nilai. Kode di atas menunjukkan representasi stringnya, yang mana kode sumbernya.
Pastinya, fungsi adalah nilai spesial, dengan anggapan bahwa kita bisa memanggilnya seperti `sayHi()`.
Tapi ia tetaplah nilai. Jadi kita bisa memakainya seperti macam nilai lainnya.
Kita bisa mengkopi fungsi ke variabel lain:
```js run no-beautify
function sayHi() { // (1) buat
alert( "Hello" );
}
let func = sayHi; // (2) kopi
func(); // Hello // (3) jalankan kopinya (ia bekerja)!
sayHi(); // Hello // ini juga masih bekerja (kenapa tidak)
```
Inilah yang terjadi di atas secara detil:
1. Deklarasi Fungsi `(1)` membuat fungsi dan menaruhnya ke variabel bernama `sayHi`.
2. Baris `(2)` mengkopinya ke variabel `func`. Tolong ingat lagi: tak ada tanda kurung setelah `sayHi`. Jika ada, maka `func = sayHi()` akan menulis *hasil panggilan* `sayHi()` ke `func`, bukan *fungsi* `sayHi` itu sendiri.
3. Sekarang fungsi bisa dipanggil baik sebagai `sayHi()` maupun `func()`.
Catat bahwa kita jusa bisa menggunakan Expresi Fungsi untuk mendeklarasi `sayHi`, di baris pertama:
```js
let sayHi = function() {
alert( "Hello" );
};
let func = sayHi;
// ...
```
Semua akan berjalan sama.
````smart header="Kenapa ada semicolon di akhir?"
Kamu mungkin penasaran, kenapa Expresi Fungsi punya semicolon `;` di akhir, tapi Deklarasi Fungsi tidak:
```js
function sayHi() {
// ...
}
let sayHi = function() {
// ...
}*!*;*/!*
```
Jawabannya simpel:
- `;` tidak dibutuhkan di akhir blok kode dan struktur syntax yang memakai mereka seperti `if { ... }`, `for { }`, `function f { }` dll.
- Expresi Fungsi digunakan di dalam pernyataan: `let sayHi = ...;`, sebagai nilai. Ia bukan blok kode, tapi lebih ke penetapan. Semicolon `;` disarankan di akhir pernyataan, tak peduli nilainya apa. Jadi semicolon di sini tak ada hubungannya dengan Expresi Fungsi itu sendiri, ia hanya menstop pernyataan.
````
## Fungsi callback
Ayo kita lihat pada contoh lain mengoper fungsi sebagai nilai dan menggunakan expresi fungsi.
Kita akan menulis fungsi `ask(question, yes, no)` dengan tiga parameter:
`question`
: Teks pertanyaan
`yes`
: Fungsi yang berjalan jika jawabannya "Yes"
`no`
: Fungsi yang berjalan jika jawabannya "No"
Fungsinya akan menanyakan `question` dan, tergantung jawabannya pengguna, panggil `yes()` atau `no()`:
```js run
*!*
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
*/!*
function showOk() {
alert( "You agreed." );
}
function showCancel() {
alert( "You canceled the execution." );
}
// usage: functions showOk, showCancel are passed as arguments to ask
ask("Do you agree?", showOk, showCancel);
```
Pada praktiknya, fungsi macam ini agak berguna. Perbedaan besar antara `ask` kehidupan-nyata dan contoh di atas adalah fungsi kehidupan-nyata memakai cara komplex untuk berinteraksi dengan pengguna daripada sekedar `confirm`. Di peramban, fungsi macam ini biasanya menarik window pertanyaan menarik. Tapi itu cerita lain lagi.
**Argumen `showOk` dan `showCancel` dari `ask` dipanggil *fungsi callback* atau hanya *callback*.**
Idenya adalah kita mengoper fungsi dan berharap ia "dipanggil kembali" kemudian jika dibutuhkan. Pada kasus kita, `showOk` menjadi callback untuk jawaban "yes", dan `showCancel` untuk jawaban "no".
Kita bisa memakai Expresi Fungsi untuk menulis fungsi yang sama lebih pendek:
```js run no-beautify
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
*!*
ask(
"Do you agree?",
function() { alert("You agreed."); },
function() { alert("You canceled the execution."); }
);
*/!*
```
Di sini, fungsi dideklarasi tepat di dalam panggilan `ask(...)`. Mereka tak punya nama, jadinya disebut *anonymous*. Fungsi macam ini tak bisa diakses di luar `ask` (karena mereka tak diset ke variabel), tapi itulah yang kita mau di sini.
Kode macam ini muncul di script kita secara sangat alamiah, ia ada di dalam semangat JavaScript.
```smart header="Fungsi adalah nilai yang mewakili \"aksi\""
Nilai reguler seperti string atau angka mewakiliki *data*.
Fungsi bisa dianggap sebagai *aksi*.
Kita bisa mengopernya antara variabel dan menjalankannya kapanpun kita mau.
```
## Expresi Fungsi vs Deklarasi Fungsi
Mari kita rumuskan kunci perbedaan antara Deklarasi dan Expresi Fungsi.
Pertama, syntax: bagaimana membedakan antara mereka dalam kode.
- *Deklarasi Fungsi:* fungsi, yang dideklarasi sebagai pernyataan terpisah, dalam aliran kode utama.
```js
// Deklarasi Fungsi
function sum(a, b) {
return a + b;
}
```
- *Expresi Fungsi:* fungsi, yang dibuat dalam expresi atau dalam konstruksi syntax lain. Di sini, fungsi dibuat pada sisi kanan dari "expresi penetapan" `=`:
```js
// Expresi Fungsi
let sum = function(a, b) {
return a + b;
};
```
Perbedaan yang lebih halus ialah *ketika* fungsi dibuat oleh JavaScript engine.
**Expresi Fungsi dibuat ketika exekusi mencapainya dan hanya dapat dipakai saat itu saja.**
Sekali aliran exekusi melewati sisi kanan penetapan `let sum = function…` -- di sinilah, fungsi dibuat dan bisa digunakan (diset, dipanggil, dll. ) dari sekarang.
Deklarasi Fungsi berbeda.
**Deklarasi Fungsi bisa dipanggil lebih cepat dari ia didefinisi.**
Misalnya, Deklarasi Fungsi global terlihat di seluruh script, tak peduli di mana ia berada.
Itu karena algoritma internal. Saat JavaScript siap menjalankan script, pertama ia melihat Deklarasi Fungsi global di dalam dan membuat fungsi. Kita bisa anggap itu sebagai "tahap inisialisasi".
Dan setelah semua Deklarasi Fungsi diproses, kodenya diexekusi. Jadi ia punya akses ke fungsi-fungsi ini.
Misalnya, ini berjalan:
```js run refresh untrusted
*!*
sayHi("John"); // Hello, John
*/!*
function sayHi(name) {
alert( `Hello, ${name}` );
}
```
Deklarasi Fungsi `sayHi` dibuat saat JavaScript siap memulai scriptnya dan terlihat di manapun di dalam.
...Jika ia Expresi Fungsi, maka ia tak akan berjalan:
```js run refresh untrusted
*!*
sayHi("John"); // galat!
*/!*
let sayHi = function(name) { // (*) tak ada magic lagi
alert( `Hello, ${name}` );
};
```
Expresi Fungsi dibuat saat exekusi mencapainya. Itu hanya akan terjadi pada baris `(*)`. Sudah telat banget.
Fitur spesial lain dari Deklarasi Fungsi ialah scope blok mereka.
**Di mode ketat, ketika Deklarasi Fungsi berada di jangkauan blok kode, ia terlihat di manapun di dalam blok. Tapi tidak di luarnya.**
Misalnya, bayangkan kita harus mendeklarasi fungsi `welcome()` tergantung variabel `age` yang kita dapat saat runtime. Lalu kita berencana akan menggunakannya kemudian.
Jika kita memakai Deklarasi Fungsi, ia tak akan bekerja sesuai harapan:
```js run
let age = prompt("What is your age?", 18);
// secara kondisional mendeklarasi fungsi
if (age < 18) {
function welcome() {
alert("Hello!");
}
} else {
function welcome() {
alert("Greetings!");
}
}
// ...pakai ini kemudian
*!*
welcome(); // Error: welcome is not defined
*/!*
```
Itu karena Deklarasi Fungsi cuma terlihat di dalam blok kode yang ia tinggali.
Ini contoh lainnya:
```js run
let age = 16; // ambil 16 sebagai contoh
if (age < 18) {
*!*
welcome(); // \ (berjalan)
*/!*
// |
function welcome() { // |
alert("Hello!"); // | Deklarasi Fungsi tersedia
} // | di manapun dalam blok kode tempat dia dideklarasi
// |
*!*
welcome(); // / (berjalan)
*/!*
} else {
function welcome() {
alert("Greetings!");
}
}
// Di sini kita di luar kurung kurawal,
// jadi kita tak bisa melihat Deklarasi Fungsi yang dibuat di dalamnya.
*!*
welcome(); // Error: welcome is not defined
*/!*
```
Apa yang bisa kita lakukan supaya `welcome` terlihat di luar `if`?
Pendekatan yang benar ialah menggunakan Expresi Fungsi dan menetapkan `welcome` ke variabel yang dideklarasi di luar `if` dan punya visibilitas yang cukup.
Kode ini berjalan sesuai harapan:
```js run
let age = prompt("What is your age?", 18);
let welcome;
if (age < 18) {
welcome = function() {
alert("Hello!");
};
} else {
welcome = function() {
alert("Greetings!");
};
}
*!*
welcome(); // sekarang ok
*/!*
```
Atau kita bisa menyederhanakannya lebih lanjut menggunakan operator tanda tanya `?`:
```js run
let age = prompt("What is your age?", 18);
let welcome = (age < 18) ?
function() { alert("Hello!"); } :
function() { alert("Greetings!"); };
*!*
welcome(); // sekarang ok
*/!*
```
```smart header="Kapan harus memilih Deklarasi Fungsi versus Expresi Fungsi?"
Sebagai aturan praktis, saat kita harus mendeklarasi fungsi, hal pertama yang kita pertimbangkan ialah syntax Deklarasi Fungsi. Ia memberi kebebasan lebih dalam bagaimana mengorganisir kode kita, karena kita bisa memanggil fungsi macam ini sebelum mereka dideklarasi.
Itu juga untuk keterbacaan yang l
gitextract_3kej2r86/ ├── .gitattributes ├── .gitignore ├── 1-js/ │ ├── 01-getting-started/ │ │ ├── 1-intro/ │ │ │ └── article.md │ │ ├── 2-manuals-specifications/ │ │ │ └── article.md │ │ ├── 3-code-editors/ │ │ │ └── article.md │ │ ├── 4-devtools/ │ │ │ ├── article.md │ │ │ └── bug.html │ │ └── 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 │ │ ├── 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/ │ │ │ │ │ └── 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/ │ │ │ │ ├── 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 │ │ │ ├── debugging.view/ │ │ │ │ ├── hello.js │ │ │ │ └── index.html │ │ │ └── head.html │ │ ├── 02-coding-style/ │ │ │ ├── 1-style-errors/ │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ └── article.md │ │ ├── 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 │ │ ├── 02-object-copy/ │ │ │ └── article.md │ │ ├── 03-garbage-collection/ │ │ │ └── article.md │ │ ├── 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 │ │ │ └── article.md │ │ ├── 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 │ │ ├── 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 │ │ ├── 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 │ │ └── index.md │ ├── 06-advanced-functions/ │ │ ├── 01-recursion/ │ │ │ ├── 01-sum-to/ │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ ├── 02-factorial/ │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ ├── 03-fibonacci-numbers/ │ │ │ │ ├── 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 │ │ ├── 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 │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ ├── 2-closure-variable-access/ │ │ │ │ ├── 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 │ │ ├── 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 │ │ ├── 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.view/ │ │ │ │ │ └── index.html │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ ├── 04-throttle/ │ │ │ │ ├── _js.view/ │ │ │ │ │ ├── solution.js │ │ │ │ │ └── test.js │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ └── article.md │ │ ├── 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 │ │ ├── 02-function-prototype/ │ │ │ ├── 1-changing-prototype/ │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ ├── 4-new-object-same-constructor/ │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ └── article.md │ │ ├── 03-native-prototypes/ │ │ │ ├── 1-defer-to-prototype/ │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ ├── 2-defer-to-prototype-extended/ │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ └── article.md │ │ ├── 04-prototype-methods/ │ │ │ ├── 2-dictionary-tostring/ │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ ├── 3-compare-calls/ │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ └── article.md │ │ └── index.md │ ├── 09-classes/ │ │ ├── 01-class/ │ │ │ ├── 1-rewrite-to-class/ │ │ │ │ ├── _js.view/ │ │ │ │ │ ├── solution.js │ │ │ │ │ └── source.js │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ └── article.md │ │ ├── 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 │ │ │ └── article.md │ │ ├── 03-static-properties-methods/ │ │ │ ├── 3-class-extend-object/ │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ └── article.md │ │ ├── 04-private-protected-properties-methods/ │ │ │ └── article.md │ │ ├── 05-extend-natives/ │ │ │ └── article.md │ │ ├── 06-instanceof/ │ │ │ ├── 1-strange-instanceof/ │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ └── article.md │ │ ├── 07-mixins/ │ │ │ ├── article.md │ │ │ └── head.html │ │ └── index.md │ ├── 10-error-handling/ │ │ ├── 1-try-catch/ │ │ │ ├── 1-finally-or-code-after/ │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ └── article.md │ │ ├── 2-custom-errors/ │ │ │ ├── 1-format-error/ │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ └── article.md │ │ └── index.md │ ├── 11-async/ │ │ ├── 01-callbacks/ │ │ │ ├── article.md │ │ │ └── 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 │ │ ├── 03-promise-chaining/ │ │ │ ├── 01-then-vs-catch/ │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ ├── article.md │ │ │ ├── getMessage.js │ │ │ ├── head.html │ │ │ ├── one.js │ │ │ ├── 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 │ │ │ ├── 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 │ │ ├── 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 │ │ ├── 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 │ │ ├── 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 │ │ └── index.md │ └── index.md ├── 2-ui/ │ ├── 1-document/ │ │ ├── 01-browser-environment/ │ │ │ └── article.md │ │ ├── 02-dom-nodes/ │ │ │ ├── article.md │ │ │ ├── elk.html │ │ │ └── head.html │ │ ├── 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 │ │ │ └── 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 │ │ ├── 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 │ │ ├── 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 │ │ │ │ ├── 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.view/ │ │ │ └── index.html │ │ ├── 10-size-and-scroll-window/ │ │ │ └── article.md │ │ ├── 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 │ │ │ └── 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/ │ │ │ │ ├── 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/ │ │ │ │ ├── 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 │ │ ├── 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.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 │ │ │ ├── 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/ │ │ │ │ │ ├── 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 │ │ ├── 6-pointer-events/ │ │ │ ├── article.md │ │ │ ├── ball-2.view/ │ │ │ │ └── index.html │ │ │ ├── ball.view/ │ │ │ │ └── index.html │ │ │ ├── multitouch.view/ │ │ │ │ └── index.html │ │ │ └── slider.view/ │ │ │ ├── index.html │ │ │ └── style.css │ │ ├── 7-keyboard-events/ │ │ │ ├── 2-check-sync-keydown/ │ │ │ │ ├── solution.md │ │ │ │ ├── solution.view/ │ │ │ │ │ └── index.html │ │ │ │ └── task.md │ │ │ ├── article.md │ │ │ └── keyboard-dump.view/ │ │ │ ├── index.html │ │ │ ├── script.js │ │ │ └── style.css │ │ ├── 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 │ │ │ │ ├── source.view/ │ │ │ │ │ └── index.html │ │ │ │ └── task.md │ │ │ └── article.md │ │ └── index.md │ ├── 4-forms-controls/ │ │ ├── 1-form-elements/ │ │ │ ├── 1-add-select-option/ │ │ │ │ ├── solution.md │ │ │ │ └── task.md │ │ │ └── article.md │ │ ├── 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 │ │ ├── 03-event-loop/ │ │ │ └── article.md │ │ └── 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 │ │ └── article.md │ ├── 02-text-decoder/ │ │ └── article.md │ ├── 03-blob/ │ │ └── article.md │ ├── 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 │ │ └── post.view/ │ │ └── server.js │ ├── 02-formdata/ │ │ ├── article.md │ │ └── post.view/ │ │ └── server.js │ ├── 03-fetch-progress/ │ │ ├── article.md │ │ └── 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 │ ├── 06-fetch-api/ │ │ ├── article.md │ │ └── post.view/ │ │ ├── index.html │ │ └── server.js │ ├── 07-url/ │ │ └── article.md │ ├── 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 │ │ └── longpoll.view/ │ │ ├── browser.js │ │ ├── index.html │ │ └── server.js │ ├── 11-websocket/ │ │ ├── article.md │ │ ├── chat.view/ │ │ │ ├── index.html │ │ │ └── server.js │ │ └── demo.view/ │ │ └── server.js │ ├── 12-server-sent-events/ │ │ ├── article.md │ │ └── eventsource.view/ │ │ ├── index.html │ │ └── server.js │ └── index.md ├── 6-data-storage/ │ ├── 01-cookie/ │ │ ├── article.md │ │ └── 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 │ └── index.md ├── 7-animation/ │ ├── 1-bezier-curve/ │ │ └── article.md │ ├── 2-css-animations/ │ │ ├── 1-animate-logo-css/ │ │ │ ├── solution.md │ │ │ ├── solution.view/ │ │ │ │ └── index.html │ │ │ ├── source.view/ │ │ │ │ └── index.html │ │ │ └── task.md │ │ ├── 2-animate-logo-bezier-css/ │ │ │ ├── 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 │ │ ├── boat.view/ │ │ │ ├── index.html │ │ │ └── style.css │ │ ├── digits-negative-delay.view/ │ │ │ ├── index.html │ │ │ ├── script.js │ │ │ └── style.css │ │ ├── digits.view/ │ │ │ ├── index.html │ │ │ ├── script.js │ │ │ └── style.css │ │ ├── step-end.view/ │ │ │ ├── index.html │ │ │ └── style.css │ │ ├── step-list.view/ │ │ │ ├── index.html │ │ │ └── style.css │ │ ├── step.view/ │ │ │ ├── index.html │ │ │ └── style.css │ │ ├── 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.view/ │ │ │ ├── index.html │ │ │ └── style.css │ │ ├── bounce-easeinout.view/ │ │ │ ├── index.html │ │ │ └── style.css │ │ ├── bounce-easeout.view/ │ │ │ ├── index.html │ │ │ └── style.css │ │ ├── bounce.view/ │ │ │ ├── index.html │ │ │ └── style.css │ │ ├── circ.view/ │ │ │ ├── index.html │ │ │ └── style.css │ │ ├── elastic.view/ │ │ │ ├── index.html │ │ │ └── style.css │ │ ├── move-raf.view/ │ │ │ └── index.html │ │ ├── move.view/ │ │ │ └── index.html │ │ ├── quad.view/ │ │ │ ├── index.html │ │ │ └── style.css │ │ ├── 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 │ ├── 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 │ ├── 4-template-element/ │ │ └── article.md │ ├── 5-slots-composition/ │ │ ├── article.md │ │ └── menu.view/ │ │ └── index.html │ ├── 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 │ ├── 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 │ ├── 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 │ ├── 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 │ ├── 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 ├── glossary.md ├── script/ │ └── clean-unused-png.php └── todo.md
SYMBOL INDEX (176 symbols across 109 files)
FILE: 1-js/03-code-quality/01-debugging-chrome/debugging.view/hello.js
function hello (line 1) | function hello(name) {
function say (line 7) | function say(phrase) {
FILE: 1-js/03-code-quality/05-testing-mocha/pow-3.view/test.js
function makeTest (line 3) | function makeTest(x) {
FILE: 1-js/03-code-quality/05-testing-mocha/pow-4.view/test.js
function makeTest (line 5) | function makeTest(x) {
FILE: 1-js/03-code-quality/05-testing-mocha/pow-full.view/test.js
function makeTest (line 5) | function makeTest(x) {
FILE: 1-js/03-code-quality/05-testing-mocha/pow-nan.view/test.js
function makeTest (line 5) | function makeTest(x) {
FILE: 1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js
function isEmpty (line 1) | function isEmpty(obj) {
FILE: 1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/solution.js
function multiplyNumeric (line 1) | function multiplyNumeric(obj) {
FILE: 1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js
function multiplyNumeric (line 8) | function multiplyNumeric(obj) {
FILE: 1-js/04-object-basics/04-object-methods/7-calculator/_js.view/solution.js
method sum (line 2) | sum() {
method mul (line 6) | mul() {
method read (line 10) | read() {
FILE: 1-js/04-object-basics/06-constructor-new/2-calculator-constructor/_js.view/solution.js
function Calculator (line 1) | function Calculator() {
FILE: 1-js/04-object-basics/06-constructor-new/3-accumulator/_js.view/solution.js
function Accumulator (line 1) | function Accumulator(startingValue) {
FILE: 1-js/05-data-types/02-number/3-repeat-until-number/_js.view/solution.js
function readNumber (line 2) | function readNumber() {
FILE: 1-js/05-data-types/03-string/1-ucfirst/_js.view/solution.js
function ucFirst (line 1) | function ucFirst(str) {
FILE: 1-js/05-data-types/03-string/2-check-spam/_js.view/solution.js
function checkSpam (line 1) | function checkSpam(str) {
FILE: 1-js/05-data-types/03-string/3-truncate/_js.view/solution.js
function truncate (line 1) | function truncate(str, maxlength) {
FILE: 1-js/05-data-types/03-string/4-extract-currency/_js.view/solution.js
function extractCurrencyValue (line 1) | function extractCurrencyValue(str) {
FILE: 1-js/05-data-types/04-array/10-maximal-subarray/_js.view/solution.js
function getMaxSubSum (line 1) | function getMaxSubSum(arr) {
FILE: 1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js
function camelize (line 1) | function camelize(str) {
FILE: 1-js/05-data-types/05-array-methods/11-array-unique/_js.view/solution.js
function unique (line 1) | function unique(arr) {
FILE: 1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/solution.js
function groupById (line 1) | function groupById(array) {
FILE: 1-js/05-data-types/05-array-methods/2-filter-range/_js.view/solution.js
function filterRange (line 2) | function filterRange(arr, a, b) {
FILE: 1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/solution.js
function filterRangeInPlace (line 2) | function filterRangeInPlace(arr, a, b) {
FILE: 1-js/05-data-types/05-array-methods/6-calculator-extendable/_js.view/solution.js
function Calculator (line 1) | function Calculator() {
FILE: 1-js/05-data-types/07-map-set/01-array-unique-map/_js.view/solution.js
function unique (line 1) | function unique(arr) {
FILE: 1-js/05-data-types/07-map-set/02-filter-anagrams/_js.view/solution.js
function aclean (line 2) | function aclean(arr) {
FILE: 1-js/05-data-types/07-map-set/02-filter-anagrams/_js.view/test.js
function intersection (line 1) | function intersection(arr1, arr2) {
FILE: 1-js/05-data-types/09-keys-values-entries/01-sum-salaries/_js.view/solution.js
function sumSalaries (line 1) | function sumSalaries(salaries) {
FILE: 1-js/05-data-types/09-keys-values-entries/02-count-properties/_js.view/solution.js
function count (line 1) | function count(obj) {
FILE: 1-js/05-data-types/10-destructuring-assignment/6-max-salary/_js.view/solution.js
function topSalary (line 1) | function topSalary(salaries) {
FILE: 1-js/05-data-types/11-date/2-get-week-day/_js.view/solution.js
function getWeekDay (line 1) | function getWeekDay(date) {
FILE: 1-js/05-data-types/11-date/3-weekday/_js.view/solution.js
function getLocalDay (line 1) | function getLocalDay(date) {
FILE: 1-js/05-data-types/11-date/4-get-date-ago/_js.view/solution.js
function getDateAgo (line 1) | function getDateAgo(date, days) {
FILE: 1-js/05-data-types/11-date/5-last-day-of-month/_js.view/solution.js
function getLastDayOfMonth (line 1) | function getLastDayOfMonth(tahun, bulan) {
FILE: 1-js/05-data-types/11-date/8-format-date-relative/_js.view/solution.js
function formatDate (line 2) | function formatDate(date) {
FILE: 1-js/06-advanced-functions/03-closure/10-make-army/_js.view/solution.js
function makeArmy (line 1) | function makeArmy() {
FILE: 1-js/06-advanced-functions/03-closure/10-make-army/_js.view/source.js
function makeArmy (line 1) | function makeArmy() {
FILE: 1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/solution.js
function inArray (line 2) | function inArray(arr) {
function inBetween (line 6) | function inBetween(a, b) {
FILE: 1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/source.js
function inBetween (line 4) | function inBetween(a, b) {
function inArray (line 8) | function inArray(arr) {
FILE: 1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/solution.js
function byField (line 1) | function byField(fieldName){
FILE: 1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/source.js
function byField (line 1) | function byField(fieldName){
FILE: 1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/_js.view/solution.js
function makeCounter (line 1) | function makeCounter() {
FILE: 1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/_js.view/source.js
function makeCounter (line 1) | function makeCounter() {
FILE: 1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/solution.js
function sum (line 1) | function sum(a) {
FILE: 1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/source.js
function sum (line 1) | function sum(a){
FILE: 1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/solution.js
function spy (line 1) | function spy(func) {
FILE: 1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/source.js
function spy (line 1) | function spy(func) {
FILE: 1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/test.js
function work (line 3) | function work() {}
FILE: 1-js/06-advanced-functions/09-call-apply-decorators/02-delay/_js.view/solution.js
function delay (line 1) | function delay(f, ms) {
FILE: 1-js/06-advanced-functions/09-call-apply-decorators/02-delay/_js.view/test.js
function f (line 13) | function f(x) {
FILE: 1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js
function debounce (line 1) | function debounce(func, ms) {
FILE: 1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/test.js
method f (line 38) | f() {
FILE: 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/solution.js
function throttle (line 1) | function throttle(func, ms) {
FILE: 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/test.js
function f (line 5) | function f(a) {
FILE: 1-js/09-classes/01-class/1-rewrite-to-class/_js.view/solution.js
class Clock (line 1) | class Clock {
method constructor (line 2) | constructor({ template }) {
method render (line 6) | render() {
method stop (line 26) | stop() {
method start (line 30) | start() {
FILE: 1-js/09-classes/01-class/1-rewrite-to-class/_js.view/source.js
function Clock (line 1) | function Clock({ template }) {
FILE: 1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/clock.js
class Clock (line 1) | class Clock {
method constructor (line 2) | constructor({ template }) {
method render (line 6) | render() {
method stop (line 26) | stop() {
method start (line 30) | start() {
FILE: 1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js
class ExtendedClock (line 1) | class ExtendedClock extends Clock {
method constructor (line 2) | constructor(options) {
method start (line 8) | start() {
FILE: 1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/clock.js
class Clock (line 1) | class Clock {
method constructor (line 2) | constructor({ template }) {
method render (line 6) | render() {
method stop (line 26) | stop() {
method start (line 30) | start() {
FILE: 1-js/11-async/01-callbacks/one.js
function one (line 1) | function one() {
FILE: 1-js/11-async/03-promise-chaining/getMessage.js
function getMessage (line 1) | function getMessage() {
FILE: 1-js/11-async/03-promise-chaining/one.js
function one (line 1) | function one() {
FILE: 1-js/11-async/03-promise-chaining/three.js
function three (line 1) | function three() {
FILE: 1-js/11-async/03-promise-chaining/two.js
function two (line 1) | function two() {
FILE: 1-js/11-async/04-promise-error-handling/getMessage.js
function getMessage (line 1) | function getMessage() {
FILE: 1-js/11-async/04-promise-error-handling/one.js
function one (line 1) | function one() {
FILE: 1-js/11-async/04-promise-error-handling/three.js
function three (line 1) | function three() {
FILE: 1-js/11-async/04-promise-error-handling/two.js
function two (line 1) | function two() {
FILE: 1-js/11-async/05-promise-api/one.js
function one (line 1) | function one() {
FILE: 1-js/11-async/05-promise-api/two.js
function two (line 1) | function two() {
FILE: 1-js/13-modules/01-modules-intro/say.view/say.js
function sayHi (line 1) | function sayHi(user) {
FILE: 1-js/13-modules/03-modules-dynamic-imports/say.view/say.js
function hi (line 1) | function hi() {
function bye (line 5) | function bye() {
FILE: 2-ui/2-events/02-bubbling-and-capturing/both.view/script.js
function highlightThis (line 8) | function highlightThis() {
FILE: 2-ui/2-events/02-bubbling-and-capturing/capture.view/script.js
function highlightThis (line 7) | function highlightThis() {
FILE: 2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/2-hoverintent/solution.view/hoverIntent.js
class HoverIntent (line 3) | class HoverIntent {
method constructor (line 5) | constructor({
method onMouseOver (line 32) | onMouseOver(event) {
method onMouseOut (line 54) | onMouseOut(event) {
method onMouseMove (line 68) | onMouseMove(event) {
method trackSpeed (line 74) | trackSpeed() {
method destroy (line 100) | destroy() {
FILE: 2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/2-hoverintent/solution.view/test.js
function mouse (line 5) | function mouse(eventType, x, y, options) {
FILE: 2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/2-hoverintent/source.view/hoverIntent.js
class HoverIntent (line 5) | class HoverIntent {
method constructor (line 7) | constructor({
method onMouseOver (line 33) | onMouseOver(event) {
method onMouseOut (line 37) | onMouseOut(event) {
method onMouseMove (line 41) | onMouseMove(event) {
method destroy (line 46) | destroy() {
FILE: 2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/2-hoverintent/source.view/test.js
function mouse (line 5) | function mouse(eventType, x, y, options) {
FILE: 2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseenter-mouseleave-delegation-2.view/script.js
function onEnter (line 48) | function onEnter(elem) {
function onLeave (line 56) | function onLeave(elem) {
FILE: 2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseleave-table.view/script.js
function log (line 3) | function log(event) {
FILE: 2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseleave.view/script.js
function mouselog (line 1) | function mouselog(event) {
FILE: 2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseoverout-child.view/script.js
function mouselog (line 1) | function mouselog(event) {
FILE: 2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseoverout-fast.view/script.js
function handler (line 4) | function handler(event) {
function clearText (line 13) | function clearText() {
function log (line 22) | function log(message) {
FILE: 2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseoverout.view/script.js
function handler (line 3) | function handler(event) {
FILE: 2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/soccer.js
function onMouseUp (line 19) | function onMouseUp(event) {
function onMouseMove (line 23) | function onMouseMove(event) {
function startDrag (line 30) | function startDrag(element, clientX, clientY) {
function finishDrag (line 49) | function finishDrag() {
function moveAt (line 63) | function moveAt(clientX, clientY) {
FILE: 2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/script.js
function handle (line 5) | function handle(e) {
FILE: 2-ui/4-forms-controls/2-focus-blur/4-edit-td-click/solution.view/script.js
function makeTdEditable (line 24) | function makeTdEditable(td) {
function finishTdEdit (line 47) | function finishTdEdit(td, isOk) {
FILE: 4-binary/01-arraybuffer-binary-arrays/01-concat/_js.view/solution.js
function concat (line 1) | function concat(arrays) {
FILE: 4-binary/01-arraybuffer-binary-arrays/01-concat/_js.view/source.js
function concat (line 1) | function concat(arrays) {
FILE: 5-network/01-fetch/01-fetch-users/_js.view/solution.js
function getUsers (line 2) | async function getUsers(names) {
FILE: 5-network/01-fetch/01-fetch-users/_js.view/source.js
function getUsers (line 2) | async function getUsers(names) {
FILE: 5-network/02-formdata/post.view/server.js
method onFile (line 20) | onFile(fieldname, file, filename, encoding, mimetype) {
method onFile (line 46) | onFile(fieldname, file, filename, encoding, mimetype) {
FILE: 5-network/06-fetch-api/post.view/server.js
function accept (line 10) | function accept(req, res) {
FILE: 5-network/08-xmlhttprequest/example.view/server.js
function accept (line 7) | function accept(req, res) {
FILE: 5-network/08-xmlhttprequest/phones-async.view/server.js
function accept (line 10) | function accept(req, res) {
FILE: 5-network/08-xmlhttprequest/phones.view/server.js
function accept (line 10) | function accept(req, res) {
FILE: 5-network/08-xmlhttprequest/post.view/server.js
function accept (line 10) | function accept(req, res) {
FILE: 5-network/09-resume-upload/upload-resume.view/server.js
function onUpload (line 10) | function onUpload(req, res) {
function onStatus (line 90) | function onStatus(req, res) {
function accept (line 102) | function accept(req, res) {
FILE: 5-network/09-resume-upload/upload-resume.view/uploader.js
class Uploader (line 1) | class Uploader {
method constructor (line 3) | constructor({file, onProgress}) {
method getUploadedBytes (line 12) | async getUploadedBytes() {
method upload (line 28) | async upload() {
method stop (line 69) | stop() {
FILE: 5-network/10-long-polling/longpoll.view/browser.js
function PublishForm (line 2) | function PublishForm(form, url) {
function SubscribePane (line 22) | function SubscribePane(elem, url) {
FILE: 5-network/10-long-polling/longpoll.view/server.js
function onSubscribe (line 10) | function onSubscribe(req, res) {
function publish (line 24) | function publish(message) {
function accept (line 34) | function accept(req, res) {
function close (line 63) | function close() {
FILE: 5-network/11-websocket/chat.view/server.js
function accept (line 17) | function accept(req, res) {
function onSocketConnect (line 32) | function onSocketConnect(ws) {
FILE: 5-network/11-websocket/demo.view/server.js
function accept (line 6) | function accept(req, res) {
function onConnect (line 22) | function onConnect(ws) {
FILE: 5-network/12-server-sent-events/eventsource.view/server.js
function onDigits (line 7) | function onDigits(req, res) {
function accept (line 33) | function accept(req, res) {
FILE: 6-data-storage/01-cookie/cookie.js
function getCookie (line 1) | function getCookie(name) {
function setCookie (line 8) | function setCookie(name, value, options = {}) {
function deleteCookie (line 34) | function deleteCookie(name) {
FILE: 7-animation/3-js-animation/width.view/animate.js
function animate (line 1) | function animate({duration, draw, timing}) {
FILE: 8-web-components/2-custom-elements/1-live-timer/solution.view/live-timer.js
class LiveTimer (line 1) | class LiveTimer extends HTMLElement {
method render (line 3) | render() {
method connectedCallback (line 12) | connectedCallback() { // (2)
method update (line 20) | update() {
method disconnectedCallback (line 26) | disconnectedCallback() {
FILE: 8-web-components/2-custom-elements/1-live-timer/solution.view/time-formatted.js
class TimeFormatted (line 1) | class TimeFormatted extends HTMLElement {
method render (line 3) | render() {
method connectedCallback (line 17) | connectedCallback() {
method observedAttributes (line 24) | static get observedAttributes() {
method attributeChangedCallback (line 28) | attributeChangedCallback(name, oldValue, newValue) {
FILE: 8-web-components/2-custom-elements/1-live-timer/source.view/live-timer.js
class LiveTimer (line 1) | class LiveTimer extends HTMLElement {
FILE: 8-web-components/2-custom-elements/1-live-timer/source.view/time-formatted.js
class TimeFormatted (line 1) | class TimeFormatted extends HTMLElement {
method render (line 3) | render() {
method connectedCallback (line 17) | connectedCallback() {
method observedAttributes (line 24) | static get observedAttributes() {
method attributeChangedCallback (line 28) | attributeChangedCallback(name, oldValue, newValue) {
Condensed preview — 1160 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (4,493K chars).
[
{
"path": ".gitattributes",
"chars": 38,
"preview": "* text=auto eol=lf\n*.svg binary\n"
},
{
"path": ".gitignore",
"chars": 175,
"preview": "*.diff\n*.err\n*.orig\n*.log\n*.rej\n*.swo\n*.swp\n*.vi\n*~\n*.sass-cache\n\n# OS or Editor folders\n.DS_Store\n.idea\n.cache\n.project"
},
{
"path": "1-js/01-getting-started/1-intro/article.md",
"chars": 9000,
"preview": "# Pengenalan JavaScript\n\nMari kita lihat apa yang spesial dari JavaScript, apa saja yang bisa kita buat menggunakan Java"
},
{
"path": "1-js/01-getting-started/2-manuals-specifications/article.md",
"chars": 2557,
"preview": "# Manual dan spesifikasi\n\nBuku ini adalah _tutorial_. Tujuannya membantu kamu memahami bahasa ini (Javascript) pelan-pel"
},
{
"path": "1-js/01-getting-started/3-code-editors/article.md",
"chars": 3014,
"preview": "# Editor kode\n\nEditor kode adalah tempat programmer menghabiskan usianya.\n\nAda dua tipe utama editor kode: IDE dan edito"
},
{
"path": "1-js/01-getting-started/4-devtools/article.md",
"chars": 3426,
"preview": "# Konsol pengembang\n\nYang namanya kode selalu rentan error. Mudah sekali bagimu bikin error... Benar kan? Kamu *tidak ak"
},
{
"path": "1-js/01-getting-started/4-devtools/bug.html",
"chars": 172,
"preview": "<!DOCTYPE HTML>\n<html>\n\n<head>\n <meta charset=\"utf-8\">\n</head>\n\n<body>\n\n There is an error in the script on this page."
},
{
"path": "1-js/01-getting-started/index.md",
"chars": 71,
"preview": "# Pengenalan\n\nTentang bahasa JavaScript dan lingkungan pengembangannya."
},
{
"path": "1-js/02-first-steps/01-hello-world/1-hello-alert/index.html",
"chars": 105,
"preview": "<!DOCTYPE html>\n<html>\n\n<body>\n\n <script>\n alert( \"I'm JavaScript!\" );\n </script>\n\n</body>\n\n</html>\n"
},
{
"path": "1-js/02-first-steps/01-hello-world/1-hello-alert/solution.md",
"chars": 27,
"preview": "\r\n[html src=\"index.html\"]\r\n"
},
{
"path": "1-js/02-first-steps/01-hello-world/1-hello-alert/solution.view/index.html",
"chars": 104,
"preview": "<!DOCTYPE html>\n<html>\n\n<body>\n\n <script>\n alert( \"I'm JavaScript!\" );\n </script>\n\n</body>\n\n</html>"
},
{
"path": "1-js/02-first-steps/01-hello-world/1-hello-alert/task.md",
"chars": 205,
"preview": "nilai penting: 5\n\n---\n\n# Tampilkan alert\n\nBuat laman yang menampilkan pesan \"I'm JavaScript!\".\n\nLakukan dalam sandbox, a"
},
{
"path": "1-js/02-first-steps/01-hello-world/2-hello-alert-ext/alert.js",
"chars": 25,
"preview": "alert(\"I'm JavaScript!\");"
},
{
"path": "1-js/02-first-steps/01-hello-world/2-hello-alert-ext/index.html",
"chars": 84,
"preview": "<!DOCTYPE html>\n<html>\n\n<body>\n\n <script src=\"alert.js\"></script>\n\n</body>\n\n</html>"
},
{
"path": "1-js/02-first-steps/01-hello-world/2-hello-alert-ext/solution.md",
"chars": 108,
"preview": "Kode HTML:\n\n[html src=\"index.html\"]\n\nUntuk file `alert.js` di dalam folder yang sama:\n\n[js src=\"alert.js\"]\n\n"
},
{
"path": "1-js/02-first-steps/01-hello-world/2-hello-alert-ext/task.md",
"chars": 283,
"preview": "nilai penting: 5\n\n---\n\n# Tampilkan alert dengan script external\n\nAmbil solusi dari tugas sebelumnya <info:task/hello-ale"
},
{
"path": "1-js/02-first-steps/01-hello-world/article.md",
"chars": 4910,
"preview": "# Hello, world!\n\nBagian dari tutorial ini ialah tentang inti JavaScript itu sendiri.\n\nTapi kita butuh lingkungan kerja u"
},
{
"path": "1-js/02-first-steps/02-structure/article.md",
"chars": 5467,
"preview": "# Struktur kode\n\nHal pertama yang kita akan pelajari ialah membangun blok kode.\n\n## Pernyataan\n\nPernyataan ialah konsep "
},
{
"path": "1-js/02-first-steps/03-strict-mode/article.md",
"chars": 3762,
"preview": "# The modern mode, \"use strict\"\n\nSelama ini, JavaScript tumbuh tanpa isu kompatibilitas. Fitur baru ditambahkan tanpa me"
},
{
"path": "1-js/02-first-steps/04-variables/1-hello-variables/solution.md",
"chars": 218,
"preview": "Dalam kode di bawah, tiap baris berkorespondensi ke item di dalam daftar tugas.\n\n```js run\nlet admin, name; // bisa mend"
},
{
"path": "1-js/02-first-steps/04-variables/1-hello-variables/task.md",
"chars": 247,
"preview": "nilai penting: 2\n\n---\n\n# Bekerja dengan variabel\n\n1. Deklarasikan dua variabel: `admin` and `name`.\n2. Assign nilai `\"Jo"
},
{
"path": "1-js/02-first-steps/04-variables/2-declare-variables/solution.md",
"chars": 667,
"preview": "## Variabel untuk planet kita\n\nItu simpel:\n\n```js\nlet ourPlanetName = \"Earth\";\n```\n\nIngat, kita bisa menggunakan nama le"
},
{
"path": "1-js/02-first-steps/04-variables/2-declare-variables/task.md",
"chars": 224,
"preview": "nilai penting: 3\n\n---\n\n# Memberikan nama yang tepat\n\n1. Buat variabel dengan nama planet kita. Bagaimana kamu akan menam"
},
{
"path": "1-js/02-first-steps/04-variables/3-uppercast-constant/solution.md",
"chars": 595,
"preview": "Kita umumnya menggunakan case yang layak untuk konstan yang \"dihard-code\". Atau, dengan kata lain, ketika nilainya dike"
},
{
"path": "1-js/02-first-steps/04-variables/3-uppercast-constant/task.md",
"chars": 552,
"preview": "nilai penting: 4\n\n---\n\n# Const huruf kapital?\n\nCek kode berikut:\n\n```js\nconst birthday = '18.04.1982';\n\nconst age = some"
},
{
"path": "1-js/02-first-steps/04-variables/article.md",
"chars": 12608,
"preview": "# Variabel\n\nSeringnya, aplikasi JavaScript butuh kerja dengan informasi. Di sini ada dua contoh:\n1. Toko online -- infor"
},
{
"path": "1-js/02-first-steps/05-types/1-string-quotes/solution.md",
"chars": 316,
"preview": "\nBacktick mengembed expresi di dalam `${...}` ke dalam string.\n\n```js run\nlet name = \"Ilya\";\n\n// expresinya ialah angka "
},
{
"path": "1-js/02-first-steps/05-types/1-string-quotes/task.md",
"chars": 191,
"preview": "nilai penting: 5\n\n---\n\n# Petik string\n\nApa output dari script ini?\n\n```js\nlet name = \"Ilya\";\n\nalert( `hello ${1}` ); // "
},
{
"path": "1-js/02-first-steps/05-types/article.md",
"chars": 10554,
"preview": "# Tipe data\n\nDalam Javascript terdapat beberapa tipe data yang dapat digunakan, sebuah *string* atau sebuah *number*\n\nTe"
},
{
"path": "1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/solution.md",
"chars": 280,
"preview": "Kode JavaScript:\n\n```js demo run\nlet name = prompt(\"Siapakah nama Anda?\", \"\");\nalert(name);\n```\n\nLaman penuh:\n\n```html\n<"
},
{
"path": "1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/task.md",
"chars": 100,
"preview": "nilai penting: 4\n\n---\n\n# Laman simpel\n\nBuat laman web yang meminta nama dan menampilkannya.\n\n[demo]\n"
},
{
"path": "1-js/02-first-steps/06-alert-prompt-confirm/article.md",
"chars": 3419,
"preview": "# Interaksi: alert, prompt, confirm\n\nsebagaimana kita akan menggunakan peramban sebagai lingkungan percobaan kode, ayo k"
},
{
"path": "1-js/02-first-steps/07-type-conversions/article.md",
"chars": 4809,
"preview": "# Konversi Tipe\n\nSeringkali, operator dan fungsi otomatis mengkonversi nilai yang diberikan ke mereka ke tipe yang sesua"
},
{
"path": "1-js/02-first-steps/08-operators/1-increment-order/solution.md",
"chars": 301,
"preview": "\nJawabannya adalah:\n\n- `a = 2`\n- `b = 2`\n- `c = 2`\n- `d = 1`\n\n```js run no-beautify\nlet a = 1, b = 1;\n\nalert( ++a ); // "
},
{
"path": "1-js/02-first-steps/08-operators/1-increment-order/task.md",
"chars": 201,
"preview": "nilai penting: 5\n\n---\n\n# Bentuk postfix dan prefix\n\nBerapa nilai final dari semua variabel `a`, `b`, `c` dan `d` setelah"
},
{
"path": "1-js/02-first-steps/08-operators/2-assignment-result/solution.md",
"chars": 80,
"preview": "Jawabannya adalah:\n\n- `a = 4` (dikali 2)\n- `x = 5` (dikalkulasi sebagai 1 + 4)\n\n"
},
{
"path": "1-js/02-first-steps/08-operators/2-assignment-result/task.md",
"chars": 139,
"preview": "nilai penting: 3\n\n---\n\n# Hasil penetapan\n\nBerapa nilai dari `a` dan `x` setelah kode berikut?\n\n```js\nlet a = 2;\n\nlet x ="
},
{
"path": "1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md",
"chars": 1114,
"preview": "\n```js no-beautify\n\"\" + 1 + 0 = \"10\" // (1)\n\"\" - 1 + 0 = -1 // (2)\ntrue + false = 1\n6 / \"3\" = 2\n\"2\" * \"3\" = 6\n4 + 5 + \"p"
},
{
"path": "1-js/02-first-steps/08-operators/3-primitive-conversions-questions/task.md",
"chars": 309,
"preview": "nilai penting: 5\n\n---\n\n# Konversi tipe\n\nApa hasil dari expresi ini?\n\n```js no-beautify\n\"\" + 1 + 0\n\"\" - 1 + 0\ntrue + fals"
},
{
"path": "1-js/02-first-steps/08-operators/4-fix-prompt/solution.md",
"chars": 759,
"preview": "Alasannya adalah karena kotak *prompt* mengembalikan inputan dari user sebagai string.\n\nJadi nilai dari masing-masing va"
},
{
"path": "1-js/02-first-steps/08-operators/4-fix-prompt/task.md",
"chars": 434,
"preview": "nilai penting: 5\n\n---\n\n# Benarkan penambahan\n\nIni adalah kode yang menanyakan pengguna untuk memasukan dua angka dan men"
},
{
"path": "1-js/02-first-steps/08-operators/article.md",
"chars": 16259,
"preview": "# Operator dasar, maths\n\nKita tahu banyak operator dari sekolah. Mereka adalah penambahan `+`, perkalian `*`, penguranga"
},
{
"path": "1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md",
"chars": 622,
"preview": "\n\n```js no-beautify\n5 > 4 → true\n\"apple\" > \"pineapple\" → false\n\"2\" > \"12\" → true\nundefined == null → true\nundefined === "
},
{
"path": "1-js/02-first-steps/09-comparison/1-comparison-questions/task.md",
"chars": 201,
"preview": "nilai penting: 5\n\n---\n\n# Pembandingan\n\nApa hasil dari expresi ini?\n\n```js no-beautify\n5 > 4\n\"apple\" > \"pineapple\"\n\"2\" > "
},
{
"path": "1-js/02-first-steps/09-comparison/article.md",
"chars": 8435,
"preview": "# Perbandingan\n\nKita tahu beberapa operator pembanding dari matematika.\n\nDidalam Javascript operator-operator itu dituli"
},
{
"path": "1-js/02-first-steps/10-ifelse/1-if-zero-string/solution.md",
"chars": 241,
"preview": "**Ya, tentu saja.**\n\nSetiap string kecuali yang kosong (ingat bahwa `\" 0 \"` tidak kosong) menjadi `true` dalam konteks l"
},
{
"path": "1-js/02-first-steps/10-ifelse/1-if-zero-string/task.md",
"chars": 131,
"preview": "Nilai penting: 5\n\n---\n\n# if (string berisi angka nol)\n\nApakah `alert` akan dieksekusi?\n\n```js\nif (\"0\") {\n alert( 'Hello"
},
{
"path": "1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2/index.html",
"chars": 291,
"preview": "<!DOCTYPE html>\n<html>\n\n<body>\n <script>\n 'use strict';\n\n let value = prompt('Apakah nama \"official\" dari Javascr"
},
{
"path": "1-js/02-first-steps/10-ifelse/2-check-standard/solution.md",
"chars": 43,
"preview": "\n\n[html run src=\"ifelse_task2/index.html\"]\n"
},
{
"path": "1-js/02-first-steps/10-ifelse/2-check-standard/task.md",
"chars": 327,
"preview": "Nilai penting: 2\n\n---\n\n# Nama JavaScript\n\nDengan menggunakan konstruksi `if..else`, tulis kode yang menanyakan: 'Apa nam"
},
{
"path": "1-js/02-first-steps/10-ifelse/3-sign/if_sign/index.html",
"chars": 262,
"preview": "<!DOCTYPE html>\n<html>\n\n<body>\n\n <script>\n 'use strict';\n\n let value = prompt('Tuliskan sebuah angka', 0);\n\n i"
},
{
"path": "1-js/02-first-steps/10-ifelse/3-sign/solution.md",
"chars": 159,
"preview": "\n\n```js run\nlet value = prompt('Masukan sebuah angka', 0);\n\nif (value > 0) {\n alert( 1 );\n} else if (value < 0) {\n ale"
},
{
"path": "1-js/02-first-steps/10-ifelse/3-sign/task.md",
"chars": 381,
"preview": "Nilai penting: 2\n\n---\n\n# Tunjukkan tandanya\n\nDengan menggunakan `if..else`, tulis kode yang mendapatkan nomor melalui` p"
},
{
"path": "1-js/02-first-steps/10-ifelse/5-rewrite-if-question/solution.md",
"chars": 59,
"preview": "\n\n```js\nlet result = (a + b < 4) ? 'Kurang' : 'Lebih';\n```\n"
},
{
"path": "1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md",
"chars": 209,
"preview": "Nilai penting: 5\n\n---\n\n# Tulis ulang 'if' menggunakan '?'\n\nTulis ulang `if` menggunakan operator kondisional `'?'`:\n\n```"
},
{
"path": "1-js/02-first-steps/10-ifelse/6-rewrite-if-else-question/solution.md",
"chars": 143,
"preview": "\n\n```js\nlet message = (login == 'Karyawan') ? 'Hallo' :\n (login == 'Direksi') ? 'Salam Hangat!' :\n (login == '') ? 'Be"
},
{
"path": "1-js/02-first-steps/10-ifelse/6-rewrite-if-else-question/task.md",
"chars": 419,
"preview": "Nilai penting: 5\n\n---\n\n# Tulis ulang 'if..else' menjadi '?'\n\nTulis ulang `if..else` menggunakan beberapa operator ternar"
},
{
"path": "1-js/02-first-steps/10-ifelse/article.md",
"chars": 7848,
"preview": "# Kondisi bercabang: if, '?'\n\nTerkadang, kita perlu melakukan tindakan berbeda berdasarkan kondisi yang berbeda.\n\nUntuk "
},
{
"path": "1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/solution.md",
"chars": 91,
"preview": "Jawabannya `2`, itu nilai truthy pertama.\n\n```js run\nalert( null || 2 || undefined );\n```\n\n"
},
{
"path": "1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/task.md",
"chars": 125,
"preview": "nilai penting: 5\n\n---\n\n# Apa hasil dari OR?\n\nApakah keluaran dari kode dibawah?\n\n```js\nalert( null || 2 || undefined );\n"
},
{
"path": "1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md",
"chars": 546,
"preview": "Jawabannya: pertama `1`, lalu `2`.\n\n```js run\nalert( alert(1) || 2 || alert(3) );\n```\n\nPanggilan `alert` tak mengembalik"
},
{
"path": "1-js/02-first-steps/11-logical-operators/2-alert-or/task.md",
"chars": 136,
"preview": "niai penting: 3\n\n---\n\n# Apa hasil dari alert yang di-OR-kan?\n\nApa output kode di bawah?\n\n```js\nalert( alert(1) || 2 || a"
},
{
"path": "1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md",
"chars": 122,
"preview": "Jawabannya: `null`, karena `null` adalah nilai falsy pertama yang ada di daftar.\n\n```js run\nalert( 1 && null && 2 );\n```"
},
{
"path": "1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/task.md",
"chars": 109,
"preview": "nilai penting: 5\n\n---\n\n# Apa hasil AND?\n\nKode ini akan menampilkan apa?\n\n```js\nalert( 1 && null && 2 );\n```\n\n"
},
{
"path": "1-js/02-first-steps/11-logical-operators/4-alert-and/solution.md",
"chars": 384,
"preview": "Jawabannya: `1`, dan kemudian `undefined`.\n\n```js run\nalert( alert(1) && alert(2) );\n```\n\nPanggilan `alert` mengembalika"
},
{
"path": "1-js/02-first-steps/11-logical-operators/4-alert-and/task.md",
"chars": 138,
"preview": "nilai penting: 3\n\n---\n\n# Apa hasil dari alert yang di-AND-kan?\n\nKode ini akan menampilkan apa?\n\n```js\nalert( alert(1) &&"
},
{
"path": "1-js/02-first-steps/11-logical-operators/5-alert-and-or/solution.md",
"chars": 257,
"preview": "Jawabannya: `3`.\n\n```js run\nalert( null || 2 && 3 || 4 );\n```\n\nPresedensi AND `&&` lebih tinggi dari `||`, jadi ia jalan"
},
{
"path": "1-js/02-first-steps/11-logical-operators/5-alert-and-or/task.md",
"chars": 113,
"preview": "nilai penting: 5\n\n---\n\n# Hasil dari OR AND OR\n\nHasilnya akan jadi apa?\n\n```js\nalert( null || 2 && 3 || 4 );\n```\n\n"
},
{
"path": "1-js/02-first-steps/11-logical-operators/6-check-if-in-range/solution.md",
"chars": 41,
"preview": "\n\n```js\nif (age >= 14 && age <= 90)\n```\n\n"
},
{
"path": "1-js/02-first-steps/11-logical-operators/6-check-if-in-range/task.md",
"chars": 210,
"preview": "nilai penting: 3\n\n---\n\n# Cek kisaran antara\n\nTulis satu kondisi \"if\" untuk mengecek bahwa `age` ada di antara `14` dan `"
},
{
"path": "1-js/02-first-steps/11-logical-operators/7-check-if-out-range/solution.md",
"chars": 111,
"preview": "Varian pertama:\n\n```js\nif (!(age >= 14 && age <= 90))\n```\n\nVarian kedua:\n\n```js\nif (age < 14 || age > 90)\n```\n\n"
},
{
"path": "1-js/02-first-steps/11-logical-operators/7-check-if-out-range/task.md",
"chars": 204,
"preview": "nilai penting: 3\n\n---\n\n# Cek kisaran luar\n\nTulis satu kondisi `if` untuk mengecek bahwa `age` BUKAN di antara 14 dan 90 "
},
{
"path": "1-js/02-first-steps/11-logical-operators/8-if-question/solution.md",
"chars": 436,
"preview": "Jawabannya: pertama dan ketiga akan diexekusi.\n\nDetil:\n\n```js run\n// Berjalan.\n// Hasil dari -1 || 0 = -1, truthy\nif (-1"
},
{
"path": "1-js/02-first-steps/11-logical-operators/8-if-question/task.md",
"chars": 271,
"preview": "nilai penting: 5\n\n---\n\n# Pertanyaan tentang \"if\"\n\nMana dari `alert` berikut yang akan diexekusi?\n\nHasil expresinya akan "
},
{
"path": "1-js/02-first-steps/11-logical-operators/9-check-login/solution.md",
"chars": 543,
"preview": "\n\n```js run demo\nlet userName = prompt(\"Who's there?\", '');\n\nif (userName === 'Admin') {\n\n let pass = prompt('Password?"
},
{
"path": "1-js/02-first-steps/11-logical-operators/9-check-login/task.md",
"chars": 737,
"preview": "nilai penting: 3\n\n---\n\n# Cek login\n\nTulis kode yang meminta login dengan `prompt`.\n\nJika pengunjung menekan `\"Admin\"`, m"
},
{
"path": "1-js/02-first-steps/11-logical-operators/article.md",
"chars": 8109,
"preview": "# Operator logika\n\nAda tiga operator logika di JavaScript: `||` (OR), `&&` (AND), `!` (NOT).\n\nMeski mereka dipanggil \"lo"
},
{
"path": "1-js/02-first-steps/12-nullish-coalescing-operator/article.md",
"chars": 6546,
"preview": "# Operator penggabungan nullish '??'\n\n[browser terbaru=\"baru\"]\n\nOperator penggabungan nullish ditulis sebagai dua tanda "
},
{
"path": "1-js/02-first-steps/13-while-for/1-loop-last-value/solution.md",
"chars": 521,
"preview": "Jawabannya: `1`.\n\n```js run\nlet i = 3;\n\nwhile (i) {\n alert( i-- );\n}\n```\n\nSetiap pengulangan mengurangi `i` dengan `1`"
},
{
"path": "1-js/02-first-steps/13-while-for/1-loop-last-value/task.md",
"chars": 164,
"preview": "importance: 3\n\n---\n\n# Nilai terakhir perulangan\n\nApa nilai terakhir yang diperingatkan oleh kode ini? Mengapa?\n\n```js\nle"
},
{
"path": "1-js/02-first-steps/13-while-for/2-which-value-while/solution.md",
"chars": 1601,
"preview": "Tugas mendemonstrasikan bagaimana bentuk postfix/prefix dapat menyebabkan hasil yang berbeda ketika digunakan dalam perb"
},
{
"path": "1-js/02-first-steps/13-while-for/2-which-value-while/task.md",
"chars": 394,
"preview": "importance: 4\n\n---\n\n# Nilai mana yang ditampilkan perulangan while?\n\nUntuk setiap iterasi, tulis nilai mana yang dikelua"
},
{
"path": "1-js/02-first-steps/13-while-for/3-which-value-for/solution.md",
"chars": 546,
"preview": "**Jawabanya: dari `0` ke `4` pada kedua kasus.**\n\n```js run\nfor (let i = 0; i < 5; ++i) alert( i );\n\nfor (let i = 0; i <"
},
{
"path": "1-js/02-first-steps/13-while-for/3-which-value-for/task.md",
"chars": 390,
"preview": "importance: 4\n\n---\n\n# Nilai mana yang ditampilkan oleh perulangan \"for\" ?\n\nUntuk setiap perulangan tulis nilai mana yang"
},
{
"path": "1-js/02-first-steps/13-while-for/4-for-even/solution.md",
"chars": 201,
"preview": "\n\n```js run demo\nfor (let i = 2; i <= 10; i++) {\n if (i % 2 == 0) {\n alert( i );\n }\n}\n```\n\nKita menggunakan operato"
},
{
"path": "1-js/02-first-steps/13-while-for/4-for-even/task.md",
"chars": 147,
"preview": "importance: 5\n\n---\n\n# Menghasilkan angka genap di perulangan\n\nGunakan perulangan `for` untuk menghasilkan angka genap da"
},
{
"path": "1-js/02-first-steps/13-while-for/5-replace-for-while/solution.md",
"chars": 80,
"preview": "\n\n```js run\nlet i = 0;\nwhile (i < 3) {\n alert( `number ${i}!` );\n i++;\n}\n```\n\n"
},
{
"path": "1-js/02-first-steps/13-while-for/5-replace-for-while/task.md",
"chars": 231,
"preview": "importance: 5\n\n---\n\n# Ganti \"for\" dengan \"while\"\n\nTulis ulang kode ubah perulangan `for` ke `while` tanpa mengubah peril"
},
{
"path": "1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md",
"chars": 611,
"preview": "\n```js run demo\nlet num;\n\ndo {\n num = prompt(\"Masukan angka lebih dari 100?\", 0);\n} while (num <= 100 && num);\n```\n\nPer"
},
{
"path": "1-js/02-first-steps/13-while-for/6-repeat-until-correct/task.md",
"chars": 504,
"preview": "importance: 5\n\n---\n\n# Ulangi sampai inputnya benar\n\nTulis sebuah perulangan yang meminta angka lebih dari `100`. Jika pe"
},
{
"path": "1-js/02-first-steps/13-while-for/7-list-primes/solution.md",
"chars": 947,
"preview": "Ada banyak algoritma untuk tugas ini.\n\nMari gunakan perulangan bersarang:\n\n```js\nFor each i in the interval {\n cek if i"
},
{
"path": "1-js/02-first-steps/13-while-for/7-list-primes/task.md",
"chars": 647,
"preview": "importance: 3\n\n---\n\n# Menghasilkan bilangan prima\n\nAngka integer lebih dari `1` disebut [bilangan prima](https://en.wiki"
},
{
"path": "1-js/02-first-steps/13-while-for/article.md",
"chars": 11756,
"preview": "# Perulangan: while dan for\n\nKita sering perlu untuk mengulangi tindakan.\n\nContohnya, Mengeluarkan barang dari sebuah da"
},
{
"path": "1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/solution.md",
"chars": 657,
"preview": "Supaya fungsionalitas `switch` persis sama, `if` harus memakai pembandingan ketat `'==='`.\n\nTapi untuk string yang diber"
},
{
"path": "1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/task.md",
"chars": 431,
"preview": "nilai penting: 5\n\n---\n\n# Tulis kembali \"switch\" menjadi \"if\"\n\nTulis kode menggunakan `if..else` yang akan berkorespon de"
},
{
"path": "1-js/02-first-steps/14-switch/2-rewrite-if-switch/solution.md",
"chars": 574,
"preview": "Dua cek pertama berubah ke `case`. Cek ketiga dipecah menjadi dua case:\n\n```js run\nlet a = +prompt('a?', '');\n\nswitch (a"
},
{
"path": "1-js/02-first-steps/14-switch/2-rewrite-if-switch/task.md",
"chars": 278,
"preview": "nilai penting: 4\n\n---\n\n# Tulis kembali \"if\" ke dalam \"switch\"\n\nTulis ulang kode berikut menggunakan pernyataan `switch` "
},
{
"path": "1-js/02-first-steps/14-switch/article.md",
"chars": 3700,
"preview": "# Pernyataan \"switch\"\n\nPernyataan `switch` bisa mengganti pengecekan ganda `if`.\n\nIa memberi cara lebih deskriptif untuk"
},
{
"path": "1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md",
"chars": 20,
"preview": "Tidak ada perbedaan."
},
{
"path": "1-js/02-first-steps/15-function-basics/1-if-else-required/task.md",
"chars": 631,
"preview": "nilai penting: 4\n\n---\n\n# Apakah \"else\" dibutuhkan ?\n\nFungsi berikut mengembalikan nilai `true` jika parameter `age` lebi"
},
{
"path": "1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/solution.md",
"chars": 437,
"preview": "Menggunakan tanda tanya operator `'?'`:\n\n```js\nfunction checkAge(age) {\n return (age > 18) ? true : confirm('Did parent"
},
{
"path": "1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/task.md",
"chars": 572,
"preview": "nilai penting: 4\n\n---\n\n# Tulis ulang fungsi menggunakan '?' atau '||'\n\nFungsi berikut mengembalikan nilai `true` jika pa"
},
{
"path": "1-js/02-first-steps/15-function-basics/3-min/solution.md",
"chars": 302,
"preview": "Solusi menggunakan `if`:\n\n```js\nfunction min(a, b) {\n if (a < b) {\n return a;\n } else {\n return b;\n }\n}\n```\n\nSo"
},
{
"path": "1-js/02-first-steps/15-function-basics/3-min/task.md",
"chars": 220,
"preview": "nilai penting: 1\n\n---\n\n# Fungsi min(a,b)\n\nTulis sebuah fungsi `min(a,b)` yang mengembalikan nilai paling terkecil dari d"
},
{
"path": "1-js/02-first-steps/15-function-basics/4-pow/solution.md",
"chars": 305,
"preview": "\n```js menjalankan demo\nfunction pow(x, n) {\n let result = x;\n\n for (let i = 1; i < n; i++) {\n result *= x;\n }\n\n "
},
{
"path": "1-js/02-first-steps/15-function-basics/4-pow/task.md",
"chars": 559,
"preview": "nilai penting: 4\n\n---\n\n# Fungsi pow(X,n)\n\nTulis sebuah fungsi `pow(x,n)` yang mengembalikkan nilai `x` pada pangkat `n`."
},
{
"path": "1-js/02-first-steps/15-function-basics/article.md",
"chars": 17806,
"preview": "# Fungsi\n\nSering kali, kita harus melakukan tindakan yang sama pada skrip di banyak tempat\n\nSebagai contoh, kita menghar"
},
{
"path": "1-js/02-first-steps/16-function-expressions/article.md",
"chars": 11210,
"preview": "# Expresi fungsi\n\nDi JavaScript, fungsi bukan \"struktur bahasa magis\", melaikan satu bentuk nilai spesial.\n\nSyntax yang "
},
{
"path": "1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/solution.md",
"chars": 242,
"preview": "\n```js run\nfunction ask(question, yes, no) {\n if (confirm(question)) yes();\n else no();\n}\n\nask(\n \"Do you agree?\",\n*!*"
},
{
"path": "1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/task.md",
"chars": 313,
"preview": "\n# Rewrite with arrow functions\n\nGanti Expresi Fungsi dengan fungsi panah dalam kode berikut:\n\n```js run\nfunction ask(qu"
},
{
"path": "1-js/02-first-steps/17-arrow-functions-basics/article.md",
"chars": 3935,
"preview": "# Dasar-dasar fungsi Arrow\n\nTerdapat sintaks lain yang sangat sederhana dan ringkas untuk membuat fungsi-fungsi, bahkan "
},
{
"path": "1-js/02-first-steps/18-javascript-specials/article.md",
"chars": 8307,
"preview": "# Spesial JavaScript\n\nBab ini secara singkat merekap fitur JavaScript yang sudah kita pelajari sekarang, membayar perhat"
},
{
"path": "1-js/02-first-steps/index.md",
"chars": 66,
"preview": "# JavaScript Dasar\n\nMari kita belajar dasar-dasar pembuatan skrip."
},
{
"path": "1-js/03-code-quality/01-debugging-chrome/article.md",
"chars": 10209,
"preview": "# Mendebug di Chrome\n\nSebelum menulis kode lebih komplex, ayo kita bahas tentang mendebug.\n\n[Mendebug](https://en.wikipe"
},
{
"path": "1-js/03-code-quality/01-debugging-chrome/debugging.view/hello.js",
"chars": 129,
"preview": "function hello(name) {\n let phrase = `Hello, ${name}!`;\n\n say(phrase);\n}\n\nfunction say(phrase) {\n alert(`** ${phrase}"
},
{
"path": "1-js/03-code-quality/01-debugging-chrome/debugging.view/index.html",
"chars": 145,
"preview": "<!DOCTYPE HTML>\n<html>\n<body>\n\n <script src=\"hello.js\"></script>\n\n Contoh debugging.\n\n <script>\n hello(\"John\");\n </"
},
{
"path": "1-js/03-code-quality/01-debugging-chrome/head.html",
"chars": 156,
"preview": "<style>\nspan.devtools {\n display: inline-block;\n background-image: url(/article/debugging-chrome/largeIcons.svg);\n he"
},
{
"path": "1-js/03-code-quality/02-coding-style/1-style-errors/solution.md",
"chars": 1304,
"preview": "\nKamu bisa perhatikan berikut:\n\n```js no-beautify\nfunction pow(x,n) // <- tak ada spasi diantara arguments\n{ // <- men"
},
{
"path": "1-js/03-code-quality/02-coding-style/1-style-errors/task.md",
"chars": 377,
"preview": "nilai penting: 4\n\n---\n\n# Gaya jelek\n\nApa yang salah dengan gaya kode di bawah?\n\n```js no-beautify\nfunction pow(x,n)\n{\n "
},
{
"path": "1-js/03-code-quality/02-coding-style/article.md",
"chars": 10446,
"preview": "# Gaya Mengkode\n\nKode kita harus sebisa mungkin bersih dan mudah dibaca.\n\nIni sebenarnya seni pemrograman -- ambil tugas"
},
{
"path": "1-js/03-code-quality/03-comments/article.md",
"chars": 6127,
"preview": "# Komentar\n\nSeperti yang kita tahu dari bab <info:structure>, komentar bisa sebaris tunggal: mulai dari `//` dan baris-g"
},
{
"path": "1-js/03-code-quality/04-ninja-code/article.md",
"chars": 10662,
"preview": "# Kode ninja\n\n\n```quote author=\"Confucius (Analects)\"\nLearning without thought is labor lost; thought without learning i"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/solution.md",
"chars": 1510,
"preview": "Tes ini mendemonstrasikan satu dari godaan yang pengembang temui dan saat menulis tes.\n\nApa yang kita punya di sini sebe"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/task.md",
"chars": 371,
"preview": "nilai penting: 5\n\n---\n\n# Apa yang salah dalam tes ini?\n\nApa yang salah dalam tes `pow` di bawah?\n\n```js\nit(\"Raises x to "
},
{
"path": "1-js/03-code-quality/05-testing-mocha/article.md",
"chars": 15523,
"preview": "# Pengetesan terotomasi dengan Mocha\n\nPengetesan terotomasi akan dipakai di tugas lebih lanjut, dan juga luas dipakai di"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/beforeafter.view/index.html",
"chars": 1023,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <!-- Tambahkan mocha css untuk menampilkan hasil. -->\n <link\n rel=\"styleshee"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/beforeafter.view/test.js",
"chars": 646,
"preview": "describe(\"test\", function() {\n \n // Mocha usually waits for the tests for 2 seconds before considering them wrong\n \n"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/index.html",
"chars": 948,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <!-- add mocha css, to show results -->\n <link rel=\"stylesheet\" href=\"https://cdnjs.clo"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/pow-1.view/index.html",
"chars": 963,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <!-- add mocha css, to show results -->\n <link rel=\"stylesheet\" href=\"https://cdnjs.clo"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/pow-1.view/test.js",
"chars": 115,
"preview": "describe(\"pow\", function() {\n\n it(\"raises to n-th power\", function() {\n assert.equal(pow(2, 3), 8);\n });\n\n});\n"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/pow-2.view/index.html",
"chars": 941,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <!-- add mocha css, to show results -->\n <link rel=\"stylesheet\" href=\"https://cdnjs.clo"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/pow-2.view/test.js",
"chars": 206,
"preview": "describe(\"pow\", function() {\n\n it(\"2 raised to power 3 is 8\", function() {\n assert.equal(pow(2, 3), 8);\n });\n\n it("
},
{
"path": "1-js/03-code-quality/05-testing-mocha/pow-3.view/index.html",
"chars": 1019,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <!-- add mocha css, to show results -->\n <link rel=\"stylesheet\" href=\"https://cdnjs.clo"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/pow-3.view/test.js",
"chars": 256,
"preview": "describe(\"pow\", function() {\n\n function makeTest(x) {\n let expected = x * x * x;\n it(`${x} in the power 3 is ${ex"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/pow-4.view/index.html",
"chars": 1019,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <!-- add mocha css, to show results -->\n <link rel=\"stylesheet\" href=\"https://cdnjs.clo"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/pow-4.view/test.js",
"chars": 399,
"preview": "describe(\"pow\", function() {\n\n describe(\"raises x to power 3\", function() {\n\n function makeTest(x) {\n let expec"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/pow-full.view/index.html",
"chars": 1089,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <!-- add mocha css, to show results -->\n <link rel=\"stylesheet\" href=\"https://cdnjs.clo"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/pow-full.view/test.js",
"chars": 521,
"preview": "describe(\"pow\", function() {\n\n describe(\"raises x to power 3\", function() {\n\n function makeTest(x) {\n let expec"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/pow-min.view/index.html",
"chars": 937,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <!-- add mocha css, to show results -->\n <link rel=\"stylesheet\" href=\"https://cdnjs.clo"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/pow-min.view/test.js",
"chars": 115,
"preview": "describe(\"pow\", function() {\n\n it(\"raises to n-th power\", function() {\n assert.equal(pow(2, 3), 8);\n });\n\n});\n"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/pow-nan.view/index.html",
"chars": 1017,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <!-- add mocha css, to show results -->\n <link rel=\"stylesheet\" href=\"https://cdnjs.clo"
},
{
"path": "1-js/03-code-quality/05-testing-mocha/pow-nan.view/test.js",
"chars": 521,
"preview": "describe(\"pow\", function() {\n\n describe(\"raises x to power 3\", function() {\n\n function makeTest(x) {\n let expec"
},
{
"path": "1-js/03-code-quality/06-polyfills/article.md",
"chars": 5535,
"preview": "# Polyfill dan transpiler\n\nJavaScript secara konsisten terus berevolusi. Proposal-proposal untuk menambah fitur-fitur ba"
},
{
"path": "1-js/03-code-quality/index.md",
"chars": 124,
"preview": "# Kualitas Kode\n\nBab ini menjelaskan tentang *coding practices* yang akan kita selanjutnya gunakan di proses *developmen"
},
{
"path": "1-js/04-object-basics/01-object/2-hello-object/solution.md",
"chars": 110,
"preview": "\n\n```js\nlet user = {};\nuser.name = \"John\";\nuser.surname = \"Smith\";\nuser.name = \"Pete\";\ndelete user.name;\n```\n\n"
},
{
"path": "1-js/04-object-basics/01-object/2-hello-object/task.md",
"chars": 301,
"preview": "nilai penting: 5\n\n---\n\n# Hello, object\n\nTulis kode, satu baris untuk setiap aksi:\n\n1. Buatlah sebuah objek kosong `user`"
},
{
"path": "1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js",
"chars": 148,
"preview": "function isEmpty(obj) {\n for (let key in obj) {\n // jika perulangan dimulai, berarti ada sebuah properti\n return "
},
{
"path": "1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js",
"chars": 251,
"preview": "describe(\"isEmpty\", function() {\n it(\"returns true for an empty object\", function() {\n assert.isTrue(isEmpty({}));\n "
},
{
"path": "1-js/04-object-basics/01-object/3-is-empty/solution.md",
"chars": 92,
"preview": "Lakukanlah perulangan pada objek dan segera `return false` jika ada setidaknya satu properti"
},
{
"path": "1-js/04-object-basics/01-object/3-is-empty/task.md",
"chars": 343,
"preview": "nilai penting: 5\n\n---\n\n# cek kekosongan\n\nTulislah sebuah fungsi `isEmpty(obj)` yang mana akan mengembalikan `true` jika "
},
{
"path": "1-js/04-object-basics/01-object/5-sum-object/solution.md",
"chars": 161,
"preview": "\n```js run\nlet salaries = {\n John: 100,\n Ann: 160,\n Pete: 130\n};\n\nlet sum = 0;\nfor (let key in salaries) {\n sum += s"
},
{
"path": "1-js/04-object-basics/01-object/5-sum-object/task.md",
"chars": 369,
"preview": "nilai penting: 5\n\n---\n\n# Tambahkan properti objek\n\nKita punya sebuah objek untuk menyimpan gaji dari tim kita:\n\n```js\nle"
},
{
"path": "1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/solution.js",
"chars": 128,
"preview": "function multiplyNumeric(obj) {\n for (let key in obj) {\n if (typeof obj[key] == 'number') {\n obj[key] *= 2;\n "
},
{
"path": "1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js",
"chars": 247,
"preview": "let menu = {\n width: 200,\n height: 300,\n title: \"My menu\"\n};\n\n\nfunction multiplyNumeric(obj) {\n \n /* Tulis kodemu d"
},
{
"path": "1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js",
"chars": 439,
"preview": "describe(\"multiplyNumeric\", function() {\n it(\"multiplies all numeric properties by 2\", function() {\n let menu = {\n "
},
{
"path": "1-js/04-object-basics/01-object/8-multiply-numeric/solution.md",
"chars": 0,
"preview": ""
},
{
"path": "1-js/04-object-basics/01-object/8-multiply-numeric/task.md",
"chars": 559,
"preview": "nilai penting: 3\n\n---\n\n# Kalikan properti numerik dengan 2\n\nBuatlah sebuah fungsi `multiplyNumerik(obj)` yang mengkalika"
},
{
"path": "1-js/04-object-basics/01-object/article.md",
"chars": 14607,
"preview": "\n# Objek\n\nSeperti yang kita tahu dari bab <info:types>, ada delapan tipe data di JavaScript. Enak dari mereka disebut \"p"
},
{
"path": "1-js/04-object-basics/02-object-copy/article.md",
"chars": 9443,
"preview": "# Referensi objek dan menyalinnya\n\nSalah satu perbedaan mendasar dari objek versus primitif adalah bahwa objek disimpan "
},
{
"path": "1-js/04-object-basics/03-garbage-collection/article.md",
"chars": 9662,
"preview": "# Pengumpulan sampah (_Garbage collection_)\n\nManajemen memori di JavaScript dilakukan secara otomatis dan tak terlihat o"
},
{
"path": "1-js/04-object-basics/04-object-methods/4-object-property-this/solution.md",
"chars": 1073,
"preview": "**Jawaban: error.**\n\nCoba ini:\n```js run\nfunction makeUser() {\n return {\n name: \"John\",\n ref: this\n };\n}\n\nlet us"
},
{
"path": "1-js/04-object-basics/04-object-methods/4-object-property-this/task.md",
"chars": 335,
"preview": "importance: 5\n\n---\n\n# Menggunakan \"this\" dalam penulisan objek\n\nBerikut ini adalah fungsi `makeUser` yang mengembalikan "
},
{
"path": "1-js/04-object-basics/04-object-methods/7-calculator/_js.view/solution.js",
"chars": 186,
"preview": "let calculator = {\n sum() {\n return this.a + this.b;\n },\n\n mul() {\n return this.a * this.b;\n },\n\n read() {\n "
},
{
"path": "1-js/04-object-basics/04-object-methods/7-calculator/_js.view/test.js",
"chars": 694,
"preview": "\n\ndescribe(\"calculator\", function() {\n \n context(\"when 2 and 3 entered\", function() {\n beforeEach(function() {\n "
},
{
"path": "1-js/04-object-basics/04-object-methods/7-calculator/solution.md",
"chars": 290,
"preview": "\n```js run demo solution\nlet calculator = {\n sum() {\n return this.a + this.b;\n },\n\n mul() {\n return this.a * th"
},
{
"path": "1-js/04-object-basics/04-object-methods/7-calculator/task.md",
"chars": 473,
"preview": "importance: 5\n\n---\n\n# Membuat sebuah kalkulator\n\nBuatlah sebuah objek `calculator` dengan tiga metode:\n\n- `read()` mendo"
},
{
"path": "1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/solution.js",
"chars": 201,
"preview": "\nlet ladder = {\n step: 0,\n up: function() { \n this.step++;\n return this;\n },\n down: function() { \n this.ste"
},
{
"path": "1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/test.js",
"chars": 836,
"preview": "\ndescribe('Ladder', function() {\n before(function() {\n window.alert = sinon.stub(window, \"alert\");\n });\n \n before"
},
{
"path": "1-js/04-object-basics/04-object-methods/8-chain-calls/solution.md",
"chars": 577,
"preview": "Solusinya adalah untuk mengembalikan objek itu sendiri dari setiap panggilan.\n\n```js run demo\nlet ladder = {\n step: 0,\n"
},
{
"path": "1-js/04-object-basics/04-object-methods/8-chain-calls/task.md",
"chars": 767,
"preview": "importance: 2\n\n---\n\n# *Chaining* (merantaikan)\n\nAda sebuah objek layaknya tangga (`ladder`) yang dapat naik dan turun:\n\n"
},
{
"path": "1-js/04-object-basics/04-object-methods/article.md",
"chars": 8929,
"preview": "# Metode objek, \"this\"\n\nObjek-objek biasanya dibuat untuk merepresentasikan benda di dunia nyata, seperti para pengguna,"
},
{
"path": "1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/solution.md",
"chars": 380,
"preview": "Ya, hal itu memungkinkan.\n\nJika sebuah fungsi mengembalikan sebuah objek lalu `new` mengembalikan objek tersebut sebagai"
},
{
"path": "1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md",
"chars": 288,
"preview": "importance: 2\n\n---\n\n# Dua fungsi – satu objek\n\nApakah mungkin untuk membuat fungsi `A` dan fungsi `B` seperti `new A()=="
},
{
"path": "1-js/04-object-basics/06-constructor-new/2-calculator-constructor/_js.view/solution.js",
"chars": 240,
"preview": "function Calculator() {\n\n this.read = function() {\n this.a = +prompt('a?', 0);\n this.b = +prompt('b?', 0);\n };\n\n"
},
{
"path": "1-js/04-object-basics/06-constructor-new/2-calculator-constructor/_js.view/test.js",
"chars": 705,
"preview": "\ndescribe(\"calculator\", function() {\n let calculator;\n before(function() {\n sinon.stub(window, \"prompt\")\n\n promp"
},
{
"path": "1-js/04-object-basics/06-constructor-new/2-calculator-constructor/solution.md",
"chars": 388,
"preview": "```js run demo\nfunction Calculator() {\n\n this.read = function() {\n this.a = +prompt('a?', 0);\n this.b = +prompt('"
},
{
"path": "1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md",
"chars": 496,
"preview": "importance: 5\n\n---\n\n# Buat Kalkulator baru\n\nBuatlah sebuah fungsi konstruktor `Calculator` yang membuat objek dengan 3 m"
},
{
"path": "1-js/04-object-basics/06-constructor-new/3-accumulator/_js.view/solution.js",
"chars": 154,
"preview": "function Accumulator(startingValue) {\n this.value = startingValue;\n\n this.read = function() {\n this.value += +promp"
},
{
"path": "1-js/04-object-basics/06-constructor-new/3-accumulator/_js.view/test.js",
"chars": 703,
"preview": "describe(\"Accumulator\", function() {\n\n beforeEach(function() {\n sinon.stub(window, \"prompt\")\n });\n\n afterEach(func"
},
{
"path": "1-js/04-object-basics/06-constructor-new/3-accumulator/solution.md",
"chars": 280,
"preview": "\n\n```js run demo\nfunction Accumulator(startingValue) {\n this.value = startingValue;\n\n this.read = function() {\n thi"
},
{
"path": "1-js/04-object-basics/06-constructor-new/3-accumulator/task.md",
"chars": 831,
"preview": "importance: 5\n\n---\n\n# Membuat Akumulator baru\n\nBuatlah sebuah fungsi konstruktor `Accumulator(startingValue)`.\n\nObjek ya"
},
{
"path": "1-js/04-object-basics/06-constructor-new/article.md",
"chars": 8289,
"preview": "# Konstruktor, operator \"new\"\n\nSintaks reguler `{...}` memungkinkan kita untuk membuat satu objek. Tapi seringkali kita "
},
{
"path": "1-js/04-object-basics/07-optional-chaining/article.md",
"chars": 7891,
"preview": "\n# Optional chaining '?.'\n\n[recent browser=\"new\"]\n\nThe optional chaining `?.` is a safe way to access nested object prop"
},
{
"path": "1-js/04-object-basics/08-symbol/article.md",
"chars": 12221,
"preview": "\n# Tipe simbol\n\nMenurut spesifikasi spesifikasi, properti-properti kunci objek bisa saja bertipe *string*, atau bertipe "
},
{
"path": "1-js/04-object-basics/09-object-toprimitive/article.md",
"chars": 5505,
"preview": "# Menolak konversi primitif\n\nApa yang terjadi ketika objek ditambahkan `obj1 + obj2`, dikurangi `obj1 - obj2` atau dicet"
},
{
"path": "1-js/04-object-basics/index.md",
"chars": 23,
"preview": "# Objects: dasar-dasar\n"
},
{
"path": "1-js/05-data-types/01-primitives-methods/1-string-new-property/solution.md",
"chars": 958,
"preview": "\nCobalah jalankan:\n\n```js run\nlet str = \"Hello\";\n\nstr.test = 5; // (*)\n\nalert(str.test);\n```\n\nTergantung apakah kamu gun"
},
{
"path": "1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md",
"chars": 221,
"preview": "nilai penting: 5\n\n---\n\n# Bisakah saya menambahkan properti string?\n\n\nPerhatikan kode berikut:\n\n```js\nlet str = \"Hello\";\n"
},
{
"path": "1-js/05-data-types/01-primitives-methods/article.md",
"chars": 5578,
"preview": "# Metode primitif\n\nJavascript memperbolehkan kita untuk bekerja dengan primitif (string, angka, dan lain-lain.) seperti "
},
{
"path": "1-js/05-data-types/02-number/1-sum-interface/solution.md",
"chars": 322,
"preview": "\n\n```js run demo\nlet a = +prompt(\"The first number?\", \"\");\nlet b = +prompt(\"The second number?\", \"\");\n\nalert( a + b );\n`"
},
{
"path": "1-js/05-data-types/02-number/1-sum-interface/task.md",
"chars": 198,
"preview": "nilai penting: 5\n\n---\n\n# Jumlahkan angka dari pengunjung\n\nBuat skrip yang meminta pengunjung untuk memasukkan dua angka "
},
{
"path": "1-js/05-data-types/02-number/2-why-rounded-down/solution.md",
"chars": 1148,
"preview": "Secara internal pecahan desimal `6.35` adalah sebuah biner tanpa akhir. Seperti biasa dalam kasus seperti ini, disimpan "
},
{
"path": "1-js/05-data-types/02-number/2-why-rounded-down/task.md",
"chars": 436,
"preview": "nilai penting: 4\n\n---\n\n# Kenapa 6.35.toFixed(1) == 6.3?\n\nBerdasarkan dokumentasi `Math.round` dan `toFixed` keduanya mem"
},
{
"path": "1-js/05-data-types/02-number/3-repeat-until-number/_js.view/solution.js",
"chars": 188,
"preview": "\nfunction readNumber() {\n let num;\n\n do {\n num = prompt(\"Enter a number please?\", 0);\n } while ( !isFinite(num) );"
},
{
"path": "1-js/05-data-types/02-number/3-repeat-until-number/_js.view/test.js",
"chars": 852,
"preview": "beforeEach(function() {\n sinon.stub(window, \"prompt\");\n});\n\nafterEach(function() {\n prompt.restore();\n});\n\ndescribe(\"r"
},
{
"path": "1-js/05-data-types/02-number/3-repeat-until-number/solution.md",
"chars": 694,
"preview": "\n```js run demo\nfunction readNumber() {\n let num;\n\n do {\n num = prompt(\"Enter a number please?\", 0);\n } while ( !i"
},
{
"path": "1-js/05-data-types/02-number/3-repeat-until-number/task.md",
"chars": 408,
"preview": "nilai penting: 5\n\n---\n\n# Ulangi sampai masukan adalah sebuah angka\n\nBuatlah sebuah fungsi `readNumber` yang meminta (pro"
},
{
"path": "1-js/05-data-types/02-number/4-endless-loop-error/solution.md",
"chars": 435,
"preview": "Itu karena `i` tidak akan pernah sebanding dengan `10`.\n\nJalankan ini untuk melihat nilai *real* dari `i`:\n\n```js run\nle"
},
{
"path": "1-js/05-data-types/02-number/4-endless-loop-error/task.md",
"chars": 173,
"preview": "nilai penting: 4\n\n---\n\n# Lingkaran tak terbatas tak berkala\n\nLoop ini tidak terbatas. Tidak pernah berakhir. Mengapa?\n\n`"
},
{
"path": "1-js/05-data-types/02-number/8-random-min-max/solution.md",
"chars": 522,
"preview": "Kita perlu \"memetakan\" semua nilai dari interval 0..1 ke dalam nilai dari `min` ke` max`.\n\nItu bisa dilakukan dalam dua "
}
]
// ... and 960 more files (download for full content)
About this extraction
This page contains the full source code of the javascript-tutorial/id.javascript.info GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 1160 files (3.7 MB), approximately 1.1M tokens, and a symbol index with 176 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.