├── .gitignore ├── 1. JavaScript Language ├── 1.1. Introduction into JavaScript │ ├── README.md │ └── images │ │ └── js-logo.png ├── 1.2. Manuals and specifications │ └── README.md ├── 1.3. Code editors │ └── README.md ├── 1.4. Developer tools │ ├── README.md │ └── src │ │ ├── index.html │ │ └── index.js ├── 10.1. Try, catch │ ├── README.md │ └── src │ │ └── 1-finally-or-just-a-code.js ├── 10.2. Custom errors │ ├── README.md │ └── src │ │ └── 1-inheritance-from-syntax-error.js ├── 11.1. Callbacks │ ├── README.md │ └── src │ │ └── 1-animate-circle.js ├── 11.2. Promises, basics │ ├── README.md │ └── src │ │ ├── 1-start-promise-again.js │ │ ├── 2-delay.js │ │ └── 3-animate-circle.js ├── 11.3. Promise chaining │ ├── README.md │ └── src │ │ └── 1-compare-then-and-catch.js ├── 11.4. Promise, error handling │ ├── README.md │ └── src │ │ └── 1-settimeout-error.js ├── 11.5. Promise API │ └── README.md ├── 11.6. Promisify │ └── README.md ├── 11.7. Microtask queue │ └── README.md ├── 11.8. Async, await │ ├── README.md │ └── src │ │ ├── 1-refactor-using-async-await.js │ │ ├── 2-refactor-using-async-await-2.js │ │ └── 3-return-async-function.js ├── 12.1. Generators │ ├── README.md │ └── src │ │ └── 1-pseudo-random-generator.js ├── 12.2. Async iterators, generators │ └── README.md ├── 13.1. Modules intro │ └── README.md ├── 13.2. Import, export │ └── README.md ├── 13.3. Dynamic imports │ └── README.md ├── 14.1. Proxy, reflect │ └── README.md ├── 14.2. Eval │ ├── README.md │ └── src │ │ └── 1-eval-calculator.js ├── 14.3. Currying partials │ └── README.md ├── 14.4. Bitwise operators │ ├── README.md │ └── src │ │ ├── 1-bitwise-operator-and-value.js │ │ ├── 2-is-number-an-integer.js │ │ ├── 3-are-operations-identical.js │ │ └── 4-why-result-is-different.js ├── 14.5. Bigint │ └── README.md ├── 14.6. Intl │ ├── README.md │ └── src │ │ └── 1-sort-array.js ├── 2.1. Hello world │ ├── README.md │ └── src │ │ ├── index.html │ │ └── scripts │ │ └── 1-call-alert.js ├── 2.10. If else │ ├── README.md │ └── src │ │ ├── 1-if-string-with-null.js │ │ ├── 2-javascript-name.js │ │ ├── 3-show-integer-sign.js │ │ ├── 4-refactor-if-to-question-mark.js │ │ └── 5-refactor-if-to-multiple-question-mark.js ├── 2.11. Logical operators │ ├── README.md │ └── src │ │ ├── 1-what-will-output-alert.js │ │ ├── 2-what-will-output-alert.js │ │ ├── 3-what-will-output-alert.js │ │ ├── 4-what-will-output-alert.js │ │ ├── 5-what-will-output-alert.js │ │ ├── 6-check-range.js │ │ ├── 7-check-out-of-range.js │ │ ├── 8-question-about-if.js │ │ └── 9-check-login.js ├── 2.12. Nullish coalescing operator │ └── README.md ├── 2.13. While and for │ ├── README.md │ └── src │ │ ├── 1-last-loop-value.js │ │ ├── 2-what-values-will-output-while.js │ │ ├── 3-what-values-will-output-for.js │ │ ├── 4-output-even-numbers.js │ │ ├── 5-replace-for-loop-on-while.js │ │ ├── 6-repeat-loop-while-input-wrong.js │ │ └── 7-output-prime-numbers.js ├── 2.14. Switch │ ├── README.md │ └── src │ │ ├── 1-refactor-if-to-switch.js │ │ └── 2-refactor-switch-to-if.js ├── 2.15. Functions basics │ ├── README.md │ └── src │ │ ├── 1-do-you-need-else.js │ │ ├── 2-refactor-function-using-operators.js │ │ ├── 3-function-min.js │ │ └── 4-function-pow.js ├── 2.16. Function expression │ └── README.md ├── 2.17. Arrow functions │ ├── README.md │ └── src │ │ └── 1-refactor-function-expression-to-arrow-function.js ├── 2.18. JavaScript specials │ └── README.md ├── 2.2. Code structure │ └── README.md ├── 2.3. Strict mode │ └── README.md ├── 2.4. Variables │ ├── README.md │ └── src │ │ ├── 1-work-with-variables.js │ │ ├── 2-come-up-with-correct-names.js │ │ └── 3-constants-naming-uppercase-or-lowercase.js ├── 2.5. Types │ ├── README.md │ └── src │ │ └── 1-template-literals.js ├── 2.6. Alert, prompt, confirm │ ├── README.md │ └── src │ │ └── 1-simple-page.js ├── 2.7. Type conversions │ └── README.md ├── 2.8. Operators │ ├── README.md │ └── src │ │ ├── 1-postfix-and-prefix-forms.js │ │ ├── 2-assignment-result.js │ │ ├── 3-type-conversions.js │ │ └── 4-fix-addition.js ├── 2.9. Comparison │ ├── README.md │ └── src │ │ └── 1-comparison-operators.js ├── 3.1. Debugging chrome │ └── README.md ├── 3.2. Coding style │ ├── README.md │ └── src │ │ └── 1-bad-style.js ├── 3.3. Comments │ └── README.md ├── 3.4. Ninja code │ └── README.md ├── 3.5. Testing mocha │ ├── README.md │ └── src │ │ └── 1-what-is-wrong-with-test.js ├── 3.6. Polyfills │ └── README.md ├── 4.1. Object │ ├── README.md │ └── src │ │ ├── 1-hello-object.js │ │ ├── 2-check-is-empty.js │ │ ├── 2-check-is-empty.spec.js │ │ ├── 3-objects-constants.js │ │ ├── 4-sum-object-values.js │ │ ├── 4-sum-object-values.spec.js │ │ ├── 5-multiply-all-numeric-object-values.js │ │ └── 5-multiply-all-numeric-object-values.spec.js ├── 4.2. Object copy │ └── README.md ├── 4.3. Garbage collection │ └── README.md ├── 4.4. This │ ├── README.md │ └── src │ │ ├── 1-check-syntax.js │ │ ├── 2-explain-this-value.js │ │ ├── 3-using-this-in-object-literal.js │ │ ├── 4-create-calculator.js │ │ └── 5-methods-chaining.js ├── 4.5. Constructor, new │ ├── README.md │ └── src │ │ ├── 1-two-functions-one-object.js │ │ ├── 2-constructor-calculator.js │ │ └── 3-create-accumulator.js ├── 4.6. Optional chaining │ └── README.md ├── 4.7. Symbol │ └── README.md ├── 4.8. Object to primitive │ └── README.md ├── 5.1. Primitives methods │ ├── README.md │ └── src │ │ └── 1-can-you-add-property-to-string.js ├── 5.10. Destructuring assignment │ ├── README.md │ └── src │ │ ├── 1-destructuring-assignment.js │ │ └── 2-max-salary.js ├── 5.11. Date │ ├── README.md │ └── src │ │ ├── 1-create-date.js │ │ ├── 2-show-week-day.js │ │ ├── 3-week-day-euro.js │ │ ├── 4-get-date-ago.js │ │ ├── 5-last-day.js │ │ ├── 6-get-seconds-today.js │ │ ├── 7-get-seconds-to-tomorrow.js │ │ └── 8-format-date.js ├── 5.12. JSON │ ├── README.md │ └── src │ │ ├── 1-stringify-and-parse.js │ │ └── 2-exclude-recursive-links.js ├── 5.2. Number │ ├── README.md │ └── src │ │ ├── 1-sum-user-input.js │ │ ├── 2-to-fixed-problem.js │ │ ├── 3-prompt-number.js │ │ ├── 4-infinite-loop.js │ │ ├── 5-random-number.js │ │ └── 6-random.integer.js ├── 5.3. String │ ├── README.md │ └── src │ │ ├── 1-capitalize.js │ │ ├── 2-check-spam.js │ │ ├── 3-truncate-string.js │ │ └── 4-extract-currency-value.js ├── 5.4. Array │ ├── README.md │ └── src │ │ ├── 1-is-array-cloned.js │ │ ├── 2-array-operations.js │ │ ├── 3-call-in-array-context.js │ │ ├── 4-sum-inputs.js │ │ ├── 5-subarray-max-sum.js │ │ └── 5-subarray-max-sum.spec.js ├── 5.5. Array methods │ ├── README.md │ └── src │ │ ├── 1-camelize.js │ │ ├── 10-shuffle.js │ │ ├── 11-get-average-age.js │ │ ├── 12-unique-elements-array.js │ │ ├── 2-filter-range.js │ │ ├── 3-filter-range-in-place.js │ │ ├── 4-sort-array-desc.js │ │ ├── 5-copy-and-sort-array.js │ │ ├── 6-calculator.js │ │ ├── 7-transform-user-names.js │ │ ├── 8-transform-to-obj.js │ │ └── 9-sort-users-by-age.js ├── 5.6. Iterators │ └── README.md ├── 5.7. Map and Set │ ├── README.md │ └── src │ │ ├── 1-filter-unique-array.js │ │ ├── 2-filter-anagrams.js │ │ └── 3-iterateble-keys.js ├── 5.8. WeakMap and WeakSet │ ├── README.md │ └── src │ │ ├── 1-store-read-info.js │ │ └── 2-store-read-date.js ├── 5.9. Object.keys, values, entries │ ├── README.md │ └── src │ │ ├── 1-object-sum.js │ │ └── 2-object-length.js ├── 6.1. Recursion │ ├── README.md │ └── src │ │ ├── 1-sum-to.js │ │ ├── 1-sum-to.spec.js │ │ ├── 2-factorial.js │ │ ├── 2-factorial.spec.js │ │ ├── 3-fibonacci.js │ │ ├── 3-fibonacci.spec.js │ │ ├── 4-print-list.js │ │ ├── 4-print-list.spec.js │ │ ├── 5-print-list-backwards.js │ │ └── 5-print-list-backwards.spec.js ├── 6.10. Bind │ ├── README.md │ └── src │ │ ├── 1-binded-function-as-method.js │ │ ├── 2-two-binded-function.js │ │ ├── 3-property-of-bind-function.js │ │ ├── 4-refactor-function.js │ │ └── 5-partial-application.js ├── 6.11. Arrow functions │ └── README.md ├── 6.2. Rest parameters, spread operator │ └── README.md ├── 6.3. Closure │ ├── README.md │ └── src │ │ ├── 1-are-counters-independent.js │ │ ├── 2-counter-obj.js │ │ ├── 3-function-if.js │ │ ├── 4-sum-with-closures.js │ │ ├── 4-sum-with-closures.spec.js │ │ ├── 5-filter-with-fn.js │ │ ├── 5-filter-with-fn.spec.js │ │ ├── 6-sort-by-field-cb.js │ │ ├── 6-sort-by-field-cb.spec.js │ │ └── 7-functions-army.js ├── 6.4. Var │ └── README.md ├── 6.5. Global object │ └── README.md ├── 6.6. Function-object │ ├── README.md │ └── src │ │ ├── 1-set-and-decrease-counter.js │ │ ├── 1-set-and-decrease-counter.spec.js │ │ ├── 2-fn-sum.js │ │ └── 2-fn-sum.spec.js ├── 6.7. New Function │ └── README.md ├── 6.8. SetTimeout and SetInterval │ ├── README.md │ └── src │ │ ├── 1-print-numbers.js │ │ └── 2-what-will-output-set-timeout.js ├── 6.9. Call, apply, decorators │ ├── README.md │ └── src │ │ ├── 1-spy.js │ │ ├── 1-spy.spec.js │ │ ├── 2-delay.js │ │ ├── 3-debounce.js │ │ └── 4-throttle.js ├── 7.1. Property descriptors │ └── README.md ├── 7.2. Property accessors │ └── README.md ├── 8.1. Prototype inheritance │ ├── README.md │ └── src │ │ ├── 1-work-with-proto.js │ │ ├── 2-search-alghorithm.js │ │ ├── 3-where-will-write.js │ │ └── 4-why-eat-up-both-hamsters.js ├── 8.2. Function prototype │ ├── README.md │ └── src │ │ ├── 1-changing-prototype.js │ │ └── 2-create-new-object-with-existing-one.js ├── 8.3. Native Prototypes │ ├── README.md │ └── src │ │ ├── 1-add-defer-to-functions.js │ │ └── 2-add-defer-decorate-to-functions.js ├── 8.4. Prototype methods │ ├── README.md │ └── src │ │ ├── 1-to-string-to-dictionary.js │ │ └── 2-check-difference.js ├── 9.1. Class │ ├── README.md │ └── src │ │ └── 1-refactor-class.js ├── 9.2. Class inheritance │ ├── README.md │ └── src │ │ ├── 1-create-instance-error.js │ │ └── 2-upgraded-clock.js ├── 9.3. Static properties, methods │ ├── README.md │ └── src │ │ └── 1-is-class-extends-object.js ├── 9.4. Private, protected properties, methods │ └── README.md ├── 9.5. Extend natives │ └── README.md ├── 9.6. Instanceof │ ├── README.md │ └── src │ │ └── 1-strange-instance-of.js └── 9.7. Mixins │ └── README.md ├── 10. Articles └── 1. Evil one-liners │ └── README.md ├── 11. Videos └── React │ └── 01. React Batching │ ├── README.md │ └── images │ └── 1-batching-history.png ├── 2. Browser: document, events, interfaces ├── 1.1. Browser environment │ └── README.md ├── 1.10. Size and scroll window │ └── README.md ├── 1.11. Coordinates │ └── README.md ├── 1.2. DOM Nodes │ └── README.md ├── 1.3. DOM Navigation │ ├── README.md │ └── src │ │ ├── 1-get-child-elements-in-dom.js │ │ ├── 2-question-about-siblings.js │ │ └── 3-fill-red-cells.js ├── 1.4. Searching elements in DOM │ ├── README.md │ └── src │ │ └── 1-searching-elements.js ├── 1.5. Basic DOM node properties │ ├── README.md │ ├── images │ │ └── 1-dom-node-hierarchy.png │ └── src │ │ ├── 1-count-descedants.js │ │ ├── 2-what-contains-nodetype.js │ │ ├── 3-what-will-output-this-code.js │ │ └── 4-where-is-document.js ├── 1.6. DOM Attributes and properties │ ├── README.md │ └── src │ │ ├── 1-get-attribute.js │ │ └── 2-color-orange-for-external-links.js ├── 1.7. Modifiying document │ ├── README.md │ └── src │ │ ├── 1-createTextnode-innerHTML-textContent.js │ │ ├── 2-clear-elem.js │ │ ├── 3-why-aaa-stays.js │ │ ├── 4-create-list.js │ │ ├── 5-create-tree-from-obj.js │ │ └── 6-output-descendants.js ├── 1.8. Styles and classes │ ├── README.md │ └── src │ │ └── 1-show-notification.js ├── 1.9. Size and scroll │ ├── README.md │ └── src │ │ └── 1-find-scroll-bottom.js ├── 2.1. Introduction-browser-events │ ├── README.md │ └── src │ │ ├── 1-hide-element-on-click.js │ │ ├── 2-hide-self.js │ │ ├── 3-which-handler-will-emit.js │ │ ├── 4-move-ball.js │ │ └── 5-create-expandable-menu.js ├── 2.2. Bubbling and capturing │ └── README.md ├── 2.3. Event Delegation │ ├── README.md │ └── src │ │ ├── 1-hide-with-event-delegation.js │ │ ├── 2-accordion-tree.js │ │ └── 3-sort-an-table.js ├── 2.4. Default Browser Action │ ├── README.md │ └── src │ │ ├── 1-why-return-false-not-work.js │ │ ├── 2-catch-website-leave.js │ │ └── 3-image-gallery.js ├── 2.5. Dispatch user events │ └── README.md ├── 3.1. Mouse event basics │ ├── README.md │ └── src │ │ └── 1-selectable-list.js ├── 3.2. Mousemove, MouseOver etc. │ └── README.md ├── 3.3. Mouse drag and drop │ └── README.md ├── 3.4. Keyboard Events │ └── README.md ├── 3.5. Pointer-events │ └── README.md ├── 3.6. On scroll │ ├── README.md │ └── src │ │ ├── 1-infinite-scroll.js │ │ └── 2-scroll-to-top-button.js ├── 4.1. Form elements │ ├── README.md │ └── src │ │ └── 1-add-option-to-select.js ├── 4.2. Focus and blur │ └── README.md ├── 4.3. Change, input, copy │ └── README.md ├── 4.4. Form submit │ └── README.md ├── 5.1. DOMContentLoaded, load, beforeunload, unload │ └── README.md ├── 5.2. Scripts async, defer │ └── README.md ├── 5.3. Onload, onerror │ ├── README.md │ └── src │ │ └── 1-preload-images.js ├── 6.1. MutationObserver │ └── README.md ├── 6.2. Selection, Range │ └── README.md └── 6.3. Event loop │ ├── README.md │ └── src │ └── 1-what-will-output.js ├── 3. Thematic sections ├── 1.1. Popup windows │ └── README.md └── 1.2. Cross window communication │ └── README.md ├── 4. Additional └── 4.1 Programming paradigms │ ├── 4.1.1 Object-oriented programming │ ├── 4.1.1.3 Prototype-based programming │ │ └── README.md │ └── README.md │ └── 4.1.2 Procedural │ └── README.md ├── 5. Tasks ├── codewars │ ├── 1 kyu │ │ ├── 1. Multiline Task++: Hello world.js │ │ └── 2. Functional SQL.js │ ├── 2 kyu │ │ ├── 1. Multi Line Task++: Hello World.js │ │ ├── 3. Evaluate mathematical expression.js │ │ └── ASCII Games: Dance Dance Evolution I.js │ ├── 3 kyu │ │ ├── 1. Texas Hold'em Hands.js │ │ └── 2. Spiralize.js │ ├── 4 kyu │ │ ├── 1. Strings mix.js │ │ ├── 10. Next bigger number with the same digits.js │ │ ├── 11. Sort binary tree by levels.js │ │ ├── 2. The observed PIN.js │ │ ├── 3. Nesting Structure Comparison.js │ │ ├── 4. Roman Numerals Helper.js │ │ ├── 5. Strip comments.js │ │ ├── 6. Permutations.js │ │ ├── 7. Sum Strings as Numbers.js │ │ ├── 8. Text align justify.js │ │ └── 9. Range extraction.js │ ├── 5 kyu │ │ ├── 1. int32 to IPv4.js │ │ ├── 10. Array.diff hero.js │ │ ├── 11. Calculating with Functions.js │ │ ├── 12. Simple events.js │ │ ├── 13. Caesar Cipher Helper.js │ │ ├── 14. Can you get the loop.js │ │ ├── 15. Molecule to atoms.js │ │ ├── 16. Function Cache.js │ │ ├── 2. Tic-Tac-Toe Checker.js │ │ ├── 3. Product of consecutive Fib numbers.js │ │ ├── 4. Perimeter of squares in a rectangle.js │ │ ├── 5. The Hashtag generator.js │ │ ├── 6. Weight for weight.js │ │ ├── 7. 1's, 0's and wildcards.js │ │ ├── 8. Greed is good.js │ │ └── 9. Number of trailing zeros of N!.js │ ├── 6 kyu │ │ ├── 1. Your order, please!.js │ │ ├── 10. Roman Numerals Decoder.js │ │ ├── 11. Get Length of missing array.js │ │ ├── 12. Duplicate Encoder.js │ │ ├── 13. Take a number and sum its digits raised. Eureca.js │ │ ├── 14. Tortoise racing.js │ │ ├── 15. Build tower.js │ │ ├── 16. Triple Double.js │ │ ├── 17. Function composition.js │ │ ├── 18. Data Reverse.js │ │ ├── 19. Find the missing letter.js │ │ ├── 2. The Supermarket Queue.js │ │ ├── 20. Easy balance checking.js │ │ ├── 21. Find the last Fibonacci digit.js │ │ ├── 22. The Office V - Find a Chair.js │ │ ├── 23. Guess the number!.js │ │ ├── 24. Frog jumping.js │ │ ├── 25. Number Zoo Patrol.js │ │ ├── 26. CamelCase method.js │ │ ├── 27. Parse a linked list from a string.js │ │ ├── 28. PhoneWords.js │ │ ├── 29. Longest consecutive.js │ │ ├── 3. Training on Ping Pong.js │ │ ├── 30. Maximum and minimum.js │ │ ├── 31. Plenty of Fish in the Pond.js │ │ ├── 32. Word mesh.js │ │ ├── 33. Zero-plentiful Array.js │ │ ├── 34. Remove the parentheses.js │ │ ├── 35. Car number plate calculator.js │ │ ├── 36. Killer Garage Door.js │ │ ├── 37. Salesman's Travel.js │ │ ├── 38. Lottery Ticket.js │ │ ├── 39. Simple Fun #52: Pair of Shoes.js │ │ ├── 4. Sorting on Planet Twisted 3-7.js │ │ ├── 5. Group in 10s.js │ │ ├── 6. Split strings.js │ │ ├── 7. Rectangle into squares.js │ │ ├── 8. Handshake problem.js │ │ └── 9. Lets Recycle.js │ ├── 7 kyu │ │ ├── 1. Don't give me five!.js │ │ ├── 10. The Coupon Code.js │ │ ├── 11. Remove anchor from URL.js │ │ ├── 12. Number of People in the Bus.js │ │ ├── 13. Sorted? yes? no? how?.js │ │ ├── 14. Multiply word in string.js │ │ ├── 15. Vowel one.js │ │ ├── 16. Alternate capitalization.js │ │ ├── 17. Last Survivor.js │ │ ├── 18. Largest Elements.js │ │ ├── 19. Factorial.js │ │ ├── 2. Disemvowel Trolls.js │ │ ├── 20. Two oldest ages.js │ │ ├── 21. Power of two.js │ │ ├── 22. Flatten and sort an array.js │ │ ├── 23. Survive the attack.js │ │ ├── 24. Form the minimum.js │ │ ├── 25. The 12 Days of Christmas.js │ │ ├── 26. Alan Partridge I - Partridge Watch.js │ │ ├── 27. Alan Partridge III - London.js │ │ ├── 28. How many are smaller than me.js │ │ ├── 29. Previous multiple of three.js │ │ ├── 3. Sum of a sequence.js │ │ ├── 4. Friend or Foe.js │ │ ├── 5. Check the exam.js │ │ ├── 6. Ultimate Array Reverser.js │ │ ├── 7. Simple fun #176. Reverse letter.js │ │ ├── 8. Anagram detection.js │ │ └── 9. Sum of odd numbers.js │ └── 8 kyu │ │ ├── 1. Fake Binary.js │ │ ├── 10. Jehny's secret message.js │ │ ├── 11. Grasshopper - Check for factor.js │ │ ├── 12. Do I get a bonus.js │ │ ├── 13. Find multiplies of a number.js │ │ ├── 14. Is it a palindrome.js │ │ ├── 15. Get nth even number.js │ │ ├── 16. Opposites attract.js │ │ ├── 17. Stringy string.js │ │ ├── 18. Welcome!.js │ │ ├── 19. N-th Power.js │ │ ├── 2. DNA to RNA conversion.js │ │ ├── 20. FIXME: Replace all dots.js │ │ ├── 21. The Feast of many Beasts.js │ │ ├── 22. No zeros for heros.js │ │ ├── 23. Double char.js │ │ ├── 24. Find the position!.js │ │ ├── 25. Twice as old.js │ │ ├── 26. Make negative.js │ │ ├── 27. Capitalization and Mutability.js │ │ ├── 28. Reverse list order.js │ │ ├── 29. Alternating case.js │ │ ├── 3. Leonardo Dicaprio and Oscars.js │ │ ├── 30. Remove duplicates from list.js │ │ ├── 31. Alan Partridge II - Apple Turnover.js │ │ ├── 32. Regular Ball Super Ball.js │ │ ├── 33. Grasshopper - Array Mean.js │ │ ├── 4. What is between.js │ │ ├── 5. Training on Squash the bugs.js │ │ ├── 6. Exclamation marks series #2: Remove all exclamation marks from the end of sentence.js │ │ ├── 7. Basic Variable Assignment.js │ │ ├── 8. Potenciation.js │ │ └── 9. Student's final grade.js ├── leetcode │ └── easy │ │ ├── 0383. Ransom Note.js │ │ ├── 0412. Fizz Buzz.js │ │ ├── 0724. Find Pivot Index.js │ │ ├── 1342. Number of steps to reduce a number to zero.js │ │ ├── 1480. Running sum of 1d array.js │ │ ├── 1672. Richest Customer Wealth.js │ │ └── 2235. Add two integers.js └── other │ ├── 1. Is valid brackets │ ├── is-valid-brackets.js │ └── is-valid-brackets.spec.js │ ├── 2. Sum curry │ ├── 2-sum-curry.js │ └── 2-sum-curry.spec.js │ ├── 3. Parallel │ ├── 3-parallel.js │ └── 3-parallel.spec.js │ ├── 4. Fold │ ├── 4-fold.js │ └── 4-fold.spec.js │ ├── 5. Rectangle to squares │ └── 5-rectangle-to-squares.js │ └── 6. Diff │ ├── 6-diff.js │ └── 6-diff.spec.js ├── 6. Algorithms ├── 1. Binary Search.js └── sort │ └── 1-quick-sort.js ├── 7. Books └── Clean code (Robert Martin) │ ├── 1. Clean code.md │ ├── 2. Meaningful names.md │ └── README.md ├── 8. Lectures └── HolyJS │ └── 2022 │ └── Compound Components │ └── README.md ├── 9. Courses └── 1. JS Introduction to OOP │ ├── Arrow functions context │ ├── README.md │ └── collection.js │ ├── Bind │ ├── README.md │ └── bind.js │ ├── Boxing │ ├── README.md │ └── magic.js │ ├── Constructor │ ├── Point.js │ ├── README.md │ ├── Segment.js │ └── solution.js │ ├── Context (this) │ ├── README.md │ └── rational.js │ ├── Encapsulation │ ├── README.md │ └── getMutualFriends.js │ └── Prototypes │ ├── Money.js │ └── README.md ├── README.md ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | .vscode 4 | -------------------------------------------------------------------------------- /1. JavaScript Language/1.1. Introduction into JavaScript/images/js-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meowto16/learn-javascript-ru/1ae03863f787fe5f7fcd139a58641c3560b0c4d8/1. JavaScript Language/1.1. Introduction into JavaScript/images/js-logo.png -------------------------------------------------------------------------------- /1. JavaScript Language/1.2. Manuals and specifications/README.md: -------------------------------------------------------------------------------- 1 | # Справочники и спецификации 2 | 3 | ## Спецификации 4 | 5 | - [ECMA-262 (EcmaScript спецификация JS)](https://www.ecma-international.org/publications/standards/Ecma-262.htm) 6 | - [Спецификация DOM](https://dom.spec.whatwg.org) 7 | - [Спецификация CSSOM](https://www.w3.org/TR/cssom-1/) 8 | - [Спецификация HTML](https://html.spec.whatwg.org) 9 | 10 | ## Справочники 11 | 12 | - [MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference) 13 | - [MSDN (Если вдруг пришлось иметь дело с IE)](http://msdn.microsoft.com/) 14 | 15 | ## Таблицы совместимости 16 | 17 | - [caniuse.com](http://caniuse.com) 18 | - [Таблица с возможностями языка и движками](https://kangax.github.io/compat-table) 19 | 20 | > Для поиска чего-либо обычно удобно использовать интернет-поиск со словами 21 | > «WHATWG [термин]» или «MDN [термин]» 22 | -------------------------------------------------------------------------------- /1. JavaScript Language/1.3. Code editors/README.md: -------------------------------------------------------------------------------- 1 | # Редакторы кода 2 | 3 | ## IDE 4 | 5 | - Visual Studio Code (бесплатная) 6 | - Webstorm, Phpstorm (платная, около 90$ в год). Затем с каждым годом дешевле и дешевле. 7 | 8 | ## Простые редакторы 9 | 10 | - Atom 11 | - Sublime Text 12 | - Vim 13 | 14 | > IDE действительно стоит своих денег и ускоряет работу в разы. 15 | > 16 | > Но нужно понимать как ей пользоваться, наиболее подходящим вариантом для меня стал "PhpStorm" 17 | -------------------------------------------------------------------------------- /1. JavaScript Language/1.4. Developer tools/src/index.js: -------------------------------------------------------------------------------- 1 | const form = document.querySelector('.js-form') 2 | const resultContainer = document.querySelector('.js-result-container') 3 | const result = resultContainer.querySelector('.js-result') 4 | 5 | /** 6 | * @param event {SubmitEvent} 7 | */ 8 | const handleSubmit = event => { 9 | event.preventDefault() 10 | 11 | const formData = new FormData(event.target) 12 | const { first, second } = Object.fromEntries(formData) 13 | 14 | resultContainer.classList.remove('hidden') 15 | result.innerHTML = `${+first + +second}` 16 | } 17 | 18 | form.addEventListener('submit', handleSubmit) 19 | -------------------------------------------------------------------------------- /1. JavaScript Language/10.1. Try, catch/src/1-finally-or-just-a-code.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Finally или просто код? 3 | * Сравните два фрагмента кода. 4 | * 5 | * Нам определённо нужна очистка после работы, неважно возникли ошибки или нет. 6 | * 7 | * Есть ли здесь преимущество в использовании finally или оба фрагмента кода одинаковы? 8 | * Если такое преимущество есть, то дайте пример, когда оно проявляется. 9 | */ 10 | 11 | // 1 12 | try { 13 | начать работу 14 | работать 15 | } catch (e) { 16 | обработать ошибку 17 | } finally { 18 | очистить рабочее пространство 19 | } 20 | 21 | // 2 22 | 23 | try { 24 | начать работу 25 | работать 26 | } catch (e) { 27 | обработать ошибку 28 | } 29 | 30 | очистить рабочее пространство 31 | 32 | // Решение: я думаю код одинаково будет работать 33 | // отличие будет только если код выйдет из try..catch, например при помощи return в функции. Или будет проброс ошибки. 34 | -------------------------------------------------------------------------------- /1. JavaScript Language/10.2. Custom errors/README.md: -------------------------------------------------------------------------------- 1 | # Пользовательские ошибки, расширение Error 2 | 3 | Для создания пользовательских ошибок, необходимо наследоваться от класса `Error`. 4 | 5 | ```js 6 | class ValidationError extends Error { 7 | constructor(message) { 8 | super(message); // не забываем вызывать super 9 | this.name = "ValidationError"; // и изменять name 10 | } 11 | } 12 | ``` 13 | 14 | > Можно использовать `instanceof` для проверки типа ошибки 15 | 16 | -------------------------------------------------------------------------------- /1. JavaScript Language/10.2. Custom errors/src/1-inheritance-from-syntax-error.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Наследование от SyntaxError (важность: 5) 3 | * 4 | * Создайте класс FormatError, который наследует от встроенного класса SyntaxError. 5 | * Класс должен поддерживать свойства message, name и stack. 6 | * Пример использования: 7 | */ 8 | 9 | class FormatError extends SyntaxError { 10 | constructor(message) { 11 | super(message) 12 | this.name = 'FormatError' 13 | } 14 | } 15 | 16 | let err = new FormatError("ошибка форматирования"); 17 | 18 | alert( err.message ); // ошибка форматирования 19 | alert( err.name ); // FormatError 20 | alert( err.stack ); // stack 21 | 22 | alert( err instanceof FormatError ); // true 23 | alert( err instanceof SyntaxError ); // 24 | -------------------------------------------------------------------------------- /1. JavaScript Language/11.1. Callbacks/README.md: -------------------------------------------------------------------------------- 1 | # Введение: колбэки 2 | 3 | `Callback` - это функция, которая будет вызвана по завершению асинхронного действия. Т.е в функции, где выполняются 4 | какие-либо асинхронные действия, передаются в виде аргументов функции `callback`'и. 5 | 6 | ## Callback в callback'е 7 | 8 | Для того чтобы выполнить асинхронные действия друг за другом, ранее вызывались `callback`'и внутри других `callback`'ов. 9 | Это называлось **Callback hell**. 10 | 11 | ## Перехват ошибок 12 | 13 | Подход **«error-first callback»** очень распространен в простых приложениях на `express`. Это когда мы в качестве первого 14 | аргумента передаем ошибку (если она есть). 15 | -------------------------------------------------------------------------------- /1. JavaScript Language/11.1. Callbacks/src/1-animate-circle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Анимация круга с помощью колбэка 3 | */ 4 | 5 | function showCircle(cx, cy, radius, onCompleted) { 6 | let div = document.createElement('div'); 7 | div.style.width = 0; 8 | div.style.height = 0; 9 | div.style.left = cx + 'px'; 10 | div.style.top = cy + 'px'; 11 | div.className = 'circle'; 12 | document.body.append(div); 13 | 14 | div.addEventListener('transitionend', () => { 15 | onCompleted(div) 16 | }) 17 | 18 | setTimeout(() => { 19 | div.style.width = radius * 2 + 'px' 20 | div.style.height = radius * 2 + 'px' 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /1. JavaScript Language/11.2. Promises, basics/src/1-start-promise-again.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Можно ли "перевыполнить" промис? 3 | * 4 | * Что выведет код ниже? 5 | */ 6 | 7 | let promise = new Promise(function(resolve, reject) { 8 | resolve(1); 9 | 10 | setTimeout(() => resolve(2), 1000); 11 | }); 12 | 13 | promise.then(alert); 14 | 15 | // Решение, выведет только 1 16 | // resolve(2) не отработает, так как промис уже будет находиться в состоянии fulfilled 17 | -------------------------------------------------------------------------------- /1. JavaScript Language/11.2. Promises, basics/src/2-delay.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Задержка на промисах 3 | * 4 | * Встроенная функция setTimeout использует колбэк-функции. Создайте альтернативу, использующую промисы. 5 | * Функция delay(ms) должна возвращать промис, который перейдёт в состояние «выполнен» через ms миллисекунд, 6 | * так чтобы мы могли добавить к нему .then: 7 | */ 8 | 9 | function delay(ms) { 10 | return new Promise(resolve => { 11 | setTimeout(() => { 12 | resolve() 13 | }, ms) 14 | }) 15 | } 16 | 17 | delay(3000).then(() => alert('выполнилось через 3 секунды')); 18 | -------------------------------------------------------------------------------- /1. JavaScript Language/11.3. Promise chaining/README.md: -------------------------------------------------------------------------------- 1 | # Цепочка промисов 2 | 3 | Если обработчик в `.then` (или в `catch`/`finally`, без разницы) возвращает промис, 4 | последующие элементы цепочки ждут, пока этот промис выполнится. 5 | Когда это происходит, результат его выполнения (или ошибка) передаётся дальше. 6 | 7 | Если с обработчика приходит не промис, то они выполняются просто по очереди. 8 | -------------------------------------------------------------------------------- /1. JavaScript Language/11.3. Promise chaining/src/1-compare-then-and-catch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Промисы: сравните then и catch 3 | * 4 | * Являются ли фрагменты кода ниже эквивалентными? 5 | * Другими словами, ведут ли они себя одинаково во всех обстоятельствах, для всех переданных им обработчиков? 6 | */ 7 | 8 | promise.then(f1).catch(f2); 9 | 10 | promise.then(f1, f2); 11 | 12 | // Решение: не совсем, в первом случае ошибка может возникнуть и в .then(f1) - тогда она поймается в .catch(f2) 13 | // Во втором случае, ошибка может быть только в самом промисе. 14 | -------------------------------------------------------------------------------- /1. JavaScript Language/11.4. Promise, error handling/src/1-settimeout-error.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ошибка в setTimeout 3 | * 4 | * Что вы думаете? Выполнится ли .catch? Поясните свой ответ. 5 | */ 6 | 7 | new Promise(function(resolve, reject) { 8 | setTimeout(() => { 9 | throw new Error("Whoops!"); 10 | }, 1000); 11 | }).catch(alert); 12 | 13 | // Решение: нет, не выполнится. Скрытый try..catch обрабатывает только синхронный код, а ошибка генерится асинхронно. 14 | -------------------------------------------------------------------------------- /1. JavaScript Language/11.7. Microtask queue/README.md: -------------------------------------------------------------------------------- 1 | # Микрозадачи 2 | 3 | Обработчики промисов `.then`/`.catch`/`.finally` всегда асинхронны. 4 | 5 | ## Очередь микрозадач 6 | 7 | `PromiseJobs` - более известная как "очередь микрозадач". 8 | 9 | - FIFO. Первым пришел, первым ушел 10 | - Выполнение задачи происходит только в том случае, если более ничего не запущено. 11 | Задачи движок берет тогда, когда освобождается от текущего кода. 12 | 13 | В большинстве движков JS, микрозадачи тесно связаны с событийным циклом и макрозадачами. 14 | -------------------------------------------------------------------------------- /1. JavaScript Language/11.8. Async, await/src/3-return-async-function.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Вызовите async–функцию из "обычной" 3 | * 4 | * async function wait() { 5 | * await new Promise(resolve => setTimeout(resolve, 1000)); 6 | * 7 | * return 10; 8 | * } 9 | * 10 | * function f() { 11 | * // ...что здесь написать? 12 | * // чтобы вызвать wait() и дождаться результата "10" от async–функции 13 | * // не забывайте, здесь нельзя использовать "await" 14 | * } 15 | */ 16 | 17 | async function wait() { 18 | await new Promise(resolve => setTimeout(resolve, 1000)); 19 | 20 | return 10; 21 | } 22 | 23 | function f() { 24 | wait().then(res => alert(res)) 25 | } -------------------------------------------------------------------------------- /1. JavaScript Language/13.3. Dynamic imports/README.md: -------------------------------------------------------------------------------- 1 | # Динамические импорты 2 | 3 | Динамический импорт (dynamic import) используется почти также как и статический, 4 | но имеет несколько ключевых отличий: 5 | 6 | - Возвращает `Promise`, который резолвится когда загрузится модуль и все его зависимости 7 | - Хоть и выглядит как функция, но таковой не является. Не наследуется от `Function.prototype` 8 | 9 | ```js 10 | import(modulePath) 11 | .then(obj => obj /* <объект модуля> */) 12 | .catch(err => err /* <ошибка загрузки, например если нет такого модуля> */) 13 | ``` -------------------------------------------------------------------------------- /1. JavaScript Language/14.2. Eval/src/1-eval-calculator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Eval-калькулятор 3 | * важность: 4 4 | * 5 | * Создайте калькулятор, который запрашивает ввод какого-нибудь арифметического выражения и возвращает результат его вычисления. 6 | * В этой задаче нет необходимости проверять полученное выражение на корректность, просто вычислить и вернуть результат. 7 | */ 8 | 9 | // без учета атак и прочего 10 | const a = +prompt('Введите число 1') 11 | const operator = prompt('Введите оператор') 12 | const b = +prompt('Введите число 2') 13 | 14 | const result = window.eval(`a ${operator} b`) 15 | alert(result) -------------------------------------------------------------------------------- /1. JavaScript Language/14.3. Currying partials/README.md: -------------------------------------------------------------------------------- 1 | # Каррирование 2 | 3 | **Каррирование** – это трансформация функций таким образом, 4 | чтобы они принимали аргументы не как `f(a, b, c)`, а как `f(a)(b)(c)`. 5 | 6 | Функция каррирования есть в `lodash`, `_.curry(func)`. 7 | 8 | Либо же можно написать свою реализацию: 9 | 10 | ```js 11 | function curry(func) { 12 | return function curried(...args) { 13 | if (args.length >= func.length) { 14 | return func.apply(this, args); 15 | } else { 16 | return function(...args2) { 17 | return curried.apply(this, args.concat(args2)); 18 | } 19 | } 20 | }; 21 | } 22 | ``` 23 | 24 | Что касается пользы каррирования - позволяет удобно применять функцию *частично*. -------------------------------------------------------------------------------- /1. JavaScript Language/14.4. Bitwise operators/src/1-bitwise-operator-and-value.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Побитовый оператор и значение (важность: 5) 3 | * 4 | * Почему побитовые операции в примерах ниже не меняют число? Что они делают внутри? 5 | */ 6 | 7 | // Решение: это исключающее ИЛИ. 0 в битовом представлении будет представлен 32-мя нулями, соответственно число он не поменяет. 8 | alert( 123 ^ 0 ); // 123 9 | 10 | // Решение: точно то же самое, что и выше. 11 | alert( 0 ^ 123 ); // 123 12 | 13 | // Решение: это побитовое НЕ. Мы первым ~ инвертируем число и получаем -124, а вторым ~ инвертируем его обратно. 14 | alert( ~~123 ); // 123 15 | 16 | -------------------------------------------------------------------------------- /1. JavaScript Language/14.4. Bitwise operators/src/2-is-number-an-integer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Проверка, целое ли число (важность: 3) 3 | * 4 | * Напишите функцию isInteger(num), которая возвращает true, если num – целое число, иначе false. 5 | */ 6 | 7 | // Правда тут не учитываются большие числа 8 | function isInteger(num) { 9 | return (num ^ 0) === num 10 | } -------------------------------------------------------------------------------- /1. JavaScript Language/14.4. Bitwise operators/src/3-are-operations-identical.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Симметричны ли операции ^, |, &? (важность: 5) 3 | * 4 | * Верно ли, что для любых a и b выполняются равенства ниже? 5 | * Иными словами, при перемене мест – всегда ли результат останется тем же? 6 | */ 7 | 8 | /** 9 | * (a ^ b) == (b ^ a) - Да, операторы симметричны у исключающего ИЛИ 10 | * (a & b) == (b & a) - Да, операторы симметричны у побитового И 11 | * (a | b) == (b | a) - Да, операторы симметричны у побитового ИЛИ 12 | */ -------------------------------------------------------------------------------- /1. JavaScript Language/14.4. Bitwise operators/src/4-why-result-is-different.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Почему результат разный? (важность: 5) 3 | * 4 | * Почему результат второго alert'а такой странный? 5 | */ 6 | 7 | alert( 123456789 ^ 0 ); // 123456789 8 | alert( 12345678912345 ^ 0 ); // 1942903641 9 | 10 | // Решение: потому что побитовые операторы умеют работать только с числами меньше 2'147'483'647 11 | // Это наибольшее число, которое вмещает 32-битный знаковый целый тип данных 12 | // Обычно число в JavaScript имеет 64-битный формат с плавающей точкой. При этом часть 13 | // 123_456_789 < 2_147_483_647 === true 14 | // 12_345_678_912_345 < 2_147_483_647 === false -------------------------------------------------------------------------------- /1. JavaScript Language/14.6. Intl/src/1-sort-array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Отсортируйте массив с буквой ё (важность: 5) 3 | * 4 | * Используя Intl.Collator, отсортируйте массив: 5 | * В этом примере порядок сортировки не должен зависеть от регистра. 6 | * 7 | * Что касается буквы "ё", то мы следуем обычным правилам сортировки буквы ё, по которым «е» и «ё» считаются одной 8 | * и той же буквой, за исключением случая, когда два слова отличаются только в позиции буквы «е» / «ё» – 9 | * тогда слово с «е» ставится первым. 10 | */ 11 | 12 | let animals = ["тигр", "ёж", "енот", "ехидна", "АИСТ", "ЯК"]; 13 | 14 | // Решение: 15 | // По-моему проще через встроенный метод в прототип, это тот же Intl.Collator 16 | animals.sort((a, b) => a.localeCompare(b, 'ru')) 17 | 18 | alert( animals ); // АИСТ,ёж,енот,ехидна,тигр,ЯК -------------------------------------------------------------------------------- /1. JavaScript Language/2.1. Hello world/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | Document 9 | 10 | 11 | 12 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.1. Hello world/src/scripts/1-call-alert.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Покажите сообщение с помощью внешнего скрипта 3 | * 4 | * Возьмите решение предыдущей задачи. Вызвать alert, и измените его. Извлеките содержимое скрипта во внешний файл alert.js, лежащий в той же папке. 5 | * Откройте страницу, убедитесь, что оповещение работает. 6 | */ 7 | alert('Я JavaScript!') 8 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.10. If else/src/1-if-string-with-null.js: -------------------------------------------------------------------------------- 1 | /** 2 | * if (строка с нулём) (важность: 5) 3 | * 4 | * Выведется ли alert? 5 | */ 6 | 7 | if ("0") { 8 | alert( 'Привет' ); 9 | } 10 | 11 | // Решение: выведется, так как "0" - не пустая строка, соответственно truthy-значение 12 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.10. If else/src/2-javascript-name.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Название JavaScript (важность: 2) 3 | * 4 | * Используя конструкцию if..else, напишите код, который будет спрашивать: „Какое «официальное» название JavaScript?“ 5 | * Если пользователь вводит «ECMAScript», то показать: «Верно!», в противном случае – отобразить: «Не знаете? ECMAScript!» 6 | */ 7 | 8 | const answer = prompt('Какое "официальное" название JavaScript?') 9 | 10 | if (answer.toLowerCase() === 'ecmascript') { 11 | alert('Верно!') 12 | } else { 13 | alert('Не знаете? ECMAScript!') 14 | } 15 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.10. If else/src/3-show-integer-sign.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Покажите знак числа (важность: 2) 3 | * 4 | * Используя конструкцию if..else, напишите код, который получает число через prompt, а затем выводит в alert: 5 | * - '1', если значение больше нуля, 6 | * - '-1', если значение меньше нуля, 7 | * - '0', если значение равно нулю. 8 | * Предполагается, что пользователь вводит только числа. 9 | */ 10 | 11 | const number = prompt('Введите число', '') 12 | 13 | if (number > 0) { 14 | alert('Положительное число') 15 | } else if (number < 0) { 16 | alert('Отрицательное число') 17 | } else { 18 | alert('Ноль') 19 | } 20 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.10. If else/src/4-refactor-if-to-question-mark.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Перепишите 'if' в '?' (важность: 5) 3 | * 4 | * Перепишите конструкцию if с использованием условного оператора '?': 5 | */ 6 | 7 | // let result; 8 | // 9 | // if (a + b < 4) { 10 | // result = 'Мало'; 11 | // } else { 12 | // result = 'Много'; 13 | // } 14 | 15 | let result = (a + b < 4) ? 'Мало' : 'Много' 16 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.10. If else/src/5-refactor-if-to-multiple-question-mark.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Перепишите 'if..else' в '?' (важность: 5) 3 | * 4 | * Перепишите if..else с использованием нескольких операторов '?'. 5 | * Для читаемости рекомендуется разбить код на несколько строк. 6 | */ 7 | 8 | // let message; 9 | // 10 | // if (login == 'Сотрудник') { 11 | // message = 'Привет'; 12 | // } else if (login == 'Директор') { 13 | // message = 'Здравствуйте'; 14 | // } else if (login == '') { 15 | // message = 'Нет логина'; 16 | // } else { 17 | // message = ''; 18 | // } 19 | 20 | let message = 21 | (login == 'Сотрудник') ? 'Привет' 22 | : (login == 'Директор') ? 'Здравствуйте' 23 | : (login == '') ? 'Нет логина' 24 | : '' 25 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.11. Logical operators/src/1-what-will-output-alert.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Что выведет alert (ИЛИ)? (важность: 5) 3 | * 4 | * Что выведет код ниже? 5 | */ 6 | 7 | alert( null || 2 || undefined ); 8 | 9 | // Решение: 10 | // Выведет 2, так как это первое truthy-значение 11 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.11. Logical operators/src/2-what-will-output-alert.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Что выведет alert (ИЛИ)? (важность: 3) 3 | * 4 | * Что выведет код ниже? 5 | */ 6 | 7 | alert( alert(1) || 2 || alert(3) ); 8 | // Решение: 9 | // Сработает alert(1) -> вернет undefined 10 | // Затем вернет 2 в алерте 11 | // alert(3) не сработает, так как уже нашлось truthy-значение 2 12 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.11. Logical operators/src/3-what-will-output-alert.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Что выведет alert (И)? (важность: 5) 3 | * 4 | * Что выведет код ниже? 5 | */ 6 | 7 | alert( 1 && null && 2 ); 8 | // Решение: 9 | // Вернет null, так как это первое ложное значение 10 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.11. Logical operators/src/4-what-will-output-alert.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Что выведет alert (И)? (важность: 3) 3 | * 4 | * Что выведет код ниже? 5 | */ 6 | 7 | alert( alert(1) && alert(2) ); 8 | // Решение: 9 | // Так как alert возвращает undefined, то выведет сначала 1, затем `undefined` 10 | // До alert(2) выполнение не дойдет 11 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.11. Logical operators/src/5-what-will-output-alert.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Что выведет этот код? (важность: 5) 3 | * 4 | * Что выведет код ниже? 5 | */ 6 | 7 | alert( null || 2 && 3 || 4 ); 8 | // Решение: 9 | // У && выше приоритет, поэтому сначала вычислится 2 && 3, вернет 3 10 | // Затем вычислится null || 3, вернет 3, так как 3 truthy-значение 11 | // Затем сработает alert(3), до 4 дело не дойдет 12 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.11. Logical operators/src/6-check-range.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Проверка значения из диапазона (важность: 3) 3 | * 4 | * Напишите условие if для проверки, что переменная age находится в диапазоне между 14 и 90 включительно. 5 | * «Включительно» означает, что значение переменной age может быть равно 14 или 90. 6 | */ 7 | 8 | const age = 28 9 | 10 | if (age >= 14 && age <= 90) { 11 | // ... 12 | } 13 | 14 | [age >= 14, age <= 90].every(Boolean) 15 | 16 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.11. Logical operators/src/7-check-out-of-range.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Проверка значения вне диапазона (важность: 3) 3 | * 4 | * Напишите условие if для проверки, что значение переменной age НЕ находится в диапазоне 14 и 90 включительно. 5 | * Напишите два варианта: первый с использованием оператора НЕ !, второй – без этого оператора. 6 | */ 7 | 8 | const age = 28 9 | 10 | if (!(age >= 14 && age <= 90)) { 11 | // ... 12 | } 13 | 14 | if (age < 14 || age > 90) { 15 | // ... 16 | } 17 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.11. Logical operators/src/8-question-about-if.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Вопрос о "if" (важность: 5) 3 | * 4 | * Какие из перечисленных ниже alert выполнятся? 5 | * Какие конкретно значения будут результатами выражений в условиях if(...)? 6 | */ 7 | 8 | if (-1 || 0) alert( 'first' ); 9 | if (-1 && 0) alert( 'second' ); 10 | if (null || -1 && 1) alert( 'third' ); 11 | 12 | // Решение: 13 | // alert('first') выполнится, так как -1 - это truthy-значение 14 | // alert('second') не выполнится, так как 0 - это falsy-значение 15 | // alert('third') выполнится, так как сначала выполнится -1 && 1 -> вернет 1, как последнее truthy-значение 16 | // затем null || 1 -> вернет 1, так как это первое truthy-значение. 17 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.13. While and for/src/1-last-loop-value.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Последнее значение цикла (важность: 3) 3 | * 4 | * Какое последнее значение выведет этот код? Почему? 5 | */ 6 | 7 | let i = 3; 8 | 9 | while (i) { 10 | alert( i-- ); 11 | } 12 | 13 | /** 14 | * Решение: 15 | * Выведет 3, 2, 1. Последнее значение - 1 16 | * 17 | * Когда i станет 0, это falsy-значение 18 | */ 19 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.13. While and for/src/2-what-values-will-output-while.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Какие значения выведет цикл while? (важность: 4) 3 | * 4 | * Для каждого цикла запишите, какие значения он выведет. Потом сравните с ответом. 5 | * Оба цикла выводят alert с одинаковыми значениями или нет? 6 | */ 7 | 8 | // 1. Префиксный вариант ++i: 9 | 10 | let i = 0; 11 | while (++i < 5) alert( i ); 12 | 13 | // 2. Постфиксный вариант i++ 14 | 15 | let j = 0; 16 | while (j++ < 5) alert( j ); 17 | 18 | /** 19 | * Решение: 20 | * 1-ый цикл начнет итерироваться с единицы, выведет 1,2,3,4 21 | * 2-ой цикл выведет 1,2,3,4,5 22 | */ 23 | 24 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.13. While and for/src/3-what-values-will-output-for.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Какие значения выведет цикл for? (важность: 4) 3 | * 4 | * Для каждого цикла запишите, какие значения он выведет. Потом сравните с ответом. 5 | * Оба цикла выведут alert с одинаковыми значениями или нет? 6 | */ 7 | 8 | // 1. Постфиксная форма 9 | for (let i = 0; i < 5; i++) alert( i ); 10 | 11 | // 2. Префиксная форма 12 | for (let i = 0; i < 5; ++i) alert( i ); 13 | 14 | /** 15 | * Решение: 16 | * 17 | * В обоих вариантах от 0 до 4, так как шаг выполняется после тела цикла и перед следующим условием. 18 | * Соответственно уже в условие попадут одинаковые индексы i, разницы нет 19 | */ 20 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.13. While and for/src/4-output-even-numbers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Выведите чётные числа (важность: 5) 3 | * 4 | * При помощи цикла for выведите чётные числа от 2 до 10. 5 | */ 6 | 7 | for (let i = 2; i <= 10; i += 2) alert(i) 8 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.13. While and for/src/5-replace-for-loop-on-while.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Замените for на while (важность: 5) 3 | * 4 | * Перепишите код, заменив цикл for на while, без изменения поведения цикла. 5 | */ 6 | 7 | for (let i = 0; i < 3; i++) { 8 | alert( `number ${i}!` ); 9 | } 10 | 11 | // Решение: 12 | let i = 0 13 | while (i < 3) { 14 | alert( `number ${i}!` ) 15 | i++ 16 | } 17 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.13. While and for/src/6-repeat-loop-while-input-wrong.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Повторять цикл, пока ввод неверен (важность: 5) 3 | * 4 | * Напишите цикл, который предлагает prompt ввести число, большее 100. Если посетитель ввёл другое число – попросить ввести ещё раз, и так далее. 5 | * Цикл должен спрашивать число пока либо посетитель не введёт число, большее 100, либо не нажмёт кнопку Отмена (ESC). 6 | * Предполагается, что посетитель вводит только числа. Предусматривать обработку нечисловых строк в этой задаче необязательно. 7 | */ 8 | 9 | let input 10 | do { 11 | input = +prompt('Введите число больше 100') || 0 12 | } while (input <= 100) 13 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.13. While and for/src/7-output-prime-numbers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Вывести простые числа (важность: 3) 3 | * 4 | * Натуральное число, большее 1, называется простым, если оно ни на что не делится, кроме себя и 1. 5 | * Другими словами, n > 1 – простое, если при его делении на любое число кроме 1 и n есть остаток. 6 | * Например, 5 это простое число, оно не может быть разделено без остатка на 2, 3 и 4. 7 | * Напишите код, который выводит все простые числа из интервала от 2 до n. 8 | * Для n = 10 результат должен быть 2,3,5,7. 9 | * P.S. Код также должен легко модифицироваться для любых других интервалов. 10 | */ 11 | 12 | const FROM = 2 13 | const TO = 15 14 | 15 | outer: for (let i = FROM; i <= TO; i++) { 16 | inner: for (let j = 2; j < i ** 1/2; j++) { 17 | if (i % j === 0) continue outer 18 | } 19 | 20 | alert(i) 21 | } 22 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.14. Switch/src/1-refactor-if-to-switch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Переписать условия "if" на "switch" (важность: 4) 3 | * 4 | * Перепишите код с использованием одной конструкции switch: 5 | */ 6 | 7 | const number = +prompt('Введите число между 0 и 3', ''); 8 | 9 | // if (number === 0) { 10 | // alert('Вы ввели число 0'); 11 | // } 12 | // 13 | // if (number === 1) { 14 | // alert('Вы ввели число 1'); 15 | // } 16 | // 17 | // if (number === 2 || number === 3) { 18 | // alert('Вы ввели число 2, а может и 3'); 19 | // } 20 | 21 | // Решение: 22 | 23 | switch (number) { 24 | case 0: 25 | alert('Вы ввели число 0') 26 | break 27 | case 1: 28 | alert('Вы ввели число 1') 29 | break 30 | case 2: 31 | case 3: 32 | alert('Вы ввели число 2, а может и 3') 33 | break 34 | } 35 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.15. Functions basics/src/1-do-you-need-else.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Обязателен ли "else"? (важность: 4) 3 | * 4 | * Следующая функция возвращает true, если параметр age больше 18. 5 | * В ином случае она запрашивает подтверждение через confirm и возвращает его результат: 6 | */ 7 | function checkAge(age) { 8 | if (age > 18) { 9 | return true; 10 | } else { 11 | // ... 12 | return confirm('Родители разрешили?'); 13 | } 14 | } 15 | /** 16 | * Будет ли эта функция работать как-то иначе, если убрать else? 17 | */ 18 | function checkAge(age) { 19 | if (age > 18) { 20 | return true; 21 | } 22 | // ... 23 | return confirm('Родители разрешили?'); 24 | } 25 | 26 | /** 27 | * Решение: Нет, отличий нет. return прерывает функцию, поэтому если первый if сработает - функция не продолжится. 28 | */ 29 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.15. Functions basics/src/2-refactor-function-using-operators.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Перепишите функцию, используя оператор '?' или '||' (важность: 4) 3 | * 4 | * Следующая функция возвращает true, если параметр age больше 18. 5 | * В ином случае она задаёт вопрос confirm и возвращает его результат. 6 | */ 7 | 8 | function checkAge(age) { 9 | if (age > 18) { 10 | return true; 11 | } else { 12 | return confirm('Родители разрешили?'); 13 | } 14 | } 15 | 16 | /** 17 | * Перепишите функцию, чтобы она делала то же самое, но без if, в одну строку. 18 | * 19 | * Сделайте два варианта функции checkAge: 20 | * 21 | * Используя оператор ? 22 | * Используя оператор || 23 | */ 24 | 25 | function checkAge(age) { 26 | return (age > 18) ? true : confirm('Родители разрешили?') 27 | } 28 | 29 | function checkAge(age) { 30 | return (age > 18) || confirm('Родители разрешили?') 31 | } 32 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.15. Functions basics/src/3-function-min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Функция min(a, b) (важность: 1) 3 | * 4 | * Напишите функцию min(a,b), которая возвращает меньшее из чисел a и b. 5 | * Пример вызовов: 6 | */ 7 | 8 | function min(a, b) { 9 | if (a < b) return a 10 | if (b <= a) return b 11 | } 12 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.15. Functions basics/src/4-function-pow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Функция pow(x,n) (важность: 4) 3 | * 4 | * Напишите функцию pow(x,n), которая возвращает x в степени n. Иначе говоря, умножает x на себя n раз и возвращает результат. 5 | */ 6 | 7 | // Решение: 8 | function pow(x, n) { 9 | return x ** n 10 | } 11 | 12 | /** 13 | * Создайте страницу, которая запрашивает x и n, а затем выводит результат pow(x,n). 14 | */ 15 | 16 | /** 17 | * Решение: 18 | */ 19 | function askInteger(message) { 20 | let input 21 | do { 22 | input = prompt(message, '') 23 | } while (!Number.isInteger(+input) || +input < 1) 24 | 25 | return input 26 | } 27 | 28 | const x = askInteger('Введите целое число') 29 | const n = askInteger('Введите степень, в которую необходимо возвести число') 30 | 31 | alert(pow(x, n)) 32 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.17. Arrow functions/src/1-refactor-function-expression-to-arrow-function.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Перепишите с использованием функции-стрелки 3 | * 4 | * Замените код Function Expression стрелочной функцией: 5 | */ 6 | 7 | function ask(question, yes, no) { 8 | if (confirm(question)) yes() 9 | else no(); 10 | } 11 | 12 | ask( 13 | "Вы согласны?", 14 | function() { alert("Вы согласились."); }, 15 | function() { alert("Вы отменили выполнение."); } 16 | ); 17 | 18 | // Решение: 19 | 20 | ask( 21 | 'Вы согласны?', 22 | () => alert('Вы согласились.'), 23 | () => alert('Вы отменили выполнение.'), 24 | ) 25 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.18. JavaScript specials/README.md: -------------------------------------------------------------------------------- 1 | # Особенности JavaScript 2 | 3 | - [Rules of automatic semicolon insertion](https://262.ecma-international.org/7.0/#sec-rules-of-automatic-semicolon-insertion) 4 | - [Use strict](https://tc39.es/ecma262/#sec-directive-prologues-and-the-use-strict-directive) 5 | - [MDN приоритет операторов](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Operator_Precedence) 6 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.2. Code structure/README.md: -------------------------------------------------------------------------------- 1 | # Структура кода 2 | 3 | ## Инструкции 4 | 5 | Инструкция - это синтаксическая конструкция или команда, которая выполняет некое действие. 6 | Например `alert('Привет, мир!')` - это инструкция. 7 | 8 | ## Точка с запятой 9 | 10 | Для разделения инструкций используется `;` - точка с запятой. 11 | 12 | Либо же новая строка, тогда движок пользуется правилами 13 | [автоматической вставки точки с запятой](https://tc39.es/ecma262/#sec-automatic-semicolon-insertion) 14 | описанной в спецификации ECMA-262 15 | 16 | ## Комментарии 17 | 18 | JS поддерживает два вида комментариев 19 | 20 | - Однострочные комментарии 21 | ```js 22 | // Я комментарий 23 | ``` 24 | - Многострочные комментарии 25 | ```js 26 | /* 27 | Я комментарий 28 | Многострочный 29 | */ 30 | ``` 31 | 32 | Многострочные комментарии используются в [JSDoc](https://jsdoc.app/) при описании документации к коду. 33 | 34 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.4. Variables/src/1-work-with-variables.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Работа с переменными (важность: 2) 3 | * 4 | * 1. Объявите две переменные: admin и name. 5 | * 2. Запишите строку "Джон" в переменную name. 6 | * 3. Скопируйте значение из переменной name в admin. 7 | * 4. Выведите на экран значение admin, используя функцию alert (должна показать «Джон»). 8 | */ 9 | 10 | let admin 11 | let name 12 | 13 | name = 'Джон' 14 | admin = name 15 | 16 | alert(admin) 17 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.4. Variables/src/2-come-up-with-correct-names.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Придумайте правильные имена (важность: 3) 3 | * 4 | * 1. Создайте переменную для названия нашей планеты. Как бы вы её назвали? 5 | * 2. Создайте переменную для хранения имени текущего посетителя сайта. Как бы вы назвали такую переменную? 6 | */ 7 | 8 | // 1. 9 | let ourPlanetName = 'Earth' 10 | 11 | // 2. 12 | let currentVisitorName = 'John' 13 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.4. Variables/src/3-constants-naming-uppercase-or-lowercase.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Какие буквы (заглавные или строчные) использовать для имён констант? (важность: 4) 3 | * 4 | * Можно ли использовать заглавные буквы для имени birthday? А для age? Или одновременно для обеих переменных? 5 | */ 6 | 7 | const someCode = date => new Date(date) 8 | 9 | const BIRTHDAY_DATE = '18.04.1982'; // Заранее известное значение, можно использовать заглавные буквы 10 | const age = someCode(BIRTHDAY_DATE); // вычисляется в рантайме, только camelCase 11 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.5. Types/src/1-template-literals.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Шаблонные строки 3 | * 4 | * Что выведет этот скрипт? 5 | */ 6 | 7 | let name = "Ilya"; 8 | 9 | alert( `hello ${1}` ); // hello 1 10 | 11 | alert( `hello ${"name"}` ); // hello name 12 | 13 | alert( `hello ${name}` ); // hello Ilya 14 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.6. Alert, prompt, confirm/README.md: -------------------------------------------------------------------------------- 1 | # Взаимодействие: alert, prompt, confirm 2 | 3 | - `alert` 4 | - Показывает сообщение и ждет пока пользователь нажмет "ОК" 5 | - Возвращает `undefined` 6 | - `prompt` 7 | - Отображает модальное окно с текстом и полем для ввода 8 | - Возвращает `string`, текст введенный в поле пользователем или `null` если ввод отменен 9 | - Для IE следует указывать значение по-умолчанию 10 | - `confirm` 11 | - Отображает модальное окно с текстом и двумя кнопками "ОК" и "Отмена". 12 | - Возвращает `boolean` 13 | 14 | Данные методы являются "модальными" и останавливают работу скрипта, а также не позволяют пользователю 15 | взаимодействовать с остальной частью страницы. 16 | 17 | Также данные окна нельзя кастомизировать. 18 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.6. Alert, prompt, confirm/src/1-simple-page.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Простая страница (важность: 4) 3 | * 4 | * Создайте страницу, которая спрашивает имя у пользователя и выводит его. 5 | */ 6 | 7 | let name 8 | 9 | while (!name) { 10 | name = prompt('Введите имя') 11 | } 12 | 13 | alert(`Привет, ${name}`) 14 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.8. Operators/src/1-postfix-and-prefix-forms.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Постфиксная и префиксная формы (важность: 5) 3 | * 4 | * Чему будут равны переменные a, b, c и d в примере ниже? 5 | */ 6 | 7 | let a = 1, b = 1; 8 | 9 | let c = ++a; 10 | let d = b++; 11 | 12 | // a === 2 13 | // b === 2 14 | // c === 2 15 | // d === 1 16 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.8. Operators/src/2-assignment-result.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Результат присваивания (важность: 3) 3 | * 4 | * Чему будут равны переменные a и x после исполнения кода в примере ниже? 5 | */ 6 | 7 | let a = 2; 8 | 9 | let x = 1 + (a *= 2); 10 | 11 | // a === 4 12 | // x === 5 13 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.8. Operators/src/3-type-conversions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Преобразование типов (важность: 5) 3 | * 4 | * Какой результат будет у выражений ниже? 5 | */ 6 | 7 | "" + 1 + 0 // '10' 8 | "" - 1 + 0 // -1 9 | true + false // 1 10 | 6 / "3" // 2 11 | "2" * "3" // 6 12 | 4 + 5 + "px" // '9px' 13 | "$" + 4 + 5 // '$45' 14 | "4" - 2 // 2 15 | "4px" - 2 // NaN 16 | 7 / 0 // Infinity 17 | " -9 " + 5 // ' -9 5' 18 | " -9 " - 5 // -14 19 | null + 1 // 1 20 | undefined + 1 // NaN 21 | " \t \n" - 2 // -2 22 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.8. Operators/src/4-fix-addition.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Исправьте сложение (важность: 5) 3 | * 4 | * Ниже приведён код, который запрашивает у пользователя два числа и показывает их сумму. 5 | * Он работает неправильно. Код в примере выводит 12 (для значения полей по умолчанию). 6 | * В чём ошибка? Исправьте её. Результат должен быть 3. 7 | */ 8 | 9 | let a = prompt("Первое число?", '1'); 10 | let b = prompt("Второе число?", '2'); 11 | 12 | alert(a + b); // 12 13 | 14 | // Решение: 15 | alert(+a + +b) // 12 16 | -------------------------------------------------------------------------------- /1. JavaScript Language/2.9. Comparison/src/1-comparison-operators.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Операторы сравнения (важность: 5) 3 | * 4 | * Каким будет результат этих выражений? 5 | */ 6 | 7 | 5 > 4 // true 8 | "ананас" > "яблоко" // false 9 | "2" > "12" // true 10 | undefined == null // true 11 | undefined === null // false 12 | null == "\n0\n" // false 13 | null === +"\n0\n" // false 14 | -------------------------------------------------------------------------------- /1. JavaScript Language/3.2. Coding style/src/1-bad-style.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Плохой стиль (важность: 4) 3 | * 4 | * Какие недостатки вы видите в стиле написания кода этого примера? 5 | */ 6 | 7 | function pow(x,n) 8 | { 9 | let result=1; 10 | for(let i=0;i { 4 | it(`should return true if object doesn't have any keys`, () => { 5 | const mock = {} 6 | const result = isEmpty(mock) 7 | 8 | expect(result).toBe(true) 9 | }) 10 | 11 | it(`should return false if object have one key`, () => { 12 | const mock = { a: 1 } 13 | const result = isEmpty(mock) 14 | 15 | expect(result).toBe(false) 16 | }) 17 | 18 | it('should return false if object have more than one key', () => { 19 | const mock = { a: 1, b: {}, c: '' } 20 | const result = isEmpty(mock) 21 | 22 | expect(result).toBe(false) 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /1. JavaScript Language/4.1. Object/src/3-objects-constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Объекты-константы? (важность: 5) 3 | * 4 | * Можно ли изменить объект, объявленный с помощью const? Как вы думаете? 5 | */ 6 | 7 | const user = { 8 | name: "John" 9 | }; 10 | 11 | // это будет работать? 12 | user.name = "Pete"; 13 | 14 | // Решение: 15 | // Будет, так как сама переменная user не изменяется. Переменная user хранится в стеке, const смотрит именно на то, что 16 | // не меняется ли значение переменной в стеке. В переменной user хранится ссылка на объект в куче (Memory heap). 17 | // А мы изменяем значение свойства объекта, который хранится в куче. 18 | // 19 | // В общем - это будет работать. 20 | -------------------------------------------------------------------------------- /1. JavaScript Language/4.1. Object/src/4-sum-object-values.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Сумма свойств объекта (важность: 5) 3 | * 4 | * У нас есть объект, в котором хранятся зарплаты нашей команды: 5 | * Напишите код для суммирования всех зарплат и сохраните результат в переменной sum. 6 | */ 7 | 8 | function getObjectValuesSum(obj) { 9 | let result = 0 10 | for (let key in obj) { 11 | const value = obj[key] 12 | if (typeof value === 'number') result += value 13 | } 14 | 15 | return result 16 | } 17 | 18 | module.exports = getObjectValuesSum 19 | -------------------------------------------------------------------------------- /1. JavaScript Language/4.1. Object/src/5-multiply-all-numeric-object-values.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Умножаем все числовые свойства на 2 (важность: 3) 3 | * 4 | * Создайте функцию multiplyNumeric(obj), которая умножает все числовые свойства объекта obj на 2. 5 | */ 6 | 7 | function multiplyNumeric(obj) { 8 | const MULTIPLIER = 2 9 | 10 | for (let key in obj) { 11 | if (typeof obj[key] === 'number') obj[key] *= MULTIPLIER 12 | } 13 | } 14 | 15 | module.exports = multiplyNumeric 16 | -------------------------------------------------------------------------------- /1. JavaScript Language/4.2. Object copy/README.md: -------------------------------------------------------------------------------- 1 | # Копирование объектов и ссылки 2 | 3 | Примитивные типы: строки, числа, логические значения - присваиваются и копируются "по значению". 4 | 5 | Объекты ведут себя иначе. Они хранят не значение, а ссылку на объект. 6 | 7 | ## Сравнение по ссылке 8 | 9 | Два объекта равны только в том случае, если у них совпадает ссылка. 10 | Т.е они ссылаются на один и тот же объект. 11 | 12 | ## Копирование и объединение объектов 13 | 14 | - Можно через `Object.assign` 15 | - Можно через `spread syntax (...)` 16 | 17 | Важно понимать, что это не глубокое копирование. 18 | 19 | Если надо глубокое - либо взять из лодаша функцию, либо написать свою. 20 | 21 | Еще есть хак с `JSON.parse(JSON.stringify(variable_name))` - но он потеряет прототип и методы. 22 | -------------------------------------------------------------------------------- /1. JavaScript Language/4.4. This/src/1-check-syntax.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Проверка синтаксиса (важность: 2) 3 | * 4 | * Каким будет результат выполнения этого кода? 5 | */ 6 | 7 | let user = { 8 | name: "Джон", 9 | go: function() { alert(this.name) } 10 | } 11 | 12 | (user.go)() 13 | 14 | // Решение: будет ошибка, так как нет точки с запятой после объявления user 15 | -------------------------------------------------------------------------------- /1. JavaScript Language/4.4. This/src/2-explain-this-value.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Объясните значение "this" (важность: 3) 3 | * 4 | * В представленном ниже коде мы намерены вызвать obj.go() метод 4 раза подряд. 5 | * Но вызовы (1) и (2) работают иначе, чем (3) и (4) . Почему? 6 | */ 7 | 8 | let obj, method; 9 | obj = { 10 | go: function() { alert(this); } 11 | }; 12 | obj.go(); // (1) [object Object] 13 | (obj.go)(); // (2) [object Object] 14 | (method = obj.go)(); // (3) undefined 15 | (obj.go || obj.stop)(); // (4) undefined 16 | 17 | // Решение: 18 | // 1 и 2 - вызывается значение ссылочного типа 19 | // 3 и 4 - значение ссылочного типа заменяется на функцию 20 | 21 | // В ответе: 22 | // любая другая операция (подобно операции 23 | // присваивания = или сравнения через логические операторы, например || ) 24 | // превращает это значение в обычное, которое не несёт информации, позволяющей 25 | // установить this 26 | -------------------------------------------------------------------------------- /1. JavaScript Language/4.4. This/src/3-using-this-in-object-literal.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Использование "this" в литерале объекта (важность: 5) 3 | * 4 | * Здесь функция makeUser возвращает объект. 5 | * Каким будет результат при обращении к свойству объекта ref ? Почему? 6 | */ 7 | 8 | function makeUser() { 9 | return { 10 | name: "Джон", 11 | ref: this 12 | }; 13 | } 14 | 15 | let user = makeUser(); 16 | alert( user.ref.name ); // Каким будет результат? 17 | 18 | // Решение: 19 | // Так как важен только момент вызова метода, то метод тут вызывается не в контексте какого-то объекта. 20 | // Соответственно this == undefined 21 | -------------------------------------------------------------------------------- /1. JavaScript Language/4.4. This/src/4-create-calculator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Создайте калькулятор (важность: 5) 3 | * 4 | * Создайте объект calculator (калькулятор) с тремя методами: 5 | * read() (читать) запрашивает два значения и сохраняет их как свойства объекта. 6 | * sum() (суммировать) возвращает сумму сохранённых значений. 7 | * mul() (умножить) перемножает сохранённые значения и возвращает результат. 8 | */ 9 | 10 | const calculator = { 11 | _firstvalue: null, 12 | _secondvalue: null, 13 | read() { 14 | this._firstvalue = +prompt('Введите первое значение', 0) 15 | this._secondvalue = +prompt('Введите второе значение', 0) 16 | }, 17 | sum() { 18 | return this._firstvalue + this._secondvalue 19 | }, 20 | mul() { 21 | return this._firstvalue * this._secondvalue 22 | } 23 | } 24 | 25 | calculator.read() 26 | alert( calculator.sum() ); 27 | alert( calculator.mul() ); 28 | -------------------------------------------------------------------------------- /1. JavaScript Language/4.5. Constructor, new/src/1-two-functions-one-object.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Две функции - один объект (важность: 2) 3 | * 4 | * Возможно ли создать функции A и B в примере ниже, где объекты равны new A()==new B()? 5 | */ 6 | 7 | /** 8 | * function A() { ... } 9 | * function B() { ... } 10 | * 11 | * let a = new A; 12 | * let b = new B; 13 | * 14 | * alert( a == b ); // true 15 | */ 16 | 17 | // Решение: 18 | 19 | const someObj = {} 20 | 21 | function A() { 22 | return someObj 23 | } 24 | 25 | function B() { 26 | return someObj 27 | } 28 | 29 | let a = new A() 30 | let b = new B() 31 | 32 | console.log(a === b) 33 | -------------------------------------------------------------------------------- /1. JavaScript Language/4.6. Optional chaining/README.md: -------------------------------------------------------------------------------- 1 | # Опциональная цепочка 2 | 3 | Опциональная цепочка `?.` останавливает вычисление и возвращает `undefined`, 4 | если часть перед `?.` имеет значение `undefined` или `null`. 5 | 6 | ## Другие варианты применения 7 | 8 | - С вычисляемыми свойствами объекта `?.[]` 9 | - С методами объекта `?.()` 10 | 11 | По сути - это просто безопасный способ доступа к свойствам вложенных объектов. Т.е он вернет и приостановит вычисление 12 | если левая - это `undefined` 13 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.1. Primitives methods/src/1-can-you-add-property-to-string.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Можно ли добавить свойство строке? (важность: 5) 3 | * 4 | * Взгляните на следующий код: 5 | */ 6 | 7 | let str = "Привет"; 8 | 9 | str.test = 5; 10 | 11 | alert(str.test); 12 | 13 | // Решение: на экран выведется undefined, конкретно строке нельзя добавить свойство 14 | // Можно добавить прототипу String это свойство, но тогда оно появится у всех свойств 15 | // Строка присвоения ошибки не вызовет, но просто проигнорирует это 16 | 17 | // Решение портала: 18 | // Также в режиме `use strict` строка с присвоением выбросит ошибку 19 | // Без строгого режима - создается обертка - добавляется свойство - обертка удаляется - str больше не имеет доступа к test 20 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.10. Destructuring assignment/src/1-destructuring-assignment.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Деструктурирующее присваивание (важность: 5) 3 | * 4 | * let user = { 5 | * name: "John", 6 | * years: 30 7 | * }; 8 | * 9 | * Напишите деструктурирующее присваивание, которое: 10 | * 11 | * свойство name присвоит в переменную name. 12 | * свойство years присвоит в переменную age. 13 | * свойство isAdmin присвоит в переменную isAdmin (false, если нет такого свойства) 14 | * Пример переменных после вашего присваивания: 15 | */ 16 | 17 | let user = { name: "John", years: 30 }; 18 | 19 | let { name, years: age, isAdmin = false } = user 20 | // ваш код должен быть с левой стороны: 21 | // ... = user 22 | 23 | alert( name ); // John 24 | alert( age ); // 30 25 | alert( isAdmin ); // false 26 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.10. Destructuring assignment/src/2-max-salary.js: -------------------------------------------------------------------------------- 1 | /** 2 | * У нас есть объект salaries с зарплатами: 3 | * 4 | * Создайте функцию topSalary(salaries), которая возвращает имя самого высокооплачиваемого сотрудника. 5 | * 6 | * Если объект salaries пустой, то нужно вернуть null. 7 | * Если несколько высокооплачиваемых сотрудников, можно вернуть любого из них. 8 | * P.S. Используйте Object.entries и деструктурирование, чтобы перебрать пары ключ/значение. 9 | */ 10 | 11 | let salaries = { 12 | "John": 100, 13 | "Pete": 300, 14 | "Mary": 250 15 | }; 16 | 17 | function topSalary(salaries) { 18 | return Object.entries(salaries).reduce((prev, cur) => { 19 | const [prevName, prevSalary] = prev 20 | const [curName, curSalary] = cur 21 | 22 | if (prev === null) return [curName, curSalary] 23 | 24 | return curSalary >= prevSalary ? cur : prev 25 | }, null) 26 | } 27 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.11. Date/src/1-create-date.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Создайте дату (важность: 5) 3 | * 4 | * Создайте объект Date для даты: 20 февраля 2012 года, 3 часа 12 минут. Временная зона – местная. 5 | * Для вывода используйте alert. 6 | */ 7 | 8 | const date = new Date(2012, 1, 20, 3, 12) 9 | 10 | alert(date) 11 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.11. Date/src/2-show-week-day.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Покажите день недели (важность: 5) 3 | * 4 | * Напишите функцию getWeekDay(date), показывающую день недели в коротком формате: «ПН», «ВТ», «СР», «ЧТ», «ПТ», «СБ», «ВС». 5 | * Например: 6 | */ 7 | 8 | function getWeekDay(date) { 9 | const weekDay = ['ВС', 'ПН', 'ВТ', 'СР', 'ЧТ', 'ПТ', 'СБ'] 10 | 11 | return weekDay[date.getDay()] 12 | } 13 | 14 | let date = new Date(2012, 0, 3); // 3 января 2012 года 15 | alert( getWeekDay(date) ); 16 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.11. Date/src/3-week-day-euro.js: -------------------------------------------------------------------------------- 1 | /** 2 | * День недели в европейской нумерации (важность: 5) 3 | * 4 | * В Европейских странах неделя начинается с понедельника (день номер 1), затем идёт вторник (номер 2) и так 5 | * до воскресенья (номер 7). Напишите функцию getLocalDay(date), которая возвращает «европейский» день недели для даты date. 6 | */ 7 | 8 | function getLocalDay(date) { 9 | const day = date.getDay() 10 | 11 | return day === 0 ? 7 : day 12 | } 13 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.11. Date/src/4-get-date-ago.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Какой день месяца был много дней назад? (важность: 4) 3 | * 4 | * Создайте функцию getDateAgo(date, days), возвращающую число, которое было days дней назад от даты date. 5 | * К примеру, если сегодня двадцатое число, то getDateAgo(new Date(), 1) вернёт девятнадцатое и getDateAgo(new Date(), 2) – восемнадцатое. 6 | * Функция должна надёжно работать при значении days=365 и больших значениях: 7 | */ 8 | 9 | function getDateAgo(date, days) { 10 | const newDate = new Date(date.getTime()) 11 | newDate.setDate(date.getDate() - days) 12 | 13 | return newDate.getDate() 14 | } 15 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.11. Date/src/5-last-day.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Последнее число месяца? (важность: 5) 3 | * 4 | * Напишите функцию getLastDayOfMonth(year, month), возвращающую последнее число месяца. Иногда это 30, 31 или даже февральские 28/29. 5 | * 6 | * Параметры: 7 | * 8 | * year – год из четырёх цифр, например, 2012. 9 | * month – месяц от 0 до 11. 10 | * К примеру, getLastDayOfMonth(2012, 1) = 29 (високосный год, февраль). 11 | */ 12 | 13 | function getLastDayOfMonth(year, month) { 14 | return new Date(year, month, -1).getDate() 15 | } 16 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.11. Date/src/6-get-seconds-today.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Сколько сегодня прошло секунд? 3 | * 4 | * Напишите функцию getSecondsToday(), возвращающую количество секунд с начала сегодняшнего дня. 5 | * Например, если сейчас 10:00, и не было перехода на зимнее/летнее время, то: 6 | * 7 | * getSecondsToday() == 36000 // (3600 * 10) 8 | * 9 | * Функция должна работать в любой день, т.е. в ней не должно быть конкретного значения сегодняшней даты. 10 | */ 11 | 12 | function getSecondsToday() { 13 | const today = new Date() 14 | const hours = today.getHours() 15 | const minutes = today.getMinutes() 16 | const seconds = today.getSeconds() 17 | 18 | return (hours * 60 * 60) + (minutes * 60) + seconds 19 | } 20 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.11. Date/src/7-get-seconds-to-tomorrow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Сколько секунд осталось до завтра? (важность: 5) 3 | * 4 | * Создайте функцию getSecondsToTomorrow(), возвращающую количество секунд до завтрашней даты. 5 | * 6 | * Например, если сейчас 23:00, то: 7 | * 8 | * P.S. Функция должна работать в любой день, т.е. в ней не должно быть конкретного значения сегодняшней даты. 9 | */ 10 | 11 | function getSecondsToTomorrow() { 12 | const today = new Date() 13 | const nextDay = new Date() 14 | nextDay.setHours(0) 15 | nextDay.setMinutes(0) 16 | nextDay.setSeconds(0) 17 | nextDay.setDate(nextDay.getDate() + 1) 18 | 19 | return (nextDay - today) / 1000 20 | } 21 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.12. JSON/README.md: -------------------------------------------------------------------------------- 1 | # Формат JSON, Метод toJSON 2 | 3 | **JSON (JavaScript Object Notation)** – это общий формат для представления значений и объектов. 4 | 5 | JavaScript предоставляет методы: 6 | 7 | - `JSON.stringify` для преобразования объектов в `JSON`. 8 | - Принимает вторым аргументом массив ключей, которые должны присутствовать. Или функцию для фильтрации ключей 9 | - Принимает третьим аргументом `space` отступы в документе. 10 | - `JSON.parse` для преобразования `JSON` обратно в объект. 11 | - Принимает вторым аргументом `reviver`, позволяет трансформировать значения некоторых ключей 12 | 13 | Если объект имеет метод `toJSON`, то он вызывается через JSON.stringify. 14 | 15 | Можно имплементировать такой метод самостоятельно. 16 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.12. JSON/src/1-stringify-and-parse.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Преобразуйте объект в JSON, а затем обратно в обычный объект (важность: 5) 3 | */ 4 | 5 | let user = { 6 | name: "Василий Иванович", 7 | age: 35 8 | }; 9 | 10 | const json = JSON.stringify(user) 11 | const parsedJson = JSON.parse(json) 12 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.2. Number/src/1-sum-user-input.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Сумма пользовательских чисел 3 | * 4 | * Создайте скрипт, который запрашивает ввод двух чисел (используйте prompt) и после показывает их сумму. 5 | * P.S. Есть «подводный камень» при работе с типами. 6 | */ 7 | 8 | const num1 = prompt('Введите первое число', '0') 9 | const num2 = prompt('Введите второе число', '0') 10 | 11 | if (isFinite(+num1) && isFinite(+num2)) { 12 | const sum = +num1 + +num2 13 | alert(+sum.toFixed(6)) 14 | } else { 15 | alert('Неправильный ввод!') 16 | } 17 | 18 | 19 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.2. Number/src/2-to-fixed-problem.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Почему 6.35.toFixed(1) == 6.3? (важность: 4) 3 | * 4 | * Методы Math.round и toFixed, согласно документации, 5 | * округляют до ближайшего целого числа: 0..4 округляется в меньшую сторону, тогда как 5..9 в большую сторону. 6 | * 7 | * 8 | */ 9 | 10 | alert( 1.35.toFixed(1) ); // 1.4 11 | alert( 6.35.toFixed(1) ); // 6.3 12 | 13 | // Решение: можно добавить 0.01 к числу, затем применить toFixed 14 | // Проблема скорее всего из-за потери точности у числа 15 | 16 | // Решение с портала: 17 | // Да, дело в потере точности 18 | // Проверить можно через .toFixed(20) 19 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.2. Number/src/3-prompt-number.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ввод числового значения (важность: 5) 3 | * 4 | * Создайте функцию readNumber, которая будет запрашивать ввод числового значения до тех пор, пока посетитель его не введёт. 5 | * 6 | * Функция должна возвращать числовое значение. 7 | * 8 | * Также надо разрешить пользователю остановить процесс ввода, отправив пустую строку или нажав «Отмена». В этом случае функция должна вернуть null. 9 | */ 10 | 11 | function readNumber() { 12 | let input 13 | 14 | while (true) { 15 | input = prompt('Введите число', '') 16 | 17 | if (input === '') break 18 | if (input === null) break 19 | if (isFinite(input)) break 20 | } 21 | 22 | return Boolean(input) ? +input : null 23 | } 24 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.2. Number/src/4-infinite-loop.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Бесконечный цикл по ошибке (важность: 4) 3 | * 4 | * Этот цикл – бесконечный. Он никогда не завершится, почему? 5 | */ 6 | 7 | let i = 0; 8 | while (i != 10) { 9 | i += 0.2; 10 | } 11 | 12 | // Решение: потому что опять потеря точности 13 | // Исправить можно так: 14 | 15 | while(+i.toFixed(1) !== 10) { 16 | i += 0.2 17 | console.log(i) 18 | } 19 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.2. Number/src/5-random-number.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Случайное число от min до max (важность: 2) 3 | * 4 | * Встроенный метод Math.random() возвращает случайное число от 0 (включительно) до 1 (но не включая 1) 5 | * Напишите функцию random(min, max), которая генерирует случайное число с плавающей точкой от min до max (но не включая max). 6 | * Пример работы функции: 7 | */ 8 | 9 | function random(min ,max) { 10 | return min + Math.random() * (max - min) 11 | } 12 | 13 | alert( random(1, 5) ); // 1.2345623452 14 | alert( random(1, 5) ); // 3.7894332423 15 | alert( random(1, 5) ); // 4.3435234525 16 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.2. Number/src/6-random.integer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Случайное целое число от min до max (важность: 2) 3 | * 4 | * Напишите функцию randomInteger(min, max), которая генерирует случайное целое (integer) число от min до max (включительно). 5 | * Любое число из интервала min..max должно появляться с одинаковой вероятностью. 6 | * Пример работы функции: 7 | */ 8 | 9 | function randomInteger(min ,max) { 10 | return Math.floor(min + Math.random() * (max + 1 - min)) 11 | } 12 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.3. String/src/1-capitalize.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Сделать первый символ заглавным (важность: 5) 3 | * 4 | * Напишите функцию ucFirst(str), возвращающую строку str с заглавным первым символом. Например: 5 | */ 6 | 7 | function ucFirst(str) { 8 | return str.length > 1 9 | ? str[0].toUpperCase() + str.slice(1) 10 | : '' 11 | } 12 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.3. String/src/2-check-spam.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Проверка на спам (важность: 5) 3 | * 4 | * Напишите функцию checkSpam(str), возвращающую true, если str содержит 'viagra' или 'XXX', а иначе false. 5 | * Функция должна быть нечувствительна к регистру: 6 | */ 7 | 8 | function checkSpam(str) { 9 | const bannedWords = ['viagra', 'xxx'] 10 | 11 | return bannedWords.some(bannedWord => (str || '').toLowerCase().includes(bannedWord)) 12 | } 13 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.3. String/src/3-truncate-string.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Усечение строки (важность: 5) 3 | * 4 | * Создайте функцию truncate(str, maxlength), которая проверяет длину строки str и, если она превосходит maxlength, заменяет конец str на "…", так, чтобы её длина стала равна maxlength. 5 | * Результатом функции должна быть та же строка, если усечение не требуется, либо, если необходимо, усечённая строка. 6 | * Например: 7 | */ 8 | 9 | function truncate(str, maxLength) { 10 | return str.length > maxLength 11 | ? str.slice(0, maxLength - 1) + '…' 12 | : str 13 | } 14 | 15 | truncate("Вот, что мне хотелось бы сказать на эту тему:", 20) === "Вот, что мне хотело…" 16 | truncate("Всем привет!", 20) === "Всем привет!" 17 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.3. String/src/4-extract-currency-value.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Выделить число (важность: 4) 3 | * 4 | * Есть стоимость в виде строки "$120". То есть сначала идёт знак валюты, а затем – число. 5 | * Создайте функцию extractCurrencyValue(str), которая будет из такой строки выделять числовое значение и возвращать его. 6 | * Например: 7 | */ 8 | 9 | function extractCurrencyValue(str) { 10 | return +str.slice(1) 11 | } 12 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.4. Array/src/1-is-array-cloned.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Скопирован ли массив? (важность: 3) 3 | * 4 | * Что выведет следующий код? 5 | */ 6 | 7 | let fruits = ["Яблоки", "Груша", "Апельсин"]; 8 | 9 | // добавляем новое значение в "копию" 10 | let shoppingCart = fruits; 11 | shoppingCart.push("Банан"); 12 | 13 | // что в fruits? 14 | alert( fruits.length ); // ? 15 | 16 | // Решение: выведет 4, так как массив не копируется, а копируется ссылка на него. 17 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.4. Array/src/2-array-operations.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Операции с массивами (важность: 5) 3 | * 4 | * Давайте произведём 5 операций с массивом. 5 | * 6 | * Создайте массив styles с элементами «Джаз» и «Блюз». 7 | * Добавьте «Рок-н-ролл» в конец. 8 | * Замените значение в середине на «Классика». Ваш код для поиска значения в середине должен работать для массивов с любой длиной. 9 | * Удалите первый элемент массива и покажите его. 10 | * Вставьте «Рэп» и «Регги» в начало массива. 11 | * Массив по ходу выполнения операций: 12 | * 13 | * Джаз, Блюз 14 | * Джаз, Блюз, Рок-н-ролл 15 | * Джаз, Классика, Рок-н-ролл 16 | * Классика, Рок-н-ролл 17 | * Рэп, Регги, Классика, Рок-н-ролл 18 | */ 19 | 20 | const styles = ['Джаз', 'Блюз'] 21 | styles.push('Рок-н-ролл') 22 | styles[Math.floor((styles.length - 1) / 2)] = 'Классика' 23 | alert(styles.shift()) 24 | styles.unshift('Рэп', 'Регги') 25 | 26 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.4. Array/src/3-call-in-array-context.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Вызов в контексте массива (важность: 5) 3 | * 4 | * Каков результат? Почему? 5 | */ 6 | 7 | let arr = ["a", "b"]; 8 | 9 | arr.push(function() { 10 | alert( this ); 11 | }) 12 | 13 | arr[2](); // ? 14 | 15 | // Решение: выведет содержимое массива (весь массив), так как вызов свойства идет в массиве (тот же объект) 16 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.4. Array/src/4-sum-inputs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Сумма введённых чисел (важность: 4) 3 | * 4 | * Напишите функцию sumInput(), которая: 5 | * 6 | * Просит пользователя ввести значения, используя prompt и сохраняет их в массив. 7 | * Заканчивает запрашивать значения, когда пользователь введёт не числовое значение, пустую строку или нажмёт «Отмена». 8 | * Подсчитывает и возвращает сумму элементов массива. 9 | * P.S. Ноль 0 – считается числом, не останавливайте ввод значений при вводе «0». 10 | */ 11 | 12 | function sumInput() { 13 | let input 14 | 15 | const inputs = [] 16 | 17 | while (true) { 18 | input = prompt(`Введите число. Предыдущий ввод: [${inputs}]`) 19 | if (input === null || input === '' || isFinite(input)) break 20 | else inputs.push(+input) 21 | } 22 | 23 | return inputs.reduce((acc, cur) => acc + cur, 0) 24 | } 25 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.5. Array methods/src/1-camelize.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Переведите текст вида border-left-width в borderLeftWidth (важность: 5) 3 | * 4 | * Напишите функцию camelize(str), которая преобразует строки вида «my-short-string» в «myShortString». 5 | * То есть дефисы удаляются, а все слова после них получают заглавную букву. 6 | * Примеры: 7 | * 8 | * P.S. Подсказка: используйте split, чтобы разбить строку на массив символов, потом переделайте всё как нужно и методом join соедините обратно. 9 | */ 10 | 11 | function camelize(str) { 12 | if (str === '') return '' 13 | return str 14 | .split('-') 15 | .map((chunk, idx) => { 16 | if (idx === 0) return chunk 17 | if (chunk.length === 0) return chunk 18 | return chunk[0].toUpperCase() + chunk.slice(1) 19 | }) 20 | .join('') 21 | } 22 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.5. Array methods/src/10-shuffle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Перемешайте массив (важность: 3) 3 | * 4 | * Напишите функцию shuffle(array), которая перемешивает (переупорядочивает случайным образом) элементы массива. 5 | * Многократные прогоны через shuffle могут привести к разным последовательностям элементов. Например: 6 | */ 7 | 8 | let arr = [1, 2, 3]; 9 | 10 | function shuffle(arr) { 11 | for (let i = arr.length - 1; i > 0; i--) { 12 | let j = Math.floor(Math.random() * (i + 1)); 13 | 14 | [arr[i], arr[j]] = [arr[j], arr[i]]; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.5. Array methods/src/11-get-average-age.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Получить средний возраст (важность: 4) 3 | * 4 | * Напишите функцию getAverageAge(users), которая принимает массив объектов со свойством age и возвращает средний возраст. 5 | * 6 | * Формула вычисления среднего арифметического значения: (age1 + age2 + ... + ageN) / N. 7 | * 8 | * Например: 9 | * 10 | * let vasya = { name: "Вася", age: 25 }; 11 | * let petya = { name: "Петя", age: 30 }; 12 | * let masha = { name: "Маша", age: 29 }; 13 | * 14 | * let arr = [ vasya, petya, masha ]; 15 | * 16 | * alert( getAverageAge(arr) ); // (25 + 30 + 29) / 3 = 28 17 | */ 18 | 19 | function getAverageAge(users) { 20 | return users.reduce((acc, user) => acc + user.age, 0) / users.length 21 | } 22 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.5. Array methods/src/12-unique-elements-array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Оставить уникальные элементы массива (важность: 4) 3 | * 4 | * Пусть arr – массив строк. 5 | * 6 | * Напишите функцию unique(arr), которая возвращает массив, содержащий только уникальные элементы arr. 7 | */ 8 | 9 | function unique(arr) { 10 | const map = {} 11 | 12 | return arr.reduce((acc, str) => { 13 | if (map[str]) return acc 14 | 15 | map[str] = true 16 | acc.push(str) 17 | 18 | return acc 19 | }, []) 20 | } 21 | 22 | let strings = ["кришна", "кришна", "харе", "харе", 23 | "харе", "харе", "кришна", "кришна", ":-O" 24 | ]; 25 | 26 | alert( unique(strings) ); // кришна, харе, :-O 27 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.5. Array methods/src/2-filter-range.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Фильтрация по диапазону (важность: 4) 3 | * 4 | * Напишите функцию filterRange(arr, a, b), которая принимает массив arr, ищет в нём элементы между a и b и отдаёт массив этих элементов. 5 | * Функция должна возвращать новый массив и не изменять исходный. 6 | * Например: 7 | * 8 | * let arr = [5, 3, 8, 1]; 9 | * let filtered = filterRange(arr, 1, 4); 10 | * alert( filtered ); // 3,1 (совпадающие значения) 11 | * alert( arr ); // 5,3,8,1 (без изменений) 12 | */ 13 | 14 | function filterRange(arr, minValue, maxValue) { 15 | return arr.filter(num => num >= minValue && num <= maxValue) 16 | } 17 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.5. Array methods/src/3-filter-range-in-place.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Напишите функцию filterRangeInPlace(arr, a, b), которая принимает 3 | * массив arr и удаляет из него все значения кроме тех, которые находятся между a и b. 4 | * То есть, проверка имеет вид a ≤ arr[i] ≤ b. 5 | * Функция должна изменять принимаемый массив и ничего не возвращать. 6 | * Например: 7 | * 8 | * let arr = [5, 3, 8, 1]; 9 | * filterRangeInPlace(arr, 1, 4); // удалены числа вне диапазона 1..4 10 | * alert( arr ); // [3, 1] 11 | */ 12 | 13 | function filterRangeInPlace(arr, min ,max) { 14 | for (let i = 0; i < arr.length; i++) { 15 | const num = arr[i] 16 | if (num < min || num > max) arr.splice(i, 1) 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.5. Array methods/src/4-sort-array-desc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Сортировать в порядке по убыванию (важность: 4) 3 | */ 4 | 5 | let arr = [5, 2, 1, -10, 8]; 6 | 7 | arr.sort((a, b) => b - a) 8 | // ... ваш код для сортировки по убыванию 9 | 10 | alert( arr ); // 8, 5, 2, 1, -10 11 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.5. Array methods/src/5-copy-and-sort-array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Скопировать и отсортировать массив (важность: 5) 3 | * 4 | * У нас есть массив строк arr. Нужно получить отсортированную копию, но оставить arr неизменённым. 5 | * 6 | * Создайте функцию copySorted(arr), которая будет возвращать такую копию. 7 | * 8 | */ 9 | 10 | let arr = ["HTML", "JavaScript", "CSS"]; 11 | 12 | let sorted = copySorted(arr); 13 | 14 | alert( sorted ); // CSS, HTML, JavaScript 15 | alert( arr ); // HTML, JavaScript, CSS (без изменений) 16 | 17 | function copySorted(arr) { 18 | return [...arr].sort((a, b) => a.localeCompare(b)) 19 | } 20 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.5. Array methods/src/7-transform-user-names.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Трансформировать в массив имён (важность: 5) 3 | * 4 | * У вас есть массив объектов user, и в каждом из них есть user.name. Напишите код, который преобразует их в массив имён. 5 | * 6 | * Например: 7 | */ 8 | 9 | let vasya = { name: "Вася", age: 25 }; 10 | let petya = { name: "Петя", age: 30 }; 11 | let masha = { name: "Маша", age: 28 }; 12 | 13 | let users = [ vasya, petya, masha ]; 14 | 15 | let names = users.map(user => user.name) 16 | 17 | alert( names ); // Вася, Петя, Маша 18 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.5. Array methods/src/8-transform-to-obj.js: -------------------------------------------------------------------------------- 1 | /** 2 | * У вас есть массив объектов user, и у каждого из объектов есть name, surname и id. 3 | * Напишите код, который создаст ещё один массив объектов с параметрами id и fullName, где fullName – состоит из name и surname. 4 | * Например: 5 | */ 6 | 7 | let vasya = { name: "Вася", surname: "Пупкин", id: 1 }; 8 | let petya = { name: "Петя", surname: "Иванов", id: 2 }; 9 | let masha = { name: "Маша", surname: "Петрова", id: 3 }; 10 | 11 | let users = [ vasya, petya, masha ]; 12 | 13 | const usersMapped = users.map((user, idx) => ({ fullName: `${user.name} ${user.surname}`, id: idx + 1 })) 14 | 15 | /* 16 | usersMapped = [ 17 | { fullName: "Вася Пупкин", id: 1 }, 18 | { fullName: "Петя Иванов", id: 2 }, 19 | { fullName: "Маша Петрова", id: 3 } 20 | ] 21 | */ 22 | 23 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.5. Array methods/src/9-sort-users-by-age.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Отсортировать пользователей по возрасту (важность: 5) 3 | * 4 | * Напишите функцию sortByAge(users), которая принимает массив объектов со свойством age и сортирует их по нему. 5 | * Например: 6 | */ 7 | 8 | let vasya = { name: "Вася", age: 25 }; 9 | let petya = { name: "Петя", age: 30 }; 10 | let masha = { name: "Маша", age: 28 }; 11 | 12 | let arr = [ vasya, petya, masha ]; 13 | 14 | sortByAge(arr); 15 | 16 | function sortByAge(arr) { 17 | arr.sort((a, b) => a.age - b.age) 18 | } 19 | 20 | // теперь: [vasya, masha, petya] 21 | alert(arr[0].name); // Вася 22 | alert(arr[1].name); // Маша 23 | alert(arr[2].name); // Петя 24 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.7. Map and Set/src/1-filter-unique-array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Допустим, у нас есть массив arr. 3 | * 4 | * Создайте функцию unique(arr), которая вернёт массив уникальных, не повторяющихся значений массива arr. 5 | * 6 | * Например: 7 | */ 8 | 9 | function unique(arr) { 10 | return [...new Set(arr)] 11 | } 12 | 13 | let values = ["Hare", "Krishna", "Hare", "Krishna", 14 | "Krishna", "Krishna", "Hare", "Hare", ":-O" 15 | ]; 16 | 17 | alert( unique(values) ); // Hare,Krishna,:-O 18 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.7. Map and Set/src/2-filter-anagrams.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Отфильтруйте анаграммы (важность: 4) 3 | * 4 | * Анаграммы – это слова, у которых те же буквы в том же количестве, но они располагаются в другом порядке. 5 | */ 6 | 7 | let arr = ["nap", "teachers", "cheaters", "PAN", "ear", "era", "hectares"]; 8 | 9 | function aclean(arr) { 10 | const map = new Map(); 11 | arr.forEach((word) => { 12 | const key = word.toLowerCase().split('').sort().join('') 13 | map.set(key, word) 14 | }) 15 | return [...map.values()]; 16 | } 17 | 18 | alert( aclean(arr) ); // "nap,teachers,ear" или "PAN,cheaters,era" 19 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.7. Map and Set/src/3-iterateble-keys.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Перебираемые ключи (важность: 5) 3 | * 4 | * Мы хотели бы получить массив ключей map.keys() в переменную и далее работать с ними, например, применить метод .push. 5 | * 6 | * Но это не выходит: 7 | */ 8 | 9 | let map = new Map(); 10 | 11 | map.set("name", "John"); 12 | 13 | let keys = map.keys(); 14 | 15 | // Error: keys.push is not a function 16 | // Ошибка: keys.push -- это не функция 17 | keys.push("more"); 18 | 19 | // Решение: использовать Array.from, так как map.keys() - это итерабельный объект (MapIterator). 20 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.9. Object.keys, values, entries/README.md: -------------------------------------------------------------------------------- 1 | # Object.keys, values, entries 2 | 3 | ## Методы 4 | 5 | `Object.keys(obj)` – возвращает массив ключей. 6 | `Object.values(obj)` – возвращает массив значений. 7 | `Object.entries(obj)` – возвращает массив пар `[ключ, значение]`. 8 | 9 | > Данные методы игнорирует символьные свойства 10 | 11 | ## Трансформации 12 | 13 | 1. Вызов `Object.entries(obj)` возвращает массив пар ключ/значение для `obj`. 14 | 2. На нём вызываем методы массива, например, `map`. 15 | 3. Используем `Object.fromEntries(array)` на результате, чтобы преобразовать его обратно в объект. 16 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.9. Object.keys, values, entries/src/1-object-sum.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Сумма свойств объекта (важность: 5) 3 | * 4 | * Есть объект salaries с произвольным количеством свойств, содержащих заработные платы. 5 | * Напишите функцию sumSalaries(salaries), которая возвращает сумму всех зарплат с помощью метода Object.values и цикла for..of. 6 | * Если объект salaries пуст, то результат должен быть 0. 7 | * Например: 8 | */ 9 | 10 | let salaries = { 11 | "John": 100, 12 | "Pete": 300, 13 | "Mary": 250 14 | }; 15 | 16 | function sumSalaries(salaries) { 17 | return Object.values(salaries).reduce((sum, salary) => sum + salary, 0) 18 | } 19 | 20 | alert( sumSalaries(salaries) ); // 650 21 | -------------------------------------------------------------------------------- /1. JavaScript Language/5.9. Object.keys, values, entries/src/2-object-length.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Напишите функцию count(obj), которая возвращает количество свойств объекта: 3 | * 4 | * Постарайтесь сделать код как можно короче. 5 | * 6 | * P.S. Игнорируйте символьные свойства, подсчитывайте только «обычные». 7 | */ 8 | 9 | let user = { 10 | name: 'John', 11 | age: 30 12 | }; 13 | 14 | function count(obj) { 15 | return Object.keys(obj).length 16 | } 17 | 18 | alert( count(user) ); // 2 19 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.1. Recursion/src/1-sum-to.spec.js: -------------------------------------------------------------------------------- 1 | const { sumToArithmetic, sumToLoop, sumToRecursive } = require('./1-sum-to') 2 | 3 | describe('sum to functions', () => { 4 | const cases = [ 5 | { input: 1, output: 1 }, 6 | { input: 2, output: 3 }, 7 | { input: 3, output: 6 }, 8 | { input: 4, output: 10 }, 9 | { input: 5, output: 15 }, 10 | { input: 100, output: 5050 }, 11 | ]; 12 | 13 | [sumToLoop, sumToRecursive, sumToArithmetic].forEach(sumTo => { 14 | describe(sumTo.name, () => { 15 | cases.forEach(({ input, output }) => { 16 | it(`${sumTo.name}(${input}) should be ${output}`, () => { 17 | expect(sumTo(input)).toBe(output) 18 | }) 19 | }) 20 | }) 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.1. Recursion/src/2-factorial.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Вычислить факториал (важность: 4) 3 | * 4 | * Факториал натурального числа – это число, умноженное на "себя минус один", затем на "себя минус два", и так далее до 1. 5 | * Факториал n обозначается как n! 6 | * Определение факториала можно записать как: 7 | */ 8 | 9 | function factorial(n) { 10 | if (n === 1) return 1 11 | return n * factorial(n - 1) 12 | } 13 | 14 | module.exports = factorial 15 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.1. Recursion/src/2-factorial.spec.js: -------------------------------------------------------------------------------- 1 | const factorial = require('./2-factorial') 2 | 3 | describe('factorial', () => { 4 | const cases = [ 5 | { input: 1, output: 1 }, 6 | { input: 2, output: 2 }, 7 | { input: 3, output: 6 }, 8 | { input: 4, output: 24 }, 9 | { input: 5, output: 120 }, 10 | ] 11 | 12 | cases.forEach(({ input, output }) => { 13 | it(`factorial(${input}) should be ${output}`, () => { 14 | expect(factorial(input)).toBe(output) 15 | }) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.1. Recursion/src/3-fibonacci.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Числа Фибоначчи (важность: 5) 3 | * 4 | * Последовательность чисел Фибоначчи определяется формулой Fn = Fn-1 + Fn-2. То есть, 5 | * следующее число получается как сумма двух предыдущих. 6 | * Первые два числа равны 1, затем 2(1+1), затем 3(1+2), 5(2+3) и так далее: 1, 1, 2, 3, 5, 8, 13, 21.... 7 | * Числа Фибоначчи тесно связаны с золотым сечением и множеством природных явлений вокруг нас. 8 | * Напишите функцию fib(n) которая возвращает n-е число Фибоначчи. 9 | * Пример работы: 10 | */ 11 | 12 | function fibonacci(n) { 13 | const numbers = [1, 1] 14 | if (n <= 2) return numbers[n] 15 | 16 | for (let i = 3; i <= n; i++) { 17 | const first = numbers[numbers.length - 1] 18 | const second = numbers[numbers.length - 2] 19 | numbers.push(first + second) 20 | } 21 | 22 | return numbers[numbers.length - 1] 23 | } 24 | 25 | module.exports = fibonacci 26 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.1. Recursion/src/3-fibonacci.spec.js: -------------------------------------------------------------------------------- 1 | const fibonacci = require('./3-fibonacci') 2 | 3 | describe('fibonacci', () => { 4 | const cases = [ 5 | { input: 3, output: 2 }, 6 | { input: 7, output: 13 }, 7 | { input: 77, output: 5527939700884757 }, 8 | ] 9 | 10 | cases.forEach(({ input, output }) => { 11 | it(`fibonacci(${input}) should be ${output}`, () => { 12 | expect(fibonacci(input)).toBe(output) 13 | }) 14 | }) 15 | }) 16 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.1. Recursion/src/4-print-list.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Вывод односвязного списка (важность: 5) 3 | * 4 | * Напишите функцию printList(list), которая выводит элементы списка по одному. 5 | * Сделайте два варианта решения: используя цикл и через рекурсию. 6 | * Как лучше: с рекурсией или без? 7 | * 8 | * // Решение: мне кажется лучше без рекурсии, так как будет быстрее. Но с рекурсией код выглядит привлекательнее 9 | */ 10 | 11 | function printListLoop(list) { 12 | let head = list 13 | 14 | while (head) { 15 | alert(head.value) 16 | head = head.next 17 | } 18 | } 19 | 20 | function printListRecursive(list) { 21 | alert(list.value) 22 | if (list.next) printListRecursive(list.next) 23 | } 24 | 25 | module.exports = { 26 | printListLoop, 27 | printListRecursive 28 | } 29 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.1. Recursion/src/5-print-list-backwards.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Вывод односвязного списка в обратном порядке (важность: 5) 3 | * 4 | * Выведите односвязный список из предыдущего задания Вывод односвязного списка в обратном порядке. 5 | * 6 | * Сделайте два решения: с использованием цикла и через рекурсию. 7 | */ 8 | 9 | function printListBackwardsLoop(list) { 10 | let head = list 11 | let values = [head.value] 12 | 13 | while (head.next) { 14 | head = head.next 15 | values.push(head.value) 16 | } 17 | 18 | for (let i = values.length - 1; i >= 0; i--) { 19 | alert(values[i]) 20 | } 21 | } 22 | 23 | function printListBackwardsRecursive(list) { 24 | if (list.next) printListBackwardsRecursive(list.next) 25 | alert(list.value) 26 | } 27 | 28 | module.exports = { 29 | printListBackwardsLoop, 30 | printListBackwardsRecursive 31 | } 32 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.10. Bind/src/1-binded-function-as-method.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Связанная функция как метод (важность: 5) 3 | * 4 | * Что выведет функция? 5 | */ 6 | 7 | function f() { 8 | alert(this); 9 | } 10 | 11 | let user = { 12 | g: f.bind(null) 13 | }; 14 | 15 | user.g(); 16 | 17 | // Решение: функция выведет null, так как привязанный однажды контекст уже нельзя изменить. 18 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.10. Bind/src/2-two-binded-function.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Повторный bind (важность: 5) 3 | * 4 | * Можем ли мы изменить this дополнительным связыванием? 5 | * 6 | * Что выведет этот код? 7 | */ 8 | 9 | function f() { 10 | alert(this.name); 11 | } 12 | 13 | f = f.bind( {name: "Вася"} ).bind( {name: "Петя" } ); 14 | 15 | f(); 16 | 17 | // Решение: выведет "Вася". Нельзя дважды прибиндить контекст. 18 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.10. Bind/src/3-property-of-bind-function.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Свойство функции после bind (важность: 5) 3 | * 4 | * В свойство функции записано значение. Изменится ли оно после применения bind? Обоснуйте ответ. 5 | */ 6 | 7 | function sayHi() { 8 | alert( this.name ); 9 | } 10 | sayHi.test = 5; 11 | 12 | let bound = sayHi.bind({ 13 | name: "Вася" 14 | }); 15 | 16 | alert( bound.test ); // что выведет? почему? 17 | 18 | // Решение: выведет undefined, результатом работы `bind` является другой объект. 19 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.10. Bind/src/4-refactor-function.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Исправьте функцию, теряющую "this" (важность: 5) 3 | * 4 | * Вызов askPassword() в приведённом ниже коде должен проверить пароль и затем вызвать 5 | * user.loginOk/loginFail в зависимости от ответа. 6 | * 7 | * Однако, его вызов приводит к ошибке. Почему? 8 | * 9 | * Исправьте выделенную строку, чтобы всё работало (других строк изменять не надо). 10 | */ 11 | 12 | function askPassword(ok, fail) { 13 | let password = prompt("Password?", ''); 14 | if (password == "rockstar") ok(); 15 | else fail(); 16 | } 17 | 18 | let user = { 19 | name: 'Вася', 20 | 21 | loginOk() { 22 | alert(`${this.name} logged in`); 23 | }, 24 | 25 | loginFail() { 26 | alert(`${this.name} failed to log in`); 27 | }, 28 | 29 | }; 30 | 31 | askPassword(user.loginOk.bind(user), user.loginFail.bind(user)); 32 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.11. Arrow functions/README.md: -------------------------------------------------------------------------------- 1 | # Повторяем стрелочные функции 2 | 3 | - У стрелочных функций нет `«this»`, они берут родительский контекст 4 | - Нельзя использовать в качестве конструктора 5 | - Не имеют `arguments` 6 | - Нет `super` 7 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.3. Closure/src/1-are-counters-independent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Независимы ли счётчики? (важность: 5) 3 | * 4 | * Здесь мы делаем два счётчика: counter и counter2, используя одну и ту же функцию makeCounter. 5 | * Они независимы? Что покажет второй счётчик? 0,1 или 2,3 или что-то ещё? 6 | */ 7 | 8 | function makeCounter() { 9 | let count = 0; 10 | 11 | return function() { 12 | return count++; 13 | }; 14 | } 15 | 16 | let counter = makeCounter(); 17 | let counter2 = makeCounter(); 18 | 19 | alert( counter() ); // 0 20 | alert( counter() ); // 1 21 | 22 | alert( counter2() ); // ? 23 | alert( counter2() ); // ? 24 | 25 | // Решение: счетчики независимы, так как каждый создаст свое лексическое окружение 26 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.3. Closure/src/2-counter-obj.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Объект счётчика (важность: 5) 3 | * 4 | * Здесь объект счётчика создан с помощью функции-конструктора. 5 | * Будет ли он работать? Что покажет? 6 | */ 7 | 8 | function Counter() { 9 | let count = 0; 10 | 11 | this.up = function() { 12 | return ++count; 13 | }; 14 | this.down = function() { 15 | return --count; 16 | }; 17 | } 18 | 19 | let counter = new Counter(); 20 | 21 | alert( counter.up() ); // ? (1) 22 | alert( counter.up() ); // ? (2) 23 | alert( counter.down() ); // ? (1) 24 | 25 | // Решение: будет работать, так как у обоих функций одно и то же внешнее лексическое окружение. 26 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.3. Closure/src/3-function-if.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Функция в if 3 | * 4 | * Посмотрите на код. Какой будет результат у вызова на последней строке? 5 | */ 6 | 7 | let phrase = "Hello"; 8 | 9 | if (true) { 10 | let user = "John"; 11 | 12 | function sayHi() { 13 | alert(`${phrase}, ${user}`); 14 | } 15 | } 16 | 17 | sayHi(); 18 | 19 | // Решение: должна быть ошибка, так как функция объявлена в лексическом окружении тела if'а 20 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.3. Closure/src/4-sum-with-closures.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Сумма с помощью замыканий (важность: 4) 3 | * 4 | * Напишите функцию sum, которая работает таким образом: sum(a)(b) = a+b. 5 | * Да, именно таким образом, используя двойные круглые скобки (не опечатка). 6 | * Например: 7 | */ 8 | 9 | function sum(a) { 10 | return function(b) { 11 | return a + b 12 | } 13 | } 14 | 15 | module.exports = sum 16 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.3. Closure/src/4-sum-with-closures.spec.js: -------------------------------------------------------------------------------- 1 | const sum = require('./4-sum-with-closures') 2 | 3 | describe('sum', () => { 4 | it('sum(1)(2) should be 3', () => { 5 | expect(sum(1)(2)).toBe(3) 6 | }) 7 | 8 | 9 | it('sum(5)(-1) should be 4', () => { 10 | expect(sum(5)(-1)).toBe(4) 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.3. Closure/src/5-filter-with-fn.spec.js: -------------------------------------------------------------------------------- 1 | const { inBetween, inArray } = require('./5-filter-with-fn') 2 | 3 | describe('filter util functions', () => { 4 | const arr = [1, 2, 3, 4, 5, 6, 7]; 5 | 6 | describe('inBetween', () => { 7 | it('inBetween(3,6) should be [3,4,5,6]', () => { 8 | const result = arr.filter(inBetween(3, 6)) 9 | expect(result).toStrictEqual([3,4,5,6]) 10 | }) 11 | }) 12 | 13 | describe('inArray', () => { 14 | it('inArray([1,2,10]) should be [1,2]', () => { 15 | const result = arr.filter(inArray([1, 2, 10])) 16 | expect(result).toStrictEqual([1,2]) 17 | }) 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.3. Closure/src/6-sort-by-field-cb.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Сортировать по полю (важность: 5) 3 | * 4 | * У нас есть массив объектов, который нужно отсортировать: 5 | * 6 | * let users = [ 7 | * { name: "John", age: 20, surname: "Johnson" }, 8 | * { name: "Pete", age: 18, surname: "Peterson" }, 9 | * { name: "Ann", age: 19, surname: "Hathaway" } 10 | * ]; 11 | * 12 | * Можем ли мы сделать его короче, скажем, вот таким? 13 | * 14 | * users.sort(byField('name')); 15 | * users.sort(byField('age')); 16 | */ 17 | 18 | function byField(key, order = 'ASC') { 19 | return function(a, b) { 20 | if (order.toUpperCase() === 'DESC') { 21 | return a[key] < b[key] ? 1 : -1 22 | } 23 | 24 | return a[key] > b[key] ? 1 : -1 25 | } 26 | } 27 | 28 | module.exports = byField 29 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.4. Var/README.md: -------------------------------------------------------------------------------- 1 | # Устаревшее ключевое слово var 2 | 3 | - Для «var» не существует блочной области видимости 4 | - Но существует для тела функций. 5 | - «var» допускает повторное объявление 6 | - «var» обрабатываются в начале запуска функции 7 | - Это поведение называется «hoisting» (всплытие, поднятие), потому что все 8 | объявления переменных var «всплывают» в самый верх функции. 9 | - Объявления переменных «всплывают», но присваивания значений – нет. 10 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.5. Global object/README.md: -------------------------------------------------------------------------------- 1 | # Глобальный объект 2 | 3 | - В браузере это `window`, в Node.JS `global`. 4 | Глобальный объект имеет универсальное имя – `globalThis`, появился недавно. 5 | - Переменные объявленные через `var` становятся глобальными, а через `let/const` - нет. 6 | - Для того, чтобы код был проще и в будущем его легче было поддерживать, следует обращаться к свойствам 7 | глобального объекта напрямую, как `window.x` 8 | 9 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.6. Function-object/README.md: -------------------------------------------------------------------------------- 1 | # Объект функции, NFE 2 | 3 | В JavaScript функции – это объекты. 4 | 5 | - Свойство `name` - отдает имя функции 6 | - Свойство `length` - отдает кол-во параметров функции в ее объявлении. rest не считаются 7 | 8 | Если функция объявляется как `Function Expression`, то она может быть `NFE`, т.е иметь имя. Используется 9 | для рекурсивных вызовов самой себя и т.д. 10 | 11 | Также функции могут содержать дополнительные свойства. 12 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.6. Function-object/src/1-set-and-decrease-counter.spec.js: -------------------------------------------------------------------------------- 1 | const makeCounter = require('./1-set-and-decrease-counter') 2 | 3 | describe('makeCounter', () => { 4 | it('counter() should return next value', () => { 5 | const counter = makeCounter() 6 | expect(counter()).toBe(1) 7 | expect(counter()).toBe(2) 8 | expect(counter()).toBe(3) 9 | }) 10 | 11 | it('counter.set(value) should set value and return it', () => { 12 | const counter = makeCounter() 13 | expect(counter.set(5)).toBe(5) 14 | expect(counter.set(10)).toBe(10) 15 | expect(counter()).toBe(11) 16 | }) 17 | 18 | it('counter.decrease() should decrease value and return it', () => { 19 | const counter = makeCounter() 20 | expect(counter.decrease()).toBe(-1) 21 | expect(counter.decrease()).toBe(-2) 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.6. Function-object/src/2-fn-sum.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Сумма с произвольным количеством скобок (важность: 2) 3 | * 4 | * Напишите функцию sum, которая бы работала следующим образом: 5 | */ 6 | 7 | function sum(value) { 8 | let sum = 0 9 | 10 | const fn = function (value = 0) { 11 | sum += value 12 | return fn 13 | } 14 | 15 | fn[Symbol.toPrimitive] = function() { 16 | return sum 17 | } 18 | 19 | return fn(value) 20 | } 21 | 22 | module.exports = sum 23 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.6. Function-object/src/2-fn-sum.spec.js: -------------------------------------------------------------------------------- 1 | const sum = require('./2-fn-sum') 2 | 3 | describe('sum', () => { 4 | it('sum(1)(2) should be 3', () => { 5 | const result = sum(1)(2) 6 | expect(+result).toBe(3) 7 | }) 8 | it('sum(1)(2)(3) should be 6', () => { 9 | const result = sum(1)(2)(3) 10 | expect(+result).toBe(6) 11 | }) 12 | it('sum(5)(-1)(2) should be 6', () => { 13 | const result = sum(5)(-1)(2) 14 | expect(+result).toBe(6) 15 | }) 16 | it('sum(6)(-1)(-2)(-3) should be 0', () => { 17 | const result = sum(6)(-1)(-2)(-3) 18 | expect(+result).toBe(0) 19 | }) 20 | it('sum(0)(1)(2)(3)(4)(5) should be 15', () => { 21 | const result = sum(0)(1)(2)(3)(4)(5) 22 | expect(+result).toBe(15) 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.7. New Function/README.md: -------------------------------------------------------------------------------- 1 | # Синтаксис "new Function" 2 | 3 | Имеется еще один вариант объявления функции: 4 | 5 | ```js 6 | const fn = new Function('a', 'b', 'return a + b') 7 | ``` 8 | 9 | - Есть проблемы с замыканиями, такие функции не видят внешнего окружения. Только глобальное 10 | - Функция может генерироваться из строки 11 | - Будут проблемы с минификаторами 12 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.8. SetTimeout and SetInterval/README.md: -------------------------------------------------------------------------------- 1 | # Планирование: setTimeout и setInterval 2 | 3 | - `setTimeout` позволяет вызвать функцию один раз через определённый интервал времени. 4 | - можно передать строку кода, но не рекомендуется 5 | - если запускать рекурсивно, можно имитировать setInterval 6 | - возвращает идентификатор таймера, который можно отменить через `clearTimeout` 7 | - Браузер ограничивает 4-мя мс минимальную задержку между пятью и более вложенными вызовами setTimeout, 8 | а также для setInterval, начиная с 5-го вызова. 9 | - `setInterval` позволяет вызывать функцию регулярно, повторяя вызов через определённый интервал времени. 10 | - возвращает идентификатор таймера, который можно отменить через `clearInterval` 11 | - `setImmediate` - для Node.JS 12 | 13 | > Реальная задержка между вызовами func с помощью setInterval меньше, чем указано в коде 14 | 15 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.8. SetTimeout and SetInterval/src/1-print-numbers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Вывод каждую секунду (важность: 5) 3 | * 4 | * Напишите функцию printNumbers(from, to), которая выводит число каждую секунду, начиная от from и заканчивая to. 5 | * 6 | * Сделайте два варианта решения. 7 | * 8 | * Используя setInterval. 9 | * Используя рекурсивный setTimeout. 10 | */ 11 | 12 | function printNumbersInterval(from, to) { 13 | let interval = setInterval(function () { 14 | alert(from) 15 | from++ 16 | if (from > to) clearInterval(interval) 17 | }, 1000) 18 | } 19 | 20 | function printNumbersTimeout(from, to) { 21 | let timeout = setTimeout(function interval() { 22 | alert(from) 23 | from++ 24 | if (from <= to) setTimeout(interval, 1000) 25 | }, 1000) 26 | } 27 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.8. SetTimeout and SetInterval/src/2-what-will-output-set-timeout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Что покажет setTimeout? (важность: 5) 3 | * 4 | * В приведённом ниже коде запланирован вызов setTimeout, а затем выполняется сложное вычисление, для завершения которого требуется более 100 мс. 5 | * 6 | * Когда будет выполнена запланированная функция? 7 | * 8 | * После цикла. 9 | * Перед циклом. 10 | * В начале цикла. 11 | * Что покажет alert? 12 | */ 13 | 14 | let i = 0; 15 | 16 | setTimeout(() => alert(i), 100); 17 | 18 | for(let j = 0; j < 100000000; j++) { 19 | i++; 20 | } 21 | 22 | // Решение: i покажет 100000000, так как функция будет выполнена после цикла. 23 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.9. Call, apply, decorators/README.md: -------------------------------------------------------------------------------- 1 | # Декораторы и переадресация вызова, call/apply 2 | 3 | **Декоратор** – это обёртка вокруг функции, которая изменяет поведение последней. 4 | Основная работа по-прежнему выполняется функцией. 5 | 6 | Декоратор – это обёртка вокруг функции, которая изменяет поведение последней. Основная работа по-прежнему выполняется функцией. 7 | 8 | - `func.call(context, arg1, arg2…)` – вызывает `func` с данным контекстом и аргументами. 9 | - `func.apply(context, args)` – вызывает `func`, передавая `context` как this и псевдомассив args как список аргументов. 10 | 11 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.9. Call, apply, decorators/src/1-spy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Декоратор-шпион (важность: 5) 3 | * 4 | * Создайте декоратор spy(func), который должен возвращать обёртку, которая сохраняет все вызовы функции в своём свойстве calls. 5 | * Каждый вызов должен сохраняться как массив аргументов. 6 | * Например: 7 | */ 8 | 9 | function spy(func) { 10 | function wrapper(...args) { 11 | wrapper.calls.push([...args]) 12 | return func.apply(this, arguments) 13 | } 14 | 15 | wrapper.calls = [] 16 | 17 | return wrapper 18 | } 19 | 20 | module.exports = spy 21 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.9. Call, apply, decorators/src/1-spy.spec.js: -------------------------------------------------------------------------------- 1 | const spy = require('./1-spy') 2 | 3 | global.alert = jest.fn(); 4 | 5 | describe('spy', () => { 6 | let work 7 | 8 | beforeEach(() => { 9 | work = function(a, b) { 10 | alert( a + b ); // произвольная функция или метод 11 | } 12 | work = spy(work); 13 | }) 14 | 15 | it('work.calls should contain all args', () => { 16 | work(1, 2) 17 | work(4, 5) 18 | 19 | expect(work.calls).toStrictEqual([[1,2], [4,5]]) 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.9. Call, apply, decorators/src/2-delay.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Задерживающий декоратор (важность: 5) 3 | * 4 | * Создайте декоратор delay(f, ms), который задерживает каждый вызов f на ms миллисекунд. Например: 5 | */ 6 | 7 | function delay(func, ms) { 8 | function wrapper(...args) { 9 | setTimeout(func.bind(this, ...args), ms) 10 | } 11 | 12 | return wrapper 13 | } 14 | -------------------------------------------------------------------------------- /1. JavaScript Language/6.9. Call, apply, decorators/src/3-debounce.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Декоратор debounce (важность: 5) 3 | * 4 | * Результатом декоратора debounce(f, ms) должна быть обёртка, которая передаёт вызов f не более одного раза в 5 | * ms миллисекунд. Другими словами, когда мы вызываем debounce, это гарантирует, 6 | * что все остальные вызовы будут игнорироваться в течение ms. 7 | * Например: 8 | */ 9 | 10 | function debounce(func, ms) { 11 | let isCoolDown = false 12 | 13 | return function(...args) { 14 | if (isCoolDown) return 15 | 16 | func.apply(this, args) 17 | isCoolDown = true 18 | setTimeout(() => isCoolDown = false, ms) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /1. JavaScript Language/7.2. Property accessors/README.md: -------------------------------------------------------------------------------- 1 | # Свойства - геттеры и сеттеры 2 | 3 | Ранее мы рассматривали *свойства-данные*. Есть еще один вариант объявления свойств - это *свойств-аксессоры*. 4 | 5 | Если говорить простым языком - то это некие функции, которые используются для присвоения или получения значения, но 6 | в коде они выглядят как обычные свойства объекта. 7 | 8 | ```js 9 | let obj = { 10 | get propName() { 11 | // геттер, срабатывает при чтении obj.propName 12 | }, 13 | 14 | set propName(value) { 15 | // сеттер, срабатывает при записи obj.propName = value 16 | } 17 | }; 18 | ``` 19 | -------------------------------------------------------------------------------- /1. JavaScript Language/8.1. Prototype inheritance/src/1-work-with-proto.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Работа с прототипами 3 | * 4 | * В приведённом ниже коде создаются и изменяются два объекта. 5 | * 6 | * Какие значения показываются в процессе выполнения кода? 7 | */ 8 | 9 | let animal = { 10 | jumps: null 11 | }; 12 | 13 | let rabbit = { 14 | __proto__: animal, 15 | jumps: true 16 | }; 17 | 18 | alert( rabbit.jumps ); // true (1) 19 | 20 | delete rabbit.jumps; 21 | 22 | alert( rabbit.jumps ); // null (2) 23 | 24 | delete animal.jumps; 25 | 26 | alert( rabbit.jumps ); // undefined (3) 27 | -------------------------------------------------------------------------------- /1. JavaScript Language/8.1. Prototype inheritance/src/3-where-will-write.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Куда будет произведена запись? (важность: 5) 3 | * 4 | * Объект rabbit наследует от объекта animal. 5 | * 6 | * Какой объект получит свойство full при вызове rabbit.eat(): animal или rabbit? 7 | */ 8 | 9 | let animal = { 10 | eat() { 11 | this.full = true; 12 | } 13 | }; 14 | 15 | let rabbit = { 16 | __proto__: animal 17 | }; 18 | 19 | rabbit.eat(); 20 | 21 | // Решение: получит rabbit, так как вызывается в контексте rabbit 22 | -------------------------------------------------------------------------------- /1. JavaScript Language/8.1. Prototype inheritance/src/4-why-eat-up-both-hamsters.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Почему наедаются оба хомяка? (важность: 5) 3 | * 4 | * У нас есть два хомяка: шустрый (speedy) и ленивый (lazy); оба наследуют от общего объекта hamster. 5 | * 6 | * Когда мы кормим одного хомяка, второй тоже наедается. Почему? Как это исправить? 7 | */ 8 | 9 | let hamster = { 10 | eat(food) { 11 | this.stomach.push(food); 12 | } 13 | }; 14 | 15 | let speedy = { 16 | stomach: [], 17 | __proto__: hamster 18 | }; 19 | 20 | let lazy = { 21 | stomach: [], 22 | __proto__: hamster 23 | }; 24 | 25 | // Этот хомяк нашёл еду 26 | speedy.eat("apple"); 27 | alert( speedy.stomach ); // apple 28 | 29 | // У этого хомяка тоже есть еда. Почему? Исправьте 30 | alert( lazy.stomach ); // apple 31 | 32 | // Решение: добавить каждому объекту свое свойство `stomach` 33 | -------------------------------------------------------------------------------- /1. JavaScript Language/8.2. Function prototype/README.md: -------------------------------------------------------------------------------- 1 | # F.prototype 2 | 3 | Если в `F.prototype` содержится объект, оператор new устанавливает его в качестве `[[Prototype]]` для нового объекта. 4 | 5 | Установка `Rabbit.prototype = animal` буквально говорит интерпретатору следующее: "При создании объекта через `new Rabbit() ` 6 | запиши ему `animal` в `[[Prototype]]`". 7 | ```js 8 | let animal = { 9 | eats: true 10 | }; 11 | 12 | function Rabbit(name) { 13 | this.name = name; 14 | } 15 | 16 | Rabbit.prototype = animal; 17 | 18 | let rabbit = new Rabbit("White Rabbit"); // rabbit.__proto__ == animal 19 | 20 | alert( rabbit.eats ); // true 21 | ``` 22 | 23 | > F.prototype используется только в момент вызова функции конструктора. 24 | 25 | В обычных объектах prototype не является чем-то особенным. Будет обычным свойством. 26 | 27 | 28 | -------------------------------------------------------------------------------- /1. JavaScript Language/8.2. Function prototype/src/2-create-new-object-with-existing-one.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Создайте новый объект с помощью уже существующего (важность: 5) 3 | * 4 | * Представьте, что у нас имеется некий объект obj, созданный функцией-конструктором – 5 | * мы не знаем какой именно, но хотелось бы создать ещё один объект такого же типа. 6 | * 7 | * Можем ли мы сделать так? 8 | */ 9 | 10 | let obj2 = new obj.constructor(); // можем так сделать, но только если не перезаписали свойство prototype 11 | 12 | -------------------------------------------------------------------------------- /1. JavaScript Language/8.3. Native Prototypes/src/1-add-defer-to-functions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Добавить функциям метод "f.defer(ms)" (важность: 5) 3 | * 4 | * Добавьте всем функциям в прототип метод defer(ms), который вызывает функции через ms миллисекунд. 5 | * После этого должен работать такой код: 6 | */ 7 | 8 | Function.prototype.defer = function(ms) { 9 | setTimeout(this, ms) 10 | } 11 | 12 | function f() { 13 | alert("Hello!"); 14 | } 15 | 16 | f.defer(1000); // выведет "Hello!" через 1 секунду 17 | -------------------------------------------------------------------------------- /1. JavaScript Language/8.3. Native Prototypes/src/2-add-defer-decorate-to-functions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Добавьте функциям декорирующий метод "defer()" (важность: 4) 3 | * 4 | * Добавьте всем функциям в прототип метод defer(ms), который возвращает обёртку, откладывающую вызов функции на ms миллисекунд. 5 | * Например, должно работать так: 6 | */ 7 | 8 | Function.prototype.defer = function(ms) { 9 | return (...args) => { 10 | setTimeout(() => this(...args), ms) 11 | } 12 | } 13 | 14 | function f(a, b) { 15 | alert( a + b ); 16 | } 17 | 18 | f.defer(1000)(1, 2); // выведет 3 через 1 секунду. 19 | -------------------------------------------------------------------------------- /1. JavaScript Language/8.4. Prototype methods/README.md: -------------------------------------------------------------------------------- 1 | # Методы прототипов, объекты без свйоства __proto__ 2 | 3 | Свойство `__proto__` считается устаревшим, и по стандарту оно должно поддерживаться только браузерами. 4 | 5 | Что касается современных методов, это: 6 | 7 | - `Object.create(proto, [descriptors])` - создает пустой объект со свойством `[[Prototype]]`, и необязательными 8 | дескрипторами свойств. 9 | - `Object.getPrototypeOf(obj)` - возвращает свойство `[[Prototype]]` объекта `obj` 10 | - `Object.setPrototypeOf(obj, proto)` - устанавливает свойство `[[Prototype]]` объекта `obj` как `proto`. 11 | 12 | Эти методы нужно использовать вместо `__proto__` 13 | 14 | 15 | -------------------------------------------------------------------------------- /1. JavaScript Language/9.2. Class inheritance/src/1-create-instance-error.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ошибка создания экземпляра класса (важность: 5) 3 | * 4 | * В коде ниже класс Rabbit наследует Animal. 5 | * К сожалению, объект класса Rabbit не создаётся. Что не так? Исправьте ошибку. 6 | */ 7 | 8 | class Animal { 9 | 10 | constructor(name) { 11 | this.name = name; 12 | } 13 | 14 | } 15 | 16 | class Rabbit extends Animal { 17 | constructor(name) { 18 | super(name) 19 | this.created = Date.now(); 20 | } 21 | } 22 | 23 | let rabbit = new Rabbit("Белый кролик"); // Error: this is not defined 24 | alert(rabbit.name); 25 | -------------------------------------------------------------------------------- /1. JavaScript Language/9.4. Private, protected properties, methods/README.md: -------------------------------------------------------------------------------- 1 | # Приватные и защищённые методы и свойства 2 | 3 | Разделение внутреннего и внешнего интерфейсов - одна из важнейших задач в ООП. Это инкапсуляция. 4 | 5 | В JS есть два вида полей: 6 | 7 | - **Private**. Приватные поля, 8 | - **Public**. Публичные поля, доступны снаружи класса. 9 | 10 | В других языках программирования есть еще `protected` поля, но в JS их имитируют при помощи нижнего подчеркивания `_`. 11 | 12 | > Приватные свойства 13 | > 14 | > Можно обозначать при помощи #. Но для старых браузеров потребуется полифилл 15 | 16 | ## Зачем нужно 17 | 18 | - Сокрытие сложности 19 | - Поддерживаемость 20 | - Защита для пользователей, чтобы не выстрелили себе в ногу 21 | -------------------------------------------------------------------------------- /1. JavaScript Language/9.5. Extend natives/README.md: -------------------------------------------------------------------------------- 1 | # Расширение встроенных классов 2 | 3 | Встроенные классы типа `Array`, `Map` тоже можно наследовать. 4 | 5 | > При помощи специального статического геттера `[Symbol.species]` можно вернуть конструктор, 6 | > который JavaScript будет использовать в filter, map и других методах для создания новых объектов. 7 | 8 | - Встроенные классы – исключение. Они не наследуют статические методы друг друга. 9 | -------------------------------------------------------------------------------- /1. JavaScript Language/9.6. Instanceof/src/1-strange-instance-of.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Странный instanceof (важность: 5) 3 | * 4 | * Почему instanceof в примере ниже возвращает true? Мы же видим, что a не создан с помощью B(). 5 | */ 6 | 7 | function A() {} 8 | function B() {} 9 | 10 | A.prototype = B.prototype = {}; 11 | 12 | let a = new A(); 13 | 14 | alert( a instanceof B ); // true 15 | 16 | // Решение: потому что сравнивается a.__proto__ с Object.prototype, а они у них одинаковые, так как prototype 17 | // был изменен руками. 18 | -------------------------------------------------------------------------------- /11. Videos/React/01. React Batching/images/1-batching-history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meowto16/learn-javascript-ru/1ae03863f787fe5f7fcd139a58641c3560b0c4d8/11. Videos/React/01. React Batching/images/1-batching-history.png -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/1.11. Coordinates/README.md: -------------------------------------------------------------------------------- 1 | #1.11. Координаты 2 | 3 | - 'clientX' - test 4 | 5 | -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/1.3. DOM Navigation/README.md: -------------------------------------------------------------------------------- 1 | # Навигация по DOM-элементам 2 | 3 | Все операции с DOM начинаются с объекта `document`. 4 | Это главная «точка входа» в `DOM`. Из него мы можем получить доступ к любому узлу. 5 | 6 | - `document.documentElement` = `` 7 | - `document.body` = `` 8 | - `document.head` = `` 9 | 10 | > В мире DOM `null` означает «не существует» 11 | > 12 | > В DOM значение `null` значит «не существует» или «нет такого узла». 13 | 14 | Свойства `firstChild` и `lastChild` обеспечивают 15 | быстрый доступ к первому и последнему дочернему элементу. 16 | 17 | Свойства `previousSibling` и `nextSibling` правый и левый соседи. 18 | 19 | ## DOM-коллекции 20 | 21 | - DOM-коллекции – только для чтения 22 | - DOM-коллекции живые 23 | - Не используйте цикл `for..in` для перебора коллекций 24 | -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/1.3. DOM Navigation/src/1-get-child-elements-in-dom.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Дочерние элементы в DOM (важность: 5) 3 | * 4 | * Для страницы: 5 | * 6 | * 7 | *
Пользователи:
8 | * 12 | * 13 | * 14 | */ 15 | 16 | const div = document.body.firstElementChild 17 | const ul = div.nextElementSibling 18 | const secondLi = ul.lastElementChild -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/1.3. DOM Navigation/src/2-question-about-siblings.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Вопрос о соседях (важность: 5) 3 | * 4 | * Если elem – произвольный узел DOM-элемента… 5 | * 6 | * Правда, что elem.lastChild.nextSibling всегда равен null? Да 7 | * Правда, что elem.children[0].previousSibling всегда равен null ? Нет 8 | */ -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/1.3. DOM Navigation/src/3-fill-red-cells.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Выделите ячейки по диагонали (важность: 5) 3 | * 4 | * Напишите код, который выделит красным цветом все ячейки в таблице по диагонали. 5 | * Вам нужно получить из таблицы все диагональные
и выделить их, используя код: 6 | */ 7 | 8 | const table = document.body.firstElementChild; 9 | const tbody = table.firstElementChild 10 | const rows = tbody.children 11 | 12 | Array.from(rows).forEach((row, idx) => { 13 | row.children[idx].style.backgroundColor = 'red' 14 | }) -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/1.5. Basic DOM node properties/images/1-dom-node-hierarchy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meowto16/learn-javascript-ru/1ae03863f787fe5f7fcd139a58641c3560b0c4d8/2. Browser: document, events, interfaces/1.5. Basic DOM node properties/images/1-dom-node-hierarchy.png -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/1.5. Basic DOM node properties/src/1-count-descedants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Считаем потомков (важность: 5) 3 | * 4 | * У нас есть дерево, структурированное как вложенные списки ul/li. 5 | * 6 | * Напишите код, который выведет каждый элемент списка
  • : 7 | * 8 | * Какой в нём текст (без поддерева) ? 9 | * Какое число потомков – всех вложенных
  • (включая глубоко вложенные) ? 10 | */ 11 | 12 | const ul = document.querySelector('ul') 13 | const li = ul.querySelectorAll('li') 14 | document.write(ul.textContent) 15 | document.write(`Число li: ${li.length}`) -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/1.5. Basic DOM node properties/src/2-what-contains-nodetype.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Что содержит свойство nodeType? (важность: 5) 3 | * 4 | * Что выведет этот код? 5 | * 6 | * 7 | * 8 | * 9 | * 12 | * 13 | * 14 | * 15 | */ 16 | 17 | // Я думаю выведет 1, так как на момент выполнения скрипта браузер еще не обработает тег 13 | */ 14 | 15 | // Выведет BODY -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/1.5. Basic DOM node properties/src/4-where-is-document.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Где в DOM-иерархии "document"? (важность: 4) 3 | * 4 | * Объектом какого класса является document? 5 | * 6 | * Какое место он занимает в DOM-иерархии? 7 | * 8 | * Наследует ли он от Node или от Element, или может от HTMLElement? 9 | */ 10 | 11 | // document – объект класса HTMLDocument. 12 | // Document -> Node -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/1.6. DOM Attributes and properties/src/1-get-attribute.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Получите атрибут (важность: 5) 3 | * 4 | * Напишите код для выбора элемента с атрибутом data-widget-name из документа и прочитайте его значение. 5 | * 6 | * 7 | * 8 | * 9 | * 10 | *
    Choose the genre
    11 | * 12 | * 15 | * 16 | * 17 | * 18 | * 19 | */ 20 | 21 | const element = document.querySelector('[data-widget-name]') 22 | const widgetName = element.dataset.widgetName 23 | 24 | -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/1.6. DOM Attributes and properties/src/2-color-orange-for-external-links.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Сделайте внешние ссылки оранжевыми (важность: 3) 3 | * Сделайте все внешние ссылки оранжевыми, изменяя их свойство style. 4 | * 5 | * Ссылка является внешней, если: 6 | * 7 | * Её href содержит :// 8 | * Но не начинается с http://internal.com. 9 | * Пример: 10 | */ 11 | 12 | const isExternalLink = link => { 13 | return link.includes('://') 14 | && !link.startsWith(window.location.origin) 15 | && !link.startsWith('http://internal.com') 16 | } 17 | 18 | const links = document.querySelectorAll('a') 19 | const externalLinks = [...links].filter((link) => isExternalLink(link.href)) 20 | 21 | externalLinks.forEach(link => link.style.color = 'orange') -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/1.7. Modifiying document/src/1-createTextnode-innerHTML-textContent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * createTextNode vs innerHTML vs textContent (важность: 5) 3 | * 4 | * У нас есть пустой DOM-элемент elem и строка text. 5 | * 6 | * Какие из этих 3-х команд работают одинаково? 7 | * 8 | * elem.append(document.createTextNode(text)) 9 | * elem.innerHTML = text 10 | * elem.textContent = text 11 | */ 12 | 13 | /** 14 | * Решение: ни один 15 | * 16 | * В первом случае вставится текст в конец, и не затрет другой текст 17 | * Во втором случае похож на третий (тем что затирает), но он вставляет еще HTML 18 | */ -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/1.7. Modifiying document/src/2-clear-elem.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Очистите элемент (важность: 5) 3 | * 4 | * Создайте функцию clear(elem), которая удаляет всё содержимое из elem. 5 | * 6 | * 7 | *
      8 | *
    1. Привет
    2. 9 | *
    3. Мир
    4. 10 | *
    11 | * 12 | * 18 | */ 19 | 20 | function clear(elem) { 21 | elem.innerHTML = '' 22 | } 23 | 24 | -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/1.7. Modifiying document/src/3-why-aaa-stays.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Почему остаётся "aaa"? (важность: 1) 3 | * 4 | * Запустите этот пример. Почему вызов remove не удалил текст "aaa"? 5 | * 6 | * 7 | * aaa 8 | * 9 | * 10 | * 11 | *
    Тест
    12 | * 13 | * 19 | */ 20 | 21 | // Решение: потому что HTML некорректный и текст сдвигается до -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/1.7. Modifiying document/src/6-output-descendants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Выведите список потомков в дереве (важность: 5) 3 | * 4 | * Есть дерево, организованное в виде вложенных списков ul/li. 5 | * 6 | * Напишите код, который добавит каждому элементу списка
  • количество вложенных в него элементов. Узлы нижнего уровня, без детей – пропускайте. 7 | * 8 | * Результат: 9 | */ 10 | 11 | const nodes = document.querySelectorAll('li') 12 | 13 | for (const li of nodes) { 14 | const liCount = li.querySelectorAll('li').length 15 | const firstNode = li.firstChild 16 | 17 | if (liCount > 0 && firstNode.nodeType === 3) { 18 | 19 | firstNode.nodeValue += `[${liCount}]` 20 | } 21 | } -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/1.9. Size and scroll/src/1-find-scroll-bottom.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Найти размер прокрутки снизу (важность: 5) 3 | * 4 | * Свойство elem.scrollTop содержит размер прокрученной области при отсчёте сверху. А как подсчитать размер прокрутки снизу (назовём его scrollBottom)? 5 | * Напишите соответствующее выражение для произвольного элемента elem. 6 | * 7 | * P.S. Проверьте: если прокрутки нет вообще или элемент полностью прокручен – оно должно давать 0. 8 | */ 9 | 10 | /** 11 | * 12 | * @param {HTMLElement} elem 13 | * @return {number} 14 | */ 15 | const getScrollBottom = (elem) => { 16 | return elem.scrollHeight - elem.scrollTop - elem.clientHeight 17 | } 18 | 19 | -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/2.1. Introduction-browser-events/src/1-hide-element-on-click.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Скрыть элемент по нажатию кнопки (важность: 5) 3 | * 4 | * Добавьте JavaScript к кнопке button, чтобы при нажатии элемент
    исчезал. 5 | */ 6 | 7 | const buttonNode = document.getElementById('hider') 8 | const textNode = document.getElementById('text') 9 | 10 | buttonNode.addEventListener('click', () => textNode.style.display = 'none') 11 | -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/2.1. Introduction-browser-events/src/2-hide-self.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Спрятать себя (важность: 5) 3 | * 4 | * Создайте кнопку, которая будет скрывать себя по нажатию. 5 | */ 6 | 7 | document.getElementById('button').addEventListener('click', function() { 8 | this.style.display = 'none' 9 | }) 10 | -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/2.1. Introduction-browser-events/src/3-which-handler-will-emit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Какой обработчик запустится? (важность: 5) 3 | * 4 | * В переменной button находится кнопка. Изначально на ней нет обработчиков. 5 | * Который из обработчиков запустится? Что будет выведено при клике после выполнения кода? 6 | */ 7 | 8 | button.addEventListener("click", () => alert("1")); 9 | 10 | button.removeEventListener("click", () => alert("1")); 11 | 12 | button.onclick = () => alert(2); 13 | 14 | // Решение: 15 | // 1. Сначала выведется alert("1"), затем alert(2) 16 | // alert("1") - не удалится, так как там стрелочная функция при удалении. А надо ссылку на функцию -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/2.1. Introduction-browser-events/src/5-create-expandable-menu.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Создать раскрывающееся меню (важность: 5) 3 | * 4 | * Создать меню, которое по нажатию открывается либо закрывается: 5 | */ 6 | 7 | -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/2.3. Event Delegation/README.md: -------------------------------------------------------------------------------- 1 | # Делегирование событий 2 | 3 | Вместо того, чтобы назначать обработчик каждому - можно ставить один обработчик на их общего предка. 4 | Далее, в зависимости от `event.target`, определяем что нужно выполнить. 5 | 6 | ### Плюсы: 7 | - Упрощает процесс инициализации и экономит память: не нужно вешать много обработчиков. 8 | - Меньше кода: при добавлении и удалении элементов не нужно ставить или снимать обработчики. 9 | - Удобство изменений DOM: можно массово добавлять или удалять элементы путём изменения innerHTML и ему подобных. 10 | 11 | ### Минусы: 12 | - Событие должно всплывать 13 | - делегирование создаёт дополнительную нагрузку на браузер (но она незначительна) 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/2.3. Event Delegation/src/1-hide-with-event-delegation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Спрячьте сообщения с помощью делегирования 3 | * 4 | * Дан список сообщений с кнопками для удаления [x]. Заставьте кнопки работать. 5 | * @type {HTMLElement} 6 | */ 7 | 8 | const container = document.getElementById('container') 9 | 10 | container.addEventListener('click', (event) => { 11 | const pane = event.target.closest('.pane') 12 | const isRemoveButtonPressed = Boolean(event.target.closest('button.remove-button')) 13 | 14 | if (isRemoveButtonPressed) { 15 | pane.hidden = true 16 | } 17 | }) -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/2.3. Event Delegation/src/2-accordion-tree.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Раскрывающееся дерево (важность: 5) 3 | * 4 | * Создайте дерево, которое по клику на заголовок скрывает-показывает потомков: 5 | * 6 | * Требования: 7 | * 8 | * - Использовать только один обработчик событий (применить делегирование) 9 | * - Клик вне текста заголовка (на пустом месте) ничего делать не должен. 10 | */ 11 | 12 | const container = document.getElementById('tree') 13 | 14 | container.addEventListener('click', (event) => { 15 | const isClickedSpan = event.target.tagName === 'SPAN' 16 | 17 | if (!isClickedSpan) { 18 | return 19 | } 20 | 21 | const listItem = event.target.closest('li') 22 | const ul = listItem.querySelector('ul') 23 | 24 | if (!ul) { 25 | return 26 | } 27 | 28 | ul.hidden = !ul.hidden 29 | }) -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/2.4. Default Browser Action/src/1-why-return-false-not-work.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Почему не работает return false? (важность: 3) 3 | * 4 | * Почему в коде ниже return false не работает? 5 | */ 6 | 7 | /** 8 | * 14 | * 15 | * браузер откроет w3.org 16 | */ 17 | 18 | // Решение: надо возвращать значение из handler() 19 | // браузер откроет w3.org 20 | -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/3.3. Mouse drag and drop/README.md: -------------------------------------------------------------------------------- 1 | # Drag'n'Drop с событиями мыши 2 | 3 | Базовый алгоритм Drag’n’Drop выглядит так: 4 | 5 | - При `mousedown` – готовим элемент к перемещению, если необходимо (например, создаём его копию). 6 | - Затем при `mousemove` передвигаем элемент на новые координаты путём смены `left`/`top` и `position:absolute`. 7 | - При `mouseup` – остановить перенос элемента и произвести все действия, связанные с окончанием Drag’n’Drop. 8 | 9 | В начале перетаскивания: запоминаем начальное смещение указателя относительно элемента: 10 | `shiftX`/`shiftY` – и сохраняем его при перетаскивании. 11 | 12 | Существует метод `document.elementFromPoint(clientX, clientY)`. 13 | Он возвращает наиболее глубоко вложенный элемент по заданным координатам окна 14 | (или `null`, если указанные координаты находятся за пределами окна). 15 | 16 | 17 | -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/3.5. Pointer-events/README.md: -------------------------------------------------------------------------------- 1 | # События указателя 2 | 3 | События указателя (Pointer events) – это современный способ обработки ввода с помощью различных указывающих устройств, 4 | таких как мышь, перо/стилус, сенсорный экран и так далее. 5 | 6 | Мы можем заменить `mouse` на `pointer` в названиях событий и код продолжит работать для мыши, 7 | при этом получив лучшую поддержку других типов устройств. 8 | 9 | Дополнительные возможности событий указателя: 10 | 11 | - Поддержка мультитач с помощью `pointerId` и `isPrimary`. 12 | - Особые свойства для определённых устройств, такие как `pressure`, `width`/`height` и другие. 13 | - Захват указателя: мы можем перенаправить все события указателя на определённый элемент до наступления события `pointerup`/`pointercancel`. 14 | 15 | -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/3.6. On scroll/README.md: -------------------------------------------------------------------------------- 1 | # Прокрутка 2 | 3 | Событие прокрутки `scroll` позволяет реагировать на прокрутку страницы или элемента. 4 | 5 | Нельзя предотвратить прокрутку, используя `event.preventDefault()` в обработчике `onscroll`, 6 | потому что он срабатывает после того, как прокрутка уже произошла. -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/4.1. Form elements/src/1-add-option-to-select.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Добавьте пункт к выпадающему списку (важность: 5) 3 | * 4 | * Используя JavaScript: 5 | * 6 | * Выведите значение и текст выбранного пункта. 7 | * Добавьте пункт: . 8 | * Сделайте его выбранным. 9 | */ 10 | 11 | const select = document.getElementById('genres') 12 | const selectedOption = select.options[select.selectedIndex] 13 | 14 | alert(`Сейчас выбрана опция "${selectedOption.innerText}"" со значением ${selectedOption.value}`) 15 | 16 | select.append(new Option('Классика', 'classic', true, true)) -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/4.2. Focus and blur/README.md: -------------------------------------------------------------------------------- 1 | # Фокусировка: focus/blur 2 | 3 | Элемент получает `focus`, когда пользователь кликает по нему или использует клавишу `Tab`. 4 | Момент потери фокуса (`blur`) может быть важнее. 5 | Это момент, когда пользователь кликает куда-то ещё или нажимает `Tab`, чтобы переключиться на 6 | следующее поле формы. 7 | 8 | Методы `elem.focus()` и `elem.blur()` устанавливают/снимают фокус. 9 | 10 | ## Включаем фокусировку на любом элементе: tabindex 11 | 12 | Любой элемент поддерживает фокусировку, если имеет `tabindex`. 13 | 14 | При совпадающих `tabindex` элементы перебираются в том порядке, в котором идут в документе. 15 | 16 | - `tabindex="0"` ставит элемент в один ряд с элементами без tabindex. 17 | - `tabindex="-1"` позволяет фокусировать на элементе только программно. 18 | 19 | -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/4.3. Change, input, copy/README.md: -------------------------------------------------------------------------------- 1 | # События: change, input, cut, copy, paste 2 | 3 | ## Событие: change 4 | 5 | - срабатывает по окончании изменения элемента. 6 | - Для текстовых `` это означает, что событие происходит при потере фокуса. 7 | 8 | ## Событие: input 9 | 10 | Событие `input` срабатывает каждый раз при изменении значения. 11 | 12 | Событие `input` происходит после изменения значения. 13 | Поэтому мы не можем использовать `event.preventDefault()` там – будет уже слишком поздно, 14 | никакого эффекта не будет. 15 | 16 | ## События: cut, copy, paste 17 | 18 | Эти события происходят при вырезании/копировании/вставке данных. 19 | Действие можно предотвратить. 20 | Свойство `event.clipboardData` предоставляет доступ на чтение/запись в буфер обмена… 21 | 22 | -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/4.4. Form submit/README.md: -------------------------------------------------------------------------------- 1 | # Отправка формы: событие и метод submit 2 | 3 | Когда форма отправляется, то срабатывает событие `submit`. 4 | 5 | > Обычно событие `submit` используется для валидации формы 6 | 7 | Есть два основных способа отправить форму: 8 | 9 | 1. Первый – нажать кнопку `` или ``. 10 | 2. Второй – нажать `Enter`, находясь на каком-нибудь поле. 11 | 12 | > При отправке формы по нажатию `Enter` в текстовом поле, 13 | > генерируется событие `click` на кнопке ``. 14 | 15 | Метод `form.submit()` позволяет инициировать отправку формы из JavaScript. 16 | При этом событие `submit` уже не сработает, так как предполагается, что программист 17 | знает что делает... (провалидировал данные заранее и т.д) 18 | 19 | -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/5.3. Onload, onerror/src/1-preload-images.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Загрузите изображения с колбэком (важность: 4) 3 | * 4 | * Создайте функцию preloadImages(sources, callback), которая загружает все изображения из массива sources и, 5 | * когда все они будут загружены, вызывает callback. 6 | */ 7 | 8 | function loadImage(src) { 9 | return new Promise((resolve, reject) => { 10 | const image = new Image() 11 | image.addEventListener('load', resolve.bind(this, image)) 12 | image.addEventListener('error', reject.bind(this, image)) 13 | 14 | image.src = src 15 | }) 16 | } 17 | 18 | function preloadImages(sources, callback) { 19 | return Promise.all(sources.map(loadImage)).finally(callback) 20 | } -------------------------------------------------------------------------------- /2. Browser: document, events, interfaces/6.3. Event loop/src/1-what-will-output.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Что код выведет в консоли? (важность: 5) 3 | * 4 | */ 5 | 6 | 7 | setTimeout(function timeout() { 8 | console.log('Таймаут'); 9 | }, 0); 10 | 11 | let p = new Promise(function(resolve, reject) { 12 | console.log('Создание промиса'); 13 | resolve(); 14 | }); 15 | 16 | p.then(function(){ 17 | console.log('Обработка промиса'); 18 | }); 19 | 20 | console.log('Конец скрипта'); 21 | 22 | // Решение: 23 | // 1. "Создание промиса". Так как callback внутри промиса является обычным синхронным кодом 24 | // 2. "Конец скрипта". Обычный синхронный код, но в конце страницы 25 | // 3. "Обработка промиса". Так как это микрозадача 26 | // 4. "Таймаут". Так как это макрозадача. 27 | -------------------------------------------------------------------------------- /4. Additional/4.1 Programming paradigms/4.1.2 Procedural/README.md: -------------------------------------------------------------------------------- 1 | # Процедурное программирование 2 | 3 | Программа ожидает на вход какие-либо данные, выполняет ряд процедур и возвращает результат. 4 | 5 | Подобный подход и называется процедурным: 6 | ```javascript 7 | const width = 5 8 | const height = 5 9 | 10 | function calcRectArea(width, height) { 11 | return width * height 12 | } 13 | 14 | calcRectArea(width, height) 15 | ``` 16 | 17 | Задача разбивается на **шаги** и выполняется **шаг за шагом** 18 | 19 | > Изначально все программы писались именно с процедурным подходом. 20 | > Позже, когда программы стали становиться больше, данный подход начал отходить на второй план 21 | 22 | 23 | -------------------------------------------------------------------------------- /5. Tasks/codewars/2 kyu/1. Multi Line Task++: Hello World.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5935558a32fb828aad001213 2 | 3 | f= 4 | '' 5 | [ 6 | '\ 7 | t\ 8 | r\ 9 | i\ 10 | m' 11 | ][ 12 | '\ 13 | b\ 14 | i\ 15 | n\ 16 | d' 17 | ]` 18 | H\ 19 | e\ 20 | l\ 21 | l\ 22 | o\ 23 | ,\ 24 | \ 25 | w\ 26 | o\ 27 | r\ 28 | l\ 29 | d\ 30 | !` -------------------------------------------------------------------------------- /5. Tasks/codewars/4 kyu/10. Next bigger number with the same digits.js: -------------------------------------------------------------------------------- 1 | function nextBigger(n){ 2 | const digits = String(n).split('') 3 | const permutations = [] 4 | const permutate = (digits, tail) => { 5 | const seenDigits = {} 6 | 7 | digits.forEach((digit, idx) => { 8 | if (seenDigits[digit]) return; 9 | 10 | const digitsLeft = [...digits] 11 | digitsLeft.splice(idx, 1) 12 | 13 | seenDigits[digit] = true 14 | 15 | if (digitsLeft.length >= 1) { 16 | return permutate(digitsLeft, tail + digit) 17 | } else { 18 | permutations.push(Number(tail + digit)) 19 | } 20 | }) 21 | } 22 | 23 | permutate(digits, '') 24 | permutations.sort((a, b) => a - b) 25 | 26 | const foundIdx = permutations.findIndex((number) => number === n) 27 | 28 | return permutations[foundIdx + 1] || -1 29 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/4 kyu/11. Sort binary tree by levels.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/52bef5e3588c56132c0003bc 2 | function treeByLevels(rootNode) { 3 | const list = [] 4 | 5 | function sortByLvl(tree, level = 0) { 6 | if (!tree) { 7 | return; 8 | } 9 | 10 | if (!list[level]) { 11 | list[level] = [] 12 | } 13 | 14 | list[level].push(tree.value) 15 | 16 | 17 | if (tree.left) { 18 | sortByLvl(tree.left, level + 1) 19 | } 20 | 21 | if (tree.right) { 22 | sortByLvl(tree.right, level + 1) 23 | } 24 | } 25 | 26 | sortByLvl(rootNode) 27 | 28 | return list.flat() 29 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/4 kyu/3. Nesting Structure Comparison.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.codewars.com/kata/520446778469526ec0000001/javascript 3 | */ 4 | Array.prototype.sameStructureAs = function (other) { 5 | if (this.length !== other.length) { 6 | return false; 7 | } 8 | 9 | for (let key in this) { 10 | const isPrimitives = !Array.isArray(this[key]) && !Array.isArray(other[key]) 11 | const isArrays = Array.isArray(this[key]) && Array.isArray(other[key]) 12 | 13 | if (!isPrimitives && !isArrays) { 14 | return false 15 | } 16 | 17 | if (isPrimitives) { 18 | continue; 19 | } 20 | 21 | const checkNested = this[key].sameStructureAs(other[key]) 22 | 23 | if (!checkNested) { 24 | return false 25 | } 26 | } 27 | 28 | return true; 29 | }; -------------------------------------------------------------------------------- /5. Tasks/codewars/4 kyu/5. Strip comments.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/51c8e37cee245da6b40000bd 2 | 3 | function solution(input, markers) { 4 | const hashMap = markers.reduce((acc, cur) => { 5 | acc[cur] = true; 6 | return acc 7 | }, {}) 8 | 9 | const rows = input.split('\n') 10 | const filtered = rows.map((row) => { 11 | const commentIdx = [...row].findIndex((char) => hashMap[char]) 12 | const commented = commentIdx === -1 ? row : row.slice(0, commentIdx) 13 | 14 | return commented.trim() 15 | }) 16 | 17 | return filtered.filter(Boolean).join('\n') 18 | } 19 | -------------------------------------------------------------------------------- /5. Tasks/codewars/4 kyu/6. Permutations.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5254ca2719453dcc0b00027d 2 | 3 | function permutations(string) { 4 | const letters = string.split('') 5 | const permutations = [] 6 | 7 | function recursive(letters, tail = '') { 8 | if (letters.length === 1) return permutations.push(tail + letters[0]) 9 | 10 | const tree = {} 11 | 12 | for (let i = 0; i < letters.length; i++) { 13 | const letter = letters[i] 14 | 15 | if (tree[letter]) continue 16 | 17 | const otherLetters = [...letters] 18 | otherLetters.splice(i, 1) 19 | 20 | tree[letter] = recursive(otherLetters, tail + letter) 21 | } 22 | 23 | return tree 24 | } 25 | 26 | recursive(letters) 27 | 28 | return permutations 29 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/4 kyu/7. Sum Strings as Numbers.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5324945e2ece5e1f32000370 2 | 3 | function sumStrings(a,b) { 4 | return String(BigInt(a) + BigInt(b)) 5 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/4 kyu/9. Range extraction.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/51ba717bb08c1cd60f00002f 2 | 3 | function solution(list){ 4 | const ranges = [] 5 | 6 | let rangeIdx = 0; 7 | 8 | for (let i = 0; i < list.length; i++) { 9 | const current = list[i] 10 | const next = list[i + 1] 11 | 12 | if (!ranges[rangeIdx]) ranges[rangeIdx] = [] 13 | ranges[rangeIdx].push(current) 14 | 15 | if (next - current > 1) { 16 | rangeIdx++ 17 | } 18 | } 19 | 20 | return ranges.map((range) => { 21 | const start = range[0] 22 | const end = range.length > 1 ? range[range.length - 1] : null 23 | 24 | if (range.length === 1) return `${start}` 25 | if (range.length === 2) return `${start},${end}` 26 | 27 | return `${start}-${end}` 28 | }).join(',') 29 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/5 kyu/1. int32 to IPv4.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.codewars.com/kata/52e88b39ffb6ac53a400022e 3 | */ 4 | 5 | function int32ToIp(int32){ 6 | const bytes = (+int32).toString(2).padStart(32, '0'); 7 | const octets = [ 8 | bytes.slice(0, 8), 9 | bytes.slice(8, 16), 10 | bytes.slice(16, 24), 11 | bytes.slice(24, 32) 12 | ]; 13 | 14 | return octets 15 | .map((binary) => parseInt(binary, 2).toString()) 16 | .join('.') 17 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/5 kyu/10. Array.diff hero.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/581fc49b55c3d2d83c0000f8 2 | 3 | function arrayDiffVeryFast(a, b) { 4 | const valuesFromSecondMap = b.reduce((acc, cur) => { 5 | acc[cur] = true 6 | return acc 7 | }, {}) 8 | const notExistsInSecond = value => !valuesFromSecondMap[value] 9 | 10 | return a.filter(notExistsInSecond) 11 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/5 kyu/12. Simple events.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/52d3b68215be7c2d5300022f 2 | 3 | function Event() { 4 | this._subscribers = []; 5 | 6 | this.subscribe = function(callback) { 7 | this._subscribers.push(callback); 8 | } 9 | 10 | this.unsubscribe = function(callback) { 11 | this._subscribers = this._subscribers.filter((subscriber) => subscriber !== callback); 12 | } 13 | 14 | this.emit = function(...data) { 15 | this._subscribers.forEach((subscriber) => { 16 | subscriber.call(this, ...data); 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /5. Tasks/codewars/5 kyu/14. Can you get the loop.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/52a89c2ea8ddc5547a000863 2 | 3 | function loop_size(node){ 4 | const memoized = new Map() 5 | 6 | let current = node 7 | let size = 1; 8 | 9 | while (true) { 10 | if (memoized.get(current)) { 11 | break; 12 | } 13 | 14 | if (!current.getNext() || current.getNext() === current) { 15 | return size; 16 | } 17 | 18 | memoized.set(current, true) 19 | current = current.getNext() 20 | } 21 | 22 | let loopStart = current; 23 | 24 | while (loopStart !== current.getNext()) { 25 | size++ 26 | current = current.getNext() 27 | } 28 | 29 | return size 30 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/5 kyu/16. Function Cache.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/525481903700c1a1ff0000e1 2 | 3 | function cache(func) { 4 | const memory = {} 5 | 6 | return (...args) => { 7 | const key = JSON.stringify(args) 8 | 9 | if (key in memory) { 10 | return memory[key] 11 | } 12 | 13 | const result = func.call(this, ...args) 14 | memory[key] = result 15 | 16 | return result 17 | } 18 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/5 kyu/3. Product of consecutive Fib numbers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.codewars.com/kata/5541f58a944b85ce6d00006a/javascript 3 | */ 4 | function productFib(prod){ 5 | const fibo = [0, 1] 6 | let next = 1; 7 | let idx = 0; 8 | 9 | while (next < Number.MAX_SAFE_INTEGER) { 10 | next = fibo[idx] + fibo[idx + 1] 11 | fibo.push(next) 12 | idx++ 13 | } 14 | 15 | for (let i = 0; i < fibo.length; i++) { 16 | const left = fibo[i] 17 | const right = fibo[i + 1] 18 | 19 | const mult = left * right 20 | 21 | if (mult === prod) { 22 | return [left, right, true] 23 | } 24 | 25 | if (mult > prod) { 26 | return [left, right, false] 27 | } 28 | } 29 | 30 | return null; 31 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/5 kyu/5. The Hashtag generator.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/52449b062fb80683ec000024/ 2 | 3 | function capitalize(str) { 4 | return str.slice(0, 1).toUpperCase() + str.slice(1) 5 | } 6 | 7 | function generateHashtag (str) { 8 | str = str.trim().replace(/\s{2,}/g, ' ') 9 | 10 | if (str === "") return false 11 | 12 | const hashtag = str 13 | .split(' ') 14 | .map(capitalize) 15 | .join(``) 16 | 17 | if (hashtag.length >= 140) return false 18 | 19 | return `#${hashtag}` 20 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/5 kyu/7. 1's, 0's and wildcards.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/588f3e0dfa74475a2600002a 2 | 3 | function possibilities(str) { 4 | const permutations = [] 5 | const position = str.indexOf('?') 6 | 7 | if (position === -1) { 8 | return [str] 9 | } 10 | 11 | const first = str.slice(0, position) + '0' + str.slice(position + 1) 12 | const second = str.slice(0, position) + '1' + str.slice(position + 1) 13 | 14 | permutations.push( 15 | ...possibilities(first), 16 | ...possibilities(second), 17 | ) 18 | 19 | return permutations; 20 | } 21 | -------------------------------------------------------------------------------- /5. Tasks/codewars/5 kyu/9. Number of trailing zeros of N!.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/52f787eb172a8b4ae1000a34 2 | 3 | // A trailing zero is always produced by prime factors 2 and 5. 4 | // If we can count the number of 5s and 2s, our task is done. 5 | 6 | function zeros (n) { 7 | if (n < 0) return -1 8 | 9 | let count = 0 10 | 11 | for (let i = 5; Math.floor(n / i) >= 1; i *= 5) { 12 | count += Math.floor(n / i) 13 | } 14 | 15 | return count 16 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/1. Your order, please!.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.codewars.com/kata/55c45be3b2079eccff00010f/javascript 3 | */ 4 | 5 | function order(words){ 6 | if (words === "") return "" 7 | 8 | const onlyNum = (str) => +str.replace(/[^0-9]/g, '') 9 | 10 | return words 11 | .split(' ') 12 | .sort((a, b) => { 13 | return onlyNum(a) - onlyNum(b) 14 | }) 15 | .join(' ') 16 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/11. Get Length of missing array.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/57b6f5aadb5b3d0ae3000611 2 | 3 | function getLengthOfMissingArray(arr) { 4 | if (!arr?.length) return 0 5 | 6 | const lengths = {} 7 | 8 | for (let inner of arr) { 9 | if (!inner?.length) return 0 10 | 11 | lengths[inner.length] = inner.length 12 | } 13 | 14 | const keys = Object.keys(lengths) 15 | let lastKey = Number(keys[0]) 16 | 17 | for (let i = 1; i < keys.length; i++) { 18 | const currentKey = Number(keys[i]) 19 | const shouldBeKey = lastKey + 1 20 | 21 | if (currentKey !== shouldBeKey) return shouldBeKey 22 | 23 | lastKey = shouldBeKey 24 | } 25 | 26 | return 0 27 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/12. Duplicate Encoder.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/54b42f9314d9229fd6000d9c 2 | 3 | function duplicateEncode(word){ 4 | const charsCountMap = word.split('').reduce((acc, char) => { 5 | char = char.toLowerCase() 6 | acc[char] = (acc[char] || 0) + 1 7 | 8 | return acc 9 | }, {}) 10 | 11 | return word 12 | .split('') 13 | .map((char) => charsCountMap[char.toLowerCase()] === 1 ? '(' : ')') 14 | .join('') 15 | } 16 | -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/13. Take a number and sum its digits raised. Eureca.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5626b561280a42ecc50000d1 2 | 3 | function sumDigPow(from, to) { 4 | const eurica = [] 5 | 6 | for (let num = from; num <= to; num++) { 7 | const digits = String(num).split('') 8 | const powed = digits.map((num, i) => num ** (i + 1)) 9 | const sum = powed.reduce((acc, cur) => acc + cur) 10 | 11 | if (sum === num) { 12 | eurica.push(num) 13 | } 14 | } 15 | 16 | return eurica 17 | } 18 | -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/14. Tortoise racing.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/55e2adece53b4cdcb900006c 2 | 3 | function race(v1, v2, g) { 4 | const s1 = v1 / 60 / 60 5 | const s2 = v2 / 60 / 60 6 | 7 | const speedDiff = (v2 - v1) / 60 / 60 8 | 9 | const distanceToLead = Math.floor(g / speedDiff) 10 | 11 | const hours = Math.floor(distanceToLead / 3600) 12 | const minutes = Math.floor((distanceToLead - (hours * 3600)) / 60) 13 | const seconds = Math.floor(distanceToLead - (hours * 3600) - (minutes * 60)) 14 | 15 | const result = [hours, minutes, seconds] 16 | 17 | if (result.some((value) => value < 0)) return null 18 | 19 | return [hours, minutes, seconds] 20 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/15. Build tower.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/576757b1df89ecf5bd00073b 2 | 3 | const towerBuilder = floors => Array.from({ length: floors }, (_, i) => { 4 | const spaces = floors - 1 - i; 5 | const stars = 1 + (i * 2); 6 | 7 | return ' '.repeat(spaces) + '*'.repeat(stars) + ' '.repeat(spaces) 8 | }) 9 | -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/16. Triple Double.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/55d5434f269c0c3f1b000058 2 | 3 | function tripledouble(num1, num2) { 4 | const FOUND_RESPONSE = 1 5 | const NOT_FOUND_RESPONSE = 0 6 | 7 | const possibles = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 8 | const [first, second] = [num1, num2].map(String) 9 | 10 | for (const possible of possibles) { 11 | const triple = String(possible).repeat(3) 12 | const double = String(possible).repeat(2) 13 | 14 | const foundTripleInFirst = first.indexOf(triple) !== -1 15 | const foundDoubleInSecond = second.indexOf(double) !== -1 16 | 17 | if (foundTripleInFirst && foundDoubleInSecond) { 18 | return FOUND_RESPONSE 19 | } 20 | } 21 | 22 | return NOT_FOUND_RESPONSE 23 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/17. Function composition.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5655c60db4c2ce0c2e000026 2 | 3 | const compose = (...functions) => arg => functions.reduceRight((res, fn) => fn.call(this, res), arg); -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/18. Data Reverse.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/569d488d61b812a0f7000015 2 | 3 | function dataReverse(data) { 4 | const SEGMENT_SIZE = 8 5 | 6 | const result = [] 7 | 8 | for (let i = data.length; i >= 0; i -= SEGMENT_SIZE) { 9 | result.push(...data.slice(i - SEGMENT_SIZE, i)) 10 | } 11 | 12 | return result 13 | } 14 | -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/19. Find the missing letter.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5839edaa6754d6fec10000a2 2 | 3 | function findMissingLetter(letters) { 4 | let lastCharCode 5 | 6 | for (const letter of letters) { 7 | const charCode = letter.charCodeAt() 8 | const diff = charCode - lastCharCode 9 | 10 | if (diff > 1) { 11 | return String.fromCharCode(lastCharCode + 1) 12 | } 13 | 14 | lastCharCode = charCode 15 | } 16 | 17 | return null 18 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/21. Find the last Fibonacci digit.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/56b7771481290cc283000f28 2 | 3 | function lastFibDigit(n){ 4 | const pattern = [0, 1, 1, 2, 3, 5, 8, 3, 1, 4, 5, 9, 4, 3, 7, 0, 7, 7, 4, 1, 5, 6, 1, 7, 8, 5, 3, 8, 1, 9, 0, 9, 9, 8, 7, 5, 2, 7, 9, 6, 5, 1, 6, 7, 3, 0, 3, 3, 6, 9, 5, 4, 9, 3, 2, 5, 7, 2, 9, 1] 5 | const idx = n % 60 6 | 7 | return pattern[idx] 8 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/22. The Office V - Find a Chair.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/57f6051c3ff02f3b7300008b 2 | 3 | function meeting(rooms, needChairs){ 4 | if (!needChairs) return 'Game On' 5 | 6 | const result = [] 7 | 8 | for (const [occupants, chairsInRoom] of rooms) { 9 | if (needChairs === 0) return result 10 | 11 | const availableChairs = Math.max(chairsInRoom - occupants.length, 0) 12 | const willGetChairs = needChairs - availableChairs >= 0 13 | ? availableChairs 14 | : needChairs 15 | 16 | needChairs -= willGetChairs; 17 | result.push(willGetChairs); 18 | } 19 | 20 | if (needChairs >= 1) return 'Not enough!' 21 | 22 | return result 23 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/23. Guess the number!.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5452113c699b538c18000b01 2 | 3 | Guesser.prototype.getNumber = function() { 4 | const phrase = { 5 | greater: 'Too low!', 6 | lower: 'Too high!', 7 | equal: 'Correct!', 8 | } 9 | 10 | let number = 500 11 | let diff = 250 12 | let lastAnswer = null 13 | 14 | while (lastAnswer !== phrase.equal) { 15 | lastAnswer = this.guess(number) 16 | 17 | if (lastAnswer === phrase.greater) { 18 | number += diff 19 | } 20 | 21 | if (lastAnswer === phrase.lower) { 22 | number -= diff 23 | } 24 | 25 | if (lastAnswer === phrase.equal) { 26 | return number 27 | } 28 | 29 | diff = Math.round(diff / 2) 30 | } 31 | 32 | return number 33 | }; -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/24. Frog jumping.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/536950ffc8a5ca9982001371 2 | 3 | function solution(arr) { 4 | const MAX_JUMPS = 10_000; 5 | 6 | let idx = 0 7 | let jumps = 0 8 | 9 | while (idx >= 0 && idx < arr.length) { 10 | if (jumps >= MAX_JUMPS) { 11 | return -1; 12 | } 13 | 14 | idx += arr[idx]; 15 | jumps++; 16 | } 17 | 18 | return jumps 19 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/25. Number Zoo Patrol.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5276c18121e20900c0000235 2 | 3 | function findNumber(array) { 4 | const set = new Set(array) 5 | 6 | for (let i = 1; i < 999_999; i++) { 7 | if (!set.has(i)) { 8 | return i; 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/26. CamelCase method.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/587731fda577b3d1b0001196 2 | 3 | String.prototype.camelCase=function(){ 4 | return this 5 | .split(' ') 6 | .filter(Boolean) 7 | .map((str) => str[0].toUpperCase() + str.slice(1)) 8 | .join('') 9 | } 10 | -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/27. Parse a linked list from a string.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/582c5382f000e535100001a7 2 | 3 | function parse(string) { 4 | const nodes = string.split(' -> ') 5 | 6 | let result = null; 7 | 8 | while (nodes.length) { 9 | const node = nodes.pop() 10 | 11 | if (node === 'null') continue 12 | result = new Node(+node, result) 13 | } 14 | 15 | return result 16 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/28. PhoneWords.js: -------------------------------------------------------------------------------- 1 | function phoneWords(stringOfNums) { 2 | const buttons = { 3 | '2': 'abc', 4 | '3': 'def', 5 | '4': 'ghi', 6 | '5': 'jkl', 7 | '6': 'mno', 8 | '7': 'pqrs', 9 | '8': 'tuv', 10 | '9': 'wxyz', 11 | '0': ' ' 12 | } 13 | 14 | return stringOfNums.replace( 15 | /([0]+)|([1]+)|([2]+)|([3]+)|([4]+)|([5]+)|([6]+)|([7]+)|([8]+)|([9]+)/g, 16 | (group) => { 17 | const button = group[0] 18 | const buttonKeys = buttons[button] 19 | 20 | if (!buttonKeys) return '' 21 | 22 | const chunks = [] 23 | const chunkSize = buttonKeys.length 24 | 25 | for (let i = 0; i < group.length; i += chunkSize) { 26 | const chunk = group.slice(i, i + chunkSize); 27 | chunks.push(chunk); 28 | } 29 | 30 | return chunks.map(chunk => buttonKeys[chunk.length - 1]).join('') 31 | } 32 | ) 33 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/29. Longest consecutive.js: -------------------------------------------------------------------------------- 1 | https://www.codewars.com/kata/56a5d994ac971f1ac500003e 2 | 3 | const longestConsec = (strarr, k) => { 4 | if(k > strarr.length || k < 0) return "" 5 | 6 | let maxLengthString = ''; 7 | 8 | for (let i = 0; i < strarr.length + 1 - k; i++) { 9 | const combined = strarr.slice(i, i + k).join('') 10 | 11 | if (combined.length > maxLengthString.length) { 12 | maxLengthString = combined 13 | } 14 | } 15 | 16 | return maxLengthString 17 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/30. Maximum and minimum.js: -------------------------------------------------------------------------------- 1 | function max(...args) { 2 | const flatten = args.map((arg) => { 3 | return Array.isArray(arg) 4 | ? max(...arg.flat()) 5 | : +arg 6 | }) 7 | 8 | let maxValue = flatten[0] || 0 9 | 10 | for (const number of flatten) { 11 | if (Number.isNaN(number)) { 12 | return NaN 13 | } 14 | 15 | maxValue = maxValue > number ? maxValue : number 16 | } 17 | 18 | return maxValue 19 | } 20 | 21 | function min(...args) { 22 | const flatten = args.map((arg) => { 23 | return Array.isArray(arg) 24 | ? min(...arg.flat()) 25 | : +arg 26 | }) 27 | 28 | let minValue = flatten[0] || 0 29 | 30 | for (const number of flatten) { 31 | if (Number.isNaN(number)) { 32 | return NaN 33 | } 34 | 35 | minValue = minValue < number ? minValue : number 36 | } 37 | 38 | return minValue 39 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/31. Plenty of Fish in the Pond.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5904be220881cb68be00007d 2 | 3 | function fish(shoal){ 4 | const AMOUNT_STEP = 4 5 | 6 | const fishes = shoal.split('').sort((a, b) => a - b) 7 | 8 | function getNewSize(score) { 9 | let size = 1; 10 | let amountExtra = AMOUNT_STEP; 11 | 12 | while (score - amountExtra >= 0) { 13 | score -= amountExtra; 14 | size++; 15 | amountExtra += AMOUNT_STEP; 16 | } 17 | 18 | return size; 19 | } 20 | 21 | let size = 1; 22 | let score = 0; 23 | 24 | for (let i = 0; i < fishes.length; i++) { 25 | const fishToEatSize = Number(fishes[i]) 26 | 27 | if (size < fishToEatSize) { 28 | return size; 29 | } 30 | 31 | score += fishToEatSize; 32 | size = getNewSize(score); 33 | } 34 | 35 | return size; 36 | } 37 | -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/32. Word mesh.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5c1ae703ba76f438530000a2 2 | 3 | function wordMesh(arr){ 4 | const FAILED_TO_MESH_ERROR = 'failed to mesh' 5 | 6 | let result = '' 7 | 8 | for (let i = 1; i < arr.length; i++) { 9 | const current = arr[i] 10 | const prev = arr[i - 1] 11 | const minLength = Math.min(prev.length, current.length) 12 | 13 | let same = '' 14 | 15 | for (let j = minLength; j >= 1; j--) { 16 | const left = prev.slice(-j) 17 | const right = current.slice(0, j) 18 | 19 | if (left === right) { 20 | same = left 21 | break 22 | } 23 | } 24 | 25 | if (!same) { 26 | return FAILED_TO_MESH_ERROR 27 | } 28 | 29 | result += same 30 | } 31 | 32 | return result || FAILED_TO_MESH_ERROR 33 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/33. Zero-plentiful Array.js: -------------------------------------------------------------------------------- 1 | function zeroPlentiful(arr){ 2 | let groupsCount = 0 3 | let currentStreak = 0 4 | 5 | for (let i = 0; i < arr.length; i++) { 6 | const number = arr[i] 7 | const isZero = number === 0 8 | const isLast = i === arr.length - 1; 9 | 10 | if (isZero) { 11 | currentStreak++; 12 | } 13 | 14 | if (!isZero || isLast) { 15 | if (currentStreak >= 1 && currentStreak < 4) { 16 | return 0; 17 | } 18 | 19 | if (currentStreak >= 4) { 20 | groupsCount++; 21 | currentStreak = 0; 22 | } 23 | } 24 | } 25 | 26 | return groupsCount 27 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/34. Remove the parentheses.js: -------------------------------------------------------------------------------- 1 | function removeParentheses(sentence) { 2 | let depth = 0 3 | let result = '' 4 | 5 | for (const char of sentence) { 6 | if (char === '(') depth++; 7 | if (char === ')') depth--; 8 | if (depth === 0 && char !== ')' && char !== '(') result += char; 9 | } 10 | 11 | return result 12 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/35. Car number plate calculator.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5f25f475420f1b002412bb1f 2 | 3 | function findTheNumberPlate(customerId){ 4 | const leftCount = Math.floor(customerId / 999) 5 | const rightCount = customerId % 999 6 | 7 | const leftPart = (() => { 8 | const alphabet = 'abcdefghijklmnopqrstuvwxyz' 9 | const counters = [ 10 | leftCount % alphabet.length, 11 | Math.floor(leftCount / alphabet.length) % alphabet.length, 12 | Math.floor(leftCount / alphabet.length ** 2) % alphabet.length, 13 | ] 14 | 15 | return counters.map(idx => alphabet[idx]).join('') 16 | })() 17 | 18 | const rightPart = String(rightCount + 1).padStart(3, '0') 19 | 20 | 21 | return leftPart + rightPart 22 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/38. Lottery Ticket.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/57f625992f4d53c24200070e 2 | 3 | function bingo(ticket, win){ 4 | let miniwins = 0 5 | 6 | for (const [characters, characterCodeToWin] of ticket) { 7 | if (characters.split('').some(char => char.charCodeAt() === characterCodeToWin)) { 8 | miniwins++ 9 | } 10 | } 11 | 12 | return miniwins >= win 13 | ? 'Winner!' 14 | : 'Loser!' 15 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/39. Simple Fun #52: Pair of Shoes.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/58885a7bf06a3d466e0000e3 2 | 3 | function pairOfShoes(shoes) { 4 | const LEFT_SHOE = 0 5 | const RIGHT_SHOE = 1 6 | 7 | const sizes = {} 8 | 9 | for (const [type, size] of shoes) { 10 | if (!sizes[size]) { 11 | sizes[size] = {} 12 | } 13 | 14 | sizes[size][type] = (sizes[size][type] || 0) + 1 15 | } 16 | 17 | for (const [size, types] of Object.entries(sizes)) { 18 | const leftShoesCount = types[LEFT_SHOE] 19 | const rightShoesCount = types[RIGHT_SHOE] 20 | 21 | if (leftShoesCount !== rightShoesCount) { 22 | return false 23 | } 24 | } 25 | 26 | return true 27 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/4. Sorting on Planet Twisted 3-7.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.codewars.com/kata/58068479c27998b11900056e/javascript 3 | * @param array 4 | * @returns {*[]} 5 | */ 6 | 7 | function sortTwisted37(array) { 8 | const twist = (digit) => { 9 | if (digit === '3') return '7' 10 | if (digit === '7') return '3' 11 | 12 | return digit 13 | } 14 | 15 | return [...array].sort((a, b) => { 16 | a = +`${a}`.split('').map(twist).join('') 17 | b = +`${b}`.split('').map(twist).join('') 18 | 19 | return a - b 20 | }) 21 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/6. Split strings.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.codewars.com/kata/515de9ae9dcfc28eb6000001 3 | */ 4 | 5 | function solution(str){ 6 | const CHUNK_LENGTH = 2 7 | const result = [] 8 | 9 | for (let i = 0; i < str.length; i += CHUNK_LENGTH) { 10 | const chunk = str 11 | .split('') 12 | .slice(i, i + CHUNK_LENGTH) 13 | .join('') 14 | .padEnd(CHUNK_LENGTH, '_') 15 | 16 | result.push(chunk) 17 | } 18 | 19 | return result 20 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/7. Rectangle into squares.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.codewars.com/kata/55466989aeecab5aac00003e/ 3 | */ 4 | function sqInRect(length, width){ 5 | if (length === width) return null; 6 | 7 | const result = [] 8 | 9 | const rectangle = { 10 | length, 11 | width, 12 | get area() { 13 | return this.length * this.width; 14 | } 15 | } 16 | 17 | while (rectangle.area > 0) { 18 | const square = { 19 | side: Math.min(rectangle.length, rectangle.width), 20 | } 21 | 22 | if (rectangle.length > rectangle.width) { 23 | rectangle.length -= square.side 24 | } else if (rectangle.length < rectangle.width) { 25 | rectangle.width -= square.side 26 | } else { 27 | rectangle.length -= square.side 28 | rectangle.width -= square.side 29 | } 30 | 31 | result.push(square.side) 32 | } 33 | 34 | return result 35 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/8. Handshake problem.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.codewars.com/kata/5574835e3e404a0bed00001b 3 | */ 4 | function getParticipants(handshakes){ 5 | if (handshakes === 0) return 0 6 | if (handshakes === 1) return 2 7 | 8 | let participants = 1; 9 | 10 | while (handshakes > 0) { 11 | participants++ 12 | handshakes -= (participants - 1) 13 | } 14 | 15 | return participants 16 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/6 kyu/9. Lets Recycle.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5b6db1acb118141f6b000060 2 | 3 | function recycle(bin) { 4 | const groupedByMaterial = { 5 | paper: [], 6 | glass: [], 7 | organic: [], 8 | plastic: [] 9 | } 10 | 11 | bin.forEach((trash) => { 12 | groupedByMaterial[trash.material].push(trash.type) 13 | 14 | if (trash.secondMaterial) { 15 | groupedByMaterial[trash.secondMaterial].push(trash.type) 16 | } 17 | }) 18 | 19 | return Object.values(groupedByMaterial) 20 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/1. Don't give me five!.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.codewars.com/kata/5813d19765d81c592200001a 3 | */ 4 | 5 | const dontGiveMeFive = (start, end) => Array 6 | .from({ length: end - start + 1 }, (_, i) => i + start) 7 | .filter((num) => !String(num).includes('5')) 8 | .length -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/10. The Coupon Code.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.codewars.com/kata/539de388a540db7fec000642 3 | */ 4 | 5 | function checkCoupon(enteredCode, correctCode, currentDate, expirationDate){ 6 | const isExpired = new Date(expirationDate) - new Date(currentDate) < 0; 7 | const isInvalid = enteredCode !== correctCode; 8 | 9 | return !isExpired && !isInvalid 10 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/11. Remove anchor from URL.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/51f2b4448cadf20ed0000386 2 | 3 | function removeUrlAnchor(url){ 4 | const anchorIdx = url.indexOf('#') 5 | 6 | return anchorIdx === -1 ? url : url.slice(0, anchorIdx) 7 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/12. Number of People in the Bus.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5648b12ce68d9daa6b000099 2 | 3 | var number = function(busStops){ 4 | let people = 0; 5 | 6 | for (const [gotOn = 0, gotOff = 0] of busStops) { 7 | people += gotOn - gotOff; 8 | } 9 | 10 | return people 11 | } 12 | -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/13. Sorted? yes? no? how?.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/580a4734d6df748060000045 2 | 3 | function isSortedAndHow(array) { 4 | const isSortedAscending = array.every((current, i) => { 5 | const previous = array[i - 1] ?? -Infinity 6 | 7 | return current >= previous; 8 | }) 9 | 10 | const isSortedDescending = array.every((current, i) => { 11 | const previous = array[i - 1] ?? Infinity 12 | 13 | return current <= previous 14 | }) 15 | 16 | if (isSortedAscending) return 'yes, ascending' 17 | if (isSortedDescending) return 'yes, descending' 18 | 19 | return 'no' 20 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/14. Multiply word in string.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5ace2d9f307eb29430000092 2 | 3 | function modifyMultiply (str,loc,num) { 4 | const word = str.split(' ')[loc] 5 | return Array.from({ length: num }, () => word).join('-') 6 | } 7 | -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/15. Vowel one.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/580751a40b5a777a200000a1 2 | 3 | function vowelOne(s){ 4 | const checkVowel = char => { 5 | return Boolean({ a: true, e: true, i: true, o: true, u: true }[char.toLowerCase()]) 6 | } 7 | 8 | return s.split('').map(char => checkVowel(char) ? '1' : '0').join('') 9 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/16. Alternate capitalization.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/59cfc000aeb2844d16000075 2 | 3 | function capitalize(s){ 4 | return [ 5 | s.split('').map((char, i) => i % 2 === 0 ? char.toUpperCase() : char.toLowerCase()).join(''), 6 | s.split('').map((char, i) => i % 2 !== 0 ? char.toUpperCase() : char.toLowerCase()).join(''), 7 | ] 8 | }; 9 | -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/17. Last Survivor.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/609eee71109f860006c377d1 2 | 3 | function lastSurvivor(letters, coords) { 4 | while (coords.length) { 5 | const idx = coords.shift() 6 | letters = letters.slice(0, idx) + letters.slice(idx + 1) 7 | } 8 | 9 | return letters 10 | } 11 | -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/18. Largest Elements.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/53d32bea2f2a21f666000256 2 | 3 | function largest(n,xs){ 4 | if (n <= 0) return [] 5 | return xs.sort((a, b) => a - b).slice(-n) 6 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/19. Factorial.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/54ff0d1f355cfd20e60001fc 2 | 3 | function factorial(n) { 4 | if (n < 0 || n > 12) throw new RangeError() 5 | 6 | let sum = 1 7 | 8 | while (n > 0) { 9 | sum *= n 10 | n-- 11 | } 12 | 13 | return sum 14 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/2. Disemvowel Trolls.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.codewars.com/kata/52fba66badcd10859f00097e/javascript 3 | */ 4 | function disemvowel(str) { 5 | const vowels = { a: 'a', e: 'e', i: 'i', o: 'o', u: 'u', A: 'A', E: 'E', I: 'I', O: 'O', U: 'U' } 6 | 7 | return str 8 | .split('') 9 | .reduce((result, char) => result += vowels[char] ? '' : char, '') 10 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/20. Two oldest ages.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/511f11d355fe575d2c000001 2 | 3 | function twoOldestAges(ages){ 4 | return ages.sort((a, b) => a - b).slice(-2) 5 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/21. Power of two.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/534d0a229345375d520006a0 2 | 3 | function isPowerOfTwo(n){ 4 | if (n === 1) return true 5 | if (!Number.isInteger(n) || n < 1) return false 6 | 7 | return isPowerOfTwo(n / 2) 8 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/22. Flatten and sort an array.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/57ee99a16c8df7b02d00045f 2 | 3 | const flattenAndSort = arr => [...arr].flat().sort((a, b) => a - b) 4 | -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/24. Form the minimum.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5ac6932b2f317b96980000ca 2 | 3 | function minValue(values){ 4 | const uniques = [...new Set(values)] 5 | 6 | return +uniques.sort((a, b) => a - b).join('') 7 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/25. The 12 Days of Christmas.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/57dd3a06eb0537b899000a64 2 | 3 | var comparator = function(a,b) { 4 | const correctOrders = ['On', '12', '11', '10', '9', '8', '7', '6', '5', '4', '3', '2', 'a'] 5 | const idx1 = correctOrders.findIndex((substr) => a.startsWith(substr)) 6 | const idx2 = correctOrders.findIndex((substr) => b.startsWith(substr)) 7 | 8 | return idx1 - idx2; 9 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/26. Alan Partridge I - Partridge Watch.js: -------------------------------------------------------------------------------- 1 | function part(phrases){ 2 | const related = new Set([ 3 | 'Partridge', 4 | 'PearTree', 5 | 'Chat', 6 | 'Dan', 7 | 'Toblerone', 8 | 'Lynn', 9 | 'AlphaPapa', 10 | 'Nomad', 11 | ]) 12 | 13 | const termsFoundCount = phrases.reduce((found, phrase) => { 14 | if (related.has(phrase)) { 15 | return found + 1; 16 | } 17 | 18 | return found 19 | }, 0) 20 | 21 | return termsFoundCount 22 | ? `Mine's a Pint` + '!'.repeat(termsFoundCount) 23 | : `Lynn, I've pierced my foot on a spike!!` 24 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/27. Alan Partridge III - London.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/580a41b6d6df740d6100030c 2 | 3 | function alan(stations){ 4 | stations = new Set(stations) 5 | 6 | const stops = new Set([ 7 | 'Rejection', 8 | 'Disappointment', 9 | 'Backstabbing Central', 10 | 'Shattered Dreams Parkway', 11 | ]) 12 | 13 | for (const stop of stops) { 14 | if (!stations.has(stop)) { 15 | return 'No, seriously, run. You will miss it.' 16 | } 17 | } 18 | 19 | return 'Smell my cheese you mother!' 20 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/28. How many are smaller than me.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/56a1c074f87bc2201200002e 2 | 3 | function smaller(nums) { 4 | return nums.map((num, i) => { 5 | let count = 0; 6 | 7 | for (let j = i + 1; j < nums.length; j++) { 8 | if (num > nums[j]) count++ 9 | } 10 | 11 | return count; 12 | }) 13 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/29. Previous multiple of three.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/61123a6f2446320021db987d 2 | 3 | const prevMultOfThree = n => { 4 | do { 5 | const result = n / 3 6 | 7 | if (Number.isInteger(result)) { 8 | return n 9 | } 10 | 11 | n = Math.floor(n / 10) 12 | } while (n >= 3) 13 | 14 | return null 15 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/3. Sum of a sequence.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.codewars.com/kata/586f6741c66d18c22800010a/javascript 3 | */ 4 | const sequenceSum = (begin, end, step) => { 5 | let result = 0; 6 | 7 | for (let i = begin; i <= end; i+= step) { 8 | result += i; 9 | } 10 | 11 | return result 12 | }; -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/4. Friend or Foe.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/55b42574ff091733d900002f 2 | 3 | function friend(friends) { 4 | const NEED_NAME_LENGTH = 4 5 | 6 | return friends.filter((friendName) => friendName.length === NEED_NAME_LENGTH) 7 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/5. Check the exam.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5a3dd29055519e23ec000074 2 | 3 | function checkExam(correctAnswers, studentAnswers) { 4 | const RATING_SYSTEM = { 5 | correct: 4, 6 | incorrect: -1, 7 | blank: 0 8 | } 9 | 10 | let score = 0; 11 | 12 | for (let i = 0; i < studentAnswers.length; i++) { 13 | const studentAnswer = studentAnswers[i] 14 | const correctAnswer = correctAnswers[i] 15 | 16 | const isBlank = studentAnswer.length === 0 17 | const isCorrect = studentAnswer === correctAnswer 18 | 19 | if (isBlank) { 20 | score += RATING_SYSTEM.blank 21 | continue 22 | } 23 | 24 | if (isCorrect) { 25 | score += RATING_SYSTEM.correct 26 | continue 27 | } 28 | 29 | score += RATING_SYSTEM.incorrect 30 | } 31 | 32 | return score >= 0 ? score : 0 33 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/6. Ultimate Array Reverser.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5c3433a4d828182e420f4197 2 | 3 | const ultimateReverse = sentence => { 4 | const lengths = sentence.map((word) => word.length) 5 | const reversed = sentence.join('').split('').reverse().join('') 6 | 7 | let reversedSentence = reversed 8 | 9 | return lengths.map(length => { 10 | const part = reversedSentence.slice(0, length) 11 | reversedSentence = reversedSentence.slice(length) 12 | 13 | return part 14 | }) 15 | }; -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/7. Simple fun #176. Reverse letter.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/58b8c94b7df3f116eb00005b 2 | 3 | function reverseLetter(str) { 4 | return str.replace(/[^a-z]/g, '').split('').reverse().join('') 5 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/8. Anagram detection.js: -------------------------------------------------------------------------------- 1 | const countChars = (word) => { 2 | const chars = word.split('') 3 | const map = {} 4 | 5 | chars.forEach((char) => { 6 | char = char.toLowerCase() 7 | map[char] = (map[char] || 0) + 1; 8 | }) 9 | 10 | return map 11 | } 12 | 13 | const areCharsCountEqual = (charsMap1, charsMap2) => { 14 | return Object.keys({ ...charsMap1, ...charsMap2 }) 15 | .every((key) => { 16 | return charsMap1[key] === charsMap2[key] 17 | }) 18 | } 19 | 20 | const isAnagram = (test, original) => { 21 | if (test.length !== original.length) return false 22 | 23 | const chars = { 24 | in: { 25 | test: countChars(test), 26 | original: countChars(original), 27 | } 28 | } 29 | 30 | return areCharsCountEqual(chars.in.test, chars.in.original) 31 | }; -------------------------------------------------------------------------------- /5. Tasks/codewars/7 kyu/9. Sum of odd numbers.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/55fd2d567d94ac3bc9000064 2 | 3 | const rowSumOddNumbers = n => n ** 3 4 | -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/1. Fake Binary.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Fake Binary 3 | * 4 | * Given a string of digits, you should replace any digit below 5 with '0' and any digit 5 5 | * and above with '1'. Return the resulting string. 6 | * 7 | * Note: input will never be an empty string 8 | */ 9 | 10 | const fakeBin = (x) => { 11 | return x.split('').map(char => +char < 5 ? '0' : '1').join('') 12 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/10. Jehny's secret message.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/55225023e1be1ec8bc000390 2 | 3 | function greet(name){ 4 | const greetName = name === 'Johnny' ? 'my love' : name; 5 | 6 | return `Hello, ${greetName}!` 7 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/11. Grasshopper - Check for factor.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/55cbc3586671f6aa070000fb 2 | 3 | function checkForFactor (base, factor) { 4 | return Number.isInteger(base / factor) 5 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/12. Do I get a bonus.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/56f6ad906b88de513f000d96/ 2 | 3 | function bonusTime(salary, hasBonus) { 4 | const total = hasBonus ? salary * 10 : salary 5 | return `£${total}` 6 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/13. Find multiplies of a number.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/58ca658cc0d6401f2700045f 2 | 3 | function findMultiples(integer, limit) { 4 | const multiplies = [] 5 | let multiply = integer 6 | 7 | while (multiply <= limit) { 8 | multiplies.push(multiply) 9 | multiply += integer; 10 | } 11 | 12 | return multiplies 13 | } 14 | -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/14. Is it a palindrome.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/57a1fd2ce298a731b20006a4 2 | 3 | function isPalindrome(x) { 4 | for (let i = 0; i < x.length / 2; i++) { 5 | if (x[i].toLowerCase() !== x[x.length - 1 - i].toLowerCase()) return false 6 | } 7 | 8 | return true 9 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/15. Get nth even number.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5933a1f8552bc2750a0000ed 2 | 3 | function nthEven(n){ 4 | return (n - 1) * 2 5 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/16. Opposites attract.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/555086d53eac039a2a000083 2 | 3 | function lovefunc(flower1, flower2){ 4 | return (flower1 % 2 == 0 && flower2 % 2 !== 0) || (flower1 % 2 !== 0 && flower2 % 2 === 0) 5 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/17. Stringy string.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/563b74ddd19a3ad462000054 2 | 3 | function stringy(size) { 4 | const result = '10'.repeat(Math.ceil(size / 2)) 5 | 6 | return size % 2 === 0 7 | ? result 8 | : result.slice(0, -1) 9 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/18. Welcome!.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/577ff15ad648a14b780000e7 2 | 3 | function greet(language) { 4 | const i18n = { 5 | english: 'Welcome', 6 | czech: 'Vitejte', 7 | danish: 'Velkomst', 8 | dutch: 'Welkom', 9 | estonian: 'Tere tulemast', 10 | finnish: 'Tervetuloa', 11 | flemish: 'Welgekomen', 12 | french: 'Bienvenue', 13 | german: 'Willkommen', 14 | irish: 'Failte', 15 | italian: 'Benvenuto', 16 | latvian: 'Gaidits', 17 | lithuanian: 'Laukiamas', 18 | polish: 'Witamy', 19 | spanish: 'Bienvenido', 20 | swedish: 'Valkommen', 21 | welsh: 'Croeso' 22 | } 23 | 24 | return i18n[language] || i18n.english 25 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/19. N-th Power.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/57d814e4950d8489720008db 2 | 3 | function index(array, n){ 4 | const element = array[n] 5 | 6 | if (element === undefined) { 7 | return -1; 8 | } 9 | 10 | return element ** n; 11 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/2. DNA to RNA conversion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.codewars.com/kata/5556282156230d0e5e000089/javascript 3 | */ 4 | 5 | function DNAtoRNA(dna) { 6 | const mapping = { 7 | 'T': 'U', 8 | 'U': 'T', 9 | } 10 | 11 | return dna.replace(/T|U/g, (char) => mapping[char] || char) 12 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/20. FIXME: Replace all dots.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/596c6eb85b0f515834000049 2 | 3 | const replaceDots = function(str) { 4 | return str.replace(/\./g, '-'); 5 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/21. The Feast of many Beasts.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5aa736a455f906981800360d 2 | 3 | function feast(beast, dish) { 4 | return beast[0] + beast[beast.length - 1] === dish[0] + dish[dish.length - 1] 5 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/22. No zeros for heros.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/570a6a46455d08ff8d001002 2 | 3 | function noBoringZeros(n) { 4 | if (n === 0) return n 5 | 6 | return +String(n).replace(/[0]+$/g, '') 7 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/23. Double char.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/56b1f01c247c01db92000076 2 | 3 | function doubleChar(str) { 4 | return str.split('').map(char => char.repeat(2)).join('') 5 | } 6 | -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/24. Find the position!.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5808e2006b65bff35500008f 2 | 3 | function position(letter) { 4 | const UTF_16_OFFSET = 96 5 | const letterPosition = letter.toLowerCase().charCodeAt() - UTF_16_OFFSET 6 | 7 | return `Position of alphabet: ${letterPosition}` 8 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/25. Twice as old.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5b853229cfde412a470000d0 2 | 3 | function twiceAsOld(dadYearsOld, sonYearsOld) { 4 | const diff = dadYearsOld - sonYearsOld 5 | return Math.abs(sonYearsOld - diff) 6 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/26. Make negative.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/55685cd7ad70877c23000102 2 | 3 | function makeNegative(num) { 4 | return -Math.abs(num) 5 | } 6 | -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/27. Capitalization and Mutability.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/595970246c9b8fa0a8000086 2 | 3 | function capitalizeWord(word) { 4 | word = word[0].toUpperCase() + word.slice(1); 5 | return word; 6 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/28. Reverse list order.js: -------------------------------------------------------------------------------- 1 | function reverseList(list) { 2 | return [...list].reverse() 3 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/29. Alternating case.js: -------------------------------------------------------------------------------- 1 | String.prototype.toAlternatingCase = function () { 2 | return this.replace(/\w/g, (char) => char.toUpperCase() === char ? char.toLowerCase() : char.toUpperCase()) 3 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/3. Leonardo Dicaprio and Oscars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.codewars.com/kata/56d49587df52101de70011e4 3 | */ 4 | 5 | function leo(oscar){ 6 | if (oscar === 88) return 'Leo finally won the oscar! Leo is happy' 7 | if (oscar === 86) return 'Not even for Wolf of wallstreet?!' 8 | if (oscar < 88) return 'When will you give Leo an Oscar?' 9 | 10 | return 'Leo got one already!' 11 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/30. Remove duplicates from list.js: -------------------------------------------------------------------------------- 1 | function distinct(a) { 2 | return [...new Set(a)]; 3 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/31. Alan Partridge II - Apple Turnover.js: -------------------------------------------------------------------------------- 1 | function apple(x){ 2 | return x ** 2 > 1000 3 | ? `It's hotter than the sun!!` 4 | : 'Help yourself to a honeycomb Yorkie for the glovebox.' 5 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/32. Regular Ball Super Ball.js: -------------------------------------------------------------------------------- 1 | var Ball = function(ballType = 'regular') { 2 | this.ballType = ballType 3 | }; -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/33. Grasshopper - Array Mean.js: -------------------------------------------------------------------------------- 1 | var findAverage = function (nums) { 2 | return nums.reduce((acc, cur) => acc + cur, 0) / nums.length 3 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/4. What is between.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.codewars.com/kata/55ecd718f46fba02e5000029/javascript 3 | * Complete the function that takes two integers (a, b, where a < b) and return an array 4 | * of all integers between the input parameters, including them. 5 | */ 6 | 7 | function between(from, to) { 8 | const length = to - from + 1 9 | 10 | return Array.from({ length }, (_, i) => i + from) 11 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/5. Training on Squash the bugs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.codewars.com/kata/56f173a35b91399a05000cb7 3 | */ 4 | 5 | function findLongest(str) { 6 | 7 | var spl = str.split(" "); 8 | var longest = 0 9 | 10 | for (var i = 0; i < spl.length; i++) { 11 | if (spl[i].length > longest) { 12 | longest = spl[i].length 13 | } 14 | } 15 | 16 | return longest 17 | } 18 | -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/6. Exclamation marks series #2: Remove all exclamation marks from the end of sentence.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.codewars.com/kata/57faece99610ced690000165/javascript 3 | */ 4 | function remove (string) { 5 | return string.replace(/[\!]+$/gi, '') 6 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/7. Basic Variable Assignment.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/50ee6b0bdeab583673000025 2 | 3 | const a = 'code' 4 | const b = 'wa.rs' 5 | const name = a + b 6 | -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/8. Potenciation.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/59fc72fe235f93838b002235 2 | 3 | function power(x,y){ 4 | return x ** y 5 | } -------------------------------------------------------------------------------- /5. Tasks/codewars/8 kyu/9. Student's final grade.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/5ad0d8356165e63c140014d4 2 | 3 | function finalGrade (exam, projects) { 4 | if (exam > 90 || projects > 10) return 100 5 | if (exam > 75 && projects >= 5) return 90 6 | if (exam > 50 && projects >= 2) return 75 7 | 8 | return 0 9 | } -------------------------------------------------------------------------------- /5. Tasks/leetcode/easy/0383. Ransom Note.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://leetcode.com/problems/ransom-note/ 3 | * @param {string} ransomNote 4 | * @param {string} magazine 5 | * @return {boolean} 6 | */ 7 | const canConstruct = (ransomNote, magazine) => { 8 | const countByChar = (acc, cur) => { 9 | acc[cur] = (acc[cur] || 0) + 1 10 | return acc 11 | } 12 | 13 | const countCharIn = { 14 | ransomNote: ransomNote.split('').reduce(countByChar, {}), 15 | magazine: magazine.split('').reduce(countByChar, {}) 16 | } 17 | 18 | for (const key in countCharIn.ransomNote) { 19 | const count = { 20 | ransom: countCharIn.ransomNote[key], 21 | magazine: countCharIn.magazine[key] 22 | } 23 | 24 | if ((count.magazine || 0) - count.ransom < 0) { 25 | return false 26 | } 27 | } 28 | 29 | return true 30 | }; -------------------------------------------------------------------------------- /5. Tasks/leetcode/easy/0412. Fizz Buzz.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://leetcode.com/problems/fizz-buzz/ 3 | * @param {number} n 4 | * @return {string[]} 5 | */ 6 | const fizzBuzz = function(n) { 7 | return Array.from({ length: n }, (_, i) => { 8 | const num = i + 1; 9 | 10 | if (num % 3 === 0 && num % 5 === 0) return "FizzBuzz" 11 | if (num % 3 === 0) return "Fizz" 12 | if (num % 5 === 0) return "Buzz" 13 | 14 | return String(num) 15 | }) 16 | }; -------------------------------------------------------------------------------- /5. Tasks/leetcode/easy/0724. Find Pivot Index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://leetcode.com/problems/find-pivot-index 3 | * @param {number[]} nums 4 | * @return {number} 5 | */ 6 | const pivotIndex = (nums) => { 7 | let leftSum = 0 8 | let rightSum = nums.reduce((acc, cur) => acc + cur, 0) 9 | 10 | for (let i = 0; i < nums.length; i++) { 11 | const prev = nums[i - 1] || 0 12 | const current = nums[i] 13 | 14 | leftSum += prev; 15 | rightSum -= current; 16 | 17 | if (leftSum === rightSum) { 18 | return i 19 | } 20 | } 21 | 22 | return -1 23 | }; -------------------------------------------------------------------------------- /5. Tasks/leetcode/easy/1342. Number of steps to reduce a number to zero.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://leetcode.com/problems/number-of-steps-to-reduce-a-number-to-zero/ 3 | * @param {number} num 4 | * @return {number} 5 | */ 6 | const numberOfSteps = function(num) { 7 | let steps = 0; 8 | 9 | while (num > 0) { 10 | if (num % 2 === 1) { 11 | num -= 1; 12 | steps++; 13 | } 14 | 15 | if (num) { 16 | num /= 2; 17 | steps++; 18 | } 19 | } 20 | 21 | return steps; 22 | }; -------------------------------------------------------------------------------- /5. Tasks/leetcode/easy/1480. Running sum of 1d array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://leetcode.com/problems/running-sum-of-1d-array 3 | * @param {number[]} nums 4 | * @return {number[]} 5 | */ 6 | const runningSum = function(nums) { 7 | let lastSum = 0 8 | 9 | return nums.map(num => { 10 | lastSum += num 11 | return lastSum 12 | }) 13 | }; -------------------------------------------------------------------------------- /5. Tasks/leetcode/easy/1672. Richest Customer Wealth.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://leetcode.com/problems/richest-customer-wealth/ 3 | * @param {number[][]} accounts 4 | * @return {number|null} 5 | */ 6 | const maximumWealth = function(accounts) { 7 | let maxWealth = null 8 | 9 | for (const account of accounts) { 10 | const sum = account.reduce((sum, bankWealth) => sum + bankWealth, 0) 11 | maxWealth = Math.max(maxWealth, sum) 12 | } 13 | 14 | return maxWealth 15 | }; -------------------------------------------------------------------------------- /5. Tasks/leetcode/easy/2235. Add two integers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://leetcode.com/problems/add-two-integers 3 | * @param {number} num1 4 | * @param {number} num2 5 | * @return {number} 6 | */ 7 | function sum(num1, num2) { 8 | return num1 + num2; 9 | } -------------------------------------------------------------------------------- /5. Tasks/other/2. Sum curry/2-sum-curry.js: -------------------------------------------------------------------------------- 1 | const sum = (initialNum) => { 2 | let result = 0 3 | 4 | const wrapper = function(num) { 5 | if (typeof num === 'undefined') return result 6 | 7 | result += num 8 | 9 | return wrapper 10 | } 11 | 12 | return wrapper(initialNum) 13 | } 14 | 15 | module.exports = sum 16 | -------------------------------------------------------------------------------- /5. Tasks/other/2. Sum curry/2-sum-curry.spec.js: -------------------------------------------------------------------------------- 1 | const sum = require('./2-sum-curry') 2 | 3 | describe('sum-curry', () => { 4 | it('sum(1)() should be 1', () => { 5 | expect(sum(1)()).toBe(1) 6 | }) 7 | 8 | it('sum(1)(2)() should be 3', () => { 9 | expect(sum(1)(2)()).toBe(3) 10 | }) 11 | 12 | it('sum(1)(2)(-1)() should be 2', () => { 13 | expect(sum(1)(2)(-1)()).toBe(2) 14 | }) 15 | }) 16 | -------------------------------------------------------------------------------- /5. Tasks/other/3. Parallel/3-parallel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Есть недописаная функция "parallel(funcArray, doneAll)": 3 | * 4 | * Нужно её дописать. 5 | * Что-то вроде аналога promise.all. И не забудьте, что результирующий массив должен сохранять тот порядок, в котором передавались функции. 6 | */ 7 | 8 | function parallel(funcArray, doneAll) { 9 | const unresolved = Symbol('unresolved') 10 | const funcResults = Array.from({ length: funcArray.length }, () => unresolved) 11 | 12 | function done(idx, result) { 13 | funcResults[idx] = result 14 | 15 | if (funcResults.every(res => res !== unresolved)) { 16 | doneAll(funcResults) 17 | } 18 | } 19 | 20 | funcArray.forEach((fn, idx) => { 21 | fn.call(null, done.bind(null, idx)) 22 | }) 23 | } 24 | 25 | module.exports = parallel 26 | -------------------------------------------------------------------------------- /5. Tasks/other/4. Fold/4-fold.js: -------------------------------------------------------------------------------- 1 | const fold = (str) => str.replaceAll(/(.)\1{1,}/g, (r) => r[0] + r.length) 2 | 3 | module.exports = fold -------------------------------------------------------------------------------- /5. Tasks/other/4. Fold/4-fold.spec.js: -------------------------------------------------------------------------------- 1 | const fold = require('./4-fold') 2 | 3 | describe('fold', () => { 4 | describe('should fold string with numbers for repeated chars', () => { 5 | const cases = [ 6 | ['aabbcd', 'a2b2cd'], 7 | ['maxxxpro', 'max3pro'] 8 | ]; 9 | 10 | cases.forEach(([input, output]) => { 11 | it(`Case "${input}" should be ${output}`, () => { 12 | const result = fold(input); 13 | 14 | expect(result).toBe(output); 15 | }) 16 | }) 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /5. Tasks/other/5. Rectangle to squares/5-rectangle-to-squares.js: -------------------------------------------------------------------------------- 1 | function rectangleToSquares(width, height) { 2 | while (true) { 3 | if (width < height) height -= width 4 | if (width > height) width -= height 5 | if (width === height) break 6 | } 7 | 8 | return width; 9 | } 10 | 11 | const AREA_WIDTH = 1680 12 | const AREA_HEIGHT = 640 13 | 14 | const size = rectangleToSquares(AREA_WIDTH, AREA_HEIGHT) 15 | const count = (AREA_WIDTH * AREA_HEIGHT) / size ** 2 -------------------------------------------------------------------------------- /6. Algorithms/1. Binary Search.js: -------------------------------------------------------------------------------- 1 | function binary_search(arr, item) { 2 | let from = 0; 3 | let to = arr.length - 1; 4 | 5 | while (from <= to) { 6 | const idx = Math.floor((from + to) / 2) 7 | const candidate = arr[idx] 8 | 9 | if (candidate === item) { 10 | return idx 11 | } 12 | 13 | if (candidate > item) { 14 | to = idx - 1 15 | } else { 16 | from = idx + 1 17 | } 18 | } 19 | 20 | return null 21 | } -------------------------------------------------------------------------------- /6. Algorithms/sort/1-quick-sort.js: -------------------------------------------------------------------------------- 1 | function quickSort(arr) { 2 | if (arr.length <= 1) return arr; 3 | if (arr.length === 2) return arr[0] <= arr[1] 4 | ? [arr[0], arr[1]] 5 | : [arr[1], arr[0]] 6 | 7 | const reference = arr[0] 8 | 9 | const left = [] 10 | const right = [] 11 | 12 | for (let i = 1; i < arr.length; i++) { 13 | if (arr[i] <= reference) left.push(arr[i]) 14 | else right.push(arr[i]) 15 | } 16 | 17 | return [...quickSort(left), reference, ...quickSort(right)] 18 | } -------------------------------------------------------------------------------- /7. Books/Clean code (Robert Martin)/README.md: -------------------------------------------------------------------------------- 1 | # Чистый код (Роберт Мартин) 2 | 3 | Это краткий конспект книги "Чистый код" написанной Робертом Мартином. 4 | 5 | ## Навигация 6 | 7 | - [Глава 1. Чистый код](./1.%20Clean%20code.md) 8 | - [Глава 2. Содержательные имена](./2.%20Meaningful%20names.md) -------------------------------------------------------------------------------- /9. Courses/1. JS Introduction to OOP/Arrow functions context/collection.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | // BEGIN (write your solution here) 4 | export default function each(arr, callback) { 5 | return arr.forEach((element, i, array) => callback.apply(element, [element, i, array])); 6 | } 7 | // END 8 | -------------------------------------------------------------------------------- /9. Courses/1. JS Introduction to OOP/Bind/bind.js: -------------------------------------------------------------------------------- 1 | export default function bind(obj, fn) { 2 | return function(...args) { 3 | const key = Symbol('Key'); 4 | obj[key] = fn; 5 | 6 | const result = obj[key](...args); 7 | delete obj[key]; 8 | 9 | return result; 10 | } 11 | } -------------------------------------------------------------------------------- /9. Courses/1. JS Introduction to OOP/Boxing/magic.js: -------------------------------------------------------------------------------- 1 | // BEGIN 2 | const f = (...numbers) => { 3 | const sum = numbers.reduce((acc, x) => (x + acc), 0); 4 | const inner = (...rest) => f(sum, ...rest); 5 | // функции - это объекты, что позволяет для "магического" метода установить свою функцию 6 | inner.valueOf = () => sum; // метод вызывается при сравнении, поэтому он возвращает только результат 7 | // подробнее о valueOf: https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf 8 | return inner; 9 | }; 10 | 11 | export default f; 12 | // END -------------------------------------------------------------------------------- /9. Courses/1. JS Introduction to OOP/Constructor/Point.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | // BEGIN (write your solution here) 4 | export default class Point { 5 | #x = null; 6 | 7 | #y = null; 8 | 9 | constructor(x, y) { 10 | this.#x = x; 11 | this.#y = y; 12 | } 13 | 14 | getX() { 15 | return this.#x; 16 | } 17 | 18 | getY() { 19 | return this.#y; 20 | } 21 | } 22 | // END 23 | -------------------------------------------------------------------------------- /9. Courses/1. JS Introduction to OOP/Constructor/Segment.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | // BEGIN (write your solution here) 4 | export default class Segment { 5 | #beginPoint = null; 6 | 7 | #endPoint = null; 8 | 9 | constructor(beginPoint, endPoint) { 10 | this.#beginPoint = beginPoint; 11 | this.#endPoint = endPoint; 12 | } 13 | 14 | getBeginPoint() { 15 | return this.#beginPoint; 16 | } 17 | 18 | getEndPoint() { 19 | return this.#endPoint; 20 | } 21 | } 22 | // END 23 | -------------------------------------------------------------------------------- /9. Courses/1. JS Introduction to OOP/Constructor/solution.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | import Point from './Point.js'; 4 | import Segment from './Segment.js'; 5 | 6 | // BEGIN (write your solution here) 7 | export default function reverse(segment) { 8 | const beginPoint = segment.getBeginPoint(); 9 | const endPoint = segment.getEndPoint(); 10 | 11 | return new Segment( 12 | new Point(endPoint.getX(), endPoint.getY()), 13 | new Point(beginPoint.getX(), beginPoint.getY()), 14 | ); 15 | } 16 | // END 17 | -------------------------------------------------------------------------------- /9. Courses/1. JS Introduction to OOP/Encapsulation/getMutualFriends.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | /* eslint-disable import/prefer-default-export */ 3 | 4 | // BEGIN (write your solution here) 5 | export function getMutualFriends(user1, user2) { 6 | const friendsFrom = { 7 | user1: { 8 | flat: user1.getFriends(), 9 | groupedBy: { 10 | id: null, 11 | }, 12 | }, 13 | user2: { 14 | flat: user2.getFriends(), 15 | groupedBy: { 16 | id: null, 17 | }, 18 | }, 19 | }; 20 | 21 | friendsFrom.user1.groupedBy.id = friendsFrom.user1.flat.reduce((group, user) => ({ 22 | ...group, 23 | [user.id]: user, 24 | }), {}); 25 | 26 | return friendsFrom.user2.flat.filter((friend) => { 27 | return Boolean(friendsFrom.user1.groupedBy.id[friend.id]); 28 | }); 29 | } 30 | // END 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Конспекты learn.javascript.ru 2 | 3 | - В данном репозитории я стараюсь объяснить пройденную тему самостоятельно. 4 | - Необходим для самостоятельного обучения. 5 | - Материалы взяты с сайтов: 6 | - https://learn.javascript.ru/. 7 | - https://developer.mozilla.org/ru/docs/Web/JavaScript 8 | - https://ru.wikipedia.org/ 9 | - https://habr.com/ 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "learn-javascript-ru", 3 | "version": "1", 4 | "description": "- В данном репозитории я стараюсь объяснить пройденную тему самостоятельно. - Необходим для самостоятельного обучения. - Материалы взяты с сайтов: - https://learn.javascript.ru/. - https://developer.mozilla.org/ru/docs/Web/JavaScript - https://ru.wikipedia.org/ - https://habr.com/", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/meowto16/learn-javascript-ru.git" 8 | }, 9 | "homepage": "https://github.com/meowto16/learn-javascript-ru#readme", 10 | "devDependencies": { 11 | "jest": "^27.4.5" 12 | } 13 | } 14 | --------------------------------------------------------------------------------