<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Алексей Бунин</title><subtitle>Иду во фронтенд. Прохожу курс Three.js Journey, попутно изучая 3D и JavaScript</subtitle><author><name>Алексей Бунин</name></author><id>https://teletype.in/atom/buninman</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/buninman?offset=0"></link><link rel="alternate" type="text/html" href="https://blog.buninman.ru/?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=buninman"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/buninman?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-05-06T11:03:32.159Z</updated><entry><id>buninman:learn2302</id><link rel="alternate" type="text/html" href="https://blog.buninman.ru/learn2302?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=buninman"></link><title>Прогресс обучения_Февраль 2023</title><published>2023-02-10T14:33:11.236Z</published><updated>2023-02-10T14:48:24.149Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/52/06/52065412-0c8b-4241-bd21-3799c2fa7e8c.png"></media:thumbnail><category term="lerning" label="Обучение"></category><tt:hashtag>threejs</tt:hashtag><tt:hashtag>blender</tt:hashtag><tt:hashtag>kaino</tt:hashtag><tt:hashtag>substance</tt:hashtag><tt:hashtag>курс</tt:hashtag><tt:hashtag>обучение</tt:hashtag><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/b0/44/b0448132-33cf-45bb-aa68-80ae754d97b6.png&quot;&gt;Давно ничего не писал, поэтому решил сделать статью с промежуточными итогами своего обучения за 2.5 месяца.</summary><content type="html">
  &lt;p id=&quot;mMj4&quot;&gt;Давно ничего не писал, поэтому решил сделать статью с промежуточными итогами своего обучения за 2.5 месяца.&lt;/p&gt;
  &lt;p id=&quot;2dTJ&quot;&gt;Интересно было самому посмотреть на тот путь, который я прошел. В статью многое не попало, но все равно сделать можно было куда больше за это время.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;SrX8&quot;&gt;&lt;/h2&gt;
  &lt;h2 id=&quot;4tqh&quot;&gt;Курс Three.js Journey&lt;/h2&gt;
  &lt;p id=&quot;5JTk&quot;&gt;Это курс по созданию 3д в браузерах. За время своего отсутствия я успел пройти где-то треть курса. Курс этот очень объемный, около 70 часов видеолекций, так что треть это довольно дофига.&lt;/p&gt;
  &lt;p id=&quot;s3lk&quot;&gt;Каких-то конкретных результатов или готовых работ пока нет. Изучаем разные аспекты, делаем простенькие примеры. Но скоро будем делать 3д-сцену с порталом, а к концу курса сделаем игру с полноценным физическим движком.&lt;/p&gt;
  &lt;p id=&quot;sV2g&quot;&gt;А пока, вот например работа с текстурами. Текстуры в Three.js такие же как и везде. Поддерживаются и карты нормалей и прозрачность и отражения и тени. Все что нужно.&lt;/p&gt;
  &lt;figure id=&quot;4TJz&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b0/44/b0448132-33cf-45bb-aa68-80ae754d97b6.png&quot; width=&quot;1600&quot; /&gt;
  &lt;/figure&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;PYqV&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;pT4c&quot;&gt;А вот работа с 3д-текстом, попытался сделать логотип. Идея была сделать шарики из разных материалов, а посередине логотип дизайнера интерьеров. Думаю, если идею развить, можно сделать довольно необычный сайт-портфолио. &lt;/p&gt;
  &lt;p id=&quot;boMb&quot;&gt;Но для создания такого сайта у меня тогда не хватало навыков. Как минимум логотип проще вставить 3д моделью, а не пытаться писать его 3д-текстом.&lt;/p&gt;
  &lt;figure id=&quot;yjYS&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/99/35/99358020-9352-4195-9da1-0c05c3144058.png&quot; width=&quot;1600&quot; /&gt;
  &lt;/figure&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;W725&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;4nlf&quot;&gt;Тут мы создавали целую сцену с анимацией движения света (типа призраки). Никаких 3д моделей не подгружали, все сделано силами JavaScript.&lt;/p&gt;
  &lt;figure id=&quot;s7Bz&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/0f/26/0f263ddd-7bec-4b3f-b45c-ed35a026998c.png&quot; width=&quot;1600&quot; /&gt;
  &lt;/figure&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;99n4&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;uE34&quot;&gt;Дальше идет работа с частицами, партиклами. Это просто облако разноцветных колечек. В качестве скриншота выглядит конечно не очень, но когда вертишь камерой внутри такого облака, это прикольно, видно объем.&lt;/p&gt;
  &lt;figure id=&quot;cNe1&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/1c/bd/1cbda898-e8d2-4f48-a8f8-ba47b26ad3c9.png&quot; width=&quot;1600&quot; /&gt;
  &lt;/figure&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;Chgv&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;umQJ&quot;&gt;Галактика. Тоже частицы, но уже более сложное их применение. Причем можно в реальном времени менять всякие параметры, вроде количества лучей и радиус их загиба.&lt;/p&gt;
  &lt;figure id=&quot;kIFA&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/dd/2d/dd2d517d-f99e-43ce-b383-483ec7dd6f88.png&quot; width=&quot;1600&quot; /&gt;
  &lt;/figure&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;tQcH&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;SZev&quot;&gt;А вот это уже импортированная 3д модель с полным набором текстур, динамическим освещением, HDRI-картой и рендер движком.&lt;/p&gt;
  &lt;figure id=&quot;SVEx&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/73/ad/73ad7d47-0ecd-415e-a49e-c6d1ed98ed60.png&quot; width=&quot;1600&quot; /&gt;
  &lt;/figure&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;9P9O&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;b19o&quot;&gt;Курсы по Blender&lt;/h2&gt;
  &lt;p id=&quot;i6nZ&quot;&gt;После урока со шлемом, я углубился в изучение 3д. Я начал, один за другим, проходить курсы по 3д от школы Кайно. На данный момент я прохожу уже 3й курс, и каждый следующий сложнее предыдущего.&lt;/p&gt;
  &lt;p id=&quot;8QMh&quot;&gt;Первым я прошел бесплатный курс с каретой, его легко можно найти на Ютубе. Если оборачиваться назад, то курс довольно простой и поверхностный, но на тот момент я ничего не знал про работу в Блендере и курс оказался кстати!&lt;/p&gt;
  &lt;figure id=&quot;ePkR&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/9f/dc/9fdc0e1a-3a0d-4d91-985d-539b3f2114ed.png&quot; width=&quot;1920&quot; /&gt;
    &lt;figcaption&gt;Я доделал его 10 января,а потом практически полностью пересобрал 27-го, чтоб добавить деталей и оптимизировать модель для выгрузки в веб&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;qfp2&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;X566&quot;&gt;Затем реклама мне предложила пройти марафон и я согласился. После кареты, это уже было лишнее, марафон совсем для новичков.&lt;/p&gt;
  &lt;p id=&quot;kAui&quot;&gt;Тем не менее я его прошел, а чтобы было интереснее, я делал полностью свою 3д модель, оставив только основную идею - домик в лесу.&lt;/p&gt;
  &lt;figure id=&quot;V57D&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/2b/e6/2be6f6bd-81ce-4ccf-a95e-306e8f7a5219.png&quot; width=&quot;1920&quot; /&gt;
    &lt;figcaption&gt;Я доделал его 15 января&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;9f1N&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;PVQe&quot;&gt;Следующим был курс с названием &amp;quot;2.0&amp;quot;, прошел его залпом за 2.5 дня. На нем делается высокополигональная модель самолета и есть простая работа с текстурами.&lt;/p&gt;
  &lt;p id=&quot;1cAZ&quot;&gt;Прошел его просто потому, что в более старшем курсе есть отсылки на этот курс. Авторы рассчитывают что ты будешь проходить их один за другим. В противном случае я бы его пропустил. Толку в нем не много.&lt;/p&gt;
  &lt;figure id=&quot;FAAy&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/11/66/1166ec14-1490-4550-9a97-72ee251d03d7.png&quot; width=&quot;1920&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;03nM&quot; class=&quot;m_column&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/1d/4f/1d4f13d7-483d-4a1a-ab6e-bbb2dc443bff.png&quot; width=&quot;1920&quot; /&gt;
    &lt;figcaption&gt;Я доделал его 20 января&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;akRZ&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;M2Ck&quot;&gt;Сейчас прохожу курс &amp;quot;Геймдев&amp;quot;, большой и комплексный курс. Сначала создается низкополигональная модель (лоуполи), потом высокополигональная модель (хайполи), потом запекание, текстуры и тп.&lt;/p&gt;
  &lt;p id=&quot;M2Y6&quot;&gt;Робота делать было довольно долго и скучно, но это позволяет машинально закрепить работу с горячими клавишами и хорошо запомнить последовательность действий.&lt;/p&gt;
  &lt;p id=&quot;W7vy&quot;&gt;Сейчас у меня уже полностью готова 3д-модель и я на этапе изучения программы Substance Painter, в которой будет проходить текстурирование робота и запекание текстур.&lt;/p&gt;
  &lt;figure id=&quot;qd3F&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/8f/c1/8fc1d65f-96be-474a-aa14-65467ccf332f.png&quot; width=&quot;1920&quot; /&gt;
    &lt;figcaption&gt;Лоуполи модель я доделал 30 января, а хайполи 2 февряля&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;yQUF&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;36ki&quot;&gt;Дальше&lt;/h2&gt;
  &lt;p id=&quot;XeAh&quot;&gt;После завершения курса с роботом я вернусь к изучению курса Three.js Journey, и буду параллельно делать сайт, в центре которого будет карета из первого курса.&lt;/p&gt;
  &lt;p id=&quot;EMgu&quot;&gt;Я уже доработал 3д модель этой кареты для импорта в веб, даже выложил &amp;quot;набросок&amp;quot; будущего сайта в сеть, но мне не хватает знаний о текстурировании и запекании текстур.&lt;/p&gt;
  &lt;figure id=&quot;LiNb&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://sun9-68.vkuserphoto.ru/impg/8VzVcNsT9Y1lbOSlgLwfi8rEEBX1Z8eVgwLWPg/dZCvAv9bv8A.jpg?size=1240x994&amp;quality=96&amp;sign=42b70234063212b1e472845b33664228&amp;c_uniq_tag=1inrhloo1UdC62gwioxyMauRgqbBO8fwVBV1oiAZe3Q&amp;type=album&quot; width=&quot;1240&quot; /&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;oSaU&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://kaino-wagon.vercel.app/&quot; target=&quot;_blank&quot;&gt;Вот тут уже можно посмотреть сайт, хотя смотреть особо нечего&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;kmul&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;ufsD&quot;&gt;В целом, это все, вроде получилась интересная история, с картинками. Возможно, буду продолжать подбивать итоги недели/месяца в подобные статьи.&lt;/p&gt;
  &lt;p id=&quot;Z4Yn&quot;&gt;А короткие посты я делаю в группе &lt;a href=&quot;https://vk.ru/threejsjourney&quot; target=&quot;_blank&quot;&gt;ВК&lt;/a&gt; или &lt;a href=&quot;https://t.me/threejsjourney&quot; target=&quot;_blank&quot;&gt;Телеграме&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;QgSd&quot;&gt;&lt;/p&gt;
  &lt;tt-tags id=&quot;RsUh&quot;&gt;
    &lt;tt-tag name=&quot;threejs&quot;&gt;#threejs&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;blender&quot;&gt;#blender&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;kaino&quot;&gt;#kaino&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;substance&quot;&gt;#substance&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;курс&quot;&gt;#курс&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;обучение&quot;&gt;#обучение&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry><entry><id>buninman:gameonjs-01</id><link rel="alternate" type="text/html" href="https://blog.buninman.ru/gameonjs-01?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=buninman"></link><title>Игры на JavaScript</title><published>2022-12-03T05:59:55.444Z</published><updated>2022-12-03T05:59:55.444Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/e1/54/e154b02a-f09b-4375-bbd7-b5a7c45fbf62.png"></media:thumbnail><category term="other" label="Разное"></category><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/fa/d4/fad4360d-487e-4dc5-ba15-f052c7c12ca1.png&quot;&gt;Подборка создана просто как источник вдохновения и пример того, что можно сделать используя JavaScript.</summary><content type="html">
  &lt;blockquote id=&quot;QhLJ&quot;&gt;Подборка создана просто как источник вдохновения и пример того, что можно сделать используя JavaScript.&lt;/blockquote&gt;
  &lt;p id=&quot;Be0j&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;t9au&quot;&gt;Периодически, чтоб зарядиться желанием создавать что-то, я играю в разные небольшие игрушки, смотрю что делают другие программисты.&lt;/p&gt;
  &lt;p id=&quot;qjMe&quot;&gt;Это не обязательно должны быть игры на JS, просто не сильно нагруженные механиками игры, которые вполне возможно повторить.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;qcIv&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;v6yJ&quot;&gt;Keep Out! &lt;/h2&gt;
  &lt;p id=&quot;msFq&quot;&gt;Начну с игры, на которую я наткнулся первой. Я тогда только начинал знакомится с программированием и библиотекой three.js, и игрушка произвела на меня сильное впечатление. &lt;/p&gt;
  &lt;p id=&quot;v6cU&quot;&gt;Если разобраться, сама по себе она довольно простая, ходишь по небольшому лабиринту и бьешь разных мобов. Но сделана самобытно и в нее интересно поиграть. Проблема тут только в управлении - мне было сложно привыкнуть к резким поворотам на 90°😁&lt;/p&gt;
  &lt;figure id=&quot;FAQn&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/fa/d4/fad4360d-487e-4dc5-ba15-f052c7c12ca1.png&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;kZvs&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://www.playkeepout.com/&quot; target=&quot;_blank&quot;&gt;Играть&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;ckcz&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;R4R7&quot;&gt;Gorescript&lt;/h2&gt;
  &lt;p id=&quot;ZAZT&quot;&gt;Шутер от первого лица для любителей Doom или Duke Nukem 3D, я больше люблю Дюка.&lt;/p&gt;
  &lt;p id=&quot;zD4z&quot;&gt;Играется очень приятно, есть всякие секретные двери с плюшками. Например, на первом уровне попробуйте зайти в центральный зал, там есть пулемет. Но сначала найдите способ опустить цветные колонны, иначе не доберетесь до вкусняшки.&lt;/p&gt;
  &lt;p id=&quot;eKJb&quot;&gt;Я поиграл только в первую версию игры. которая называется Gorescript Classic, но есть еще новая версия, которая продается в Steam за недорого.&lt;/p&gt;
  &lt;figure id=&quot;vJ3u&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/ee/21/ee21a178-b7fe-481b-ab7b-76da5aafe254.png&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;1JJN&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://gorescript.github.io/classic/play/&quot; target=&quot;_blank&quot;&gt;Играть в первую часть&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;dtWe&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://store.steampowered.com/app/618690/Gorescript/&quot; target=&quot;_blank&quot;&gt;Страничка второй части в Steam&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;FwdM&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;lVas&quot;&gt;Heraclos&lt;/h2&gt;
  &lt;p id=&quot;uXnI&quot;&gt;У парня выдался неудачный день - он стал избранным. Такое вот начало у этой игрушки, дальше сюжет рассказывать не буду, сами зацените😄&lt;/p&gt;
  &lt;p id=&quot;mW6D&quot;&gt;Игра представляет собой небольшое одноразовое приключение. Кое-где сделана с огрехами, но сыграть все равно интересно и сделана она с юмором.&lt;/p&gt;
  &lt;figure id=&quot;HLw7&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/cf/e6/cfe6c61f-f969-4234-9fe3-16e13b9b6961.gif&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;crA0&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://heraclosgame.com/&quot; target=&quot;_blank&quot;&gt;Играть&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;DRYL&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;rcus&quot;&gt;InterLand&lt;/h2&gt;
  &lt;p id=&quot;PWoH&quot;&gt;Игрушка от гугла. Тут 4 разных аркады которые рассказывают о том как пользоваться интернетом и сервисами гугла, конечно.&lt;/p&gt;
  &lt;p id=&quot;qzo2&quot;&gt;Играть в нее не интересно, но сделана хорошо и есть чему поучиться. За это она и попала в эту подборку.&lt;/p&gt;
  &lt;figure id=&quot;2JOl&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/35/f0/35f012c0-3b8e-4a58-9fc0-6fc762bd169e.gif&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;z9m6&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://beinternetawesome.withgoogle.com/interland&quot; target=&quot;_blank&quot;&gt;Играть&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;B4CO&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;NAKl&quot;&gt;Screeps&lt;/h2&gt;
  &lt;p id=&quot;7PZw&quot;&gt;Очень неоднозначное творение. Представляет из себя стратегию где все управление осуществляется написанием кода. Чтоб хоть что-то в ней сделать нужно хоть немного знать JavaScript.&lt;/p&gt;
  &lt;p id=&quot;TX94&quot;&gt;Я пока еще не разобрался в ней, надо потратить время на чтение документации и просмотр гайдов, но я обязательно попробую в нее поиграть и напишу отдельную статью о своих успехах. По-моему, задумка крайне интересная.&lt;/p&gt;
  &lt;p id=&quot;Cyq5&quot;&gt;Поиграть в тренировочный демо-режим можно бесплатно на сайте.&lt;/p&gt;
  &lt;figure id=&quot;yTXY&quot; class=&quot;m_column&quot;&gt;
    &lt;iframe src=&quot;https://www.youtube.com/embed/ZboTgOajnGg?autoplay=0&amp;loop=0&amp;mute=0&quot;&gt;&lt;/iframe&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;9RIi&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://screeps.com/&quot; target=&quot;_blank&quot;&gt;Сайт игры&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;WI5v&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://store.steampowered.com/app/464350/Screeps_World/&quot; target=&quot;_blank&quot;&gt;Страничка игры в Steam&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;i366&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://github.com/TooAngel/screeps&quot; target=&quot;_blank&quot;&gt;Исходный код на GitHub&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;BiL8&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;3An5&quot;&gt;Epic SkidMarks&lt;/h2&gt;
  &lt;p id=&quot;WBfX&quot;&gt;Кольцевые гоночки. Навевают воспоминаниями о близардских Rock &amp;amp; Roll Racing, которые я очень любил. Тут нет оружия, но зато можно легко подключиться с друзьями к любому серверу и погонять немножко.&lt;/p&gt;
  &lt;p id=&quot;kor0&quot;&gt;Игра сырая и создать свой сервер у меня не получилось, но поиграть вдвоем все равно прикольно.&lt;/p&gt;
  &lt;figure id=&quot;38AG&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/4c/67/4c672f56-a8a3-44c2-a56d-2d0fa3b3ffe4.gif&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;uYvQ&quot; data-align=&quot;center&quot;&gt;Играть&lt;/p&gt;
  &lt;/section&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;ExQH&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;xDre&quot;&gt;HexGL&lt;/h2&gt;
  &lt;p id=&quot;lIup&quot;&gt;Тут нам дают что-то вроде космического корабля и мы летим по трассе несколько кругов. Основная задача - ехать бысто и не врезаться в ограждения, а то взорвемся.&lt;/p&gt;
  &lt;p id=&quot;6JxZ&quot;&gt;Управление простое и понятное, но не врезаться все равно сложно. При всем моем опыте игры в Need For Speed, не взорваться я не смог😂&lt;/p&gt;
  &lt;figure id=&quot;co3X&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/a0/61/a0614481-420e-4a5e-a666-7176f1f169cf.png&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;g2pD&quot; data-align=&quot;center&quot;&gt;Играть&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;kEUK&quot; data-align=&quot;center&quot;&gt;Исходный код на GitHub&lt;/p&gt;
  &lt;/section&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;uZXv&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;FKka&quot;&gt;Diablo&lt;/h2&gt;
  &lt;p id=&quot;nBQR&quot;&gt;Я прошел всю третью часть Дьябло и очень люблю эту игру, поэтому не прошел мимо этого маленького недоделанного клона первой дьяблы😅&lt;/p&gt;
  &lt;p id=&quot;r8jf&quot;&gt;Тут есть только одна комната и несколько мобов, которых можно зарубить, но если есть желание, можешь продолжить разработку, быть может у тебя получится достойный убийца Дьябло!&lt;/p&gt;
  &lt;figure id=&quot;0exR&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/ca/0a/ca0a7f44-1f34-4cf3-9c11-826a244eccd1.png&quot; width=&quot;915&quot; /&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;8JGo&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://mitallast.github.io/diablo-js/&quot; target=&quot;_blank&quot;&gt;Играть&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;XUkN&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://github.com/mitallast/diablo-js&quot; target=&quot;_blank&quot;&gt;Исходный код на GitHub&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;uruQ&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;kf6d&quot;&gt;DuckHunt&lt;/h2&gt;
  &lt;p id=&quot;gfnP&quot;&gt;В детстве у меня была Dendy и вроде на ней была эта игра, но к сожалению, поиграть я мог только у знакомых, т.к. у моей Dendy не было ружья, который подключался к приставке.&lt;/p&gt;
  &lt;p id=&quot;F7lS&quot;&gt;Ружья на приставках тех времен были далеки от совершенства и подстрелить утку было ой как не просто.. а бесячая собака еще и смеялась над тобой постоянно😁&lt;/p&gt;
  &lt;p id=&quot;ElYp&quot;&gt;Мышкой попасть по уткам стало совсем просто, да и играть уже не так интересно, но тем не менее приятно вспомнить былые деньки.&lt;/p&gt;
  &lt;figure id=&quot;4tq5&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/75/d8/75d87c7a-7076-4e78-b11d-c1c3e66268dc.png&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;i7Gd&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://duckhuntjs.com/&quot; target=&quot;_blank&quot;&gt;Играть&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;WAHQ&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://github.com/MattSurabian/DuckHunt-JS&quot; target=&quot;_blank&quot;&gt;Исходный код на Github&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;fBiM&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;iDlU&quot;&gt;Circus&lt;/h2&gt;
  &lt;p id=&quot;2GOy&quot;&gt;Еще одна приставочная игра из детства. Основная задача - прыгать через кольца и препятствия, и при этом не поджарить льва. Это намного сложнее чем кажется и мелким я ее не сильно любил. Вообще не любил😀&lt;/p&gt;
  &lt;p id=&quot;RnCz&quot;&gt;Я вставил игры с приставки в подборку потому, что они лучше большинства игр которые сейчас есть в сервисах типа Google.Play и Яндекс.Игры. И если сделать клон какой-то из игр, но со своим &amp;quot;сюжетом&amp;quot; и графикой, уже будет классно!&lt;/p&gt;
  &lt;figure id=&quot;qzLL&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/84/ba/84baca27-4ac1-45e9-9639-cce67806717e.gif&quot; width=&quot;915&quot; /&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;jjgs&quot; data-align=&quot;center&quot;&gt;Играть&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;GkFW&quot; data-align=&quot;center&quot;&gt;Исходный код на GitHub&lt;/p&gt;
  &lt;/section&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;JuEq&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;spasibo_esli_dochitali___&quot;&gt;Спасибо, если дочитали ( ´･･)ﾉ(._.&amp;#x60;)&lt;/h2&gt;
  &lt;p id=&quot;WJCL&quot;&gt;Если ты знаешь классные игры на JavaScript, в которые можно поиграть, пиши про них в комментариях. Соберем еще одну подборку!&lt;/p&gt;
  &lt;p id=&quot;tFv0&quot;&gt;Или может ты помнишь какую-то игру из детства, которую можно воссоздать?&lt;/p&gt;

</content></entry><entry><id>buninman:pong</id><link rel="alternate" type="text/html" href="https://blog.buninman.ru/pong?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=buninman"></link><title>Игра Понг на JavaScript</title><published>2022-11-14T02:16:04.339Z</published><updated>2023-09-20T05:57:05.237Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/ec/5a/ec5aa8f6-0b4c-4c04-a1bd-5b8f71c0f5f4.png"></media:thumbnail><category term="lerning" label="Обучение"></category><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/c0/ba/c0ba3d85-a7fd-4aee-be24-5e86a8aa2345.gif&quot;&gt;Весь код моего Понга с комментариями к каждой строчке</summary><content type="html">
  &lt;blockquote id=&quot;8yiv&quot;&gt;Весь код моего Понга с комментариями к каждой строчке&lt;/blockquote&gt;
  &lt;p id=&quot;640N&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;Y4AM&quot;&gt;⚠ Эту статью также можно &lt;a href=&quot;https://habr.com/ru/post/697870/&quot; target=&quot;_blank&quot;&gt;прочитать на Хабре&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;blockquote id=&quot;rOz6&quot;&gt;Это моя первая статья вышедшая на Хабре. Менее чем за неделю она собрала почти 4000 просмотров и 47 добавлений в избранное. Я очень рад такому результату! А еще в читатели на Хабре указали мне на то, что комментарии к функциям должны быть написаны сверху, поэтому тут выходит уже исправленный вариант.&lt;/blockquote&gt;
  &lt;p id=&quot;4VWx&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;e2RM&quot;&gt;Я был очень вдохновлен созданием &lt;a href=&quot;https://blog.buninman.ru/snake&quot; target=&quot;_blank&quot;&gt;Змейки&lt;/a&gt;. Даже не смотря на то, что она является просто повторением чужого гайда, из-за того я проанализировал в ней каждую строчку кода, мне удалось почерпнуть немало полезных знаний и навыков. Я также смог сам внести интересные изменения в ее код.&lt;/p&gt;
  &lt;p id=&quot;mlZY&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;wpXy&quot;&gt;Повторил&lt;/h3&gt;
  &lt;p id=&quot;cYhy&quot;&gt;К повторению Понга я приступил сразу же и это не заняло много времени. Но на этапе анализа стало ясно, что код очень сложный для понимания, все слишком переплетено и запутано. Еще недавно я бы подумал, что это я не все понимаю, но сейчас я уже видел как это можно сделать лучше.&lt;/p&gt;
  &lt;p id=&quot;wSJo&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;joyb&quot;&gt;Переосмыслил&lt;/h3&gt;
  &lt;p id=&quot;XTRg&quot;&gt;Я писал этот Понг с нуля, взяв из исходника только некоторые функции и концепции. Полностью поменял структуру, добавил модуль с настройками, отдельно вынес все функции рисования и многое другое.&lt;/p&gt;
  &lt;p id=&quot;x1Q4&quot;&gt;Учитывая мой совсем маленький опыт программирования, чуть меньше 2 месяцев, я очень горжусь проделанной работой.&lt;/p&gt;
  &lt;p id=&quot;Y4MT&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;riNe&quot;&gt;Расписал&lt;/h3&gt;
  &lt;p id=&quot;ZTWl&quot;&gt;В статье я постарался расписать каждую функцию и изложить ход своих мыслей. Это заняло прилично времени, но возможно кому-то зайдет такой гайд, лично мне иногда мне не хватало описаний логики функций, пояснений того, что куда передается и зачем.&lt;/p&gt;
  &lt;p id=&quot;KWZn&quot;&gt;Буду рад, если подскажите как можно улучшить код или найдете и укажите на ошибки в комментариях, даже орфографические🙂&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;STrY&quot;&gt;Гитхаб с моим Понгом: &lt;a href=&quot;https://github.com/Buninman/Pong&quot; target=&quot;_blank&quot;&gt;https://github.com/Buninman/Pong&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;UxPc&quot;&gt;А вот &lt;a href=&quot;https://youtu.be/tHnPWQKX-wE&quot; target=&quot;_blank&quot;&gt;видео-гайд&lt;/a&gt; изначального пинг-понга от автора, и его &lt;a href=&quot;https://github.com/EpicLegend/ping-pong&quot; target=&quot;_blank&quot;&gt;код на гитхабе&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;G8Lw&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;FGVl&quot;&gt;Кстати, оригинальная игра 1972 года называется Pong, а пинг-понг. Хотя идеей-прародительницей для нее действительно был настольный теннис.&lt;/p&gt;
    &lt;p id=&quot;ek6M&quot;&gt;Что примечательно, Понг была первой коммерчески успешной видеоигрой.&lt;/p&gt;
  &lt;/section&gt;
  &lt;figure id=&quot;KIau&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c0/ba/c0ba3d85-a7fd-4aee-be24-5e86a8aa2345.gif&quot; width=&quot;800&quot; /&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;QUf9&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://buninman.github.io/Pong/&quot; target=&quot;_blank&quot;&gt;Тут можно поиграть в готовый Понг&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;O1rH&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;ayxU&quot; data-align=&quot;center&quot;&gt;Начало&lt;/h2&gt;
  &lt;p id=&quot;8C7h&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;MXgP&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c5/8d/c58dea63-c7a9-4bf2-a84b-94c621bbd893.png&quot; width=&quot;1920&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;1OO0&quot;&gt;Набросал схему, чтоб было понятнее, что куда экспортируется. Но на этот раз мы пойдем не по порядку схемы, а немного по-другому. Сначала рассмотрим те модули, которые используются везде, такие как файл настроек и рисование.&lt;/p&gt;
  &lt;ol id=&quot;A4Xz&quot;&gt;
    &lt;li id=&quot;JfKq&quot;&gt;&lt;a href=&quot;#OEBg&quot;&gt;setting.js&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;B7W3&quot;&gt;&lt;a href=&quot;#k6Ov&quot;&gt;canvas.js&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;WUc5&quot;&gt;&lt;a href=&quot;#WlQe&quot;&gt;printer.js&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;l6FL&quot;&gt;&lt;a href=&quot;#dvEw&quot;&gt;game.js&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;S9OV&quot;&gt;&lt;a href=&quot;#xQFs&quot;&gt;ball.js&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;MqwH&quot;&gt;&lt;a href=&quot;#UcJA&quot;&gt;player.js&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;SJsH&quot;&gt;&lt;a href=&quot;#tW70&quot;&gt;index.html&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;sXzC&quot;&gt;&lt;a href=&quot;#jDR0&quot;&gt;style.css&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;iF9I&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;OEBg&quot; data-align=&quot;center&quot;&gt;setting.js&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;5i8w&quot;&gt;Модуль настроек. Я сложил сюда все значения которые используются в игре, кроме надписей и размеров шрифтов. Доступ к экземпляру настроек есть у всех модулей и он всегда будет присвоен переменной &lt;code&gt;set&lt;/code&gt;.&lt;/p&gt;
    &lt;pre id=&quot;QfPg&quot; data-lang=&quot;javascript&quot;&gt;export default class Setting {
  constructor() {
    // Высота и ширина игрового поля, и всех слоев канваса
    this.boxWidth = 800
    this.boxHeight = 500
    // Радиус закругления углов игрового поля
    this.boxRound = 20
    // Серый цвет заливки игрового поля
    this.boxColor = &amp;#x27;#333333&amp;#x27;
    // Толщина линий
    this.lineWidth = 6
    // Цвет линий. Темно-серый, как основной фон окна брузера в CSS
    this.lineColor = &amp;#x27;#232323&amp;#x27;
    // Светло-серый цвет, используется для текста таймера и бегунка
    this.textColor = &amp;#x27;#EBEBEB&amp;#x27;
    // Вспомогательные красный и желтый цвета,
    // используются для подсветки технических нюансов
    this.supportColorRed = &amp;#x27;#FA0556&amp;#x27;
    this.supportColorYellow = &amp;#x27;#FAC405&amp;#x27;&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;zTYg&quot;&gt;Далее идут все параметры мячика. В отдельный объект вынесены те параметры, которые изменяются в процессе игры.&lt;/p&gt;
    &lt;pre id=&quot;QfPg&quot; data-lang=&quot;javascript&quot;&gt;    // Скорость мячика
    this.ballSpeed = 7
    // Радиус мячка, диаметр получается 16px
    this.ballRadius = 8
    // Координаты мячика по умолчанию,
    // равны половине длины и ширины поля, это центр
    this.ballXDefault = (this.boxWidth / 2)
    this.ballYDefault = (this.boxHeight / 2)
    // Цвет мячика, я сделал таким же светло-серым как textColor
    this.ballColor = &amp;#x27;#EBEBEB&amp;#x27;
    // Счетчик отбитых мячей, также к нему привязано увеличение
    // скорости мячика. Увеличиваем скорость при каждом ударе
    this.ballHitScore = 0
    
    this.ball = {
      // Текущие координаты мячика, которые меняются в процессе
      // игры, изначально они равны дефолтным - мячик в центре поля
      x: this.ballXDefault,
      y: this.ballYDefault,
      // Ускорение мячика по осям. Изначально равно 0, но
      // позже получает рандомное значение от 0.8 до 1, с + или - 
      dx: 0,
      dy: 0,
      // Еще одно значение скорости, оно нужно, т.к. скорость мяча
      // постепено растет и переодически надо ее возвращать
      // к дефолтному this.ballSpeed
      speed: this.ballSpeed
    }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;nxpx&quot;&gt;Дальше идут параметры обоих игроков. В отдельные объекты вынесены параметры уникальные для каждого игрока. Мы будем передавать эти отдельные объекты при создании экземпляра класса &lt;em&gt;&lt;a href=&quot;#UcJA&quot;&gt;Player&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
    &lt;pre id=&quot;QfPg&quot; data-lang=&quot;javascript&quot;&gt;    // Радиус игрока. Правильнее было бы назвать толщиной, т.к.
    // игрок это векторная линия. Но в расчетах столкновений, 
    // я использую крайние точки как окружности, поэтому это радиус.
    // Реальная толщина игрока - это два его радиуса, 14px.
    this.playerRadius = 7        
    // Высота игрока. Растояние от верхней до нижней точки игрока.
    // Но т.к. платформы игроков имеют закругления, реальный размер
    // получается на два радиуса больше, 94px
    this.playerHeight = 80
    // Скорость игрока. Используется как коэффициент для ускорения
    this.playerSpeed = 8
    // Пространство от краев игрока до стенки сверху и снизу
    this.playerBorder = this.playerRadius * 3
    // Пространство от центра платформы игрока до стенки за ним
    this.playerSpace = this.playerRadius * 6
    // Изначальная координата игрока Y равна половине высоты
    // игрового поля минус половина высоты игрока, таким образом
    // игрок будет распологаться посередине при любой заданной длине
    this.playerYDefault =
                   (this.boxHeight / 2) - (this.playerHeight / 2)
    this.playerL = {
      // Счетчик очков
      score: 0,
      // Координата Х для появления надписей &amp;quot;+1&amp;quot; на игровом поле.
      // Для левого игрока равна ширине поля минус 2 растояния
      // до игрока. Таким образом она находится на поле противника,
      // справа
      goalPointX: this.boxWidth - this.playerSpace * 2,
      // Параметр определяет выравнивание текста &amp;quot;+1&amp;quot;.
      // Я также использую этот параметр для определения стороны
      // в которую полетит мяч после забития гола
      align: &amp;#x27;right&amp;#x27;,
      // Кординаты игрока. X равен заданному растоянию playerSpace,
      // а Y дефолтному значению, общему для обоих игроков
      x: this.playerSpace,
      y: this.playerYDefault,
      // Зарезервированная переменная со значением Y по умолчанию
      yDefault: (this.boxHeight / 2) - (this.playerHeight / 2),
      // Цвет игрока. Оранжевый
      color: &amp;#x27;#A55F02&amp;#x27;,
      // Создаем массив с парами ключ-значение.
      // Номер клавиши и строка
      // с направлением. Узнать номер клавиш можно тут:
      // https://puzzleweb.ru/javascript/char_codes-key_codes.php
      keys: [[87,&amp;#x27;up&amp;#x27;], [83,&amp;#x27;down&amp;#x27;]],  
    }
    this.playerR = {
      score: 0,
      goalPointX: this.playerSpace * 2,
      align: &amp;#x27;left&amp;#x27;,
      // Координата X для правого игрока равна всей ширине поля,
      // минус заданное растояние playerSpace
      x: this.boxWidth - (this.playerSpace),
      y: this.playerYDefault,
      // Цвет игрока. Голубой
      color: &amp;#x27;#38887A&amp;#x27;,
      keys: [[38,&amp;#x27;up&amp;#x27;], [40,&amp;#x27;down&amp;#x27;]],
    }
  }
}&lt;/pre&gt;
  &lt;/section&gt;
  &lt;blockquote id=&quot;LOYl&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#ayxU&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;7PYi&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;HPqM&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;gCmF&quot; data-align=&quot;center&quot;&gt;canvas.js&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;3JaW&quot;&gt;Модуль можно использовать в других проектах, практически в неизменном виде, т.к. он содержит непосредственные функции рисования примитивов на 2D-канвасе, которые в свою очередь используются модулем &lt;em&gt;&lt;a href=&quot;#bexA&quot;&gt;printer.js&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
    &lt;p id=&quot;x4iN&quot;&gt;Для начала рассмотрим конструктор класса &lt;em&gt;Canvas:&lt;/em&gt;&lt;/p&gt;
    &lt;pre id=&quot;tinL&quot; data-lang=&quot;javascript&quot;&gt;export default class Canvas {
  constructor(setting) {
    // Передаем переменной set общие настройки
    this.set = setting
    // Создаем элемент canvas и переменную для доступа к нему
    this.canvas = document.createElement(&amp;#x27;canvas&amp;#x27;)
    // Создаем в канвасе 2d-контекст, нужен для рисования фигур
    this.ctx = this.canvas.getContext(&amp;#x27;2d&amp;#x27;)
    // Задаем канвасу высоту и ширину
    this.canvas.width = this.set.boxWidth
    this.canvas.height = this.set.boxHeight
    // Находим в html тег game (id=&amp;quot;game&amp;quot;) и как дочерний эллемент
    // создаем в нем наш canvas
    document.querySelector(&amp;#x27;#game&amp;#x27;).appendChild(this.canvas)
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;vUhp&quot;&gt;Рисование текста. В него передается сам текст, координаты, размер текста, цвет, выравнивание и выравнивание по базовой линии (координате &lt;code&gt;y&lt;/code&gt;)&lt;/p&gt;
    &lt;pre id=&quot;b9Im&quot; data-lang=&quot;javascript&quot;&gt;  drawText(text, x, y, fontSize, color = this.set.textColor, 
                            align = &amp;quot;center&amp;quot;, baseline = &amp;#x27;middle&amp;#x27;) {
    // Указываем цвет заливки
    this.ctx.fillStyle = color
    // Указываем шрифт и атрибуты
    this.ctx.font = &amp;#x60;bold ${fontSize} &amp;#x27;Fira Mono&amp;#x27;, monospace&amp;#x60;
    // Указываем выравнивание по краю
    this.ctx.textAlign = align
    // Указываем выравнивание по базовой линии
    this.ctx.textBaseline = baseline
    // Пишем текст, передаем туда строку с текстом
    // и ккординаты начальной точки
    this.ctx.fillText(text, x, y)
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;JKOr&quot;&gt;С помощью трех функций ниже мы рисуем игровое поле, которое состоит из прямоугольника с закругленными краями, круга посередине и трех линий.&lt;/p&gt;
    &lt;p id=&quot;onlx&quot;&gt;Помимо игрового поля, линией мы рисуем игрока, а круг также используется для мячика.&lt;/p&gt;
    &lt;figure id=&quot;lqK0&quot; class=&quot;m_original&quot;&gt;
      &lt;img src=&quot;https://img2.teletype.in/files/96/13/9613590c-019e-4682-806f-5b94ea14ed20.png&quot; width=&quot;1320&quot; /&gt;
    &lt;/figure&gt;
    &lt;pre id=&quot;0vH7&quot; data-lang=&quot;javascript&quot;&gt;  drawLine(xS, yS, xF, yF, lineWidth, color) {
    // Указываем, что линия будет с закруглениями на концах
    this.ctx.lineCap = &amp;#x27;round&amp;#x27;
    // beginPath() начинает вектор
    this.ctx.beginPath() 
    // Аргументами указываем координаты начальной точки линии
    this.ctx.moveTo(xS, yS)
    // Аргументами  указываем координаты конечной точки линии
    this.ctx.lineTo(xF, yF)
    // Указываем толщину линии, ее мы также передаем аргументом
    this.ctx.lineWidth = lineWidth
    // Указываем цвет обводки
    this.ctx.strokeStyle = color
    // Рисуем обводку (линию)
    this.ctx.stroke()
    // Завершем создание вектора
    this.ctx.closePath()
  }
  
  drawRectangleRound(x, y, width, height, radius, color) {
    // beginPath() начинает вектор
    this.ctx.beginPath()
    // Указываем координаты начальной точки линии
    this.ctx.moveTo(x + radius, y)
    // Указываем координаты следующей точки линии
    this.ctx.lineTo(x + width - radius, y)
    // Указываем координаты точки, до куда будет идти закругление
    this.ctx.quadraticCurveTo(x + width, y, x + width, y + radius)
    // Указываем координаты следующей точки линии и т.д
    this.ctx.lineTo(x + width, y + height - radius)
    this.ctx.quadraticCurveTo(x + width, y + height,
                                     x + width - radius, y + height)
    this.ctx.lineTo(x + radius, y + height)
    this.ctx.quadraticCurveTo(x, y + height, x, y + height - radius)
    this.ctx.lineTo(x, y + radius)
    this.ctx.quadraticCurveTo(x, y, x + radius, y)
    // Завершем создание вектора
    this.ctx.closePath()
    // Указываем цвет заливки
    this.ctx.fillStyle = color
    // Создаем заливку
    this.ctx.fill()
  }
  
  drawCircle(x, y, radius, fillColor, stroke = true) {
    // beginPath() начинает вектор
    this.ctx.beginPath()
    // Создаем арку. Агругументами выступают координаты
    // центра окружности, радиус, начальный угол в радианах
    // и конечный угол в радианах.
    // Math.PI*2 это число Пи умноженное на 2, дает замкнутый круг
    this.ctx.arc(x, y, radius, 0, Math.PI * 2)
    // Указываем цвет заливки
    this.ctx.fillStyle = fillColor
    // Создаем заливку
    this.ctx.fill()
    // Если нам не нужна обводка, то аргументам мы передаем false,
    // а по умолчанию обводка есть
    if (stroke) {
      // Указываем толщину линии
      this.ctx.lineWidth = 6
      // Указываем цвет обводки
      this.ctx.strokeStyle = this.set.lineColor
      // Рисуем обводку
      this.ctx.stroke()
    }
    // Завершем создание вектора
    this.ctx.closePath()
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;rb9T&quot;&gt;В основе рисования круга функцией &lt;code&gt;drawCircle() &lt;/code&gt;используется метод &lt;code&gt;arc()&lt;/code&gt; в котором используется значение угла в радианах. Про радианы на википедии есть &lt;a href=&quot;https://ru.wikipedia.org/wiki/Радиан&quot; target=&quot;_blank&quot;&gt;понятная статья&lt;/a&gt; с картинкой, если интересно. ༼ つ ◕_◕ ༽つ&lt;/p&gt;
    &lt;p id=&quot;viv7&quot;&gt;Функция &lt;code&gt;drawArc()&lt;/code&gt;,  также использует в основе своей метод &lt;code&gt;arc()&lt;/code&gt;, но тут мы не замыкаем дугу, а оставляем ее небольшой кусочек. Можно было бы обойтись одной функцией, но нужно было бы передавать в нее больше аргументов. Поэтому для таймера я сделал отдельную функцию.&lt;/p&gt;
    &lt;pre id=&quot;OQxD&quot; data-lang=&quot;javascript&quot;&gt;  drawArc(radius, sAngle, eAngle, color = this.set.textColor) {
    const centerW = (this.set.boxWidth / 2)
    const centerH = (this.set.boxHeight / 2)
    
    // lineCap определяет то что обводка будет закругляться на конце
    this.ctx.lineCap = &amp;#x27;round&amp;#x27;
    this.ctx.beginPath()
    this.ctx.arc(centerW, centerH, radius, sAngle, eAngle)
    this.ctx.lineWidth = 6
    this.ctx.strokeStyle = color
    this.ctx.stroke()
    this.ctx.closePath()
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;PcGe&quot;&gt;Функция отчищает канвас. Используется в метод &lt;code&gt;clearRect()&lt;/code&gt;, который принимает начальные и конечные точки прямоугольника, который надо отчистить. В данном случае мы чистим канвас целиком.&lt;/p&gt;
    &lt;pre id=&quot;RZfY&quot; data-lang=&quot;javascript&quot;&gt;  clear() {        
    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
  }
}&lt;/pre&gt;
  &lt;/section&gt;
  &lt;blockquote id=&quot;Zdcv&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#ayxU&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;Hr1i&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;12Mj&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;bexA&quot; data-align=&quot;center&quot;&gt;printer.js&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;05cQ&quot;&gt;Модуль работает напрямую с функциями канваса. В нем создаются сразу несколько канвасов, которые выступают слоями и перерисовываются независимо друг от друга. &lt;/p&gt;
    &lt;p id=&quot;EtVB&quot;&gt;Все внутренние переменные в функциях объявлены только для удобства читаемости и компактности кода в гайде.&lt;/p&gt;
    &lt;p id=&quot;cvCi&quot;&gt;Для начала рассмотрим конструктор класса &lt;em&gt;Printer:&lt;/em&gt;&lt;/p&gt;
    &lt;pre id=&quot;GEpe&quot; data-lang=&quot;javascript&quot;&gt;// В файл подключаем класс Canvas
import Canvas from &amp;#x27;./canvas.js&amp;#x27;

export default class Printer {
  // В принтер передаем только настройки
  constructor(setting) {    
    // Передаем общие настройки переменной set,
    this.set = setting
    // а переменной ball настройки мячика, для удобства
    this.ball = setting.ball
    // Создаем новый Map с пятью классами Canvas под разные нужды,
    // порядок будущих слоев влияет на их видимость, первый будет 
    // перекрывать вторым и т.д.
    this.canvas = new Map([
      // На слое background рисуется неподвижные и необновляемые
      // элементы игры. Игровое поле
      [&amp;#x27;background&amp;#x27;, new Canvas(this.set)],
      // Слой для отрисовки счета игроков
      [&amp;#x27;score&amp;#x27;, new Canvas(this.set)],
      // Слой для впомогательных функций, не нужен для игры
      [&amp;#x27;support&amp;#x27;, new Canvas(this.set)],
      // Дополнительный слой для разных задач
      [&amp;#x27;other&amp;#x27;, new Canvas(this.set)],
      // Слой для текста, появляющегося на экране
      [&amp;#x27;text&amp;#x27;, new Canvas(this.set)],
      // Слой для игровых элементов с постоянной перерисовкой,
      // таких как мячик и игроки
      [&amp;#x27;gamelayer&amp;#x27;, new Canvas(this.set)]
      ])
    // Для сокращения ширины кода, помещаю пути обращения
    // к Canvas в переменные, можно этого не делать
    this.bgCan = this.canvas.get(&amp;#x27;background&amp;#x27;)
    this.scoreCan = this.canvas.get(&amp;#x27;score&amp;#x27;)
    this.supCan = this.canvas.get(&amp;#x27;support&amp;#x27;)
    this.othCan = this.canvas.get(&amp;#x27;other&amp;#x27;)
    this.txtCan = this.canvas.get(&amp;#x27;text&amp;#x27;)
    this.gameCan = this.canvas.get(&amp;#x27;gamelayer&amp;#x27;)
    
    // Переменная ballDirectionAngle нужна передачи значения угла,
    // под которым требуется рисовать белый бегунок, отображающий    
    // направление броска мячика
    this.ballDirectionAngle = 0
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;eLDb&quot;&gt;Функция ниже рисует игровое поле, это фон с закругленными краями и разные темные линии. Рисуется на специальном слое канваса - &amp;#x27;background&amp;#x27;.&lt;/p&gt;
    &lt;figure id=&quot;wft2&quot; class=&quot;m_original&quot;&gt;
      &lt;img src=&quot;https://img4.teletype.in/files/72/7f/727f0a41-a08a-4066-9e91-87f5fba467dd.png&quot; width=&quot;1320&quot; /&gt;
    &lt;/figure&gt;
    &lt;pre id=&quot;KeDE&quot; data-lang=&quot;javascript&quot;&gt;  drawBackground() {        
    // Высота и ширина игрового поля и всех слоев канваса
    const width = this.set.boxWidth        
    const height = this.set.boxHeight        
    // Радиус закругления углов игрового поля 
    const boxRound = this.set.boxRound        
    // Цвет заливки игрового поля         
    const boxColor = this.set.boxColor        
    // Толщина и цвет линий             
    const lineW = this.set.lineWidth        
    const lineColor = this.set.lineColor        
    // Пространство от центра платформы игрока до стенки за ним
    const plSpace = this.set.playerSpace        
    // Пространство от краев игрока до стенки сверху и снизу
    const plBorder = this.set.playerBorder        
    
    // Рисуем основной прямоугольник игрового поля с закруглениями
    this.bgCan.drawRectangleRound(0, 0, width, height,
                                               boxRound, boxColor)
    // Рисуем вертикальную линию посередине
    this.bgCan.drawLine((width / 2), 0, (width / 2),
                                           height, lineW, lineColor)
    // Рисуем круг посередине, с радиусом в 1/4 высоты поля
    this.bgCan.drawCircle((width / 2), (height / 2),
                                    (height / 4), boxColor)
    // Рисуем 2 линии под игроками с отступами от края
    this.bgCan.drawLine(plSpace, plBorder, plSpace,
                             (height - plBorder), lineW, lineColor)
    this.bgCan.drawLine((width - plSpace), plBorder,
          (width - plSpace), (height - plBorder), lineW, lineColor)
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;ygja&quot;&gt;Функция &lt;code&gt;drawBriefing()&lt;/code&gt; рисует инструкцию с клавишами управления. Рисую ее на слое для игры &amp;#x27;game&amp;#x27;, т.к. при первоначальном отчете он не перерисовывается и мы можем им воспользоваться.&lt;/p&gt;
    &lt;p id=&quot;WUkf&quot;&gt;К моменту вызова &lt;code&gt;drawBriefing()&lt;/code&gt; у нас уже будут нарисованы игроки с помощью функции &lt;code&gt;drawPlayer()&lt;/code&gt;, о ней ниже.&lt;/p&gt;
    &lt;figure id=&quot;YVVv&quot; class=&quot;m_original&quot;&gt;
      &lt;img src=&quot;https://img4.teletype.in/files/34/91/3491e556-e7b0-4b0c-8a75-de95873c81a0.png&quot; width=&quot;1320&quot; /&gt;
    &lt;/figure&gt;
    &lt;pre id=&quot;rpfE&quot; data-lang=&quot;javascript&quot;&gt;  drawBriefing() {
    // Цвета левого и правого игроков
    const plLColor = this.set.playerL.color
    const plRColor = this.set.playerR.color
    // Координаты x и y для текста с инструкцией
    // Немного сложно, но все координаты отталкиваются от статичных
    // значений и масштабируются с игровым полем
    const controlXL = (this.set.playerSpace * 2)
    const controlXR = this.set.boxWidth - (this.set.playerSpace * 2)
    const controlY = (this.set.boxHeight / 17)
    
    // Рисуем текст инструкций. Для каждого игрока свой цвет.
    // Параметры &amp;#x27;left&amp;#x27; и &amp;#x27;right&amp;#x27; отвечаю за выравнивание текста
    this.gameCan.drawText(&amp;#x27;keys:&amp;#x27;, controlXL , (controlY * 8),
                                         &amp;#x27;15px&amp;#x27;, plLColor, &amp;#x27;left&amp;#x27;)
    this.gameCan.drawText(&amp;#x27;W and S&amp;#x27;, controlXL, (controlY * 9),
                                         &amp;#x27;20px&amp;#x27;, plLColor, &amp;#x27;left&amp;#x27;)
    this.gameCan.drawText(&amp;#x27;keys:&amp;#x27;, controlXR, (controlY * 8),
                                        &amp;#x27;15px&amp;#x27;, plRColor, &amp;#x27;right&amp;#x27;)
    this.gameCan.drawText(&amp;#x27;Arrows&amp;#x27;, controlXR, (controlY * 9),
                                        &amp;#x27;20px&amp;#x27;, plRColor, &amp;#x27;right&amp;#x27;)
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;Egt8&quot;&gt;Функция &lt;code&gt;drawScore()&lt;/code&gt; отвечает за визуальное отображение текущего счета на игровом поле. Рисуется на специальном слое &amp;#x27;score&amp;#x27;.&lt;/p&gt;
    &lt;figure id=&quot;jOhg&quot; class=&quot;m_original&quot;&gt;
      &lt;img src=&quot;https://img2.teletype.in/files/1b/b4/1bb4a14f-3d1d-4f97-a181-edd046c68ed0.png&quot; width=&quot;1320&quot; /&gt;
    &lt;/figure&gt;
    &lt;pre id=&quot;utEX&quot; data-lang=&quot;javascript&quot;&gt;  drawScore() {
    // Цвета левого и правого игроков
    const plLColor = this.set.playerL.color
    const plRColor = this.set.playerR.color
    // Значение количества очков каждого игрока
    const plLScore = this.set.playerL.score
    const plRScore = this.set.playerR.score
    // Координаты x и y для отбражения очков игроков
    // отталкиваются от статичных значений ширины и высоты поля
    const scoreXL = (this.set.boxWidth / 9 * 4)
    const scoreXR = (this.set.boxWidth / 9 * 5)
    const scoreY = (this.set.boxHeight / 20)
    
    // Рисуем текст счета. Для каждого игрока свой цвет.
    // Параметр &amp;#x27;left&amp;#x27; рисует текст справа от точки координат,
    // а параметр &amp;#x27;right&amp;#x27;, наоборот, слева.
    // Таким образом цифры счета никогда не слипнутся (⊙_⊙)
    this.scoreCan.drawText(plLScore, scoreXL, scoreY, &amp;#x27;40px&amp;#x27;,
                                         plLColor, &amp;#x27;right&amp;#x27;, &amp;#x27;top&amp;#x27;)
    this.scoreCan.drawText(plRScore, scoreXR, scoreY, &amp;#x27;40px&amp;#x27;,
                                          plRColor, &amp;#x27;left&amp;#x27;, &amp;#x27;top&amp;#x27;)
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;wDUE&quot;&gt;Функции ниже проверяют какое направление для мяча выбрано и запускают цикл рисования белой полосочки бегающей по кругу. Вызывается &lt;code&gt;drawBallDirection()&lt;/code&gt; из модуля &lt;a href=&quot;#dvEw&quot;&gt;&lt;em&gt;game.js&lt;/em&gt;&lt;/a&gt;, при старте каждого матча.&lt;/p&gt;
    &lt;p id=&quot;xC0M&quot;&gt;В основе рисования этого &amp;quot;белого бегунка&amp;quot; используется метод &lt;code&gt;arc()&lt;/code&gt; в котором используется значение угла в радианах. Про радианы на википедии есть &lt;a href=&quot;https://ru.wikipedia.org/wiki/Радиан&quot; target=&quot;_blank&quot;&gt;понятная статья&lt;/a&gt; с картинкой, если интересно. ༼ つ ◕_◕ ༽つ&lt;/p&gt;
    &lt;figure id=&quot;rQcw&quot; class=&quot;m_original&quot;&gt;
      &lt;img src=&quot;https://img3.teletype.in/files/a3/aa/a3aa50e8-f5d4-491c-bc74-2e4f46d45288.gif&quot; width=&quot;1200&quot; /&gt;
    &lt;/figure&gt;
    &lt;pre id=&quot;4eBt&quot; data-lang=&quot;javascript&quot;&gt;  // В функцию передается переменная int, которая содержит
  // корректировщик коээфициента значения угла. Она может иметь
  // значение 2 для таймера после гола и 4 для начального таймера
  drawBallDirection(int = 2) {   
    // Ось координат канваса начинается сверху слева, поэтому
    // если направление мячика по X больше 0, то он летит вправо,
    // если направление мячика по Y больше 0, то он летит вниз     
    // следовательно здесь мячик летит по диагонали вправо вниз
    if (this.ball.dx &amp;gt; 0 &amp;amp;&amp;amp; this.ball.dy &amp;gt; 0) {
      // Я подобрал необходимые коэффициенты для       
      // значений угла окружности, в котором бегунок 
      // должен будет остановиться
      
      // В зависимости от направления полета мячика
      // передаем нужное значение во внешнюю переменную
      this.ballDirectionAngle = 6.3
    }
    if (this.ball.dx &amp;lt; 0 &amp;amp;&amp;amp; this.ball.dy &amp;gt; 0) {
        this.ballDirectionAngle = 6.8
    }        
    if (this.ball.dx &amp;lt; 0 &amp;amp;&amp;amp; this.ball.dy &amp;lt; 0) {
        this.ballDirectionAngle = 7.3
    }
    if (this.ball.dx &amp;gt; 0 &amp;amp;&amp;amp; this.ball.dy &amp;lt; 0) { 
        this.ballDirectionAngle = 7.8
    }
    // Запускаем цикл рисования белого бегунка,        
    // передаем в него значение угла минус значение переменной int.
    // Я нарочно увеличил значения углов на 2 оборота окружности,
    // чтоб при вычитании значения оставались положительными.
    // В противном случае появляются погрешности¯\_(ツ)_/¯
    this.loopBallDirection(this.ballDirectionAngle - int) 
  }
  
  // Функция представляет собой цикл, перерисовывающий бегунок,
  // пока он не достигнет нужного угла на окружности  
  loopBallDirection(someAngle) {    
    // Радиус окружности такой же, как радиус круга на игровом поле
    const rad = (this.set.boxHeight / 4)        
    // При первом вызове функции переменной angle присваивается   
    // значение угла, полученного из drawBallDirection(),
    // но в последствии оно берется из цикла
    let angle = someAngle        
    
    // Рисуем часть окружности через функцию канвасе      
    this.othCan.drawArc(rad, Math.PI * angle - 0.3, Math.PI * angle)
    // С помощью встроенной в JS функции setTimeout(),        
    // делаем задержку в 0.06 секунд, или &amp;#x27;60&amp;#x27; милисекунд        
    setTimeout(() =&amp;gt; {
      angle += 0.1 
      if(angle &amp;lt;= this.ballDirectionAngle) {                
      this.clear(&amp;#x27;other&amp;#x27;)                
      this.loopBallDirection(angle)            
      }        
    }, 60)
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;hkwM&quot;&gt;Первая функция ниже является посреднической, она используется для рисования текста по центру игрового поля, а две другие функции уже используют ее внутри себя для рисования различного текста на поле.&lt;/p&gt;
    &lt;figure id=&quot;IuXJ&quot; class=&quot;m_original&quot;&gt;
      &lt;img src=&quot;https://img3.teletype.in/files/62/3a/623ac7ea-5e68-496b-8da4-c104eb5b6bf8.png&quot; width=&quot;1320&quot; /&gt;
    &lt;/figure&gt;
    &lt;pre id=&quot;1wxb&quot; data-lang=&quot;javascript&quot;&gt;  // Функция рисует текст в центре экрана, по умолчанию использует    
  // белый цвет и &amp;#x27;90px&amp;#x27; размер шрифта, это счетчик стартового таймера
  centerText(text, fontSize = &amp;#x27;90px&amp;#x27;, color = this.set.textColor) {
    // Координаты центра игрового поля
    const centerW = (this.set.boxWidth / 2)
    const centerH = (this.set.boxHeight / 2)
    
    this.txtCan.drawText(text, centerW, centerH, fontSize, color)
  }
  
  // Функция рисует счетчик ударов по цетру экрана.
  // Можно было обойтись одной фунцией centerText(), но так понятнее
  drawBallHit() {
    // Используем цвет линий, чтоб счетсчик не отвлекал внимание
    this.centerText(this.set.ballHitScore, &amp;#x27;70px&amp;#x27;, this.set.lineColor)
  }
  
  // Функция вызывается из экземпляра Player и принимает координату Х,
  // цвет игрока и выравнивание
  drawGoal(x, color, align) {
    // рисуем &amp;quot;+1&amp;quot; на поле проигравшего. Цветом забившего игрока
    this.txtCan.drawText(&amp;#x27;+1&amp;#x27;, x, this.ball.y, &amp;#x27;20px&amp;#x27;, color, align)
    // Рисуем надпись &amp;quot;Goal&amp;quot; в центре. Цветом забившего игрока  
    this.centerText(&amp;#x27;Goal!&amp;#x27;, &amp;#x27;50px&amp;#x27;, color)
    // Через 0.8 сукунд отчищаем слой &amp;#x27;text&amp;#x27;
    setTimeout(() =&amp;gt; {
      this.clear(&amp;#x27;text&amp;#x27;) }, 800)
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;GZLL&quot;&gt;Функции рисуют мячик и игрока. Мячик это круг, а игрок это линия с обводкой и закругленными краями.&lt;/p&gt;
    &lt;figure id=&quot;0zJd&quot; class=&quot;m_original&quot;&gt;
      &lt;img src=&quot;https://img2.teletype.in/files/95/a5/95a5066d-b094-44ee-9e93-53806c21fb0e.png&quot; width=&quot;1320&quot; /&gt;
    &lt;/figure&gt;
    &lt;pre id=&quot;Wnc2&quot; data-lang=&quot;javascript&quot;&gt;  // Рисует мячик используя его текущее местоположение
  drawBall() {    
    let ballX = this.ball.x
    let ballY = this.ball.y
    let radius = this.set.ballRadius
    let color = this.set.ballColor
    
    this.gameCan.drawCircle(ballX, ballY, radius, color, false)
  } 
  
  // Рисуем игрока используя его текущее местоположение.
  // Принимает координату Х и две координаты Y, верхнюю и нижнюю.
  // Рисует между ними линию. Также принимает толщину линии
  // и цвет игрока
  drawPlayer(xS, yS, yF, lineWidth, color) {
    this.gameCan.drawLine(xS, yS, xS, yF, lineWidth, color)
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;wD9m&quot;&gt;Функция очистки канваса. Как аргумент принимает название слоя канваса который надо почистить и вызывает для него метод &lt;code&gt;clear()&lt;/code&gt;.  &lt;/p&gt;
    &lt;pre id=&quot;S54s&quot; data-lang=&quot;javascript&quot;&gt;  // Функция отчищает нужный канвас    
  // Передаем в нее имя нужного слоя в виде &amp;#x27;строки&amp;#x27; текста
  clear(canvas) {
    this.canvas.get(canvas).clear()    
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;xLgt&quot;&gt;Функции ниже нужны только для проверки игровых механик, они делают видимыми внутренние механизмы игры, такие как &amp;quot;тень&amp;quot; игроков, желтая зона и возможные направления вылета мячика&lt;/p&gt;
    &lt;figure id=&quot;Cmlh&quot; class=&quot;m_original&quot;&gt;
      &lt;img src=&quot;https://img2.teletype.in/files/dc/b2/dcb2dd14-9cae-4aac-8073-35df1c4de6d7.png&quot; width=&quot;1320&quot; /&gt;
    &lt;/figure&gt;
    &lt;pre id=&quot;EaOR&quot; data-lang=&quot;javascript&quot;&gt;  // Функция рисует фактический размер игрока.
  // В движении зона отбития платформы увеличивается
  drawShadowPlayer(xS, yS, yF) {    
    const color = this.set.supportColorYellow
    const plWidth = (this.set.playerRadius * 2)
  
    this.supCan.drawLine(xS, yS, xS, yF, plWidth, color)
  }
  
  // Если мячик находится в желтой зоне (перед игроком),
  // то он отскакивает от координаты X игрока. Тут мы подсвечиваем
  // эту желтую зону
  drawYellowZone(x, yS, yF) {    
    const color = this.set.supportColorYellow
    const center = (this.set.boxWidth / 2)

    this.supCan.drawLine(x, yS, center, yS, 1, color)
    this.supCan.drawLine(x, yF, center, yF, 1, color)
  }
  
  // Функция подсвечивает все направления вылета мяча,
  // нужны были для расчета угла остановки белого бегунка
  drawAngleZone() {    
    const color = this.set.supportColorRed
    const radius = (this.set.boxHeight / 4)
    
    this.supCan.drawArc(radius, Math.PI * 0.2, Math.PI * 0.3, color)
    this.supCan.drawArc(radius, Math.PI * 0.7, Math.PI * 0.8, color)
    this.supCan.drawArc(radius, Math.PI * 1.2, Math.PI * 1.3, color)
    this.supCan.drawArc(radius, Math.PI * 1.7, Math.PI * 1.8, color)
    }
  }&lt;/pre&gt;
  &lt;/section&gt;
  &lt;blockquote id=&quot;e6w6&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#ayxU&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;nW2Z&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;e2Tm&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;dvEw&quot; data-align=&quot;center&quot;&gt;game.js&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;Lh2S&quot;&gt;На этот модуль ссылается &lt;a href=&quot;#tW70&quot;&gt;index.html&lt;/a&gt; отвечает за запуск самой игры. В нем создаются почти все классы и запускается цикл отрисовки кадров анимации. Он также является хабом, через который модули взаимодействую друг с другом.&lt;/p&gt;
    &lt;p id=&quot;eIfU&quot;&gt;Для начала рассмотрим конструктор класса &lt;em&gt;Game:&lt;/em&gt;&lt;/p&gt;
    &lt;pre id=&quot;jRm0&quot; data-lang=&quot;javascript&quot;&gt;// В файл подключаем Настройки, Игрока, Мячик и Принтер
import Setting from &amp;#x27;./setting.js&amp;#x27;
import Player from &amp;#x27;./player.js&amp;#x27;
import Ball from &amp;#x27;./ball.js&amp;#x27;
import Printer from &amp;#x27;./printer.js&amp;#x27;

class Game {
  constructor() {        
    // Передаем переменной set общие настройки
    this.set = new Setting()
    // В Printer передаем настройки
    this.print = new Printer(this.set)
    // В Ball передаем весь класс Game
    this.ball = new Ball(this)
    // Создаем два класса Player и передаем туда весь класс Game, 
    // а также отдельно настройки каждого игрока
    this.playerL = new Player(this, this.set.playerL)
    this.playerR = new Player(this, this.set.playerR)
    // Переменная &amp;quot;requestId&amp;quot; служит для запуска и остановки анимации.
    // Меняя значение на false, мы сможем останавливать анимацию
    this.reqId = true        
    // Инициируем первый запуск игры
    this.firstLaunch()
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;e1Wa&quot;&gt;Функция &lt;code&gt;firstLaunch()&lt;/code&gt; отвечает только за первый запуск и срабатывает один раз при запуске. Функции которые она вызывает внутри себя будут подробнее расписаны внутри своих классов.&lt;/p&gt;
    &lt;pre id=&quot;s8Na&quot; data-lang=&quot;javascript&quot;&gt;  firstLaunch() { 
    // Рисуем игровое поле
    this.print.drawBackground()
    // Вспомогательные функции. Вызвав ее здесь, мы увидим
    // 4 возможных направления для полета мячика
    this.support()
    // Рисуем игроков
    this.playerL.draw()
    this.playerR.draw()
    // Рисуем цифры счета, они пока равны 0   
    this.print.drawScore()
    // Функция drawBriefing() рисует инструкцию по управлению  
    this.print.drawBriefing()
    // dropBall() выбирает рандомное направление для мячика 
    this.ball.dropBall()
    // drawBallDirection(4) проверяет какое направление для мяча 
    // выбрано и запускает цикл рисования белой полосочки, 
    // бегающей по кругу
    this.print.drawBallDirection(4)
    // Рисуем цифру 3. Передаем значение в метод класса Print
    this.print.centerText(&amp;#x27;3&amp;#x27;)

    setTimeout(() =&amp;gt; {
      // Отчищаем слой с цифрой 3 и рисуем цифру 2
      // с помощью встроенной в JS функции setTimeout(),
      // делаем задержку выполнений блока {} кода в 0.8 секунд, 
      // или &amp;#x27;800&amp;#x27; милисекунд
      this.print.clear(&amp;#x27;text&amp;#x27;),
      this.print.centerText(&amp;#x27;2&amp;#x27;) }, 800)
    setTimeout(() =&amp;gt; {
      // Каждое следующее действие происходит еще на &amp;#x27;800&amp;#x27; милисекунд
      // позднее предыдущего 
      this.print.clear(&amp;#x27;text&amp;#x27;),
      this.print.centerText(&amp;#x27;1&amp;#x27;) }, 1600)
    setTimeout(() =&amp;gt; {
      // Стираем цифру и пишем &amp;quot;Go&amp;quot;
      this.print.clear(&amp;#x27;text&amp;#x27;),
      this.print.centerText(&amp;#x27;Go&amp;#x27;)}, 2400)
    setTimeout(() =&amp;gt; {
      // На последней функции отчищаем слои и запускаем игру.
      // В функцию start() передаем переменную this.reqId, 
      // значение которой изначально стоит true
      this.print.clear(&amp;#x27;text&amp;#x27;),
      this.print.clear(&amp;#x27;other&amp;#x27;)
      this.start(this.reqId) }, 3200)
    }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;X7ER&quot;&gt;Далее две функции создающие постоянный цикл анимации. Тут используется функция &lt;em&gt;&lt;code&gt;requestAnimationFrame()&lt;/code&gt;&lt;/em&gt;, о ней подробно можно прочитать в &lt;a href=&quot;https://developer.mozilla.org/ru/docs/Web/API/window/requestAnimationFrame&quot; target=&quot;_blank&quot;&gt;документации&lt;/a&gt;, она перерисовывает кадр.&lt;/p&gt;
    &lt;pre id=&quot;1BUA&quot; data-lang=&quot;javascript&quot;&gt;  // Функция запускает анимацию, при условии что переданная
  // переменная равна true  
  start(reqId) {
    if (reqId) {
      // Если reqId = true, то метод requestAnimationFrame()
      // вызвает указанную функцию для обновления данных перед
      // следующим перерисовыванием 
      this.reqId = requestAnimationFrame((t) =&amp;gt; this.timeLoop(t))
    }
  }
  
  timeLoop(t) { 
    // Отчищаем игровой слой, это нужно чтоб игроки и мяч
    // не оставляли за собой след из предыдущих отрисовок
    this.print.clear(&amp;#x27;gamelayer&amp;#x27;)
    // Функции обновления мячика и игроков, они, в свою очередь, 
    // вызывают все нужные функции внутри своих классов
    this.ball.update()
    this.playerL.update()
    this.playerR.update()
    // Вспомогательные функции. Вызвав ее здесь, мы увидим
    // границы желтых зон, от которых зависит направление
    // в котором отбивается мячик от платформы
    this.support()
    // Снова вызываем start() вызывая зацикленность анимации.
    // В качестве значения передаем requestId, он содержит
    // метод requestAnimationFrame() и выдаст true
    this.start(this.reqId)
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;IZb3&quot;&gt;Функция &lt;code&gt;reStart()&lt;/code&gt; отвечает за остановку анимации и перезапуск матча. Ее задачи частично схожи с функцией &lt;code&gt;firstLaunch()&lt;/code&gt;.&lt;/p&gt;
    &lt;p id=&quot;7KNz&quot;&gt;Эта функция срабатывает при забитии гола и в нее передается свойство &lt;code&gt;align&lt;/code&gt; того игрока, который забил мяч.&lt;/p&gt;
    &lt;pre id=&quot;ggc1&quot; data-lang=&quot;javascript&quot;&gt;  reStart(align) {
    // присваиваем reqId значение false, это останавливает анимацию
    this.reqId = false        

    // Делаем задержку в 0.8 секунд, и выполняем следующее:    
    setTimeout(() =&amp;gt; {        
      // Отчищаем игровой слой
      this.print.clear(&amp;#x27;gamelayer&amp;#x27;)
      // Возвращаем игрокам и мячику значения позиций по умолчанию
      this.playerL.defaultSet()            
      this.playerR.defaultSet()            
      this.ball.defaultSet()            
      // Снова рисуем игроков и мячик, уже в стартовых позициях   
      this.playerL.draw()
      this.playerR.draw()
      this.ball.draw()
      // Вспомогательные функции. Вызвав ее здесь, мы увидим
      // 4 возможных направления для полета мячика   
      this.support()            
      // dropBall() выбирает рандомное направление для мячика 
      // Значение align укажет направление броска в забившего
      // предыдущий гол. Рандомость будет заключатся только в 
      // напрвлении вверх или вниз
      this.ball.dropBall(align)            
      // Функция запускает белый бегунок по направлению,
      // определенному выше в dropBall()
      this.print.drawBallDirection()            
    }, 800)
    
    // Следующие действия произойдут уже через 1.6 секунды
    setTimeout(() =&amp;gt; {
      // Отчищаем слой other, это удалит белый бегунок с экрана
      this.print.clear(&amp;#x27;other&amp;#x27;)
      // Снова присваиваем reqId значение true
      // и перезапускаем игровой цикл
      // Эти действия произойдут уже через 1.6 секунды,
      // после предыдущего setTimeout()
      this.reqId = true
      this.start(this.reqId)
    }, 2400)
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;i7uw&quot;&gt;Следующая функция не влияет на работоспособность и нужна исключительно для визуального понимая работы &amp;quot;желтой зоны&amp;quot; и механизма отбития мячика платформами.&lt;/p&gt;
    &lt;p id=&quot;mXgw&quot;&gt;Подробнее о желтой зоне в модуле &lt;em&gt;&lt;a href=&quot;#UcJA&quot;&gt;Player&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
    &lt;pre id=&quot;MlYo&quot; data-lang=&quot;javascript&quot;&gt;  // Функция вызывается в firstLaunch(), timeLoop() и reStart() 
  // и запускает отрисовку всех вспомогательных функций
  support() {
    // Отчищает свой слой канваса
    this.print.clear(&amp;#x27;support&amp;#x27;)
    // Рисует желтые зоны игроков
    this.playerL.support()
    this.playerR.support()
    // Рисует 4 направления для мяча
    this.print.drawAngleZone()
  }
}&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;cV8B&quot;&gt;Функция ниже запускается первой, после загрузки &lt;code&gt;index.html&lt;/code&gt;, создает класс &lt;em&gt;Game&lt;/em&gt; и по факту запускает весь остальной JavaScript код&lt;/p&gt;
    &lt;pre id=&quot;9dYS&quot; data-lang=&quot;javascript&quot;&gt;// Функция создает объект Game после того как все файлы
// будут подгружены браузером
window.onload = () =&amp;gt; {
  const game = new Game()
}&lt;/pre&gt;
  &lt;/section&gt;
  &lt;blockquote id=&quot;QjkC&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#ayxU&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;NZJ7&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;mv2l&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;xQFs&quot; data-align=&quot;center&quot;&gt;ball.js&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;UNRv&quot;&gt;Модуль отвечает за мячик. За рандомность его направления, разворот, отрисовку и т.п.&lt;/p&gt;
    &lt;pre id=&quot;l4q0&quot; data-lang=&quot;javascript&quot;&gt;export default class Ball {
  // При создании в Ball мы передали в него весь класс Game    
  constructor(Game) {  
    // Через game мы будем получать доступ в методу reStart()  
    this.game = Game
    // Передаем переменной set общие настройки
    this.set = Game.set
    // Для удобства, сразу выделим в отдельную переменную ball,
    // настройки мячика которые изменяюся по ходу игры
    this.ball = Game.set.ball
    // Переменная для доступа к модулю Printer
    this.print = Game.print
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;stMN&quot;&gt;Две функции ниже отвечают за рандомность полета мячика. Первая выбирает величину ускорения от 0.8 до 1, а вторая выбирает направления этого ускорения - с минусом или плюсом.&lt;/p&gt;
    &lt;p id=&quot;25Mx&quot;&gt;Мячик двигается путем прибавления значения ускорения к его координатам. Например, чтобы сместить мячик вправо, мы можем прибавить &lt;code&gt;1&lt;/code&gt; к координате &lt;em&gt;&lt;code&gt;x&lt;/code&gt;&lt;/em&gt;, а чтобы сместить его вниз, прибавить &lt;code&gt;1&lt;/code&gt; к координате &lt;code&gt;y&lt;/code&gt; (ось координат начинается в верхнем левом углу). Но таким образом, мячик будет лететь строго под 45°.&lt;/p&gt;
    &lt;p id=&quot;GTgf&quot;&gt;Чтоб этого не происходило есть функция &lt;code&gt;getRandom()&lt;/code&gt;, она возвращает рандомное число в промежутке от 0.8 до 1. Получается, что мы прибавляем к координатам &lt;code&gt;x&lt;/code&gt; и &lt;code&gt;y&lt;/code&gt; разные значения и мячик никогда НЕ двигается строго под 45°. Этого практически не заметно, но такое поведение не дает мячику зацикливаться в одной траектории и делает игру более разнообразной.&lt;/p&gt;
    &lt;p id=&quot;dH3K&quot;&gt;Функция &lt;code&gt;getRandomDirection()&lt;/code&gt; в случайном порядке присваивает отрицательное или положительное значение результату &lt;code&gt;getRandom()&lt;/code&gt;. &lt;/p&gt;
    &lt;pre id=&quot;hyx0&quot; data-lang=&quot;javascript&quot;&gt;  getRandom() {
    // Метод Math.random() генерирует случайное положительное        
    // значение в диапазоне от 0 до &amp;lt;1,       
    // а формула Math.random() * (max - min) + min позволяет
    // получить рандомное число в нужном диапазоне от min до max  
    return Math.random() * (1 - 0.8) + 0.8        
  }
  
  getRandomDirection() {  
    // Math.random() генерирует случайное значение        
    // Math.round() округляет это значение до целого 0 или 1
    // Boolean() возвращает 0 как false, а 1 как true          
    if (Boolean(Math.round(Math.random()))) {        
      // Если Boolean() вернул true, возвращаем случайное число   
      // в нужном нам диапазоне функцией getRandom()        
      return this.getRandom()            
    // Если Boolean() вернул false, то возвращаем тоже самое,   
    // но со знаком &amp;quot;минус&amp;quot;
    } else { return -this.getRandom() }
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;aUkO&quot;&gt;Следующие две функции отвечает за движение мячика.&lt;/p&gt;
    &lt;p id=&quot;LtVk&quot;&gt;Так, функция &lt;code&gt;dropBall()&lt;/code&gt; выбирает изначальное направление для полета мячика. Чтоб он мог полететь из центра в любой из 4 углов поля.&lt;/p&gt;
    &lt;p id=&quot;H7nT&quot;&gt;Используя описанные выше функции, она генерирует рандомные значения и присваивает их переменным &lt;code&gt;dx&lt;/code&gt; и &lt;code&gt;dy&lt;/code&gt;, это значения ускорения для каждой из координат мячика.&lt;/p&gt;
    &lt;p id=&quot;JJzJ&quot;&gt;А функция &lt;code&gt;move()&lt;/code&gt; присваевает получившиеся значения &lt;code&gt;dx&lt;/code&gt; и &lt;code&gt;dy&lt;/code&gt; реальным координатам мячика. Ее мы будем вызывать на каждом кадре.&lt;/p&gt;
    &lt;pre id=&quot;hyx0&quot; data-lang=&quot;javascript&quot;&gt;  // Функция принимаем значение align от игрока,
  // это дает нам понять какой игрок забил гол в прошлом матче
  dropBall(player) {        
    // С помощью getRandomDirection() мы генерируем        
    // рандомное ускорение с рандомным знаком + или -  
    this.ball.dx = this.getRandomDirection()  
    this.ball.dy = this.getRandomDirection()           
    // Так как мы не знаем какое значение нагенерировано,        
    // приминяем следующее:            
    switch (player) {
      // Если значение left, то подает левый игрок,
      // значит мячик должен лететь вправо.             
      case &amp;#x27;left&amp;#x27;:
        // Чтоб исключить возможность полета влево  
        // Используем метод Math.abs(), который возвращает
        // положительно значение.
        // Присваеваем dx точно положительное значение dx
        this.ball.dx = Math.abs(this.ball.dx)
        break  
      // Для полета влево мы также применяем Math.abs(),  
      // но после превращения значения в положительное,       
      // делаем его отрицательным с помощью - 
      case &amp;#x27;right&amp;#x27;:                
        this.ball.dx = -Math.abs(this.ball.dx)
        break        
    }        
    // Если значение player не было передано, т.е оно undefined, 
    // то ничего не меняется и все значения останутся
    // полностью случайны, такое случается на первом старте игры
  }
  
  // Двигает мяч в пространсте прибавляя сгенерированные ранее
  // значения к его координатам, умножая на коэффециент скорости
  // который мы задали в настройках мячика как speed
  move() {
    // Оператор += сначала складывает исходное значение (это х)
    // и расчетное значение (результат умножения),
    // а потом присваивает полученное значение переменной х
    this.ball.x += (this.ball.dx * this.ball.speed)
    this.ball.y += (this.ball.dy * this.ball.speed)
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;kCLl&quot;&gt;Функция &lt;code&gt;checkCollisionWithWalls()&lt;/code&gt; отвечает за просчет столкновений мячика со стенками игрового поля и, в случае столкновения мяча со стенкой за игроком, вызывает функцию &lt;code&gt;goalProcess()&lt;/code&gt;.&lt;/p&gt;
    &lt;p id=&quot;uW7D&quot;&gt;Ось координат в JavaScript начинается с верхнего левого угла, что показано на рисунке ниже. Следовательно верхняя и левая стенки будут иметь координаты 0, а правая и нижняя равны длине и ширине поля.&lt;/p&gt;
    &lt;figure id=&quot;GZG4&quot; class=&quot;m_original&quot;&gt;
      &lt;img src=&quot;https://img2.teletype.in/files/13/bd/13bd6e5b-33c8-4c58-8834-56952d23f6fe.png&quot; width=&quot;1320&quot; /&gt;
    &lt;/figure&gt;
    &lt;pre id=&quot;nxIU&quot; data-lang=&quot;javascript&quot;&gt;  checkCollisionWithWalls() {  
    // В данном случае ballX и ballY это координаты мяча в будующем,
    // которые будут на следующем кадре, но без учета скорости
    let ballX = (this.ball.x + this.ball.dx)   
    let ballY = (this.ball.y + this.ball.dy)    
    // Координата Х правой стены (ширина поля) минус размер 
    // радиуса мяча, чтоб при столкновении мяч не утопал в стену
    const rightWall = (this.set.boxWidth - this.set.ballRadius)
    // Координата Х левой стены (это 0) плюс размер радиуса мяча.
    // Просто отступ от края размером с половинку мячика   
    const leftWall = this.set.ballRadius
    // Координата Y верхней стены (также 0),
    // Просто берем радиус мячика    
    const TopWall = this.set.ballRadius    
    // Координата Y нижней стены (высота поля) минус радиус
    const BottomWall = (this.set.boxHeight - this.set.ballRadius)
    
      // Если координаты мячика стали больше координат правой стены,
      // то:
      if (ballX &amp;gt;= rightWall) {        
        // Меняем направление по оси Х с помощью функции reverseBall()
        this.ball.dx = this.reverseBall(this.ball.dx)
        // Вызываем функцию goalProcess() которая завершает матч
        this.goalProcess(this.set.playerL)
        }
      // Если координаты мячика стали меньше координат левой стены,
      // то:          
      if (ballX &amp;lt;= leftWall) {        
        this.ball.dx = this.reverseBall(this.ball.dx)
        this.goalProcess(this.set.playerR)
      }
      // Если мячик коснулся верхней или нижней стенки, то:  
      if (ballY &amp;gt;= BottomWall || ballY &amp;lt;= TopWall) {        
        // Разворачиваем мяч по оси Y  
        this.ball.dy = this.reverseBall(this.ball.dy)
      }
    }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;gkLe&quot;&gt;Как следует из названия, функция &lt;code&gt;reverseBall() &lt;/code&gt;разворачивает мячик по одной из оси координат. меняя значение его ускорения с отрицательного на положительное и наоборот.&lt;/p&gt;
    &lt;pre id=&quot;UTTR&quot; data-lang=&quot;javascript&quot;&gt;  // В функцию передается значение ускорения dx или dy
  reverseBall(dir) {
    // Если значение ускорения положительное, то
    if (dir &amp;gt; 0) {
      // Возвращаем новое рандомное значение для ускорения
      // со знаком минус, т.е. отрицательное
      return -this.getRandom()
    // Если значение ускорения отрицательное, то
    } else {
      // Также возвращаем новое рандомное значение,
      // но уже положительное
      return this.getRandom()
    }
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;0cwT&quot;&gt;Функция &lt;code&gt;goalProcess()&lt;/code&gt; запускает процесс завершения матча после гола. Аргументом в нее передаются настройки игрока, который забил мяч.&lt;/p&gt;
    &lt;pre id=&quot;uQi0&quot; data-lang=&quot;javascript&quot;&gt;  // Запускает процесс завершения матча после гола.
  // Сюда передается align игрока, который забил мяч
  goalProcess(winner) {
    winner.score++
    // Прибавляем к счету забившего +1 очко,
    // отчищаем старый счет со слоя &amp;#x27;score&amp;#x27; и рисуем новый счет
    this.print.clear(&amp;#x27;score&amp;#x27;)
    this.print.drawScore()
    // Отчищаем слой &amp;#x27;text&amp;#x27;, чтоб удалить с центра поля
    // счетчик количества отбитий мяча в матче
    this.print.clear(&amp;#x27;text&amp;#x27;)
    // Обнуляем счетчик отбитий, чтоб в следующем матче
    // он пошел с нуля
    this.set.ballHitScore = 0
    // Вызываем функцию рисования Гола, она просто пишет
    // в центре надпись &amp;quot;Goal!&amp;quot; и рисует &amp;quot;+1&amp;quot; на поле соперника
    this.print.drawGoal(winner.goalPointX, winner.color, winner.align)
    // Вызываем метод reStart() класса Game, он остановит анимацию,
    // обнулит положение всех элементов и нарисует их заного
    this.game.reStart(winner.align)
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;Y0tJ&quot;&gt;Для большего интереса, я создал функцию, которая увеличивает скорость мячика на &lt;code&gt;0.1&lt;/code&gt; каждый раз, когда он отражается от платформы игрока.&lt;/p&gt;
    &lt;p id=&quot;D8WY&quot;&gt;Она также прибавляет &lt;code&gt;1&lt;/code&gt; к счетчику ударов мяча о платформу, так мы видим сколько раз игрокам удалось отбить мяч.&lt;/p&gt;
    &lt;pre id=&quot;7UZv&quot; data-lang=&quot;javascript&quot;&gt;  // Увеличивает скорость мяча на 0.1    
  // и прибавляет 1 к счетчику ударов мяча о платформу.    
  // Отчищает слой &amp;#x27;text&amp;#x27; и рисует заного  
  speedМagnifier() {  
    // Оператор += сначало прибавляет 0.1,        
    //а потом присваивает полученное значение    
    this.ball.speed += 0.1        
    // Оператор ++ прибавляет 1 к значению счетчика ударов
    this.set.ballHitScore++        
    // Отчищает слой &amp;#x27;text&amp;#x27; и рисует новое значение счетчика
    // на игровом поле
    this.print.clear(&amp;#x27;text&amp;#x27;)
    this.print.drawBallHit()
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;nZCa&quot;&gt;Далее идут довольно простые функции. &lt;/p&gt;
    &lt;p id=&quot;vH7u&quot;&gt;&lt;code&gt;defaultSet()&lt;/code&gt; возвращает настройки мячика к дефолтным значениям, это требуется для перезапуска партии при забитии гола.&lt;/p&gt;
    &lt;p id=&quot;1w65&quot;&gt;&lt;code&gt;draw()&lt;/code&gt; просто вызывает функцию рисования мяча. Можно было обойтись без нее, вызывая рисование мяча напрямую из класса &lt;em&gt;Printer&lt;/em&gt; везде где это необходимо, но так мне мой код нравится больше.&lt;/p&gt;
    &lt;p id=&quot;rsSZ&quot;&gt;&lt;code&gt;update()&lt;/code&gt; вызывает все функции, которые необходимо пересчитывать для отрисовки кадров, она вызывается в цикле анимации из класса &lt;em&gt;&lt;a href=&quot;#dvEw&quot;&gt;Game&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
    &lt;pre id=&quot;cX2x&quot; data-lang=&quot;javascript&quot;&gt;  defaultSet() {
    // Ставит мячик на центр поля обнуляя координаты
    this.ball.x = this.set.ballXDefault
    this.ball.y = this.set.ballYDefault
    // Возвращает исходную скорость
    this.ball.speed = this.set.ballSpeed
  }
  
  // Функция отправляет запрос на отрисовку мячика.
  // Создана для удобства
  draw() {
    this.print.drawBall()    
  }
  
  // Функция вызывает функции проверки столкновений,
  // движения мячика и отрисовки. Создана для удобства,
  // вызывается из метода timeLoop() в классе Game
  update() {
    this.checkCollisionWithWalls()
    this.move()
    this.draw()
  }
}&lt;/pre&gt;
  &lt;/section&gt;
  &lt;blockquote id=&quot;VlNJ&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#ayxU&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;YQrM&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;MATx&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;UcJA&quot; data-align=&quot;center&quot;&gt;player.js&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;nZZN&quot;&gt;Модуль отвечает за платформу игрока, ее положение и взаимодействие с мячиком. Класса &lt;em&gt;Player&lt;/em&gt; создается два, и в каждый передаются свойства разных игроков, это делается в классе &lt;em&gt;&lt;a href=&quot;#dvEw&quot;&gt;Game&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
    &lt;p id=&quot;9efO&quot;&gt;Для начала рассмотрим конструктор класса &lt;em&gt;Player:&lt;/em&gt;&lt;/p&gt;
    &lt;pre id=&quot;wLBh&quot; data-lang=&quot;javascript&quot;&gt;export default class Player {
  // В Player мы передали весь класс Game и отдельно свойства игрока
  constructor(Game, playerSet) {
    // Передаем переменной set общие настройки     
    this.set = Game.set
    // Для удобства, выделим в отдельную переменную ball
    // все изменяемые настройки мячика, а через classBall,
    // мы будем получать доступ к классу Ball и его методам
    this.ball = Game.set.ball
    this.classBall = Game.ball
    // Для доступа к модулю Printer
    this.print = Game.print
    // Переменной player присваиваем свойсва игрока переданные
    // в класс Player, уникальные для каждого экземпляра Player
    this.player = playerSet
    // Создаем новый Map (это коллекция ключ/значение) из keys.
    // В данном случаем ключ - это номер клавиши, 
    // а значение - это строка с направлением движения
    // Пример =&amp;gt; keys: [[87,&amp;#x27;up&amp;#x27;], [83,&amp;#x27;down&amp;#x27;]], 
    this.keyMap = new Map(playerSet.keys)
    // Создаем два слушателя событий. В них передаем событие
    // (нажатие или отжатие клавиши) и слушателя
    document.addEventListener(&amp;#x27;keydown&amp;#x27;,
                             (e) =&amp;gt; this.keyController(e, true))
    document.addEventListener(&amp;#x27;keyup&amp;#x27;,
                             (e) =&amp;gt; this.keyController(e, false))
    // Две переменные, которые нужны для виртуального
    // расширения платформ во время движения, чтоб был шанс
    // отбить мяч &amp;quot;в последний момент&amp;quot; ╰(*°▽°*)╯
    // то как это работает, покажет функция support()
    this.shadowUp = 0
    this.shadowDown = 0
    // Переменная служит индикатором нахождения мяча в желтой зоне.
    // Это зона перед платформой.
    // Желтую зону также покажет функция support()
    this.yellowZone = true
    // Переменная служит для запрета разворота мячика, чтоб он
    // не мог менять направления чаще чем каждые полсекунды
    // используется в функции checkCollisionWithBall()
    this.ballReversStatus = true
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;m1Sr&quot;&gt;Функции ниже занимаются движением игроков. &lt;code&gt;keyController()&lt;/code&gt; отрабатывает нажатия с клавиатуры, а &lt;code&gt;move()&lt;/code&gt; выполняет движения в зависимости от нажатых клавиш.&lt;/p&gt;
    &lt;p id=&quot;zuom&quot;&gt;Нужно помнить, что ось координат в JavaScript начинается с верхнего левого угла, как показано на рисунке ниже. Следовательно верхняя и левая стенки будут иметь координаты 0, а правая и нижняя равны длине и ширине поля.&lt;/p&gt;
    &lt;figure id=&quot;RYdz&quot; class=&quot;m_original&quot;&gt;
      &lt;img src=&quot;https://img4.teletype.in/files/3a/c5/3ac596b2-c2e6-4035-91f2-2b9e11f349de.png&quot; width=&quot;1320&quot; /&gt;
    &lt;/figure&gt;
    &lt;pre id=&quot;oeh1&quot; data-lang=&quot;javascript&quot;&gt;  keyController(e, state) {
    // Метод has() показывает существует ли элемент
    // с указанным значением в объекте
    // И если нажата клавиша, которая есть в keyMap,
    // то он выдает true
    if(this.keyMap.has(e.keyCode)) {
      // get() возвращает связанный с ключем элемент, он
      // вернет &amp;#x27;up&amp;#x27; или &amp;#x27;down&amp;#x27; в зависимости от нажатой клавиши.
      // Создаем переменную с именем результата метода get()
      // и присваиваем ей статус true или false
      this[this.keyMap.get(e.keyCode)] = state
    }
  }
  
  // Двигает платформу игрока, прибавляя 1 к его координатам,
  // умножая на коэффециент скорости
  move() {
    // Переменные созданы только для уменьшения ширины кода,
    // чтоб он влез в статью без горизонтальной прокрутки¯\_(ツ)_/¯
    const plHeight = this.set.playerHeight
    const plSpeed = this.set.playerSpeed
    const plBorder = this.set.playerBorder
    const boxHeight = this.set.boxHeight
    
    // Если this.up = true, т.е. клавиша &amp;#x27;вверх&amp;#x27; нажата, то
    if (this.up) {
      // Бордер это растояние от задней стены, до центра игрока.
      // На такое же растояние платформы &amp;#x27;недоезжают&amp;#x27; до краев поля.
      // Если растояние от Y игрока (это верхний край платформы)
      // больше чем бордер, то
      if (this.player.y &amp;gt; plBorder) {
        // Мы уменьшаем текущую координату Y на скорость 
        // платформы игрока из настроек (по умолчанию это 10).
        // Т.е. двигаем игрока вверх на 10 пикселей
        this.player.y -= plSpeed
      // Если платформа достигла ограничения или перескочила его
      // (это возможно т.к. платформы движуться по 8 пикселей), то  
      } else {
        // Мы возвращаем платформу в последнее возможное положение,
        // на растояние бордера от края поля
        this.player.y = plBorder  
      }
      // Если this.up = true, т.е. клавиша &amp;#x27;вверх&amp;#x27; нажата, то
      // присваиваем переменной shadowUp двойное значение скорости
      // это 16 пикселей
      this.shadowUp = (plSpeed * 2)
    }
    // Если this.down = true, т.е. клавиша &amp;#x27;вниз&amp;#x27; нажата, то
    else if (this.down) {
      // Т.к. игрок это верхняя точка платформы, надо прибавить
      // длину игрока, для получения координаты нижней его точки
      if ((this.player.y + plHeight + plBorder) &amp;lt; boxHeight) {
        // Мы увеличиваем текущую координату Y на скорость 
        // платформы игрока из настроек (по умолчанию это 10).
        // Т.е. двигаем игрока вниз на 10 пикселей
        this.player.y += plSpeed
      } else {
        // Возвращаем платформу в последнее возможное положение,
        // на растояние бордера от нижнего края поля
        this.player.y = (boxHeight - plHeight - plBorder)
      }
      // Если this.down = true, т.е. клавиша &amp;#x27;вниз&amp;#x27; нажата, то
      // присваиваем переменной shadowDown двойное значение скорости
      // это 16 пикселей
      this.shadowDown = (plSpeed * 2)
    // Если клавиши не нажаты, возвращаем нашу &amp;quot;тень&amp;quot; в ноль  
    } else {
      this.shadowUp = 0
      this.shadowDown = 0
    }
  }&lt;/pre&gt;
    &lt;figure id=&quot;vOUp&quot; class=&quot;m_original&quot;&gt;
      &lt;img src=&quot;https://img1.teletype.in/files/cb/a5/cba5386d-6a72-41db-886d-7ecae24d6434.png&quot; width=&quot;1320&quot; /&gt;
    &lt;/figure&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;LxE8&quot;&gt;функция &lt;code&gt;checkYellowZone()&lt;/code&gt; проверяет находится ли мячик в желтой зоне перед игроком и присваивает переменной &lt;code&gt;yellowZone&lt;/code&gt; значения &lt;code&gt;true&lt;/code&gt; или &lt;code&gt;false&lt;/code&gt; в зависимости от результата проверки. &lt;/p&gt;
    &lt;p id=&quot;uiMf&quot;&gt;Если мячик был отбит платформой находясь в желтой зоне, значит он был отбит плоскостью платформы. А если он задел платформу, но не был в желтой зоне, то значит это было ребро платформы.&lt;/p&gt;
    &lt;pre id=&quot;vlmw&quot; data-lang=&quot;javascript&quot;&gt;  checkYellowZone() {
    // Длина игрока, растояние от его верхней до нижней точки  
    const plHeight = this.set.playerHeight
    
    // Если Y мячика больше (мячик ниже) верхней точки игрока
    // и Y мячика меньше (мячик выше) нижней точки игрока
    if (this.ball.y &amp;gt; (this.player.y - this.shadowUp)
    &amp;amp;&amp;amp; this.ball.y &amp;lt; (this.player.y + plHeight + this.shadowDown)) {
      // Значит мячик находится перед игроком, в желтой зоне
      this.yellowZone = true
    // Если нет, то не в желтой ¯\_(ツ)_/¯  
    } else {
      this.yellowZone = false
    }
  }  &lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;49aq&quot;&gt;Функция &lt;code&gt;checkCollisionWithBall()&lt;/code&gt; отвечает за столкновение мяча с платформой. Она вычисляет разницу между координатами &lt;code&gt;x&lt;/code&gt; и &lt;code&gt;y&lt;/code&gt; объектов, а затем вычисляет их фактическое расстояние &lt;code&gt;d&lt;/code&gt;. И если сумма радиусов объектов меньше, чем расстояние между ними, значит имело место столкновение этих объектов и можно производить нужные нам действия, с помощью функции &lt;code&gt;hitBall()&lt;/code&gt;.&lt;/p&gt;
    &lt;p id=&quot;1zzk&quot;&gt;Формулу расчета столкновений я взял из &lt;a href=&quot;https://habr.com/ru/post/487962/?ysclid=l9qra0gr6r515789840&quot; target=&quot;_blank&quot;&gt;этой&lt;/a&gt; статьи на хабре.&lt;/p&gt;
    &lt;figure id=&quot;kGNA&quot; class=&quot;m_original&quot;&gt;
      &lt;img src=&quot;https://img2.teletype.in/files/9f/f5/9ff5e2bb-a63a-461d-b1d9-ecae32a51f20.png&quot; width=&quot;1320&quot; /&gt;
    &lt;/figure&gt;
    &lt;pre id=&quot;KLX7&quot; data-lang=&quot;javascript&quot;&gt;  checkCollisionWithBall() {
    // Длина игрока, растояние от его верхней до нижней точки
    const plHeight = this.set.playerHeight
    // Вычисляем разницу между координатами X мячика и Y игрока
    let dx = this.ball.x - this.player.x
    // Разница между Y мячика и Y игрока (верхним краем игрока),
    // также учитываем тень, если она есть
    let dy = this.ball.y - (this.player.y - this.shadowUp)
    // Разница координаты Y мячика и нижнего края игрока,
    // с учетом его тени, если она есть
    let dyF =this.ball.y -(this.player.y + plHeight + this.shadowDown)
    // Сумма радиусов мячика и платформы
    let radSum = this.set.ballRadius + this.set.playerRadius
    // Растояние от центра мячика, до края платформы.
    // Math.sqrt() вычисляет квадратный корень, а
    // Math.pow() возводит значение dx в степень 2 (в квадрат)
    let dY = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2))
    // Растояние от центра мячика, до нижнего края платформы
    let dYF = Math.sqrt(Math.pow(dx, 2) + Math.pow(dyF, 2))
    // Убрал из расчета кординату Y, чтобы видеть столкновение
    // координат Х независимо от положения мячика по Y.
    // Это надо для расчета удара о плоскость платформы
    let dX = Math.sqrt(Math.pow(dx, 2))
    
    // Если растояние между центрами объектов меньше суммы их
    // радиусов (в данном случае это Х мячика и Х платформы), то
    if (dX &amp;lt;= radSum) {
      // Если мячик находится в желтой зоне
      // и он не менял направление последние полсекунды, то
      if (this.yellowZone &amp;amp;&amp;amp; this.ballReversStatus) {
        // Вызываем функцию hitBall() для разворота мяча
        // и передаем в нее только значение dx, т.к в желой зоне
        // мячик отбивается от плоскости платформы только по оси Х
        this.hitBall(this.ball.dx)
      }
    }
    // Если ускорение мячика положительное, т.е. мячик летит вниз, то
    if (this.ball.dy &amp;gt; 0) {
      // Если есть столкновение с верхним краем платформы, то
      if (dY &amp;lt;= radSum) {
        // Если мячик не в желтой зоне, то
        if (!this.yellowZone) {
          // Вызываем функцию hitBall() для разворота мяча по обои
          // осям, мячик развернутся на 180°
          this.hitBall(this.ball.dx, this.ball.dy)
        }
      }
    }
    // Если ускорение мячика отрицательное, т.е. мячик летит вверх, то
    if (this.ball.dy &amp;lt; 0) {
      // Если есть столкновение с нижним краем платформы, то
      if (dYF &amp;lt;= radSum) {
        // Если мячик не в желтой зоне, то
        if (!this.yellowZone) {
          // Вызываем функцию hitBall() для разворота мяча по обои
          // осям, мячик также развернутся на 180°
          this.hitBall(this.ball.dx, this.ball.dy)
        }
      }
    }
  }
  
  // Аргументом мы передаем только dx или dx и dy мячика
  hitBall(dx, dy) {
    // Разворачиваем мячик по оси Х с помощью метода reverseBall().
    // Он всегда разворачивается по оси Х при ударе о платформу
    this.ball.dx = this.classBall.reverseBall(dx)
    
    // Если мы передали в функцию значение dy, то
    if (dy) {
      // Разворачиваем мячик по оси Y. Это удар о ребро платформы
      this.ball.dy = this.classBall.reverseBall(dy)
    }
    // Т.к. мячик отбит платформой, запускаем функцию,
    // которая увеличит его скорость
    this.classBall.speedМagnifier()
    // Запрещаем мячику разворачиваться
    this.ballReversStatus = false
    // А через 500 милисекунд разрешаем мячику разворачиваться.
    // Такое поведение нужно, чтоб он не мог застрять в платформе
    // постоянно разворачиваясь
    setTimeout(() =&amp;gt; {
      this.ballReversStatus = true
    }, 500)
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;puAa&quot;&gt;Далее идут довольно простые функции. &lt;/p&gt;
    &lt;p id=&quot;ETY9&quot;&gt;&lt;code&gt;defaultSet()&lt;/code&gt; возвращает положение игрока к дефолтному значению, это требуется для перезапуска партии при забитии гола.&lt;/p&gt;
    &lt;p id=&quot;G6r4&quot;&gt;&lt;code&gt;draw()&lt;/code&gt; просто вызывает функцию рисования игрока. Можно было обойтись без нее, вызывая рисование напрямую из класса &lt;em&gt;Printer&lt;/em&gt; везде где это необходимо, но так мне мой код нравится больше.&lt;/p&gt;
    &lt;p id=&quot;2xD6&quot;&gt;&lt;code&gt;update()&lt;/code&gt; вызывает все функции, которые необходимо пересчитывать для отрисовки кадров, она вызывается в цикле анимации из класса &lt;em&gt;&lt;a href=&quot;#dvEw&quot;&gt;Game&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
    &lt;pre id=&quot;xOkb&quot; data-lang=&quot;javascript&quot;&gt;  // Функция обнуляет положение игрока,
  // так как X в процессе игры не меняется, а вторая координата Y
  // вычисляется из первой, достаточно обнулить только Y
  defaultSet() {
    this.player.y = this.set.playerYDefault
  }
  
  draw() {
    // Кордината верхней точки игрока
    let x = this.player.x
    let yStart = this.player.y
    // Кордината нижней точки игрока
    let yFinish = (this.player.y + this.set.playerHeight)
    // Цвет и толщина игрока (2 радиуса)
    const plColor = this.player.color
    const plWidth = (this.set.playerRadius * 2)
    
    // Т.к. игрок это векторная линия с закругленными краями,
    // передаем в принтер кординаты верхней и нижней точки,
    // толщину линии (2 радиуса) и цвет
    this.print.drawPlayer(x, yStart, yFinish, plWidth, plColor)
  }
  
  // Функция вызывает функции проверки желтой зоны, столкновений,
  // движения игрока и отрисовки. Создана для удобства.
  // Вызывается из метода timeLoop() в классе Game
  update() {
    this.checkYellowZone()
    this.checkCollisionWithBall()
    this.move()
    this.draw()
  }&lt;/pre&gt;
    &lt;hr /&gt;
    &lt;p id=&quot;z8oP&quot;&gt;Функция &lt;code&gt;support()&lt;/code&gt; занимается визуальной отрисовкой желтой зоны для проверки ее работы. Вызывается из класса &lt;em&gt;&lt;a href=&quot;#dvEw&quot;&gt;Game&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
    &lt;pre id=&quot;P41a&quot; data-lang=&quot;javascript&quot;&gt;  support() {
    const plHeight = this.set.playerHeight
    let x = this.player.x        
    let yS = this.player.y - this.shadowUp
    let yF = this.player.y + this.set.playerHeight + this.shadowDown
    
    this.print.drawShadowPlayer(x, yS, yF)
    if (this.yellowZone) {
      this.print.drawYellowZone(x, yS, yF)
    }
  }
}&lt;/pre&gt;
  &lt;/section&gt;
  &lt;blockquote id=&quot;rvz1&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#ayxU&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;65pf&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;9gu7&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;tW70&quot; data-align=&quot;center&quot;&gt;index.html&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;EneV&quot;&gt;В теге &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; прописан &lt;code&gt;id=&amp;quot;game&amp;quot;&lt;/code&gt; для создания канваса. Хотя можно было попробовать обойтись без него и посылать &lt;em&gt;canvas&lt;/em&gt; прямо на тег &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;. Внутри тега находиться только скрипт.&lt;/p&gt;
    &lt;pre id=&quot;rGAj&quot; data-lang=&quot;html&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;
&amp;lt;head&amp;gt;    
  &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;    
  &amp;lt;title&amp;gt;Pong by Buninman.ru&amp;lt;/title&amp;gt;    
  &amp;lt;meta name=&amp;quot;description&amp;quot; content=&amp;quot;Created by Buninman.ru&amp;quot;&amp;gt;    
  &amp;lt;meta property=&amp;quot;og:title&amp;quot; content=&amp;quot;The best Pong game&amp;quot;&amp;gt;    
  &amp;lt;meta property=&amp;quot;og:image&amp;quot; content=&amp;quot;img/pongOG.png&amp;quot;&amp;gt;    
  &amp;lt;meta property=&amp;quot;og:description&amp;quot; content=&amp;quot;Created by Buninman.ru&amp;quot;&amp;gt;  
    &amp;lt;meta http-equiv=&amp;quot;expires&amp;quot; content=&amp;quot;0&amp;quot;&amp;gt;    
  &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;pong/style.css&amp;quot;&amp;gt;    
  &amp;lt;link rel=&amp;quot;apple-touch-icon&amp;quot; sizes=&amp;quot;180x180&amp;quot; href=&amp;quot;img/icon.png&amp;quot;&amp;gt; 
  &amp;lt;link rel=&amp;quot;icon&amp;quot; type=&amp;quot;image/png&amp;quot; sizes=&amp;quot;32x32&amp;quot; href=&amp;quot;img/fv32.png&amp;quot;&amp;gt;
  &amp;lt;link rel=&amp;quot;icon&amp;quot; type=&amp;quot;image/png&amp;quot; sizes=&amp;quot;16x16&amp;quot; href=&amp;quot;img/fv16.png&amp;quot;&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body id=&amp;quot;game&amp;quot;&amp;gt;    
  &amp;lt;script src=&amp;quot;pong/game.js&amp;quot; type=&amp;quot;module&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;

&amp;lt;/html&amp;gt;&lt;/pre&gt;
  &lt;/section&gt;
  &lt;blockquote id=&quot;Yt4F&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#ayxU&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;aQH0&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;Mm8f&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;jDR0&quot; data-align=&quot;center&quot;&gt;style.css&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;0IAF&quot;&gt;В css минимальный набор стилей. Мы делаем весь &amp;lt;body&amp;gt; одним большим флекс-боксом во весь экран.&lt;/p&gt;
    &lt;pre id=&quot;qbE5&quot; data-lang=&quot;css&quot;&gt;body {
  margin: 0px;    
  height: 100vh;    
  width: 100vw;    
  display: flex;    
  justify-content: center;    
  align-items: center;    
  background-color: #232323;    
}

#game canvas {  
  display: block;    
  position: absolute;
}&lt;/pre&gt;
  &lt;/section&gt;
  &lt;blockquote id=&quot;4UtZ&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#ayxU&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;

</content></entry><entry><id>buninman:ligatures</id><link rel="alternate" type="text/html" href="https://blog.buninman.ru/ligatures?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=buninman"></link><title>Лигатуры для программистов</title><published>2022-09-30T09:14:12.554Z</published><updated>2022-12-03T05:47:27.099Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/cc/4e/cc4ee551-c962-4db5-9d59-cb24c4caf7b3.png"></media:thumbnail><category term="other" label="Разное"></category><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/09/4a/094a20cb-f518-4a80-becf-f555afd9b291.png&quot;&gt;Есть на свете шрифт, до краев наполненный разными причудами, которые могут прийтись по вкусу маленьким программистам😃</summary><content type="html">
  &lt;blockquote id=&quot;eBlw&quot;&gt;Есть на свете шрифт, до краев наполненный разными причудами, которые могут прийтись по вкусу маленьким программистам😃&lt;/blockquote&gt;
  &lt;p id=&quot;U6Dh&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;eKyL&quot;&gt;Лигатурой можно назвать любой знак образованный путём соединения двух и более графем, например, вот:&lt;/p&gt;
  &lt;figure id=&quot;z0aM&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/09/4a/094a20cb-f518-4a80-becf-f555afd9b291.png&quot; width=&quot;1000&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;NQcj&quot;&gt;Соединяя знаки, мы получаем лигатуры. Они часто использовались в древности, для ускорения письма, в книгопечатании и тп. Сейчас лигатуры почти не встречаются, за исключением некоторых шрифтов, в которых буковки как бы слипаются😏&lt;/p&gt;
  &lt;p id=&quot;Idyd&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;ayge&quot;&gt;Причем тут программисты?&lt;/h3&gt;
  &lt;p id=&quot;95rM&quot;&gt;Во всех языках программирования используются разные символы, многие из которых состоят из двух или нескольких знаков. Для лучшей читаемости, умные мужи, придумали эти знаки превращать в лигатуры, которые занимают такое же количество знаков на экране, но обладают лучше читаемостью.&lt;/p&gt;
  &lt;p id=&quot;tIgO&quot;&gt;Например, знак &amp;quot;меньше или равно&amp;quot; &amp;lt;= выглядит совсем не так, как мы писали его в школе, а знак &amp;quot;не равно&amp;quot; !==, вообще не понятен обывателю. Но использование лигатур способно это исправить.&lt;/p&gt;
  &lt;p id=&quot;mshR&quot;&gt;&lt;code&gt;Fira Code&lt;/code&gt; - это бесплатный шрифт, созданный специально для написания кода. Он содержит целую кучу разных лигатур и, вышеупомянутый, знак &amp;quot;меньше или равно&amp;quot; выглядит в нем так &lt;code&gt;&amp;lt;=&lt;/code&gt;, а вот &lt;code&gt;!==&lt;/code&gt;&amp;quot;не равно&amp;quot;, круто?🙂&lt;/p&gt;
  &lt;p id=&quot;hL5i&quot;&gt;На картинке ниже можно посмотреть некоторые примеры лигатур и то, как они преображают код. Также, тут можно заметить, что длина строк никак не меняется, знаки занимают ровно такое же количество символов, как и раньше:&lt;/p&gt;
  &lt;figure id=&quot;vJAs&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c9/70/c970df03-3b13-4cca-a571-d7e22d34a9f8.png&quot; width=&quot;1000&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;z9uO&quot;&gt;К сожалению, большинство даже не знает о существовании таких лигатур. Я и сам узнал о них только потому, что Teletype принудительно использует &lt;code&gt;Fira Code&lt;/code&gt; во всех вставках блоков кода. Чтобы в редакторе и в моих конспектах все было одинаково, я нашел способ установить сей шрифт в Visual Studio Code.&lt;/p&gt;
  &lt;p id=&quot;zRVe&quot;&gt;Сперва было не привычно, но сейчас я привык и не собираюсь отказывать от такой фишки, мне нравится как выглядит код с лигатурами. При этом проблем с чтением чужого кода без лигатур у меня нет. Поэтому могу смело рекомендовать всем, хотя бы, в качестве эксперимента.&lt;/p&gt;
  &lt;p id=&quot;ovf1&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;p6cl&quot;&gt;Как установить?&lt;/h3&gt;
  &lt;p id=&quot;z04e&quot;&gt;Сам шрифт можно свободно &lt;a href=&quot;https://fonts.google.com/specimen/Fira+Code&quot; target=&quot;_blank&quot;&gt;скачать на Google Fonts&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;hQSh&quot;&gt;Зачем, в настройках Visual Studio Code выбираем:&lt;/p&gt;
  &lt;pre id=&quot;N0ZF&quot;&gt;File &amp;gt;==&amp;gt; Preferences &amp;gt;==&amp;gt; Settings &amp;gt;==&amp;gt; Text Editor &amp;gt;==&amp;gt; Font&lt;/pre&gt;
  &lt;p id=&quot;vBAR&quot;&gt;В правой колонке, в графе &amp;quot;Font Family&amp;quot; пишем &lt;code&gt;Fira Code&lt;/code&gt;, но проще всего сразу жмякнуть чуть ниже  &amp;quot;Edit in setting.json&amp;quot; =&amp;gt; откроется небольшой файл с кодом, где нужно привести следующие строки к такому виду: &lt;/p&gt;
  &lt;pre id=&quot;zrae&quot;&gt;&amp;quot;editor.fontFamily&amp;quot;: &amp;quot;Fira Code&amp;quot;,
&amp;quot;editor.fontLigatures&amp;quot;: true,   &lt;/pre&gt;
  &lt;h2 id=&quot;a4jc&quot; data-align=&quot;center&quot;&gt;Готово!&lt;/h2&gt;

</content></entry><entry><id>buninman:snake</id><link rel="alternate" type="text/html" href="https://blog.buninman.ru/snake?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=buninman"></link><title>Игра Змейка на JavaScript</title><published>2022-09-06T06:22:35.578Z</published><updated>2022-12-03T05:46:56.240Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/cf/59/cf59fa25-54c4-4b9b-bf15-7fa30a9b731e.png"></media:thumbnail><category term="lerning" label="Обучение"></category><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/7c/27/7c270a37-33d6-4e93-bbf6-67cec58192f2.png&quot;&gt;Первая версия змейки появилась в 1976 году, а последняя - сегодня.</summary><content type="html">
  &lt;blockquote id=&quot;dsPM&quot;&gt;Первая версия змейки появилась в 1976 году, а последняя - сегодня.&lt;/blockquote&gt;
  &lt;p id=&quot;l4pS&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;RWib&quot;&gt;Пока проходил &lt;a href=&quot;https://buninman.ru/js_stashchuk&quot; target=&quot;_blank&quot;&gt;курс по JS&lt;/a&gt;, стало немного скучновато и я решил найти какой-нибудь гайд на ютубе, чтобы попрактиковаться.&lt;/p&gt;
  &lt;p id=&quot;AlmO&quot;&gt;У автора этой змейки есть две версии: в &lt;a href=&quot;https://youtu.be/TSdGHbI6veI&quot; target=&quot;_blank&quot;&gt;первом видео&lt;/a&gt; он делает змейку одним JS файлом, а &lt;a href=&quot;https://youtu.be/yq4x4zSSz70&quot; target=&quot;_blank&quot;&gt;во-втором видео&lt;/a&gt; уже на модулях с ООП (Объектно ориентированное программирование). Я сделал оба варианта, но именно второй мне захотелось разобрать по частям, чтоб лучше понять что к чему, т.к. он был намного менее понятен чем первый, там много классов и сложная модульная структура.&lt;/p&gt;
  &lt;p id=&quot;SNul&quot;&gt;Гитхаб автора со змейкой: &lt;a href=&quot;https://github.com/EpicLegend/snake2d-opp&quot; target=&quot;_blank&quot;&gt;https://github.com/EpicLegend/snake2d-opp&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;2GBo&quot;&gt;Все что будет ниже, я писал для того, чтоб просто разобрать непонятные мне части кода, но в процессе начал вносить в змейку и свои доработки. Поэтому код немного отличается от кода автора.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;RVcH&quot;&gt;Мой Гитхаб с моей змейкой: &lt;a href=&quot;https://github.com/Buninman/Snake&quot; target=&quot;_blank&quot;&gt;https://github.com/Buninman/Snake&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;JRlT&quot;&gt;Буду рад на указание ошибок, даже орфографических🙂&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;pcKm&quot;&gt;Основные изменения моей змейки:&lt;/p&gt;
    &lt;ul id=&quot;EeOm&quot;&gt;
      &lt;li id=&quot;MvBA&quot;&gt;Поменял дизайн игрового поля, добавил вниз блок с подсказкой;&lt;/li&gt;
      &lt;li id=&quot;nCWp&quot;&gt;Сделал счетчик рекорда, он запоминает наибольший накопленный результат;&lt;/li&gt;
      &lt;li id=&quot;EPOF&quot;&gt;Добавил возможность менять скорость змейки клавишами PgUp, PgDwn;&lt;/li&gt;
      &lt;li id=&quot;YmWG&quot;&gt;Теперь есть режим бога, в котором змейка не может себя съесть. Кнопка G;&lt;/li&gt;
      &lt;li id=&quot;ensi&quot;&gt;Убрал возможность змейке разворачиваться на 180º и кусать себя. Больше она не умирает от случайного нажатия.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/section&gt;
  &lt;figure id=&quot;7IMS&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/7c/27/7c270a37-33d6-4e93-bbf6-67cec58192f2.png&quot; width=&quot;1920&quot; /&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;R5Rx&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;http://bunindesign.com/snake.html&quot; target=&quot;_blank&quot;&gt;Тут можно поиграть в готовую змейку&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;OyFa&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;MMf3&quot; data-align=&quot;center&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;9FRF&quot; data-align=&quot;center&quot;&gt;Начало&lt;/h2&gt;
  &lt;p id=&quot;ndhY&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;tcY4&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/08/44/08445e26-39bf-4c49-8dcc-eb88ee6ba965.png&quot; width=&quot;1920&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;bdqI&quot;&gt;Набросал схему устройства приложения, чтоб было понятнее что куда идет в плане импорта объектов. По такому порядку и пойдем:&lt;/p&gt;
  &lt;ol id=&quot;IKTv&quot;&gt;
    &lt;li id=&quot;3YkN&quot;&gt;&lt;a href=&quot;#YXWz&quot;&gt;supportFunction.js&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;PzJd&quot;&gt;&lt;a href=&quot;#ATCr&quot;&gt;config.js&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;ckEw&quot;&gt;&lt;a href=&quot;#ONaS&quot;&gt;score.js&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;1P9K&quot;&gt;&lt;a href=&quot;#gPHO&quot;&gt;canvas.js&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;o49b&quot;&gt;&lt;a href=&quot;#JTZE&quot;&gt;berry.js&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;DoT3&quot;&gt;&lt;a href=&quot;#g4Bl&quot;&gt;snake.js&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;BS3m&quot;&gt;&lt;a href=&quot;#33UY&quot;&gt;gameLoop.js&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;ZY8F&quot;&gt;&lt;a href=&quot;#KcCl&quot;&gt;game.js&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;pz9b&quot;&gt;&lt;a href=&quot;#8JKn&quot;&gt;snake.html&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;KZUN&quot;&gt;&lt;a href=&quot;#rKwa&quot;&gt;style.css&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;NV7i&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;YXWz&quot; data-align=&quot;center&quot;&gt;supportFunction.js&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;gxlP&quot;&gt;В модуле всего одна функция, подробнее о ней можно посмотреть в &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random&quot; target=&quot;_blank&quot;&gt;документации&lt;/a&gt;, она целиком оттуда.&lt;/p&gt;
    &lt;pre id=&quot;gxlP&quot; data-lang=&quot;javascript&quot;&gt;export const getRandomInt = (min, max) =&amp;gt;
    Math.floor( Math.random() * (max - min) + min )
    
    // Math.random() возвращает псевдослучайное число
    // с плавающей запятой в диапазоне от 0 до менее 1
    // (включая 0, но не 1)
    
    // Math.floor() возвращает наибольшее целое число,
    // меньшее или равное заданному числу. Округляет&lt;/pre&gt;
    &lt;p id=&quot;jTCH&quot;&gt;Эта функция возвращает случайное число между указанными значениями. Возвращаемое значение не меньше (и, возможно, равно) &lt;code&gt;min&lt;/code&gt;и меньше (и не равно)&lt;code&gt;max&lt;/code&gt;. &lt;/p&gt;
    &lt;p id=&quot;RdRp&quot;&gt;&lt;code&gt;&lt;em&gt;getRandomInt()&lt;/em&gt;&lt;/code&gt; вызывается в файле &lt;a href=&quot;#tnaL&quot;&gt;&lt;em&gt;berry.js&lt;/em&gt;&lt;/a&gt; и имеет такой вид:&lt;/p&gt;
    &lt;pre id=&quot;jof7&quot; data-lang=&quot;javascript&quot;&gt;Для x: getRandomInt(0, this.canvas.element.width /
                       this.config.sizeCell) *
                       this.config.sizeCell
Для y: getRandomInt(0, this.canvas.element.height /
                       this.config.sizeCell) *
                       this.config.sizeCell&lt;/pre&gt;
    &lt;p id=&quot;AfNK&quot;&gt;Соответственно на &lt;code&gt;min&lt;/code&gt; передается &lt;code&gt;0&lt;/code&gt;, а на &lt;code&gt;max&lt;/code&gt; передается:&lt;/p&gt;
    &lt;pre id=&quot;1IHb&quot; data-lang=&quot;javascript&quot;&gt;Для x: ширинаПоля (688) / размерЯчейки (16) - это 43
Для y: высотаПоля (480) / размерЯчейки (16) - это 30&lt;/pre&gt;
    &lt;p id=&quot;1UHa&quot;&gt;Таким образом, когда функция срабатывает, мы получаем число в диапазоне от 1 до 42 для &lt;code&gt;x&lt;/code&gt; и от 1 до 49 для &lt;code&gt;y&lt;/code&gt;.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;Mz5C&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;Lg08&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;ATCr&quot; data-align=&quot;center&quot;&gt;config.js&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;xFgu&quot;&gt;Этот модуль претерпел самые большие изменения, вместо 8 строк кода, теперь тут 38.&lt;/p&gt;
    &lt;p id=&quot;Ck5R&quot;&gt;Значения &lt;em&gt;config.js&lt;/em&gt; используются в &lt;em&gt;&lt;a href=&quot;#JTZE&quot;&gt;berry.js&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;&lt;a href=&quot;#g4Bl&quot;&gt;snake.js&lt;/a&gt;&lt;/em&gt; и &lt;em&gt;&lt;a href=&quot;#33UY&quot;&gt;gameloop.js&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
    &lt;pre id=&quot;xFgu&quot; data-lang=&quot;javascript&quot;&gt;export default class Config {
    constructor() {        
        this.speedBlock = document.querySelector(&amp;#x27;#speed&amp;#x27;)
        this.godModeColor = document.querySelector(&amp;#x27;.game-header&amp;#x27;)
        this.textBlock = document.querySelector(&amp;#x27;.keys-conf&amp;#x27;)
        // Ищем значения в HTML коде, по названиям классов и id
        // Тут мы ищем индикатор скорости, цвет плашки под ним
        // и блок текста с инструкцией
        
        this.step = 0
        this.maxStep = 6
        // step и maxStep нужны чтоб пропускать игровой цикл,
        // их использует функция в файле gameLoop.js.
        // Также maxStep регулирует скорость змейки,
        // чем выше значение тем реже перерисовывается змейка

        this.sizeCell = 16
        this.sizeBerry = this.sizeCell / 4
        // sizeCell это размер ячейки, а sizeBerry это размер ягодки
        
        this.godMode = false
        // Переменная отвечает за режим бога. Изначально он выключен

        this.colorLight = &amp;#x27;#A55E00&amp;#x27;        
        this.colorDark = &amp;#x27;#5E3908&amp;#x27;
        // Переменные с цветами змейки. Есть темный оттенок
        // и светлый, для головы змейки
        
        this.drawSpeed()
        // Метод отрисовывает значение скорости
    }
    
    speedLevel() {        
        return 10 - this.maxStep
        // Чтоб значения скорости были понятнее я сделал
        // функцию которая меняет порядок чисел, теперь 1
        // это самая медленная скорость, а 8 - самая быстрая
    }
    
    drawSpeed() {        
        this.speedBlock.innerHTML = this.speedLevel()
        // innerHTML обращается к значению в HTML
        // и меняет на текущую скорость змейки
    }
    
    drawGodMode() {        
        if (this.godMode) {  
        // Если режим бога сейчас true то: 
                
            this.colorLight = &amp;#x27;#FA0556&amp;#x27;
            this.colorDark = &amp;#x27;#A00034&amp;#x27;
            // Меняем цвета в переменных на красные.
            // Они также подхватываются змейкой
            
            this.textBlock.innerHTML = &amp;#x27;God Mode: ON&amp;#x27;
            // Вместо инструкции пишем о включенном режиме
            
            this.godModeColor.style.backgroundColor = this.colorDark
            // style.backgroundColor получает значение цвета
            // параметра background в css-файле.
            // Тут мы меняем цвет плашки под счетом
            
        } else {
        // Если режим бога сейчас false:
        
            this.colorLight = &amp;#x27;#A55E00&amp;#x27;
            this.colorDark = &amp;#x27;#5E3908&amp;#x27;
            // Меняем цвета в переменных на оранжевые
            
            this.textBlock.innerHTML
                 =&amp;#x27;Use the Arrows and PageUp/PageDown&amp;#x27;
            // Пишем стандартную инструкцию внизу поля
            
            this.godModeColor.style.backgroundColor = this.colorDark
            // Меняем цвет плашки
        }
    }
}&lt;/pre&gt;
    &lt;p id=&quot;zZWD&quot;&gt;🙁Не смог сделать так, чтоб ягодка меняла цвет вместе со змейкой. Сделал ягодку белой.&lt;/p&gt;
    &lt;p id=&quot;FguN&quot;&gt;Свойства &lt;code&gt;step&lt;/code&gt; и &lt;code&gt;maxStep&lt;/code&gt; используются в модуле &lt;em&gt;&lt;a href=&quot;#r0Gl&quot;&gt;gameLoop.js&lt;/a&gt;, &lt;/em&gt;внутри функции &lt;code&gt;animate()&lt;/code&gt;:&lt;/p&gt;
    &lt;pre id=&quot;fUxJ&quot; data-lang=&quot;javascript&quot;&gt;animate() {
    requestAnimationFrame(this.animate)
    // Вызывает повторно функцию animate()
    // так образуется непрерывный цикл
        
    if (++this.config.step &amp;lt; this.config.maxStep) {
        return
        // Если ++step меньше maxStep, то ничего не делать.
        // Таким образом, надо 6 раз вызвать функцию,
        // чтоб змейка сделала 1 шаг
    }  
              
    this.config.step = 0
    // После движения змейки, счетчик возвращается на 0
    
    this.update()
    this.draw()
}&lt;/pre&gt;
    &lt;blockquote id=&quot;EwXj&quot;&gt;&lt;code&gt;++&lt;/code&gt; увеличивает значение на единицу и возвращает значение.&lt;/blockquote&gt;
    &lt;p id=&quot;3ftz&quot;&gt;Оператор &lt;code&gt;++&lt;/code&gt; будет прибавлять 1 к step до тех пор, пока на шестом вызове функции она не пройдет дальше. После функция обнуляет значение &lt;code&gt;step.&lt;/code&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;CHcd&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;LjaY&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;ONaS&quot; data-align=&quot;center&quot;&gt;score.js&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;fzNM&quot;&gt;Модуль отвечает за отрисовку очков за съеденные ягодки. Сюда же я добавил функцию &lt;code&gt;drawRecord()&lt;/code&gt;, которая вызывается в случае смерти змейки сохраняет наш прогресс в виде рекорда.&lt;/p&gt;
    &lt;p id=&quot;mNNO&quot;&gt;Значение &lt;em&gt;score.js&lt;/em&gt; используются в &lt;em&gt;&lt;a href=&quot;#KcCl&quot;&gt;game.js&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
    &lt;pre id=&quot;fzNM&quot; data-lang=&quot;javascript&quot;&gt;export default class Score {
    constructor(scoreBlock, recordBlock, score = 0) {
        this.scoreBlock = document.querySelector(scoreBlock)
        this.recordBlock = document.querySelector(recordBlock)
        // Ищем значения в HTML коде, по id. Тут мы ищем
        // счетчики очков и рекорда        
        this.score = score
        // Создает свойство со значением очков
        this.draw()
        // Вызывает метод объекта draw() при создании экземпляра
    }
    
    incScore() {
        this.score++
        // Добавляет 1 к счету за съеденную ягодку
        this.draw()
        // Запускает метод draw() который поменяет значение счетчика
    }

    setToZero() {
        this.score = 0
        // Обнуляет счетчик очков. Это нужно в случае сметри
        this.draw()
        // Запускает метод draw()
    }
    
    drawRecord() {
        if (this.score &amp;gt; this.record) {
        // Если значение очков больше чем текущий рекорд, то
            this.record = this.score
            // Меняем значение рекорда на текущее значение очков
            this.recordBlock.innerHTML = this.record
            // Меняем значение рекорда в HTML
        }    
    }
    
    draw() {        
        this.scoreBlock.innerHTML = this.score
        // innerHTML обращается к значению в HTML
        // и меняет значение счета в HTML
    }
}&lt;/pre&gt;
  &lt;/section&gt;
  &lt;p id=&quot;WdUA&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;ge6L&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;gPHO&quot; data-align=&quot;center&quot;&gt;canvas.js&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;e5Aq&quot;&gt;Модуль отвечает за создание и размеры игрового поля. Я менял только размер игрового поля.&lt;/p&gt;
    &lt;p id=&quot;jtn2&quot;&gt;Значение &lt;em&gt;canvas.js&lt;/em&gt; используются в &lt;em&gt;&lt;a href=&quot;#KcCl&quot;&gt;game.js&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
    &lt;pre id=&quot;6JtR&quot; data-lang=&quot;javascript&quot;&gt;export default class Canvas {
    constructor(container) {
        this.element = document.createElement(&amp;#x27;canvas&amp;#x27;)
        // .createElement создает HTML-элемент &amp;lt;canvas&amp;gt; в HTML-файле

        this.context = this.element.getContext(&amp;#x27;2d&amp;#x27;)
        // .getContext(&amp;#x27;2d&amp;#x27;) указывает JS что мы хотим рисовать в 2д.
        // Нам становится доступен набор свойст и методов
        // таких как beginPath(), которым нарисована ягодка
        
        this.element.width = 688
        this.element.height = 800
        // Это высота и ширина 2д контекста, т.к. одна ячейка
        // у нас 16рх, то значения должны быть кратны 16рх
        
        container.appendChild(this.element)
        // Как я понял, .appendChild создает дочерний элемент.
        // Он помещает наш созданный 2д контекст (игровое поле)
        // в &amp;lt;canvas&amp;gt; внутри HTML-файла
    }
}&lt;/pre&gt;
  &lt;/section&gt;
  &lt;p id=&quot;CTzm&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;fxxR&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;JTZE&quot; data-align=&quot;center&quot;&gt;berry.js&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;7jhK&quot;&gt;Модуль отвечает за все что происходит с ягодкой. &lt;/p&gt;
    &lt;p id=&quot;OLid&quot;&gt;Значение &lt;em&gt;berry.js&lt;/em&gt; используются в &lt;em&gt;&lt;a href=&quot;#KcCl&quot;&gt;game.js&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
    &lt;pre id=&quot;SayO&quot; data-lang=&quot;javascript&quot;&gt;import Config from &amp;#x27;./config.js&amp;#x27;
import {getRandomInt} from &amp;#x27;./supportFunction.js&amp;#x27;

export default class Berry {
    constructor(canvas) {
        this.x = 0
        this.y = 0
        // Это координаты ягодки        
        this.canvas = canvas
        // в Berry передаются параметры игрового поля,
        // нам нужны оттуда только высота и ширина
        this.config = new Config()
        // Передаем данные с Config, нам оттуда нужны размеры ячейки
        // и размер ягодки
        this.randomPosition()
        // Запускаем функцию получения рандомных кординат для ягодки
    }  
    
    draw(context) {
    // Функция рисования ягодки. Сюда передается наш 2д контекст
    // из класса Canvas
    
        context.beginPath()
        // Создает новый векторый контур. Начинаем рисование
        
        context.fillStyle = &amp;#x27;#EBEBEB&amp;#x27;
        // Заливка этого контура белым цветом. Если поменять ее
        // на динамичную переменную this.config.colorLight, то
        // цвет ягодки все равно не будет меняться
        // Я не понимаю почему🙁
        
        context.arc(this.x + (this.config.sizeCell / 2),
        // arc() создает векторную дугу. Замкнутая дуга это круг
        // В arc() нужно передать координаты x и y,
        // радиус, начальный угол и конечный угол
                    // Берем рандомную координату x, прибавляем
                    // к ней половину размера ячейки.
                    
                    this.y + (this.config.sizeCell / 2),
                    // Тоже самое для координаты y,
                    // Это дает нам положение центра ячейки
                    // Центр нашей ягодки
                    
                    this.config.sizeBerry, 0, 2 * Math.PI)
                    // Берем размер ягодки из Config, это радиус
                    // 0 - это начальный угол
                    // 2 * Math.PI - это конечный угол, такой
                    // параметр указан в учебнике по JS
                    
        context.fill()
        // Метод fill() создает заливку для нашей ягодки,
    }
    
    randomPosition() {
        this.x = getRandomInt(0, this.canvas.element.width / 
                                 this.config.sizeCell) * 
                                 this.config.sizeCell        
        this.y = getRandomInt(0, this.canvas.element.height / 
                                 this.config.sizeCell) *
                                 this.config.sizeCell
        // Функция получения рандомных координат, два раза
        // вызывает функцию генерации случайных чисел
        // и присваивает их x и y координатам
    }
}&lt;/pre&gt;
    &lt;p id=&quot;99IP&quot;&gt;Функция &lt;code&gt;getRandomInt()&lt;/code&gt; расписана в модуле &lt;a href=&quot;#YXWz&quot;&gt;&lt;em&gt;supportFunction.js&lt;/em&gt;&lt;/a&gt; &lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;UTZo&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;7Ian&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;g4Bl&quot; data-align=&quot;center&quot;&gt;snake.js&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;si1R&quot;&gt;Модуль за все что связано со змейкой. Я добавил функцию сохранение рекорда после смерти змейки, поменял параметры старта и изменил назначение клавиш.&lt;/p&gt;
    &lt;p id=&quot;4K9n&quot;&gt;Значение &lt;em&gt;snake.js&lt;/em&gt; используются в &lt;em&gt;&lt;a href=&quot;#KcCl&quot;&gt;game.js&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
    &lt;pre id=&quot;LXsD&quot; data-lang=&quot;javascript&quot;&gt;import Config from &amp;#x27;./config.js&amp;#x27;

export default class Snake {
    constructor() {
        this.config = new Config()
        // Передаем данные с Config, нам нужен размер ячейки
        this.x = 336
        this.y = 480
        // Начальные координаты змейки,
        // я сделал чтоб она появлялась внизу посередине
        this.dx = 0
        this.dy = -this.config.sizeCell
        // Начальное направление движения змейки,
        // по x - 0, а по y на -16рх, т.е. вверх.
        // Ось кординат начинается сверху слева
        // Ось y идет сверху вниз
        this.tails = []
        // Пустой массив для записи данных о хвосте змейки
        this.maxTails = 1
        // Параметр длины змейки. Я сделал по умолчанию 1,
        // т.е. только голова
        this.control()
        // Запускаем функцию отвечающую за упарвление змейкой        
    }
    
    update(berry, score, canvas) {
    // Функция обновления змейки. Сюда передаются данные ягодки,
    // счета и игрового поля
    
        this.x += this.dx
        this.y += this.dy
        // Прибавляем к координатам змейки размер движения.
        // Змейка перемещается путем прибавления или вычитания
        // размера ячейки от следующих координат положения головы
        
        if (this.x &amp;lt; 0) {
        // Если координата x меньше 0 то
            this.x = canvas.element.width - this.config.sizeCell
            // Присваиваем ей значение ширины игрового поля
            // минус одну ячейку.
            // Т.е. если змейка доходит до края, то
            // она появится с другой стороны
            
        } else if (this.x &amp;gt;= canvas.element.width) {
        // то, при условии, что координата x больше или равна
        // ширине игрового поля
                   this.x = 0
                   // Кордината x = 0, начало поля.
                   // Т.е. если змейка доходит до края, то
                   // она появится с другой стороны
        }

        if (this.y &amp;lt; 0) {
            this.y = canvas.element.height - this.config.sizeCell
        } else if (this.y &amp;gt;= canvas.element.height) {
                   this.y = 0
        // Логика с вертикальной осью такая же, но в расчет берем
        // высоту поля, а не ширину
        }
        
        this.tails.unshift({ x: this.x, y: this.y})
        // Метод .unshift() добавляет элемент в начало массива
        // с хостом. Добавляем туда объект с координатами x и y.
        // Это секция хвоста
        
        if (this.tails.length &amp;gt; this.maxTails) {
        // Если длина массива с хвостом больше чем параметр длинны
        // хвоста, то 
            this.tails.pop()
            // Удаляем последний элемент массива
            // Метод .pop() удаляет элемент в конце массива
        }
        
        this.tails.forEach((el, index) =&amp;gt; {
        // Метод .forEach() перебирает все элементы массива,
        // все элементы змейки, и применяет к ним функцию.
        // В функцию передаются все элементы массива и их индексы
        
            if (el.x === berry.x &amp;amp;&amp;amp; el.y === berry.y) {
            // Если координаты x и y в какой-то из секций змейки
            // совпадают с координатами ягоды, то
                this.maxTails++
                // Добавляем 1 к параметру длины змейки
                score.incScore()
                // Вызываем метод incScore(). Это метод нашего
                // объекта Score, он прибавляем 1 единичку к счету
                berry.randomPosition()
                // Вызываем метод randomPosition(). Это метод нашего
                // объекта Berry, он переносит ягодку на новые
                // случайные координаты
            }

            for (let i = index + 1; i &amp;lt; this.tails.length; i++) {
            // Цикл for запускает функцию пока условие верно.
            // Переменная i это индекс элементов массива, прибавляем
            // к ней 1, чтоб игнорировать элемент 0, это голова.
            // Цикл будет продолжаться пока i меньше длинны массива
            // Каждый цикл увеличиваем i на 1
            
                if ( el.x == this.tails[i].x &amp;amp;&amp;amp;
                     el.y == this.tails[i].y &amp;amp;&amp;amp;
                     !this.config.godMode) {
                // Если координаты x и y какого элемента равны
                // каким-то другим координатам из массива, кроме
                // головы, и если режим бога НЕ включен, то
                    this.death()
                    // Метод death() возвращает все параметры
                    // на начальные, перезапускает игру
                    score.drawRecord()
                    // Метод объекта Score, записывает наш счет
                    // в рекорд, если текущий рекорд меньше
                    score.setToZero()
                    // Обнуляет счетчик очков
                    berry.randomPosition()
                    // Вызываем метод randomPosition(). Это метод
                    // объекта Berry, он переносим ягодку на новые
                    // случайные координаты
                }            
            }        
        })    
    }
            
    draw(context) {
    // Функция рисования змейки. Сюда передается наш 2д контекст
    // из класса Canvas
    
        this.tails.forEach((el, index) =&amp;gt; {
        // Метод .forEach() перебирает все элементы массива
            if (index == 0) {
            // Если индекс элемента массива равен 0,
                context.fillStyle = this.config.colorLight
                // то красим в яркий цвет. Это голова
            } else {
                context.fillStyle = this.config.colorDark
                // Иначе красим в темный цвет, это тело змейки
            }

            context.fillRect( el.x, el.y, this.config.sizeCell,
                                          this.config.sizeCell)
            // Метод fillRect() рисует прямоугольник по двум
            // координатам и двум величинам, это размер ячейки
        }) 
    }
        
    death() {
    // Метод death() возвращает все параметры
    // на начальные, перезапускает игру 
        this.x = 336
        this.y = 480
        // Ставит змейку на нужные координаты        
        this.dx = 0
        this.dy = -this.config.sizeCell
        // Выставляет напрвление движения 
        this.tails = []
        // Обнуляем массив хвостов
        this.maxTails = 1
        // Делает параметр колическва хвостов равным 1
    }
    
    control() {        
        document.addEventListener(&amp;quot;keydown&amp;quot;, e =&amp;gt; {
        // Метод addEventListener() отслеживает события
        // Первый аргумен указывает на тип события - кнопка нажата.
        // Второй агрумент указывает на &amp;quot;слушателя&amp;quot;, тот раздражитель
        // который должен это событие вызвать и ту функцию которое
        // это событие произведет. В нашем случае это будут кнопки
        // клавиатуры
        
            if (e.code == &amp;#x27;ArrowUp&amp;#x27;) {
            // Если код слушателя равен клавише &amp;quot;Стрелка вверх&amp;quot; то
            
                if (this.dx == 0 &amp;amp;&amp;amp;
                    this.dy == this.config.sizeCell) {
                    return
                    // Если сейчас прибавление координат идет по
                    // оси y, то ничего не делаем - return
                    // Эта проверка запрещает змейке начать
                    // двигаться в противоположную от текущей
                } else {
                    this.dx = 0
                    this.dy = -this.config.sizeCell
                    // Иначе начинаем отнимать координаты
                    // от текущего положения головы змейки
                    // по оси y. Это заставит змейку двигаться
                    // вверх от текущих координат y
                }
                
            } else if (e.code == &amp;#x27;ArrowLeft&amp;#x27;) {
                if (this.dx == this.config.sizeCell &amp;amp;&amp;amp;
                    this.dy == 0) {
                    return
                } else {
                    this.dx = -this.config.sizeCell
                    this.dy = 0
                    // Для движения влево все тоже самое,
                    // но начинаем отнимать размер ячейки от
                    // оси x, не трогая значение y
                }
            
            } else if (e.code == &amp;#x27;ArrowDown&amp;#x27;) {
                if (this.dx == 0 &amp;amp;&amp;amp;
                    this.dy == -this.config.sizeCell) {
                    return
                 } else {
                    this.dx = 0
                    this.dy = this.config.sizeCell
                }
            
            } else if (e.code == &amp;#x27;ArrowRight&amp;#x27;) {
                if (this.dx == -this.config.sizeCell &amp;amp;&amp;amp;
                    this.dy == 0) { 
                    return
                } else {
                    this.dx = this.config.sizeCell
                    this.dy = 0
                }
            
            }
            
            if (e.code == &amp;#x27;KeyG&amp;#x27;) {
            // Если код слушателя равен клавише &amp;quot;G&amp;quot;, то
                if (this.config.godMode) {
                // Если параметр godMode равен true (включен)
                    this.config.godMode = false
                    // То выключаем его, делая false
                    this.config.drawGodMode()
                    // Запускаем функцию смены цветов и надписей
                    // Интерфейс и змейка становятся оранжевыми
                    
                } else {
                // Если параметр godMode равен false
                    this.config.godMode = true
                    // Включаем его, делая true
                    this.config.drawGodMode()
                    // Запускаем функцию смены цветов и надписей
                    // Интерфейс и змейка становятся красными
                }
            }        
        })    
    }
}&lt;/pre&gt;
    &lt;p id=&quot;Zo2m&quot;&gt;Занятные детали компьютерной логики:&lt;/p&gt;
    &lt;ul id=&quot;N5he&quot;&gt;
      &lt;li id=&quot;vIZT&quot;&gt;Змейка никуда не движется и постоянно растет, каждый ход к ней прирастает новая голова и отваливаться одна клетка от хвоста. &lt;/li&gt;
    &lt;/ul&gt;
    &lt;ul id=&quot;rYXx&quot;&gt;
      &lt;li id=&quot;ml7a&quot;&gt;Догнав ягодку у нас один раз НЕ отваливается хвост, так как к &lt;code&gt;maxTails&lt;/code&gt; прибавляет 1.&lt;/li&gt;
      &lt;li id=&quot;CSuP&quot;&gt;Если выставить изначальное значение &lt;code&gt;maxTails = 10&lt;/code&gt;,  то можно заметить, что змейка НЕ появляется с хвостом длиной в 10 клеток, а просто 10 ходов у нее не укорачивается хвост.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;ul id=&quot;GIbq&quot;&gt;
      &lt;li id=&quot;FKO8&quot;&gt;Скорость змейки определяется количеством пустых вызовов функции &lt;code&gt;animate()&lt;/code&gt;, зависящей от параметра &lt;code&gt;maxStep&lt;/code&gt; чем больше мы будем вызывать функцию бесполезно, тем медленнее будет бежать змейка&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/section&gt;
  &lt;p id=&quot;l2Yq&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;TXAb&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;33UY&quot; data-align=&quot;center&quot;&gt;gameLoop.js&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;Tbzn&quot;&gt;Модуль отвечает за обновление игрового пространства. Сюда я добавил контроль нажатия клавиш, чтоб регулировать скорость движения змейки.&lt;/p&gt;
    &lt;p id=&quot;dNsB&quot;&gt;Значение &lt;em&gt;gameLoop.js&lt;/em&gt; используются в &lt;em&gt;&lt;a href=&quot;#KcCl&quot;&gt;game.js&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
    &lt;pre id=&quot;tI9d&quot; data-lang=&quot;javascript&quot;&gt;import Config from &amp;#x27;./config.js&amp;#x27;

export default class GameLoop {
    constructor(update, draw) {
    // В конструктор передаются методы из класса Game
        this.update = update
        // update() отвечает за изменения в игре
        this.draw = draw
        // а draw() за отрисовку на экране
        
        this.config = new Config()
        // Передаем данные Config
        
        this.animate = this.animate.bind(this)
        // animate будет содержать метод animate().
        // Чтоб сохранить значение this, используем
        // метод bind()
        
        this.animate()
        // Запускаем метод animate() она отвечает
        // за непрерывное обновление игрового поля
        this.control()
        // Запускаем метод control() он отвечает
        // за нажатие клавиш
    }
    
    animate() {
    // Функция отвечает за непрерывный цикл внесения изменений
    // в игру
    
        requestAnimationFrame(this.animate)
        // Вызывает повторно функцию animate()
        // так образуется непрерывный цикл
        
        if (++this.config.step &amp;lt; this.config.maxStep) {
            return
            // Если ++step меньше maxStep, то ничего не делать
            // таким образом, надо 6 раз вызвать функцию,
            // чтоб змейка сделала 1 шаг
        }  
              
        this.config.step = 0
        // После движения змейки, счетчик возвращается на 0
    
        this.update()
        // Вызывается функция update(), которая обновляет 
        // данные по змейке, ягодке и очкам
        this.draw()
        // Вызывается функция, которая запускает draw() у ягодки
        // и змейки, предварительно отчистив игровое поле
    }
    
    control() {
    // Функция отвечает за изменение скорости змейки.
    // Чем выше значение maxStep, тем медленнее ползает змейка,
    // я выбрал диапазон от 2 до 9
    
        document.addEventListener(&amp;#x27;keydown&amp;#x27;, e =&amp;gt; {
        // Метод addEventListener() отслеживает события
        // также как в snake.js
        
            if (e.code == &amp;#x27;PageUp&amp;#x27;) {
                if (this.config.maxStep &amp;gt; 2) {
                // Если maxStep больше 2, то мы можем позволить
                // себе уменьшить его значение
                    this.config.maxStep--
                    // Отнимаем 1 от maxStep
                    this.config.drawSpeed()
                    // Рисуем новое значение скорости
                }
            } else if (e.code == &amp;#x27;PageDown&amp;#x27;) {
                if (this.config.maxStep &amp;lt; 9) {
                // Если maxStep меньше 9, то мы можем позволить
                // себе увеличить его значение
                    this.config.maxStep++
                    // Прибавляем 1 к maxStep
                    this.config.drawSpeed()
                    // Рисуем новое значение скорости
                }
            }        
        })    
    }    
}&lt;/pre&gt;
  &lt;/section&gt;
  &lt;p id=&quot;JOPP&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;DoEy&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;KcCl&quot; data-align=&quot;center&quot;&gt;game.js&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;pre id=&quot;9kIL&quot; data-lang=&quot;javascript&quot;&gt;import Canvas from &amp;#x27;./canvas.js&amp;#x27;
import Snake from &amp;#x27;./snake.js&amp;#x27;
import Berry from &amp;#x27;./berry.js&amp;#x27;
import Score from &amp;#x27;./score.js&amp;#x27;
import GameLoop from &amp;#x27;./gameLoop.js&amp;#x27;

class Game {
    constructor(container) {
        this.canvas = new Canvas(container)
        // Создается объект игрового поля,
        // со значением ссылки на класс в HTML-файле
        
        this.snake = new Snake()
        // Создается объект змейки

        this.berry = new Berry(this.canvas)
        // Объект ягодки
        
        this.score = new Score(&amp;#x27;#score&amp;#x27;, &amp;#x27;#record&amp;#x27;, 0)
        new GameLoop(this.update.bind(this), this.draw.bind(this))
        // Создается объект GameLoop в аргументах которого передаютя
        // container.update где container это значение в HTML-файле,
        // а update это метод объекта.
        // .bind(this) это метод, который передает методу update()
        // нужное значение this, опять же значение в HTML-файле
    }
    
    update() {
        this.snake.update(this.berry, this.score, this.canvas)
        // Вызываем медод объекта Snake, передавая в него данные
        // ягодки, счета и игрового поля
    }
    
    draw() {
    // Функция отвечает за отрисовку всего на игровом поле
        this.canvas.context.clearRect(0, 0,
            this.canvas.element.width,
            this.canvas.element.height)
        // Метод .clearRect() очищает прямоугольную область пикселей.
        // аргументы 0, 0, это начальные координаты, а ширина и высота
        // игрового поля размер отчищаемой области
        
        this.snake.draw(this.canvas.context)
        this.berry.draw(this.canvas.context)
        // Вызываем методы draw() у змейки и у ягодки, передавая
        // туда свойства и функции 2D-контекста из Канваса
    }
}

new Game(document.querySelector(&amp;#x27;.canvas-wrapper&amp;#x27;))
// Это старт игры, создается объект Game.
// querySelector ищет значение в HTML.
// У нас это пустой &amp;lt;div&amp;gt; с классом .canvas-wrapper&lt;/pre&gt;
  &lt;/section&gt;
  &lt;p id=&quot;HWIz&quot;&gt;&lt;/p&gt;
  &lt;blockquote id=&quot;2v05&quot; data-align=&quot;center&quot;&gt;HTML &amp;amp; CSS&lt;/blockquote&gt;
  &lt;p id=&quot;8t2P&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;8JKn&quot; data-align=&quot;center&quot;&gt;snake.html&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;pre id=&quot;857G&quot; data-lang=&quot;html&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;
&amp;lt;head&amp;gt;    
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;
    &amp;lt;title&amp;gt;My Snake&amp;lt;/title&amp;gt;
    &amp;lt;meta http-equiv=&amp;quot;X-UA-Compatible&amp;quot; content=&amp;quot;IE=edge&amp;quot;&amp;gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot;
          content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot;&amp;gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;css/style.css&amp;quot;&amp;gt;
    &amp;lt;link rel=&amp;quot;apple-touch-icon&amp;quot; sizes=&amp;quot;180x180&amp;quot; 
          href=&amp;quot;img/apple-touch-icon.png&amp;quot;&amp;gt;
    &amp;lt;link rel=&amp;quot;icon&amp;quot; type=&amp;quot;image/png&amp;quot; sizes=&amp;quot;32x32&amp;quot; 
          href=&amp;quot;img/favicon-32x32.png&amp;quot;&amp;gt;
    &amp;lt;link rel=&amp;quot;icon&amp;quot; type=&amp;quot;image/png&amp;quot; sizes=&amp;quot;16x16&amp;quot; 
          href=&amp;quot;img/favicon-16x16.png&amp;quot;&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;div id=&amp;quot;game&amp;quot;&amp;gt;    
        &amp;lt;div class=&amp;quot;game-header&amp;quot;&amp;gt;
            
            &amp;lt;div class=&amp;quot;game-score&amp;quot;&amp;gt;                
                &amp;lt;span class=&amp;quot;score-text&amp;quot;&amp;gt;Speed:&amp;lt;/span&amp;gt;
                &amp;lt;span class=&amp;quot;score-count&amp;quot; id=&amp;quot;speed&amp;quot; &amp;gt;0&amp;lt;/span&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div class=&amp;quot;game-score&amp;quot;&amp;gt;
                &amp;lt;span class=&amp;quot;score-text&amp;quot;&amp;gt;Score:&amp;lt;/span&amp;gt;
                &amp;lt;span class=&amp;quot;score-count&amp;quot; id=&amp;quot;score&amp;quot; &amp;gt;0&amp;lt;/span&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div class=&amp;quot;game-score&amp;quot;&amp;gt;
                &amp;lt;span class=&amp;quot;score-text&amp;quot;&amp;gt;Record:&amp;lt;/span&amp;gt;
                &amp;lt;span class=&amp;quot;score-count&amp;quot; id=&amp;quot;record&amp;quot; &amp;gt;0&amp;lt;/span&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;!--
            Блоков game-score стало три, поэтому добавил
            уникальные id, по которым теперь ориенируется
            JavaScript вместо классов
            ---&amp;gt;
        &amp;lt;/div&amp;gt;        
        &amp;lt;div class=&amp;quot;canvas-wrapper&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
        
        &amp;lt;div class=&amp;quot;game-footer&amp;quot;&amp;gt;            
            &amp;lt;div class=&amp;quot;keys-conf&amp;quot;&amp;gt;                
                &amp;lt;span&amp;gt;Use the WASD keys&amp;lt;/span&amp;gt;            
            &amp;lt;/div&amp;gt;        
        &amp;lt;/div&amp;gt;
        &amp;lt;!--
        Новый блок game-footer отвечает за текст под игровым полем.
        Научил JS его менять в режиме бога
        ---&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;script src=&amp;quot;js/game.js&amp;quot; type=&amp;quot;module&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt; 
&amp;lt;/html&amp;gt;&lt;/pre&gt;
  &lt;/section&gt;
  &lt;p id=&quot;eJk4&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;GyWG&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;h3 id=&quot;rKwa&quot; data-align=&quot;center&quot;&gt;style.css&lt;/h3&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;pre id=&quot;0tPF&quot; data-lang=&quot;css&quot;&gt;body {
    margin: 0px;    
    font-family: sans-serif;
}
#game {
    background: #353336;    
    width: 100vw;    
    height: 100vh;
    display: flex;    
    flex-direction: column;    
    justify-content: center;    
    align-items: center;
}
#game-canvas {
    display: block;    
    border-radius: 5px; 
}
.game-header {    
    margin-bottom: 15px;    
    width: 708px;    
    height: 70px;    
    background: #5E3908;    
    display: flex;    
    align-items: center;    
    justify-content: space-between;    
    border-radius: 10px;
}
.game-score {
    padding: 10px 15px;    
    min-width: 160px;    
    height: 30px;    
    background: #121214;    
    border-radius: 5px;
    display: flex;    
    justify-content: center;    
    align-items: center;
}
.score-text {
    font-size: 2vmin;    
    color: #EBEBEB;
}
.score-count {
    font-size: 3vmin;
    padding-left: 6px;    
    color: #EBEBEB;    
    font-weight: bold;
}
.canvas-wrapper {
    background-color: #161618;    
    border-radius: 5px;    
    border: 10px solid #161618;
    background-image: url(&amp;quot;data:image/svg+xml,%3Csvg width=&amp;#x27;16&amp;#x27; height=&amp;#x27;16&amp;#x27; viewBox=&amp;#x27;0 0 16 16&amp;#x27; fill=&amp;#x27;none&amp;#x27; xmlns=&amp;#x27;http://www.w3.org/2000/svg&amp;#x27;%3E%3Cg opacity=&amp;#x27;0.2&amp;#x27;%3E%3Ccircle cx=&amp;#x27;8&amp;#x27; cy=&amp;#x27;8&amp;#x27; r=&amp;#x27;4&amp;#x27; fill=&amp;#x27;%23525053&amp;#x27;/%3E%3C/g%3E%3C/svg%3E%0A&amp;quot;);
}
.game-footer {
    padding-top: 1vmin;    
    padding-bottom: 1vmin;
    display: flex;    
    justify-content: space-between;
}
.keys-conf {  
    width: 708px;    
    height: 30px;    
    display: flex;    
    justify-content: center;    
    align-items: center;
    font-size: 2vmin;    
    color: #797979;    
    font-weight: regular;
}&lt;/pre&gt;
    &lt;p id=&quot;K2Gc&quot;&gt;Основные изменения коснулись &lt;code&gt;.game-header&lt;/code&gt; и &lt;code&gt;.game-score&lt;/code&gt;, добавились классы &lt;code&gt;.game-footer&lt;/code&gt; и &lt;code&gt;.keys-conf&lt;/code&gt;.&lt;/p&gt;
    &lt;p id=&quot;2di3&quot;&gt;Уверен как-то можно заменить уродскую &lt;code&gt;url&lt;/code&gt; с svg-картинкой на нарисованную через css, если кто знает, напишите.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;7Rlm&quot; data-align=&quot;center&quot;&gt;&lt;/p&gt;
  &lt;blockquote id=&quot;PjJ4&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#9FRF&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;

</content></entry><entry><id>buninman:js_stashchuk</id><link rel="alternate" type="text/html" href="https://blog.buninman.ru/js_stashchuk?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=buninman"></link><title>Курс по JavaScript</title><published>2022-09-02T15:13:01.443Z</published><updated>2022-09-02T15:13:01.443Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/ee/d2/eed28ed1-e48f-48de-b003-837334cfe71e.png"></media:thumbnail><category term="lerning" label="Обучение"></category><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/3f/c4/3fc42406-fa92-4f2d-b7ce-8554581884bc.jpeg&quot;&gt;Все, что вы тут найдете, это ничто иное как один большой конспект курса по JavaScript от Стащук Богдана.</summary><content type="html">
  &lt;p id=&quot;PQIX&quot;&gt;Все, что вы тут найдете, это ничто иное как один большой конспект курса по JavaScript от Стащук Богдана.&lt;/p&gt;
  &lt;p id=&quot;yrM4&quot;&gt;Когда начинал проходить курс, хотел каждую тему делать отдельной статьей, но потом понял, что это сильно затрудняет навигацию и поиск, поэтому сделал все в одной статье. Букв, конечно, пришлось написать изрядное количество🙄&lt;/p&gt;
  &lt;p id=&quot;UWV0&quot;&gt;Возможно кому-то конспект пригодится😊 Если найдете ошибки, а в нем они есть, я уверен, то пишите в комментариях - исправлю.&lt;/p&gt;
  &lt;p id=&quot;9DES&quot;&gt;Курс есть в свободном доступе на &lt;a href=&quot;https://youtu.be/CxgOKJh4zWE&quot; target=&quot;_blank&quot;&gt;ютубе.&lt;/a&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;ZLne&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;4Tky&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;DhPs&quot;&gt;Оглавление&lt;/h2&gt;
  &lt;h3 id=&quot;L0bV&quot;&gt;1. &lt;a href=&quot;#XZvR&quot;&gt;Отзыв о курсе&lt;/a&gt; &lt;/h3&gt;
  &lt;h3 id=&quot;5biF&quot;&gt;2. &lt;a href=&quot;#N2bX&quot;&gt;Введение&lt;/a&gt;&lt;/h3&gt;
  &lt;h3 id=&quot;lmBE&quot;&gt;3. &lt;a href=&quot;#H4B7&quot;&gt;Переменные&lt;/a&gt;&lt;/h3&gt;
  &lt;blockquote id=&quot;Rp9I&quot;&gt;3.1. Имена переменных&lt;/blockquote&gt;
  &lt;blockquote id=&quot;NY2X&quot;&gt;3.2. Типы значений&lt;/blockquote&gt;
  &lt;blockquote id=&quot;hUUL&quot;&gt;3.3. Объявления переменных&lt;/blockquote&gt;
  &lt;h3 id=&quot;gMnf&quot;&gt;4. &lt;a href=&quot;#9rG8&quot;&gt;Объекты&lt;/a&gt;&lt;/h3&gt;
  &lt;blockquote id=&quot;0lbn&quot;&gt;4.1. Действия со свойствами объекта&lt;/blockquote&gt;
  &lt;blockquote id=&quot;CYiM&quot;&gt;4.2. Вложенные свойства объектов&lt;/blockquote&gt;
  &lt;blockquote id=&quot;IgJv&quot;&gt;4.3. Использование переменных как значения свойств &lt;/blockquote&gt;
  &lt;blockquote id=&quot;uDm0&quot;&gt;4.4. Глобальные объекты&lt;/blockquote&gt;
  &lt;blockquote id=&quot;VNAj&quot;&gt;4.5. Методы объекта&lt;/blockquote&gt;
  &lt;h3 id=&quot;QZCh&quot;&gt;5. &lt;a href=&quot;#HEZz&quot;&gt;JSON&lt;/a&gt;&lt;/h3&gt;
  &lt;h3 id=&quot;0BMV&quot;&gt;6. &lt;a href=&quot;#TC8I&quot;&gt;Мутации&lt;/a&gt;&lt;/h3&gt;
  &lt;blockquote id=&quot;xlY0&quot;&gt;6.1. Способы избежать мутаций&lt;/blockquote&gt;
  &lt;h3 id=&quot;WJim&quot;&gt;7. &lt;a href=&quot;#GIMU&quot;&gt;Функции&lt;/a&gt;&lt;/h3&gt;
  &lt;blockquote id=&quot;oUib&quot;&gt;7.1. Неявный возврат значения&lt;/blockquote&gt;
  &lt;blockquote id=&quot;iCQ9&quot;&gt;7.2. Параметры функции&lt;/blockquote&gt;
  &lt;blockquote id=&quot;QChg&quot;&gt;7.3. Мутации объектов через функции&lt;/blockquote&gt;
  &lt;blockquote id=&quot;hB7V&quot;&gt;7.4. Коллбэк функция&lt;/blockquote&gt;
  &lt;blockquote id=&quot;uFl4&quot;&gt;7.5. JSDOC-комментарии&lt;/blockquote&gt;
  &lt;h3 id=&quot;wyTZ&quot;&gt;8. &lt;a href=&quot;#bhSM&quot;&gt;Области видимости&lt;/a&gt;&lt;/h3&gt;
  &lt;h3 id=&quot;Cjzq&quot;&gt;9. &lt;a href=&quot;#JkiP&quot;&gt;Ложные значение&lt;/a&gt;&lt;/h3&gt;
  &lt;h3 id=&quot;iYZC&quot;&gt;10. &lt;a href=&quot;#1xHQ&quot;&gt;Операторы&lt;/a&gt;&lt;/h3&gt;
  &lt;h3 id=&quot;rVLW&quot;&gt;11. &lt;a href=&quot;#kiJ8&quot;&gt;Конкатенация строк&lt;/a&gt;&lt;/h3&gt;
  &lt;h3 id=&quot;wBnw&quot;&gt;12. &lt;a href=&quot;#QsF8&quot;&gt;Обработка ошибок&lt;/a&gt;&lt;/h3&gt;
  &lt;h3 id=&quot;LYOz&quot;&gt;13. &lt;a href=&quot;#s1lL&quot;&gt;Инструкции&lt;/a&gt;&lt;/h3&gt;
  &lt;h3 id=&quot;E3O3&quot;&gt;14. &lt;a href=&quot;#jFL1&quot;&gt;Массивы&lt;/a&gt;&lt;/h3&gt;
  &lt;blockquote id=&quot;lCzd&quot;&gt;14.1. Чтение значений массива&lt;/blockquote&gt;
  &lt;blockquote id=&quot;OyEK&quot;&gt;14.2. Методы массивов&lt;/blockquote&gt;
  &lt;h3 id=&quot;8SDb&quot;&gt;15. &lt;a href=&quot;#mhYq&quot;&gt;Деструктуризация&lt;/a&gt;&lt;/h3&gt;
  &lt;h3 id=&quot;q8DY&quot;&gt;16. &lt;a href=&quot;#Q0Lp&quot;&gt;Условные инструкции&lt;/a&gt;&lt;/h3&gt;
  &lt;h3 id=&quot;w6oZ&quot;&gt;17. &lt;a href=&quot;#zf4q&quot;&gt;Тернарный оператор&lt;/a&gt;&lt;/h3&gt;
  &lt;h3 id=&quot;X4da&quot;&gt;18. &lt;a href=&quot;#G2Xo&quot;&gt;Циклы&lt;/a&gt;&lt;/h3&gt;
  &lt;blockquote id=&quot;8jFC&quot;&gt;18.1. Цикл &lt;em&gt;for&lt;/em&gt;&lt;/blockquote&gt;
  &lt;blockquote id=&quot;VUeE&quot;&gt;18.2. Метод массивов &lt;em&gt;forEach&lt;/em&gt;&lt;/blockquote&gt;
  &lt;blockquote id=&quot;dKZo&quot;&gt;18.3. Циклы &lt;em&gt;while и do while&lt;/em&gt;&lt;/blockquote&gt;
  &lt;blockquote id=&quot;EEwb&quot;&gt;18.4. Цикл &lt;em&gt;for in&lt;/em&gt; для объектов&lt;/blockquote&gt;
  &lt;blockquote id=&quot;6nto&quot;&gt;18.5. Метод &lt;em&gt;forEach()&lt;/em&gt; для объектов&lt;/blockquote&gt;
  &lt;blockquote id=&quot;o8pi&quot;&gt;18.6. Цикл &lt;em&gt;for of&lt;/em&gt;&lt;/blockquote&gt;
  &lt;h3 id=&quot;fSed&quot;&gt;19. &lt;a href=&quot;#RyWC&quot;&gt;Модули&lt;/a&gt;&lt;/h3&gt;
  &lt;h3 id=&quot;1SX2&quot;&gt;20. &lt;a href=&quot;#k6X7&quot;&gt;Классы и прототипы&lt;/a&gt;&lt;/h3&gt;
  &lt;blockquote id=&quot;BPx6&quot;&gt;20.1. Статический метод&lt;/blockquote&gt;
  &lt;blockquote id=&quot;w9VQ&quot;&gt;20.2. Расширение других классов&lt;/blockquote&gt;
  &lt;blockquote id=&quot;f9ay&quot;&gt;20.3. Примитивные значения&lt;/blockquote&gt;
  &lt;h3 id=&quot;aYxa&quot;&gt;21. &lt;a href=&quot;#Ez0U&quot;&gt;Промисы&lt;/a&gt;&lt;/h3&gt;
  &lt;h3 id=&quot;kl6G&quot;&gt;22. &lt;a href=&quot;#dEYM&quot;&gt;Асинхронные функции&lt;/a&gt;&lt;/h3&gt;
  &lt;blockquote id=&quot;S3vb&quot;&gt;22.1. Переход с промисов на ASYNC/AWAIT&lt;/blockquote&gt;
  &lt;p id=&quot;60Hi&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;R1Ct&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;XZvR&quot;&gt;1. Отзыв о курсе&lt;/h2&gt;
  &lt;p id=&quot;hjMn&quot;&gt;Я только начинаю изучение JS и курс Богдана показался мне самым понятным из тех что я нашел. Подкупили простые слайды и приятный голос, - поэтому я начал именно с его курса. И не ошибся.&lt;/p&gt;
  &lt;p id=&quot;L9cD&quot;&gt;Просмотр курса занял не слишком много времени, но мое понимание JS с полного нуля знатно так прокачалось. Делая змейку по гайду с ютуба я понял 90% написанного кода, даже не пройдя курс целиком.&lt;/p&gt;
  &lt;p id=&quot;w0uj&quot;&gt;Видео смотрел на скорости 2х и не было ни одного момента где было бы что-то не понятно в словах, дикция у автора отличная. Поэтому настоятельно рекомендую ускорять видео, если будете проходить этот курс, в оригинале речь показалось очень медленной. &lt;/p&gt;
  &lt;h3 id=&quot;QwFg&quot;&gt;&lt;strong&gt;Не понятно&lt;/strong&gt;&lt;/h3&gt;
  &lt;p id=&quot;tUJA&quot;&gt;Единственный непонятный раздел в курсе - это коллбэк функции, тут мне пришлось загуглить чтоб разобраться что к чему. Все остальное объясняется очень хорошо и можно обойтись тем, что есть в курсе.&lt;/p&gt;
  &lt;h3 id=&quot;v0B7&quot;&gt;Задания&lt;/h3&gt;
  &lt;p id=&quot;EgGO&quot;&gt;На момент написания отзыва я прошел только 14 заданий из 80, но все задания проходил используя только информацию с курса, не гугля. Это сложно и иногда, чтоб найти тему задания приходилось проматывать много видео и искать где же Богдан это объяснял. Думаю стоило добавить в заданиях ссылки на разделы курса, в которых тема задания раскрывается. &lt;/p&gt;
  &lt;h3 id=&quot;RKve&quot;&gt;Курс рекомендую👍&lt;/h3&gt;
  &lt;p id=&quot;hO7j&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;rIdi&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/3f/c4/3fc42406-fa92-4f2d-b7ce-8554581884bc.jpeg&quot; width=&quot;1920&quot; /&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;xAdn&quot; data-align=&quot;center&quot;&gt;Сайт автора курса: &lt;a href=&quot;https://stashchuk.com/&quot; target=&quot;_blank&quot;&gt;stashchuk.com&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;maM9&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;52gm&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;N2bX&quot;&gt;2. Введение&lt;/h2&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;Y7Ul&quot;&gt;Самое важно в JavaScript это &lt;strong&gt;Выражение&lt;/strong&gt;, &lt;strong&gt;Функции&lt;/strong&gt; и &lt;strong&gt;Объекты&lt;/strong&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;Exfb&quot;&gt;Практически все сущности в JS это &lt;strong&gt;объекты&lt;/strong&gt; или ведут себя как объекты&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;ja02&quot;&gt;&lt;strong&gt;Объект&lt;/strong&gt; — это набор свойств&lt;strong&gt; &lt;em&gt;&amp;quot;имя: значение&amp;quot; &lt;/em&gt;&lt;/strong&gt;или &lt;strong&gt;&lt;em&gt;&amp;quot;ключ: значение&amp;quot; &lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;6Ovv&quot;&gt;Разбор выражения &lt;em&gt;console.log&lt;/em&gt;, который выводит в консоль &lt;em&gt;Hello World:&lt;/em&gt;&lt;/p&gt;
  &lt;pre id=&quot;aWmh&quot; data-lang=&quot;javascript&quot;&gt;console.log(&amp;#x27;Hello World&amp;#x27;)

console       // Это объект у которого есть свойства (имя: значение)
.             // Это точечная запись. Оператор
log()         // Это метод (функция) одного из свойств объекта consol
()            // Это оператор вызова функции
&amp;#x27;Hello World&amp;#x27; // это значение типа String (Строка). 
              // Может быть как в двойных кавычках, так и в одинарных&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;CnAT&quot;&gt;Выражения всегда возвращают значения&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;RbzV&quot;&gt;Примеры выражений:&lt;/p&gt;
  &lt;pre id=&quot;A5D7&quot; data-lang=&quot;javascript&quot;&gt;&amp;#x27;abc&amp;#x27;                 // Вернет значение &amp;#x27;abc&amp;#x27;
10                    // Вернет 10
5 + 2                 // Вернет результат 7. Тут есть оператор +
с = 10                // = это оператор присвоения. Результатом будет 10
&amp;#x27;Good &amp;#x27; + &amp;#x27;Morning&amp;#x27;   // Вернет &amp;#x27;Good Morning&amp;#x27;
a &amp;lt;= b || c !== d     // Вернет true или false. Логические операторы
                      // меньше или равно, &lt;/pre&gt;
  &lt;p id=&quot;x24X&quot;&gt;Выражение с побочными действиями (SideEffects):&lt;/p&gt;
  &lt;pre id=&quot;8q09&quot; data-lang=&quot;javascript&quot;&gt;a = 15  // Это выражение присваивания, где переменной a присваивается
        // значение 10, также это выражение возвращает значение 15
a++     // увеличивает значение переменной на единицу и вернет значение
myFunction(c, d)  // внутри функции проиходят какие-то действия&lt;/pre&gt;
  &lt;blockquote id=&quot;TIpo&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;rjLS&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;GBQy&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;H4B7&quot;&gt;3. Переменные&lt;/h2&gt;
  &lt;p id=&quot;gjFX&quot;&gt;Переменная — это коробка в которую мы можем положить значения, достать значение, заменить его на другое значение. Также мы можем дать этой коробке название.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;lbK1&quot;&gt;Переменные дают возможность &lt;strong&gt;повторного&lt;/strong&gt; доступа к значениям&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;hWaq&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;Lmc2&quot;&gt;3.1. Имена переменных&lt;/h3&gt;
  &lt;p id=&quot;rbmw&quot;&gt;Не стоит называть переменные &lt;em&gt;a b c&lt;/em&gt; и не стоит сокращать названия. Названия переменных должны быть понятны не только вам, но и другим разработчикам. Должны отражать суть и назначение переменных.&lt;/p&gt;
  &lt;p id=&quot;aU7o&quot;&gt;Есть 3 типа имен для переменных:&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;CMLw&quot;&gt;PascalCase - для типов и классы.&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;rI8w&quot;&gt;DB_USER - значения известны до запуска приложения и не меняются. Константы.&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(24,  24%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;nvxB&quot;&gt;camelCase - для всех остальных переменных.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;9uPf&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;laMo&quot;&gt;3.2. Типы значений&lt;/h3&gt;
  &lt;p id=&quot;Te0E&quot;&gt;Тип переменной определяется типом значения, которое ей присвоено.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;mMgT&quot;&gt;В JavaScript мы можем переопределять тип переменной сколько угодно раз так как JS это динамически типизируемый язык.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;jwzR&quot;&gt;Существуют &lt;strong&gt;примитивные&lt;/strong&gt; типы значений, это те значения которые хранятся непосредственно в переменных. К примитивным относятся:&lt;/p&gt;
  &lt;ul id=&quot;Oeni&quot;&gt;
    &lt;li id=&quot;udi1&quot;&gt;&lt;strong&gt;&lt;em&gt;number&lt;/em&gt; &lt;/strong&gt;(число) — это любое числовое значение, в том числе и дробные (1, -2, 3, 5.6, 1.15).&lt;/li&gt;
    &lt;li id=&quot;9N4i&quot;&gt;&lt;strong&gt;&lt;em&gt;string&lt;/em&gt; &lt;/strong&gt;(строка) — это любой текст. Можно использовать как двойные, так и одинарные кавычки.&lt;/li&gt;
    &lt;li id=&quot;4eXg&quot;&gt;&lt;em&gt;&lt;strong&gt;boolean&lt;/strong&gt;&lt;/em&gt; (логический) — всего 2 значения &lt;em&gt;true&lt;/em&gt; и &lt;em&gt;false&lt;/em&gt;.&lt;/li&gt;
    &lt;li id=&quot;cQuI&quot;&gt;&lt;em&gt;&lt;strong&gt;undefined&lt;/strong&gt;&lt;/em&gt; (неопределенный) — только значение &lt;em&gt;undefined&lt;/em&gt;. Значение не определено.&lt;/li&gt;
    &lt;li id=&quot;TlbJ&quot;&gt;&lt;em&gt;&lt;strong&gt;null&lt;/strong&gt;&lt;/em&gt; (нулевой) — только значение &lt;em&gt;null&lt;/em&gt;. Для указания отсутствия значения у переменной.&lt;/li&gt;
    &lt;li id=&quot;gH7k&quot;&gt;&lt;em&gt;&lt;strong&gt;symbol&lt;/strong&gt;&lt;/em&gt; (символ) — используется для создания уникальных значений (В этом курсе про этот тип переменных информации нет).&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;Kd7m&quot;&gt;Помимо примитивного, есть &lt;strong&gt;ссылочный&lt;/strong&gt; тип переменной. Такая переменная хранит в себе только &lt;strong&gt;ссылку&lt;/strong&gt; на значение:&lt;/p&gt;
  &lt;ul id=&quot;BH1x&quot;&gt;
    &lt;li id=&quot;7YtL&quot;&gt;&lt;em&gt;&lt;strong&gt;object&lt;/strong&gt;&lt;/em&gt; (объект) — это ссылочный тип.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;SjfB&quot;&gt;Так как переменная типа объект хранит только ссылку на объект, то изменение этого объекта коснутся всех переменных имеющих туже ссылку:&lt;/p&gt;
  &lt;pre id=&quot;HQQr&quot; data-lang=&quot;javascript&quot;&gt;const objectA = {
  name: &amp;#x27;Alex&amp;#x27;,
  age: 40
}
const objectB = objectA
// Создаем еще один объект копирующий первый
objectB.name = &amp;#x27;Victor&amp;#x27;
// Меняем значение свойства name в ObjectB
console.log(objectA.name)
// Получаем значение Victor, первый объект также изменился&lt;/pre&gt;
  &lt;p id=&quot;gQ4E&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;coLe&quot;&gt;3.3. Объявления переменных&lt;/h3&gt;
  &lt;p id=&quot;BxDM&quot;&gt;Чтобы создать переменную и присвоить ей значение, можно использовать ключевые слова &lt;em&gt;const&lt;/em&gt;, &lt;em&gt;let&lt;/em&gt; или &lt;em&gt;var&lt;/em&gt;: &lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(170, 33%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;CRCg&quot;&gt;&lt;em&gt;const&lt;/em&gt; - не позволяет менять значение переменной. Объявление и присваивание обязательно прописывается одной строкой. &lt;/p&gt;
  &lt;/section&gt;
  &lt;pre id=&quot;bMpe&quot; data-lang=&quot;javascript&quot;&gt;const myAge = 40
// объявили переменную myAge и сразу присвоили ей значение 40
myAge = 50
// попытались присвоить переменной myAge новое значение 50
// и получили ошибку!)&lt;/pre&gt;
  &lt;p id=&quot;10HB&quot;&gt;Стоит использовать &lt;em&gt;const&lt;/em&gt; максимально, где это возможно. Т.к. он решает некоторые проблемы связанные с динамической типизацией языка JS.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;McUq&quot;&gt;&lt;em&gt;let&lt;/em&gt; - для всех остальных переменных.&lt;/p&gt;
  &lt;/section&gt;
  &lt;pre id=&quot;DA1F&quot; data-lang=&quot;javascript&quot;&gt;let myAge
// объявили переменную myAge
myAge = 50
// присвоили переменной myAge значение 50
let youHere = true
//объявили переменную youHere и сразу присвоили ей значение true
youHere = false
//присвоили переменной youHere новое значение false&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;6aLr&quot;&gt;&lt;em&gt;var&lt;/em&gt; - устаревший тип и использовать его больше не имеет смысла.&lt;/p&gt;
  &lt;/section&gt;
  &lt;blockquote id=&quot;7HFk&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;yEe9&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;VyhZ&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;9rG8&quot;&gt;4. Объекты&lt;/h2&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;azkd&quot;&gt;&lt;strong&gt;Объект&lt;/strong&gt; — это набор &lt;strong&gt;свойств.&lt;/strong&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;45aF&quot;&gt;Практически все сущности в JS это объекты или ведут себя как объекты. Например, массив и функция - это объекты, а число и строка ведут себя как объекты, хотя являются примитивными значениями.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;prUe&quot;&gt;&lt;strong&gt;Свойство&lt;/strong&gt; — это пара &lt;em&gt;&lt;strong&gt;имя: значение.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;qNel&quot;&gt;Значением также может быть другой объект (&lt;a href=&quot;#8orm&quot;&gt;вложенный объект&lt;/a&gt;):&lt;/p&gt;
  &lt;pre id=&quot;seqH&quot; data-lang=&quot;javascript&quot;&gt;const objectA = {
height: 550,
weight: 440,
xyz: {
  x: -1,
  y: 2,
  z: 3.5
  },
title: &amp;#x27;cube&amp;#x27;&lt;/pre&gt;
  &lt;p id=&quot;ymDe&quot;&gt;После каждого свойства ставиться запятая, а после последнего свойства в объекте запятую можно опустить.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;q0bq&quot;&gt;Порядок свойств в объекте &lt;strong&gt;не имеет&lt;/strong&gt; значения&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;3zth&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;Qprf&quot;&gt;4.1. Действия со свойствами объекта&lt;/h3&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;K1LS&quot;&gt;С помощью оператора &lt;em&gt;&lt;strong&gt;точка&lt;/strong&gt;&lt;/em&gt; . мы получаем доступ к свойствам объектов. &lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;zsIm&quot;&gt;По аналогии с вызовом метода &lt;em&gt;log&lt;/em&gt; объекта &lt;em&gt;&lt;strong&gt;console&lt;/strong&gt;&lt;/em&gt; используем точку после названия объекта для получения значения свойств объекта &lt;em&gt;aboutMe:&lt;/em&gt;&lt;/p&gt;
  &lt;pre id=&quot;mpPo&quot; data-lang=&quot;javascript&quot;&gt;const aboutMe = {
  city: &amp;#x27;Moscow&amp;#x27;,
  designer: true,
  country: &amp;#x27;Russia&amp;#x27;
}
console.log(aboutMe.city)
// Получим &amp;#x27;Moscow&amp;#x27;
console.log(aboutMe.designer)
// Получим true&lt;/pre&gt;
  &lt;p id=&quot;oTZB&quot;&gt;Чтобы присвоить новое значение используем оператор &lt;em&gt;=&lt;/em&gt;, а чтобы удалить свойство - ключевое слово&lt;em&gt;delete. Если мы присвоим значение несуществующему свойству, то это свойство создастся автоматически:&lt;/em&gt;&lt;/p&gt;
  &lt;pre id=&quot;500L&quot; data-lang=&quot;javascript&quot;&gt;const aboutMe = {
  city: &amp;#x27;Moscow&amp;#x27;,
  designer: true,
  country: &amp;#x27;Russia&amp;#x27;
}
aboutMe.city = &amp;#x27;Perm&amp;#x27;
// Переопределим значение свойства city
aboutMe.time = 3
// Добавим новое свойство time со значением 3 в объект
delete aboutMe.designer
// Удалим свойство designer из объекта
console.log(aboutMe)
// Получим объект {city: &amp;#x27;Perm&amp;#x27;, country: &amp;#x27;Russia&amp;#x27;, time: 3}&lt;/pre&gt;
  &lt;p id=&quot;btTQ&quot;&gt;Кроме точки, доступ к свойствам объекта можно получить с помощью &lt;em&gt;[ ]&lt;/em&gt; (bracket notation).&lt;/p&gt;
  &lt;pre id=&quot;fzrM&quot; data-lang=&quot;javascript&quot;&gt;const myCity = {
  city: &amp;#x27;Kiev&amp;#x27;
}
myCity[&amp;#x27;year&amp;#x27;] = 2022
console.log(myCity.year)
// Получим 2022, мы добавили новое свойство year со значением 2022&lt;/pre&gt;
  &lt;p id=&quot;AFTQ&quot;&gt;Синтаксис с &lt;em&gt;[ ]&lt;/em&gt; используется когда название свойства является значением той или иной переменной, например:&lt;/p&gt;
  &lt;pre id=&quot;xm68&quot; data-lang=&quot;javascript&quot;&gt;const myCity = {
  city: &amp;#x27;Kiev&amp;#x27;,
  year: 2022
}
const countryPropertyName = &amp;#x27;country&amp;#x27;
// Создадим новую переменную со значение country
myCity[countryPropertyName] = &amp;#x27;Ukraine&amp;#x27;
// Добавили свойство с именем взятым из значения переменной
// countryPropertyName, т.е. country
console.log(myCity)
// Получим объект {city: &amp;#x27;Kiev&amp;#x27;, year: 2022, country: &amp;#x27;Ukraine&amp;#x27;}&lt;/pre&gt;
  &lt;p id=&quot;RFDm&quot;&gt;В &lt;em&gt;[ ]&lt;/em&gt; мы можем указать любое выражение, и результат этого выражения, станет названием свойства. &lt;/p&gt;
  &lt;p id=&quot;e3el&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;ze07&quot;&gt;4.2. Вложенные свойства объектов&lt;/h3&gt;
  &lt;p id=&quot;a1ZI&quot;&gt;Оператор точка также позволяет получить доступ к вложенным объектам. Можно комбинировать с bracket notation:&lt;/p&gt;
  &lt;pre id=&quot;CcAO&quot; data-lang=&quot;javascript&quot;&gt;const myCity = {
  city: &amp;#x27;Kiev&amp;#x27;,
  date: {
    month: 4,
    day: 22
  }
}
console.log(myCity.date.day)
// Получим 22
console.log(myCity.date[&amp;#x27;day&amp;#x27;])
// Получим также 22&lt;/pre&gt;
  &lt;p id=&quot;WoIT&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;D8FW&quot;&gt;4.3. Использование переменных как значения свойств &lt;/h3&gt;
  &lt;p id=&quot;5miw&quot;&gt;Мы можем использовать имена переменных в качестве значений свойств. При создании объекта в него будут скопированы значения этих переменных:&lt;/p&gt;
  &lt;pre id=&quot;VX4z&quot; data-lang=&quot;javascript&quot;&gt;const name = &amp;#x27;Alex&amp;#x27;
const age = 40

const userProfile = {
  userName: name,
  userAge: age,
  userCity: &amp;#x27;Pskov&amp;#x27;
}
console.log(userProfile)
// Получим объект {userName: &amp;#x27;Alex&amp;#x27;, userAge: 40, userCity: &amp;#x27;Pskov&amp;#x27;}&lt;/pre&gt;
  &lt;p id=&quot;gMiB&quot;&gt;Для удобства, можно сокращать написание свойства до названия переменной. Но тогда имя свойства будет такое же, как имя переменной:&lt;/p&gt;
  &lt;pre id=&quot;OOaE&quot; data-lang=&quot;javascript&quot;&gt;const name = &amp;#x27;Alex&amp;#x27;
const age = 40

const userProfile = {
  name,
  age,
  userCity: &amp;#x27;Pskov&amp;#x27;
}
console.log(userProfile)
// Получим объект {name: &amp;#x27;Alex&amp;#x27;, age: 40, userCity: &amp;#x27;Pskov&amp;#x27;}&lt;/pre&gt;
  &lt;p id=&quot;jMPa&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;QW2r&quot;&gt;4.4. Глобальные объекты&lt;/h3&gt;
  &lt;p id=&quot;6Shh&quot;&gt;Глобальный объект - это встроенный объект с огромным количеством свойств и методов. Для браузеров это &lt;em&gt;window&lt;/em&gt; или &lt;em&gt;globalThis&lt;/em&gt;, для &lt;strong&gt;node.js&lt;/strong&gt; это &lt;em&gt;global&lt;/em&gt; или &lt;em&gt;globalThis.&lt;/em&gt;&lt;/p&gt;
  &lt;p id=&quot;0oFP&quot;&gt;Мы можем использовать методы глобального объекта. Метод&lt;em&gt; log()&lt;/em&gt; один из таких методов:&lt;/p&gt;
  &lt;pre id=&quot;Enhr&quot; data-lang=&quot;javascript&quot;&gt;window.console.log(&amp;#x27;Hello World!&amp;#x27;)
// Объект console является одним из свойств глобального объекта window&lt;/pre&gt;
  &lt;p id=&quot;UNEn&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;lbGC&quot;&gt;4.5. Методы объекта&lt;/h3&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;WCgZ&quot;&gt;&lt;strong&gt;Метод&lt;/strong&gt; — это свойство объекта, значение которого - функция&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;yj8N&quot;&gt;Мы можем вызвать метод объекта использую точечную запись&lt;em&gt; .&lt;/em&gt; (оператор точка) и &lt;em&gt;()&lt;/em&gt; круглые скобки&lt;em&gt;:&lt;/em&gt;&lt;/p&gt;
  &lt;pre id=&quot;kPpX&quot; data-lang=&quot;javascript&quot;&gt;myCity.city // Получаем доступ к значению свойства
myCity.helloMyCity() // Вызываем метод объекта&lt;/pre&gt;
  &lt;p id=&quot;G3gd&quot;&gt;В объекте &lt;em&gt;myCity&lt;/em&gt; &lt;em&gt;city является обычным свойством&lt;/em&gt;, а &lt;em&gt;helloMyCity() методом:&lt;/em&gt;&lt;/p&gt;
  &lt;pre id=&quot;jtkB&quot; data-lang=&quot;javascript&quot;&gt;const myCity = {
  city: &amp;#x27;Pskov&amp;#x27;,
  helloMyCity: function () {
    console.log(&amp;#x27;Hello my City&amp;#x27;)
  }
}
myCity.helloMyCity()&lt;/pre&gt;
  &lt;p id=&quot;4SEJ&quot;&gt;Для удобства, можно опускать ключевое слово &lt;em&gt;function&lt;/em&gt; и ставить круглые скобки сразу после названия свойства:&lt;/p&gt;
  &lt;pre id=&quot;PFSE&quot; data-lang=&quot;javascript&quot;&gt;const myCity = {
  city: &amp;#x27;Pskov&amp;#x27;,
  helloMyCity() { // Сократили слово function
    console.log(&amp;#x27;Hello my City&amp;#x27;)
  }
}
myCity.helloMyCity()&lt;/pre&gt;
  &lt;blockquote id=&quot;ARMG&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;fI34&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;Jn6O&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;HEZz&quot;&gt;5. JavaScript Object Notation (JSON)&lt;/h2&gt;
  &lt;p id=&quot;2u1C&quot;&gt;Формат обмена данными с серверами. Если добавить переносы, то формат записи &lt;em&gt;JSON&lt;/em&gt; похож на формат записи JS:&lt;/p&gt;
  &lt;pre id=&quot;YKtV&quot;&gt;{
  &amp;quot;id&amp;quot;: 10,
  &amp;quot;title&amp;quot;: &amp;quot;user&amp;quot;,
  &amp;quot;status&amp;quot;: false
}&lt;/pre&gt;
  &lt;p id=&quot;2uTA&quot;&gt;Но передается &lt;em&gt;JSON&lt;/em&gt; в виде строки (&lt;em&gt;string&lt;/em&gt;):&lt;/p&gt;
  &lt;pre id=&quot;ZTcE&quot; data-lang=&quot;javascript&quot;&gt;&amp;#x27;{&amp;quot;id&amp;quot;:10,&amp;quot;title&amp;quot;:&amp;quot;user&amp;quot;,&amp;quot;status&amp;quot;:false}&amp;#x27;&lt;/pre&gt;
  &lt;p id=&quot;E7z8&quot;&gt;Чтобы конвертировать данные &lt;em&gt;JSON&lt;/em&gt; в объект JS, существует метод &lt;em&gt;parse()&lt;/em&gt; объекта &lt;em&gt;JSON&lt;/em&gt;, а для конвертации из JS в &lt;em&gt;JSON&lt;/em&gt;, есть метод &lt;em&gt;stringify()&lt;/em&gt;&lt;/p&gt;
  &lt;pre id=&quot;nyyI&quot; data-lang=&quot;javascript&quot;&gt;JSON.parse() // конвертирует строку JSON в JS
JSON.stringify() // конвертирует объект JS в JSON&lt;/pre&gt;
  &lt;p id=&quot;7u6T&quot;&gt;После выполнения метода &lt;em&gt;JSON.parse()&lt;/em&gt;, мы получим привычный JS набор свойств:&lt;/p&gt;
  &lt;pre id=&quot;8hB6&quot; data-lang=&quot;javascript&quot;&gt;{
  id: 10,
  title: &amp;#x27;user&amp;#x27;,
  status: false
}&lt;/pre&gt;
  &lt;p id=&quot;TzRs&quot;&gt;Пробуем конвертировать объект в &lt;em&gt;JSON&lt;/em&gt; и обратно:&lt;/p&gt;
  &lt;pre id=&quot;DMqh&quot; data-lang=&quot;javascript&quot;&gt;const normalJavaScriptObject = {
  id: 10,
  title: &amp;#x27;user&amp;#x27;,
  status: false
}
const jsonString = JSON.stringify(normalJavaScriptObject)
// Создаем новую переменную и присваиваем ей значение JSON
console.log(jsonString)
// Получим строку &amp;#x27;{&amp;quot;id&amp;quot;:10,&amp;quot;title&amp;quot;:&amp;quot;user&amp;quot;,&amp;quot;status&amp;quot;:false}&amp;#x27;
const jsonParse = JSON.parse(jsonString)
// Создаем новую переменную и конвертируем строку JSON в объект
console.log(jsonParse)
// Получим объект {id: 10, title: &amp;#x27;user&amp;#x27;, status: false}&lt;/pre&gt;
  &lt;blockquote id=&quot;XHtx&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;aNMt&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;gnae&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;TC8I&quot;&gt;6. Мутации&lt;/h2&gt;
  &lt;p id=&quot;NUdo&quot;&gt;Значения переменных &lt;a href=&quot;#opfY&quot;&gt;примитивного типа&lt;/a&gt; хранятся в самих переменных, поэтому при присвоении одной переменной значения другой переменной происходит копирование этого значения (copy by value):&lt;/p&gt;
  &lt;pre id=&quot;lDc1&quot; data-lang=&quot;javascript&quot;&gt;const a = 10
let b = a
// Создаем переменную b и копируем в нее значение переменной a, равное 10
b = 30
// Меняем значение переменной b на 30
console.log(a)
// Видим что значение переменной a по прежнему 10
console.log(b)
// А значение переменной b теперь 30&lt;/pre&gt;
  &lt;p id=&quot;7hdz&quot;&gt;Переменные ссылочного типа, содержат ссылку на объект, поэтому при присвоении одной переменной этой ссылки из другой переменной, переменные будут иметь одну и туже ссылку на один и тот же объект в памяти (copy by reference):&lt;/p&gt;
  &lt;pre id=&quot;9wW1&quot; data-lang=&quot;javascript&quot;&gt;const user = {
  name: &amp;#x27;Sofia&amp;#x27;,
  age: 50
}
user.age = 22
// Присвоим значение 22 свойству age 
user.isAdult = true
// Создадим новое свойство isAdult со значением true
console.log(user.age)
console.log(user.isAdult)
// Убедимся, что значения age и isAdult переменной user равны 22 и true

const userCopy
// Создадим новую переменную и присвоим ей значение переменной user
userCopy.age = 44
userCopy.isAdult = false
// Изменим значения свойств для новой переменной userCopy

console.log(user.age)
console.log(user.isAdult)
// Значения свойств age и isAdult первой переменной user теперь
// равны 44 и false, т.к. мы изменили объект по ссылке
// через переменную userCopy&lt;/pre&gt;
  &lt;p id=&quot;3r7j&quot;&gt;Мы изменили объект через копию переменной имеющую такую же ссылку на объект. Такое поведение называется &lt;strong&gt;мутированием&lt;/strong&gt;.&lt;/p&gt;
  &lt;p id=&quot;oYde&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;lgOi&quot;&gt;6.1. Способы избежать мутаций&lt;/h3&gt;
  &lt;p id=&quot;A5xW&quot;&gt;&lt;strong&gt;Метод&lt;em&gt; Object.assign(). &lt;/em&gt;&lt;/strong&gt;Чтобы избежать мутаций можно использовать метод &lt;em&gt;assign()&lt;/em&gt; объекта &lt;em&gt;Object.&lt;/em&gt; При создании копии объекта, этот метод скопирует все свойства первого объекта и создаст новый объект:&lt;/p&gt;
  &lt;pre id=&quot;jRh9&quot; data-lang=&quot;javascript&quot;&gt;const user = {
  name: &amp;#x27;Sofia&amp;#x27;,
  age: 50
}
const userCopy = Object.assign({}, user)&lt;/pre&gt;
  &lt;p id=&quot;9kqq&quot;&gt;&lt;strong&gt;Оператор &lt;em&gt;три точки&lt;/em&gt;(...)&lt;/strong&gt;.Также можно воспользоваться оператором &lt;em&gt;три точки&lt;/em&gt; (spread), он разделяет объект на свойства. И если мы применим такой оператор при создании нового объекта, то получим полностью новый объект, с новой ссылкой.&lt;/p&gt;
  &lt;pre id=&quot;OsRx&quot; data-lang=&quot;javascript&quot;&gt;const user = {
  name: &amp;#x27;Sofia&amp;#x27;,
  age: 50
}
const userCopy = {...user}&lt;/pre&gt;
  &lt;p id=&quot;4F31&quot;&gt;Но такие методы не подойдут если у копируемого объекта есть вложенные свойства, тоже являющиеся объектами, так как ссылки на них сохранятся.&lt;/p&gt;
  &lt;p id=&quot;Iiwj&quot;&gt;&lt;strong&gt;Методы &lt;em&gt;JSON.parse()&lt;/em&gt; и &lt;em&gt;JSON.stringify(). &lt;/em&gt;&lt;/strong&gt;Чтобы избежать мутаций полностью, даже имея вложенные объекты, можно воспользоваться конвертацией объекта в &lt;a href=&quot;#EzcE&quot;&gt;JSON&lt;/a&gt; и обратно:&lt;/p&gt;
  &lt;pre id=&quot;duR4&quot; data-lang=&quot;javascript&quot;&gt;const user = {
  name: &amp;#x27;Sofia&amp;#x27;,
  age: 50
}
const userCopy = JSON.parse(JSON.stringify(user))
// Конвертируем объект user в JSON, а потом создаем новую переменную
// userCopy и присваеваем ей полученное значение JSON
// конвертируя его обратно в JS&lt;/pre&gt;
  &lt;blockquote id=&quot;CPWO&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;sXyk&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;yl51&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;GIMU&quot;&gt;7. Функции&lt;/h2&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;Ip1p&quot;&gt;Функция - это блок кода, который можно выполнять &lt;strong&gt;многократно&lt;/strong&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;q0G6&quot;&gt;&lt;strong&gt;Функция - это объект&lt;/strong&gt;, и как любой объект она имеет свойства. Это можно увидеть применив метод метод console.dir() на функции:&lt;/p&gt;
  &lt;pre id=&quot;jO6b&quot; data-lang=&quot;javascript&quot;&gt;function myFn() {
  console.log(&amp;#x27;Hello&amp;#x27;)
}
console.dir(myFn)
// Метод dir() покажет свойства функции как объекта&lt;/pre&gt;
  &lt;p id=&quot;hpha&quot;&gt;Функция может быть:&lt;/p&gt;
  &lt;ul id=&quot;G2hJ&quot;&gt;
    &lt;li id=&quot;wc2D&quot;&gt;&lt;strong&gt;Именованной&lt;/strong&gt; (Объявленная функция). Объявляем функцию сразу указывая ее будущее имя. Будет аналогична анонимной функции присвоенной переменной через ключевое слово &lt;em&gt;let&lt;/em&gt;;&lt;/li&gt;
    &lt;li id=&quot;RpG5&quot;&gt;&lt;strong&gt;Анонимной&lt;/strong&gt;. Анонимными являются функциональные выражения и стрелочные функции;&lt;/li&gt;
    &lt;li id=&quot;Q1eh&quot;&gt;&lt;strong&gt;Присвоенная переменной&lt;/strong&gt;. Если функциональное выражение и стрелочную функцию присвоить переменной, то будет функция присвоенная переменной;&lt;/li&gt;
    &lt;li id=&quot;tZa0&quot;&gt;&lt;strong&gt;Аргументом&lt;/strong&gt;. Например, при вызове другой функции (&lt;a href=&quot;#CAc3&quot;&gt;callback function&lt;/a&gt;);&lt;/li&gt;
    &lt;li id=&quot;vPVt&quot;&gt;&lt;strong&gt;Методом&lt;/strong&gt;, т.е. значением свойства в объекте.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;pre id=&quot;va0F&quot; data-lang=&quot;javascript&quot;&gt;function myFn() {
  console.log(&amp;#x27;Hello&amp;#x27;)
}
// Именованая функция

function () {
  console.log(&amp;#x27;Hello&amp;#x27;)
}
// Функциональное выражение (анонимная функция)

const myFn = function () {
  console.log(&amp;#x27;Hello&amp;#x27;)
}
// Функциональное выражение присвоеное переменной

const myFn = () =&amp;gt; {
  console.log(&amp;#x27;Hello&amp;#x27;)
}
// Стрелочная функция присвоеная переменной

const myFn = () =&amp;gt; console.log(&amp;#x27;Hello&amp;#x27;)
// Если у стрелочной функции всего одно выражение, то {} можно опустить
// Функция будет неявно возвращать значение этого выражения

setTimeout(myFn, 5000)
// Функция как аргумент другой функции

const myObject = {
  name = &amp;#x27;Alex&amp;#x27;
  print: function
// Функция как значение одного из свойств объекта (метод)&lt;/pre&gt;
  &lt;h3 id=&quot;tyRb&quot;&gt;&lt;/h3&gt;
  &lt;p id=&quot;yaMt&quot;&gt;&lt;strong&gt;7.1. Неявный&lt;/strong&gt; возврат значения&lt;/p&gt;
  &lt;p id=&quot;6J6z&quot;&gt;Функция, как и любое выражение всегда возвращает значение. Если в функции &lt;strong&gt;явно&lt;/strong&gt; (командой &lt;em&gt;return&lt;/em&gt;) не указать какое именно значение она должна вернуть, то она всегда &lt;strong&gt;неявно&lt;/strong&gt; (без команды &lt;em&gt;return&lt;/em&gt;) возвращает &lt;em&gt;undefined:&lt;/em&gt;&lt;/p&gt;
  &lt;pre id=&quot;OgpL&quot; data-lang=&quot;javascript&quot;&gt;const myFn = () =&amp;gt; {
  5 + 5
}
// Такая функция вернет undefined, т.к. мы не указали что ей возвращать

const myFn = () =&amp;gt; {
  return 5 + 5
}
// Такая функция вернет сумму 10, т.к. мы ЯВНО указали
// командой ruturn, что ей нужно вернуть 

const myFn = () =&amp;gt; return 5 + 5
// Такая функция также вернет сумму 10, но уже НЕЯВНО, без команды ruturn&lt;/pre&gt;
  &lt;p id=&quot;ptOv&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;eldE&quot;&gt;7.2. Параметры функции&lt;/h3&gt;
  &lt;p id=&quot;RBQZ&quot;&gt;При объявлении функции опционально можно указать параметры, с которыми функция будет работать внутри себя:&lt;/p&gt;
  &lt;pre id=&quot;YnG9&quot; data-lang=&quot;javascript&quot;&gt;function mySum(a, b) {
// Указываем параметры a и b, это переменные которые действуют 
// только внутри функции в момент вызова функции
  let sum
  // Объявляем переменную sum, которая будет  
  sum = a + b
  return sum
  // Ключевое слово return указывает то, что должна вернуть функция.
}&lt;/pre&gt;
  &lt;p id=&quot;fwA8&quot;&gt;В момент вызова этой функции в круглых скобках указываются значения параметром функции - аргументы:&lt;/p&gt;
  &lt;pre id=&quot;PxrD&quot; data-lang=&quot;javascript&quot;&gt;function mySum(a, b) {
  let sum
  sum = a + b
  return sum
}
myFn(10, 3)
// Аргументы присваиваются параметрам по порядку
// Число 10 будет присвоено параметру a, а число 3 - параметру b&lt;/pre&gt;
  &lt;p id=&quot;OdQQ&quot;&gt;Можно указать какие параметры функция будет использовать по умолчанию, если не передано другое значение:&lt;/p&gt;
  &lt;pre id=&quot;8WW6&quot; data-lang=&quot;javascript&quot;&gt;function multByFactor(value, multiplier = 1) {
  return value * multiplier
}
// Аргумент multiplier будет равен 1 если не передано другое значение

multByFactor(10, 2)
// Вернет результат 20
multByFactor(5)
// Вернет результат 5, т.к. второй агрумент будет взят по умолчанию, это 1&lt;/pre&gt;
  &lt;p id=&quot;qw7s&quot;&gt;В примере функция создает объект, добавляет к нему все свойства из объекта post с помощью оператора ... и добавляет новое свойство со значением текущей даты с помощью метода &lt;em&gt;Date():&lt;/em&gt;&lt;/p&gt;
  &lt;pre id=&quot;zI3z&quot; data-lang=&quot;javascript&quot;&gt;const newPost = (post, addedAt = Date()) =&amp;gt; ({
  ...post,
  addedAt,
})
// Тело функции ({}) дополнительно обернуто круглыми скобками,
// это позволяет неявно вернуть объект, как результат функции

const firstPost = {
  id: 1,
  author: &amp;#x27;Pavel&amp;#x27;
}
newPost(firstPost)
// Функция вернет новый объект с тремя свойствами&lt;/pre&gt;
  &lt;p id=&quot;csUr&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;WaUD&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;bOoF&quot;&gt;7.3. Мутации объектов через функции&lt;/h3&gt;
  &lt;p id=&quot;h68j&quot;&gt;Аргументом в вызове функции может быть объект и в этом случае параметру функции будет передана ссылка на этот объект и все дальнейшие действия с этим параметром, будут вызывать мутации внешнего объекта по ссылке:&lt;/p&gt;
  &lt;pre id=&quot;YVFy&quot; data-lang=&quot;javascript&quot;&gt;const personOne = {
  name: &amp;#x27;Lara&amp;#x27;,
  age: 22
}

function increasePersonAge(person) {
  person.age += 1
  return person
}

increasePersonAge(personOne)
// Вызываем функцию с аргументом переменной personOne
console.log(personOne.age)
// Получим 23, т.к. внешний объект мутировал через изменение person&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;EsQ7&quot;&gt;Внутри функции &lt;strong&gt;не рекомендуется&lt;/strong&gt; мутировать внешние объекты.&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;RvPL&quot;&gt;Функция которая выполняет &lt;strong&gt;одну&lt;/strong&gt; задачу не меняет внешних переменных называется &lt;strong&gt;чистой функцией&lt;/strong&gt; (pure function).&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;Qu4T&quot;&gt;Чтобы избежать мутаций в функции можно использовать&lt;a href=&quot;#OfcC&quot;&gt; метод &lt;em&gt;assign()&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, &lt;a href=&quot;#UR6M&quot;&gt;три точки&lt;/a&gt; &lt;/em&gt;или&lt;em&gt; &lt;a href=&quot;#rvUO&quot;&gt;JSON&lt;/a&gt;&lt;/em&gt;, также как мы использовали их раннее:&lt;/p&gt;
  &lt;pre id=&quot;3d7c&quot; data-lang=&quot;javascript&quot;&gt;const personOne = {
  name: &amp;#x27;Lara&amp;#x27;,
  age: 22
}

function increasePersonAge(person) {
  const updatedPerson = Object.assign({}, person)
  // Создаем новый объект прямо внутри функции и начинаем работать с ним
  updatedPerson.age += 1
  return updatedPerson
}
const updatedPersonOne = increasePersonAge(personOne)
// Создаем новую переменную, вызываем функцию и
// присваиваем результат функции этой новой переменной&lt;/pre&gt;
  &lt;p id=&quot;MYSf&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;kL03&quot;&gt;7.4. Коллбэк функция (callback function)&lt;/h3&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;Y1pD&quot;&gt;&lt;strong&gt;Коллбэк&lt;/strong&gt; — это &lt;strong&gt;функция&lt;/strong&gt;, которая должна быть выполнена после того, как другая &lt;strong&gt;функция&lt;/strong&gt; завершит работу.&lt;/p&gt;
  &lt;/section&gt;
  &lt;pre id=&quot;hDr4&quot; data-lang=&quot;javascript&quot;&gt;function printFinish() {
  console.log(&amp;#x27;Finish&amp;#x27;)
}
console.log(&amp;#x27;Start&amp;#x27;)
// Печатаем в консоль Start
setTimeout(printFinish, 5000)
// Выполняем функцию printFinish после выполнения функции setTimeout
// setTimeout это встроенная функция, устанавливает таймер выполнения&lt;/pre&gt;
  &lt;p id=&quot;Uwgr&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;RFxK&quot;&gt;7.5. JSDOC-комментарии&lt;/h3&gt;
  &lt;p id=&quot;du87&quot;&gt;Такие комментарии позволяют указать какие типы переменных должны использоваться внутри функции:&lt;/p&gt;
  &lt;pre data-lang=&quot;javascript&quot; id=&quot;1e7F&quot;&gt;/**
*
* @param {number} a
* @param {number} b
* @returns {number} Разница чисел
*/
function myFn(a, b) {
  let c = a - b
  return c
}&lt;/pre&gt;
  &lt;blockquote id=&quot;WeEm&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;X3by&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;IItX&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;bhSM&quot;&gt;8. Области видимости&lt;/h2&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;j9Pg&quot;&gt;Глобальная область видимости - это наш файл в целом.&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;vSFS&quot;&gt;Локальная область видимости - это область внутри блока { }, между фигурными скобками.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;ijmK&quot;&gt;Может существовать целая цепочка областей видимости и переменные объявленные в локальных областях видимости не будут учитываться в глобальной области видимости.&lt;/p&gt;
  &lt;p id=&quot;ghnk&quot;&gt;При этом мы можем обратиться из локальной области видимости к переменной из глобальной области видимости, если в локальной области видимости не создана переменная с таким же именем:&lt;/p&gt;
  &lt;pre id=&quot;Zki3&quot; data-lang=&quot;javascript&quot;&gt;let a = &amp;#x27;New York&amp;#x27;
let b = &amp;#x27;New York&amp;#x27;
// Объявим две переменные и присвоим им значения New York

function myFn() {
  let b
  // Объявим переменную b внутри функции
  a = &amp;#x27;Las Vegas&amp;#x27;
  b = &amp;#x27;Las Vegas&amp;#x27;
  // Поменяем значения обеих переменных на Las Vegas
}

myFn()

console.log(a) // Получим &amp;#x27;Las Vegas&amp;#x27;
console.log(b) // Получим &amp;#x27;New York&amp;#x27;&lt;/pre&gt;
  &lt;blockquote id=&quot;4Uy2&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;gtDU&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;NQSq&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;JkiP&quot;&gt;9. Ложные значение&lt;/h2&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;jyCv&quot;&gt;Ложные значения, это те значения, которые дают false при приведении их к логическому типу boolean.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;PqxB&quot;&gt;К таким значениям относятся:&lt;/p&gt;
  &lt;pre id=&quot;PqxB&quot; data-lang=&quot;javascript&quot;&gt;false     // Ложь
0         // Ноль
&amp;#x27;&amp;#x27;        // Пустая строка
undefined // Значение неопределено
null      // Значения нет&lt;/pre&gt;
  &lt;p id=&quot;jgUt&quot;&gt;Привести значение к типу &lt;em&gt;boolean&lt;/em&gt; можно с помощью функции &lt;em&gt;Boolean()&lt;/em&gt;:&lt;/p&gt;
  &lt;pre id=&quot;g6pi&quot; data-lang=&quot;javascript&quot;&gt;const a = &amp;#x27;Alex&amp;#x27;
const b = &amp;#x27;&amp;#x27;

console.log(Boolean(a)) // true
console.log(Boolean(b)) // false&lt;/pre&gt;
  &lt;blockquote id=&quot;C74o&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;UvFW&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;AGbI&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;1xHQ&quot;&gt;10. Операторы&lt;/h2&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;rdhT&quot;&gt;&lt;strong&gt;Оператор &lt;/strong&gt;— это встроенная в JS функция&lt;/p&gt;
  &lt;/section&gt;
  &lt;pre id=&quot;KUB4&quot; data-lang=&quot;javascript&quot;&gt;=   // Оператор присваивания
,   // Позволяет объявить несколько переменных в одной строке
.   // Позволяет обращаться к свойствам объектов
()  // Оператор вызова функции
... // Оператор разделения объекта на свойства. Префиксный&lt;/pre&gt;
  &lt;h3 id=&quot;x1ld&quot;&gt;Арифметические операторы&lt;/h3&gt;
  &lt;pre id=&quot;22Ec&quot; data-lang=&quot;javascript&quot;&gt;+  // Плюс. Используется для сложения. Конвертации строк в числа
-  // Минус
*  // Умножить
/  // Разделить
++ // Увеличивает значение переменной на 1
+= // Увеличение значения
-= // Уменьшение значения&lt;/pre&gt;
  &lt;h3 id=&quot;MbYO&quot;&gt;Операторы сравнения&lt;/h3&gt;
  &lt;pre id=&quot;wpFD&quot; data-lang=&quot;javascript&quot;&gt;=== // Равно, оператор сравнения. Сравнивает как тип, так и значение
!== // Не равно
&amp;lt;=  // Меньше
&amp;gt;=  // Больше&lt;/pre&gt;
  &lt;h3 id=&quot;VUbh&quot;&gt;Логические операторы&lt;/h3&gt;
  &lt;pre id=&quot;vUXo&quot; data-lang=&quot;javascript&quot;&gt;! // Не. Префиксный оператор. Возвращает тип boolean (true или false)
&amp;amp;&amp;amp; // И. Бинарный оператор. Возвращает значение одного из операндов
|| // Или. Бинарный оператор. Возвращает значение одного из операндов&lt;/pre&gt;
  &lt;h3 id=&quot;3TSo&quot;&gt;Текстовые операторы&lt;/h3&gt;
  &lt;pre id=&quot;fw9u&quot; data-lang=&quot;javascript&quot;&gt;typeof // Проверяет тип значения. Префиксный
instanceof // Проверяет принадлежность объекта к классу. Бинарный
new // Создает новый экземпляр объекта. Префиксный
delete // С помощью него можно удалить свойство в объекте. Префиксный&lt;/pre&gt;
  &lt;h3 id=&quot;1EcV&quot;&gt;Унарные и бинарные операторы&lt;/h3&gt;
  &lt;p id=&quot;cwSl&quot;&gt;У &lt;strong&gt;унарных &lt;/strong&gt;операторов всегда &lt;strong&gt;один &lt;/strong&gt;операнд (аргумент). Они могут быть &lt;strong&gt;префиксные&lt;/strong&gt;, когда оператор стоит &lt;strong&gt;перед &lt;/strong&gt;оператором, и &lt;strong&gt;постфиксные&lt;/strong&gt;, когда оператор идет &lt;strong&gt;после&lt;/strong&gt; операнда.&lt;/p&gt;
  &lt;pre id=&quot;ng9K&quot; data-lang=&quot;javascript&quot;&gt;+myName         // + перед операндом
delete myName.a // delete перед операндом
myName++        // ++ после операнда
myName()        // () после операнда&lt;/pre&gt;
  &lt;p id=&quot;BuDp&quot;&gt;У &lt;strong&gt;бинарных &lt;/strong&gt;операторов всегда &lt;strong&gt;два &lt;/strong&gt;операнда, они имеют &lt;strong&gt;инфиксный&lt;/strong&gt; формат, когда оператор находится &lt;strong&gt;между &lt;/strong&gt;операндами.&lt;/p&gt;
  &lt;pre id=&quot;AkAY&quot; data-lang=&quot;javascript&quot;&gt;a = 5
a + b
a += 5
a === b
a &amp;amp;&amp;amp; b&lt;/pre&gt;
  &lt;p id=&quot;mqAA&quot;&gt;Существует тернарный оператор у которого 3 операнда, подробнее о нем &lt;a href=&quot;#zf4q&quot;&gt;тут.&lt;/a&gt;&lt;/p&gt;
  &lt;h3 id=&quot;ntym&quot;&gt;Оператор &lt;em&gt;typyof&lt;/em&gt;&lt;/h3&gt;
  &lt;pre id=&quot;fd10&quot; data-lang=&quot;javascript&quot;&gt;typeof 10 // &amp;#x27;number&amp;#x27;
typeof 10 === &amp;#x27;number&amp;#x27; // true
typeof &amp;#x27;Alex&amp;#x27; // &amp;#x27;string&amp;#x27;

let a
typeof a === &amp;#x27;undefined&amp;#x27; // true&lt;/pre&gt;
  &lt;h3 id=&quot;JBxP&quot;&gt;Оператор &lt;em&gt;!&lt;/em&gt;&lt;/h3&gt;
  &lt;p id=&quot;ghp3&quot;&gt;Такой оператор чаще всего используется в условных инструкциях.&lt;/p&gt;
  &lt;pre id=&quot;zbhU&quot; data-lang=&quot;javascript&quot;&gt;!10  // false
!0   // true
!!10 // true
!!0  // false&lt;/pre&gt;
  &lt;h3 id=&quot;8H9j&quot;&gt;Оператор &amp;amp;&amp;amp; и ||&lt;/h3&gt;
  &lt;p id=&quot;HknV&quot;&gt;Операторы &amp;amp;&amp;amp; и || (&lt;em&gt;и&lt;/em&gt; и &lt;em&gt;или&lt;/em&gt;) являются операторами короткого замыкания.&lt;/p&gt;
  &lt;pre id=&quot;xao4&quot; data-lang=&quot;javascript&quot;&gt;/*Выражение 1*/ &amp;amp;&amp;amp; /*Выражение 2*/&lt;/pre&gt;
  &lt;ol id=&quot;nojG&quot;&gt;
    &lt;li id=&quot;Fbbn&quot;&gt;Если выражение 1 &lt;strong&gt;ложно&lt;/strong&gt;, то выражение 2 игнорируется и возвращается результат выражения 1&lt;/li&gt;
    &lt;li id=&quot;WWAD&quot;&gt;Если выражение 1 истина, то смотрим на выражение 2 и т.д.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;ZSaT&quot;&gt;Т.е. &lt;strong&gt;истина&lt;/strong&gt; передает эстафету следующему выражению, а ложное значение прекращает выполнение и возвращает результат выражения, с которым взаимодействовала последним. &lt;/p&gt;
  &lt;pre id=&quot;wwz2&quot; data-lang=&quot;javascript&quot;&gt;/*Выражение 1*/ || /*Выражение 2*/&lt;/pre&gt;
  &lt;ol id=&quot;3yN2&quot;&gt;
    &lt;li id=&quot;cIJn&quot;&gt;Если выражение 1 &lt;strong&gt;истина&lt;/strong&gt;, то выражение 2 игнорируется и возвращается результат выражения 1&lt;/li&gt;
    &lt;li id=&quot;KCBD&quot;&gt;Если выражение 1 ложно, то смотрим на выражение 2 и т.д.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;PxSK&quot;&gt;Оператор || (&lt;em&gt;или&lt;/em&gt;) работает противоположно оператору &amp;amp;&amp;amp; (&lt;em&gt;и&lt;/em&gt;), ищет первое истинное значение и выдает его результат.&lt;/p&gt;
  &lt;pre id=&quot;6LPQ&quot; data-lang=&quot;javascript&quot;&gt;const a = 10
a &amp;amp;&amp;amp; console.log(&amp;#x27;Hello&amp;#x27;)
// т.к. значение 10 истина, то мы получим Hello в консоли,
// это результат второго выражения
let b
b &amp;amp;&amp;amp; console.log(&amp;#x27;Hello&amp;#x27;)
// второе выражение не будет выполнено, т.к. значение переменной b ложно&lt;/pre&gt;
  &lt;p id=&quot;YF09&quot;&gt;Это можно использовать для выполнения тех или иных действий, в зависимости от результата других выражений.&lt;/p&gt;
  &lt;h3 id=&quot;dz4w&quot;&gt;Оператор ...&lt;/h3&gt;
  &lt;p id=&quot;beft&quot;&gt;!!!&lt;/p&gt;
  &lt;pre id=&quot;o9GP&quot; data-lang=&quot;javascript&quot;&gt;const button = {
  width: 200,
  text: &amp;#x27;Buy&amp;#x27;
}
// Создадим объект с двумя свойствами

const redButton = {
// Создадим еще один объект
  ...button,
  // Добавим в него свойства из объекта button
  color: &amp;#x27;Red&amp;#x27;
  // Добавим третье свойство color
}
console.table(redButton)
// Метод table() выведет объект в консоль в виде таблицы&lt;/pre&gt;
  &lt;blockquote id=&quot;gNYM&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;58E5&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;bP2u&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;kiJ8&quot;&gt;11. Конкатенация (соединение) строк&lt;/h2&gt;
  &lt;p id=&quot;jcz9&quot;&gt;Для соединения строк можно использовать оператор &lt;em&gt;+&lt;/em&gt; , но нужно следить за наличием пробелов между строк и расставлять их при необходимости. Также с оператором &lt;em&gt;+&lt;/em&gt; можно использовать но только строки, но и переменные: &lt;/p&gt;
  &lt;pre id=&quot;C1td&quot; data-lang=&quot;javascript&quot;&gt;console.log(&amp;#x27;Hello, &amp;#x27; + &amp;#x27;world&amp;#x27;)
// Получим Hello, world

const hello = &amp;#x27;Hello&amp;#x27;
const world = &amp;#x27;world&amp;#x27;
console.log(hello + &amp;#x27;, &amp;#x27; + world&amp;#x27;)
// Также получим Hello, world&lt;/pre&gt;
  &lt;p id=&quot;0UkZ&quot;&gt;Обратные кавычки &amp;#x60;&amp;#x60; также позволяют внутри себя использовать любые выражения с помочью ${ } , это называется &lt;strong&gt;шаблонная строка&lt;/strong&gt; (template string literals). &lt;/p&gt;
  &lt;pre id=&quot;zENm&quot; data-lang=&quot;javascript&quot;&gt;
const name = &amp;#x27;Denis&amp;#x27;
const city = &amp;#x27;Perm&amp;#x27;
console.log(&amp;#x60;My name is ${name} and I live in ${city}&amp;#x60;)&lt;/pre&gt;
  &lt;p id=&quot;svDx&quot;&gt;При конкатенации строки с числом, JS превратит число в строку:&lt;/p&gt;
  &lt;pre id=&quot;5Y8B&quot; data-lang=&quot;javascript&quot;&gt;const string = &amp;#x27;Numder&amp;#x27;
const number = 22
console.log(string + &amp;#x27; &amp;#x27; + number)
// Получим строку &amp;#x27;Number 22&amp;#x27;&lt;/pre&gt;
  &lt;blockquote id=&quot;IFeD&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;jkWP&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;MpPR&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;QsF8&quot;&gt;12. Обработка ошибок&lt;/h2&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;SVOg&quot;&gt;После получения ошибки в JavaScript выполнение кода останавливается&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;CbdT&quot;&gt;С помощью инструкции &lt;em&gt;&lt;strong&gt;throw new Error()&lt;/strong&gt; можно искусственно создать ошибку&lt;/em&gt;&lt;/p&gt;
  &lt;pre id=&quot;sPWo&quot; data-lang=&quot;javascript&quot;&gt;const fnWithError = () =&amp;gt; {
  throw new Error(&amp;#x27;Some error&amp;#x27;)
}
// Создаем функцию которая выдаст ошибку Some error

fnWithError()
// Вызываем функцию вызывающую ошибку и получаем непойманную ошибку

console.log(&amp;#x27;Continue...&amp;#x27;)
// Эта функция выполнена не будет&lt;/pre&gt;
  &lt;p id=&quot;uTV5&quot;&gt;Непойманная ошибка (&lt;em&gt;Uncaught Error&lt;/em&gt;) это та ошибка, которая остановит выполнение кода JS.&lt;/p&gt;
  &lt;p id=&quot;hVjL&quot;&gt;&lt;strong&gt;Решение try/catch.&lt;/strong&gt; В блоке кода &lt;em&gt;&lt;strong&gt;try&lt;/strong&gt;&lt;/em&gt; мы указываем код, в котором может возникнуть ошибка, а в блоге &lt;em&gt;&lt;strong&gt;catch&lt;/strong&gt;&lt;/em&gt; с параметром &lt;em&gt;(error)&lt;/em&gt;, тот код, который будет выполнен в случае появления ошибки в блоке &lt;em&gt;&lt;strong&gt;try&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;
  &lt;pre id=&quot;01ig&quot; data-lang=&quot;javascript&quot;&gt;const fnWithError = () =&amp;gt; {
  throw new Error(&amp;#x27;Some error&amp;#x27;)
}
// Создаем функцию которая выдаст ошибку Some error
try {
  fnWithError()
} catch (error) {
    console.error(error)
    // Метод выведет всю информацию об ошибке
    console.log(error.message)
    // Выведет сообщение зашитое в ошибку, some error
}
console.log(&amp;#x27;Continue...&amp;#x27;)
// На этот раз выполнение кода продолжится и мы получим Continue...&lt;/pre&gt;
  &lt;blockquote id=&quot;jLD1&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;Oh4I&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;pnuG&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;s1lL&quot;&gt;13. Инструкции&lt;/h2&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;VCoF&quot;&gt;В JavaScript существуют:&lt;/p&gt;
    &lt;ul id=&quot;Ot3Y&quot;&gt;
      &lt;li id=&quot;gkrO&quot;&gt;&lt;strong&gt;Выражения.&lt;/strong&gt; Они всегда возвращают значения.&lt;/li&gt;
      &lt;li id=&quot;SS4C&quot;&gt;&lt;strong&gt;Инструкции.&lt;/strong&gt; Они выполняют действия (например, объявление переменной).&lt;/li&gt;
      &lt;li id=&quot;879E&quot;&gt;&lt;strong&gt;Выражения-инструкции.&lt;/strong&gt; Выражения может быть инструкцией, но инструкция не может быть выражением (инструкций-выражений НЕТ)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/section&gt;
  &lt;p id=&quot;c1Xe&quot;&gt;Инструкции следует завершать &lt;em&gt;; (точкой с запятой)&lt;/em&gt;, а также каждую инструкцию писать на отдельной строке кода.&lt;/p&gt;
  &lt;p id=&quot;nxJb&quot;&gt;После { } блока кода инструкций точка с запятой не требуется.&lt;/p&gt;
  &lt;pre id=&quot;fbPe&quot; data-lang=&quot;javascript&quot;&gt;const a = 5;
// в конце инструкции стоит ;

if (a &amp;gt; b) {
  console.log(&amp;#x27;Hello&amp;#x27;);
}
// Блоки кода {} условных инструкций не требуют ;

for (let i = 0; i++; i &amp;lt;5) {
  console.log(i);
}
// Блоки кода {} циклов тоже не требуют ;&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;krf0&quot;&gt;Точки с запятой в JavaScript можно опускать&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;bCPm&quot;&gt;Инструкции &lt;strong&gt;нельзя&lt;/strong&gt; использовать как аргументы в функциях&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;ABB5&quot;&gt;Если в конце выражения поставить точку с запятой, то мы явно укажем, что это инструкция и JS перестанет считать его выражением, даже если это выражение-инструкция&lt;/p&gt;
  &lt;pre id=&quot;bvYi&quot; data-lang=&quot;javascript&quot;&gt;function myFn(a) {
  console.log(a);
}
let c = 10
//
myFn(c = c + 1)
// Функция выдаст результат выражения, это 11
myFn(c = c + 1;)
// Поставив точку с запятой, мы указали что это инструкция,
// поэтому функция выполнена не будет&lt;/pre&gt;
  &lt;blockquote id=&quot;KOPZ&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;EDSc&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;Cmpr&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;jFL1&quot;&gt;14. Массивы&lt;/h2&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;lsRV&quot;&gt;&lt;strong&gt;Массив&lt;/strong&gt; — это объект с цифровыми именами свойств: 0, 1, 2, 3 и т.п.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;NxKQ&quot;&gt;Для создания массива используются квадратные скобки, в которых указываются будущие значения массива по порядку.&lt;/p&gt;
  &lt;pre id=&quot;NxKQ&quot; data-lang=&quot;javascript&quot;&gt;const myNumbers = [&amp;#x27;one&amp;#x27;, &amp;#x27;two&amp;#x27;, &amp;#x27;three&amp;#x27;]
console.log(myNumbers)
// Получим массив [&amp;#x27;one&amp;#x27;, &amp;#x27;two&amp;#x27;, &amp;#x27;three&amp;#x27;]&lt;/pre&gt;
  &lt;p id=&quot;3nlg&quot;&gt;Также для создания массива можно использовать ключевое слово &lt;em&gt;new&lt;/em&gt; для создание нового экземпляра класса &lt;em&gt;Array()&lt;/em&gt;, в качестве аргументов указываются будущие значения массива по порядку.&lt;/p&gt;
  &lt;pre id=&quot;4hJA&quot; data-lang=&quot;javascript&quot;&gt;const myNumbers = new Array (&amp;#x27;one&amp;#x27;, &amp;#x27;two&amp;#x27;, &amp;#x27;three&amp;#x27;)
console.log(myNumbers)
// Получим массив [&amp;#x27;one&amp;#x27;, &amp;#x27;two&amp;#x27;, &amp;#x27;three&amp;#x27;]&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;aLXc&quot;&gt;Свойства в массиве начинаются с нуля: [0: &amp;#x27;one&amp;#x27;, 1: &amp;#x27;two&amp;#x27;, 2: &amp;#x27;three&amp;#x27;]&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;8Dlf&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;4gsP&quot;&gt;14.1. Чтение значений массива&lt;/h3&gt;
  &lt;p id=&quot;9TQA&quot;&gt;Вместо точечной записи, для обращения к цифровым свойствам массива используют [] квадратные скобки:&lt;/p&gt;
  &lt;pre id=&quot;ESNU&quot; data-lang=&quot;javascript&quot;&gt;const myArray = [1, true, &amp;#x27;Petr&amp;#x27;]
console.log(myArray)
// Получим [1, true, &amp;#x27;Petr&amp;#x27;]
console.log(myArray[0])
// Получим 1
console.log(myArray[1])
// Получим true
console.log(myArray.length)
// Получим 3, это кол-во значений в массиве. Свойство length имеет
// любой массив по умолчанию и обновляется оно автоматически&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;dXek&quot;&gt;Обновлять значения поля&lt;em&gt; length&lt;/em&gt; вручную &lt;strong&gt;не рекомендуется&lt;/strong&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;pre id=&quot;sNTm&quot; data-lang=&quot;javascript&quot;&gt;const myNumbers = new Array (1, 2, 3, 4)
// Создадим массив с 4-я значениями
myNumbers[1] = &amp;#x27;new&amp;#x27;
console.log(myNumbers)
// Получим [1, &amp;#x27;new&amp;#x27;, 2, 3, 4] т.к мы присвоили свойству 1 значение &amp;#x27;new&amp;#x27;
myNumbers[4] = &amp;#x27;four&amp;#x27;
// Добавили новое значение в массив, т.к. свойства 4 не было&lt;/pre&gt;
  &lt;p id=&quot;4Q5o&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;PCTL&quot;&gt;14.2. Методы массивов&lt;/h3&gt;
  &lt;p id=&quot;3W40&quot;&gt;Метод &lt;em&gt;&lt;strong&gt;push()&lt;/strong&gt;&lt;/em&gt; добавляет аргумент как элемент&lt;strong&gt; в конец&lt;/strong&gt; массива:&lt;/p&gt;
  &lt;pre id=&quot;0835&quot; data-lang=&quot;javascript&quot;&gt;const myNumbers = [&amp;#x27;one&amp;#x27;, &amp;#x27;two&amp;#x27;, &amp;#x27;three&amp;#x27;]
// Создадим массив [0: &amp;#x27;one&amp;#x27;, 1: &amp;#x27;two&amp;#x27;, 2: &amp;#x27;three&amp;#x27;]
myNumbers.push(&amp;#x27;PUSH&amp;#x27;)
// Получим массив [0: &amp;#x27;one&amp;#x27;, 1: &amp;#x27;two&amp;#x27;, 2: &amp;#x27;three&amp;#x27;, 3: &amp;#x27;PUSH&amp;#x27;, ]&lt;/pre&gt;
  &lt;p id=&quot;Zm7z&quot;&gt;Метод &lt;em&gt;&lt;strong&gt;pop()&lt;/strong&gt;&lt;/em&gt; удаляет &lt;strong&gt;последний&lt;/strong&gt; элемент массива и возвращает его значение:&lt;/p&gt;
  &lt;pre id=&quot;QMBV&quot; data-lang=&quot;javascript&quot;&gt;const myNumbers = [&amp;#x27;one&amp;#x27;, &amp;#x27;two&amp;#x27;, &amp;#x27;three&amp;#x27;]
// Создадим массив [0: &amp;#x27;one&amp;#x27;, 1: &amp;#x27;two&amp;#x27;, 2: &amp;#x27;three&amp;#x27;]
const myPop = myNumbers.pop()
// Получим массив [0: &amp;#x27;one&amp;#x27;, 1: &amp;#x27;two&amp;#x27;] и переменную myPop
// со значением &amp;#x27;three&amp;#x27;, т.к. метод pop возвращает значение&lt;/pre&gt;
  &lt;p id=&quot;2pSx&quot;&gt;Метод &lt;em&gt;&lt;strong&gt;unshift()&lt;/strong&gt;&lt;/em&gt; добавляет аргумент как элемент &lt;strong&gt;в начало&lt;/strong&gt; массива. Все названия элементов сдвинуться на 1 вперед:&lt;/p&gt;
  &lt;pre id=&quot;e5C0&quot; data-lang=&quot;javascript&quot;&gt;const myNumbers = [&amp;#x27;one&amp;#x27;, &amp;#x27;two&amp;#x27;, &amp;#x27;three&amp;#x27;]
// Создадим массив [0: &amp;#x27;one&amp;#x27;, 1: &amp;#x27;two&amp;#x27;, 2: &amp;#x27;three&amp;#x27;]
myNumbers.unshift(&amp;#x27;UNSHIFT&amp;#x27;)
// Получим массив [0: &amp;#x27;UNSHIFT&amp;#x27;, 1: &amp;#x27;one&amp;#x27;, 2: &amp;#x27;two&amp;#x27;, 3: &amp;#x27;three&amp;#x27;]&lt;/pre&gt;
  &lt;p id=&quot;qrNL&quot;&gt;Метод &lt;em&gt;&lt;strong&gt;shift()&lt;/strong&gt;&lt;/em&gt; удаляет &lt;strong&gt;первый&lt;/strong&gt; элемент массива и возвращает его значение:&lt;/p&gt;
  &lt;pre id=&quot;a2RA&quot; data-lang=&quot;javascript&quot;&gt;const myNumbers = [&amp;#x27;one&amp;#x27;, &amp;#x27;two&amp;#x27;, &amp;#x27;three&amp;#x27;]
// Создадим массив [0: &amp;#x27;one&amp;#x27;, 1: &amp;#x27;two&amp;#x27;, 2: &amp;#x27;three&amp;#x27;]
const myShift = myNumbers.shift()
// Получим массив [0: &amp;#x27;two&amp;#x27;, 1: &amp;#x27;three&amp;#x27;] и переменную myShift
// со значением &amp;#x27;one&amp;#x27;, т.к. метод shift возвращает значение&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;c9YW&quot;&gt;Методы &lt;em&gt;push()&lt;/em&gt;,&lt;em&gt; pop()&lt;/em&gt;,&lt;em&gt; unshift() &lt;/em&gt;и&lt;em&gt; shift() &lt;/em&gt;&lt;strong&gt;мутируют&lt;/strong&gt; изначальный массив!&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;CsCF&quot;&gt;Метод&lt;em&gt; &lt;strong&gt;forEach()&lt;/strong&gt; &lt;/em&gt;перебирает все элементы массива и применяет к ним &lt;strong&gt;функцию&lt;/strong&gt;, которую мы прописываем как аргумент метода. Возвращает значение &lt;em&gt;undefined&lt;/em&gt;.&lt;/p&gt;
  &lt;pre id=&quot;pqQW&quot; data-lang=&quot;javascript&quot;&gt;const myNumber = [1, 2, 3, 4]
myNumber.forEach(element =&amp;gt; console.log(element * 2))
// Метод forEach() переберет все элементы масива, умножит их на 2
// и выведет их в консоль&lt;/pre&gt;
  &lt;p id=&quot;mazO&quot;&gt;Метод&lt;em&gt;&lt;strong&gt; map()&lt;/strong&gt;&lt;/em&gt; перебирает все элементы массива и применяет к ним функцию также как &lt;em&gt;forEach&lt;/em&gt;, но возвращает новый массив.&lt;/p&gt;
  &lt;pre id=&quot;7LbI&quot; data-lang=&quot;javascript&quot;&gt;const myNumber = [1, 2, 3, 4]
const newMyNumber = myNumber.map(element =&amp;gt; element * 2)
// Получим новый массив со значениями [2, 4, 6, 8]&lt;/pre&gt;
  &lt;blockquote id=&quot;CWHN&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;fCQf&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;P16P&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;mhYq&quot;&gt;15. Деструктуризация&lt;/h2&gt;
  &lt;p id=&quot;yK37&quot;&gt;Позволяет, используя&lt;em&gt; {}&lt;/em&gt; фигурные скобки, создавать переменные на остнове свойств объектов:&lt;/p&gt;
  &lt;pre id=&quot;zgdZ&quot; data-lang=&quot;javascript&quot;&gt;const myName = {
  name: &amp;#x27;James&amp;#x27;,
  surname: &amp;#x27;Crock&amp;#x27;,
  age: 35,
}

const {name, surname} = myName
// Будет создана переменная name со значением &amp;#x27;James&amp;#x27;
// и переменная surname со значением &amp;#x27;Crock&amp;#x27;&lt;/pre&gt;
  &lt;p id=&quot;Cz5n&quot;&gt;Похожим образом можно создавать переменные на основе свойств массивов. В фигурных скобках мы указываем названия будущих переменных, а значения для них берутся из массива по порядку:&lt;/p&gt;
  &lt;pre id=&quot;6YaB&quot; data-lang=&quot;javascript&quot;&gt;const fruits = [&amp;#x27;apple&amp;#x27;, &amp;#x27;banana&amp;#x27;]
const [fruitOne, fruitTwo] = fruits
// Получим переменную fruitOne = &amp;#x27;apple&amp;#x27; и fruitTwo = &amp;#x27;banana&amp;#x27;&lt;/pre&gt;
  &lt;p id=&quot;Iwdf&quot;&gt;В &lt;strong&gt;функциях&lt;/strong&gt; также можно использовать деструктуризацию для передачи нужных свойств объекта как аргументов&lt;/p&gt;
  &lt;pre id=&quot;djsJ&quot; data-lang=&quot;javascript&quot;&gt;const userProfile = {
  name: &amp;#x27;Pavel&amp;#x27;,
  commentsQty: 23,
  hasSignedAgreement: false
}
const userInfo = ({name, commentsQty}) =&amp;gt; {
// В переданом объекте ищем свойства name и commentsQty
  if (!commentsQty) {
  // Если в объекте нет свойства commentsQty, то мы возвращаем:
    return &amp;#x60;User ${name} has no comments&amp;#x60;
  }
  return &amp;#x60;User ${name} has ${commentsQty} comments&amp;#x60;
}
userInfo(userProfile)
// Получим &amp;#x27;User Pavel has 23 comments&amp;#x27;&lt;/pre&gt;
  &lt;blockquote id=&quot;TXYJ&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;wQhy&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;SfRF&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;Q0Lp&quot;&gt;16. Условные инструкции&lt;/h2&gt;
  &lt;p id=&quot;YFPl&quot;&gt;Инструкция &lt;em&gt;if&lt;/em&gt;. Блок кода в {} выполняется однократно если условие правдиво, если ложно - игнорируется:&lt;/p&gt;
  &lt;pre id=&quot;oUUB&quot; data-lang=&quot;javascript&quot;&gt;let val = 10

if (val &amp;gt; 5) {
// Если val больше 5, то мы выполняем блок кода в {}
  val += 20
}

console.log(val)
// Получим 30&lt;/pre&gt;
  &lt;pre id=&quot;GKFX&quot; data-lang=&quot;javascript&quot;&gt;const person = {
  age: 20
}

if (!person.name) {
// Если у объекта НЕТ свойства name, то мы выполняем блок кода в {}
  console.log(&amp;#x27;Имя не указано&amp;#x27;)
}&lt;/pre&gt;
  &lt;p id=&quot;8vcU&quot;&gt;Инструкция &lt;em&gt;if else&lt;/em&gt;. В этой инструкции можно использовать 2 блока кода. Первый блок кода { } выполняется если условие правдиво, а второй { } - если ложно:&lt;/p&gt;
  &lt;pre id=&quot;yQBo&quot; data-lang=&quot;javascript&quot;&gt;const person = {
  age: 20,
  name:&amp;#x27;Diana&amp;#x27;
}

if (person.name) {
// Если у объекта ЕСТЬ свойство name, то мы выполняем блок кода в {}
  console.log(&amp;#x60;Имя: ${person.name}&amp;#x60;)
} else {
  // Если свойства name НЕТ, то выполняем блок кода else {}
  console.log(&amp;#x27;Имя не указано&amp;#x27;)
}&lt;/pre&gt;
  &lt;p id=&quot;yZsA&quot;&gt;Можно комбинировать инструкции if else:&lt;/p&gt;
  &lt;pre id=&quot;9QLD&quot; data-lang=&quot;javascript&quot;&gt;if (/*Условие1*/) {
 // Блок кода, выполняемый однократно, если Условие1 правдиво
} else if (/*Условие2*/) {
 // Блок кода, выполняемый однократно, если Условие2 правдиво
} else {
 // Блок кода, выполняемый однократно, если предыдущие условия ложны
}&lt;/pre&gt;
  &lt;p id=&quot;WKIM&quot;&gt;Применение инструкции if в функциях:&lt;/p&gt;
  &lt;pre id=&quot;wGJs&quot; data-lang=&quot;javascript&quot;&gt;const sumPositiveNumbers = (a, b) =&amp;gt; {
  if (typeof a !== &amp;#x27;number&amp;#x27; || typeof b !== &amp;#x27;number&amp;#x27;) {
  // Если a или b не являются числами, то возвращаем
    return &amp;#x27;One of the arguments is not a number&amp;#x27;
  }
  if (a &amp;lt;= 0 || b &amp;lt;= 0) {
  // Если a или b меньше или равны нулю, то возвращаем
    return &amp;#x27;Numbers are not positive&amp;#x27;
  }
  return a + b
  // Если передыдущие условия ложны, то выполняется сложение
}&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;NOpK&quot;&gt;Инструкции &lt;em&gt;if &lt;/em&gt;и &lt;em&gt;if else&lt;/em&gt; выполняются однократно&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;1NCU&quot;&gt;Инструкция&lt;strong&gt; &lt;em&gt;switch&lt;/em&gt;.&lt;/strong&gt; Действие выполняется если выражение в условии равно &lt;em&gt;&lt;strong&gt;case&lt;/strong&gt;&lt;/em&gt; (кейс/случай). Если выражение равно нескольким кейсам, то выполнятся оба кейса.&lt;/p&gt;
  &lt;p id=&quot;PkuS&quot;&gt;Если в кейсе стоит ключевое слово &lt;em&gt;&lt;strong&gt;brake&lt;/strong&gt;&lt;/em&gt;, то после удачного выполнения этого кейса выполнение инструкции &lt;em&gt;&lt;strong&gt;switch&lt;/strong&gt;&lt;/em&gt; прекратиться, даже если какие-то кейсы еще подходят под условия:&lt;/p&gt;
  &lt;pre id=&quot;9pso&quot; data-lang=&quot;javascript&quot;&gt;switch (Выражение) {
  case A:
    // Действие, если Выражение === A
    break
    // brake это инструкция для прикращения инструкции после 
    // удачного выполнения действия в кейсе
  case B:
    // Действие, если Выражение === B
    break
  default:
    // Действие по умолчанию
}&lt;/pre&gt;
  &lt;pre id=&quot;AiUs&quot; data-lang=&quot;javascript&quot;&gt;const winterMonth = 2

switch (winterMonth) {
  case 12:
    console.log(&amp;#x27;December&amp;#x27;)
    break
  case 1:
    console.log(&amp;#x27;January&amp;#x27;)
    break
  case 2:
    console.log(&amp;#x27;February&amp;#x27;)
    break
  default:
    console.log(&amp;#x27;Its not a winter month&amp;#x27;)
}&lt;/pre&gt;
  &lt;blockquote id=&quot;mN16&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;3oFE&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;aS7R&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;zf4q&quot;&gt;17. Тернарный оператор&lt;/h2&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;LZvB&quot;&gt;Конструкция с тернарным оператором является &lt;strong&gt;выражением&lt;/strong&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;JwPm&quot;&gt;У &lt;strong&gt;тернарного&lt;/strong&gt; оператора 3 операнда, его операнды пишутся между &lt;em&gt;?&lt;/em&gt; и &lt;em&gt;: &lt;/em&gt;Конструкция с тернарным оператором является выражением и возвращает результат одного и операндов:&lt;/p&gt;
  &lt;pre id=&quot;alpF&quot; data-lang=&quot;javascript&quot;&gt;Условие (Условие) // Условием может быть любое выражение, в том числе
                      // и с другими операторами
  ? Операнд Один      // Выражение, выполняется если условие ПРАВДИВО
  : Операнд Два      // Выражение, выполняется если условие ЛОЖНО&lt;/pre&gt;
  &lt;pre id=&quot;O9G7&quot; data-lang=&quot;javascript&quot;&gt;const value1 = 11
const value2 = 25
value1 &amp;amp;&amp;amp; value2
  ? myFunction(value1, value2)
  // Если value1 и value2 правдивы, то вызываем функцию используя их
  // как аргументы
  : myFunction()
  // Если значения ложны, то вызываем функцию без аргументов&lt;/pre&gt;
  &lt;pre id=&quot;zCps&quot; data-lang=&quot;javascript&quot;&gt;let value = 11
console.log(value &amp;gt;= 0 ? value : -value)
// Если value больше или равно нулю, то возвращаем результат value
// Получим 11

value = -5
const result = value &amp;gt;= 0 ? value : -value
// Присваиваем переменной результат работы тернарного оператора,
// это возможно т.к. это выражение
console.log(result)
// значение result будет -value, а --5 это 5&lt;/pre&gt;
  &lt;blockquote id=&quot;qBNg&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;cpk9&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;GOXV&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;G2Xo&quot;&gt;18. Циклы&lt;/h2&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;uaF4&quot;&gt;Циклы — это&lt;strong&gt; инструкции&lt;/strong&gt;, они не возвращают значение, а только совершают действие&lt;/p&gt;
  &lt;/section&gt;
  &lt;h3 id=&quot;rAb2&quot;&gt;&lt;/h3&gt;
  &lt;h3 id=&quot;pZ2j&quot;&gt;18.1. Цикл &lt;em&gt;for&lt;/em&gt;&lt;/h3&gt;
  &lt;pre id=&quot;mByZ&quot; data-lang=&quot;javascript&quot;&gt;for (Начальная инструкция; Условие; Итерационное действие) {
  // Блок кода, выполняемый на КАЖДОЙ итерации
}&lt;/pre&gt;
  &lt;p id=&quot;IPJ5&quot;&gt;Итерационное действие повторяет выполняется до тех пор, пока условие верно.&lt;/p&gt;
  &lt;pre id=&quot;fDC6&quot; data-lang=&quot;javascript&quot;&gt;for (let i = 0; i &amp;lt; 5; i++) {
  console.log(i)
}&lt;/pre&gt;
  &lt;p id=&quot;0jNT&quot;&gt;Циклы можно использовать для массивов, хотя это &lt;strong&gt;не рекомендуется&lt;/strong&gt;. Для массивов есть методы &lt;em&gt;forEach&lt;/em&gt;, &lt;em&gt;map&lt;/em&gt;, &lt;em&gt;reduce&lt;/em&gt;&lt;/p&gt;
  &lt;pre id=&quot;1g65&quot; data-lang=&quot;javascript&quot;&gt;const myNumbers = [&amp;#x27;one&amp;#x27;, &amp;#x27;two&amp;#x27;, &amp;#x27;three&amp;#x27;]

for (let i = 0; i &amp;lt; myNumbers.length; i++) {
  console.log(myNumbers[i])
}
// Получим в консоли:
// one
// two
// three&lt;/pre&gt;
  &lt;p id=&quot;BEYr&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;cSFc&quot;&gt;18.2. Метод массивов &lt;em&gt;forEach&lt;/em&gt;&lt;/h3&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;13uR&quot;&gt;Метод &lt;em&gt;forEach&lt;/em&gt; вызывается столько раз, сколько элементов в массиве&lt;/p&gt;
  &lt;/section&gt;
  &lt;pre id=&quot;mlLg&quot; data-lang=&quot;javascript&quot;&gt;const myNumbers = [&amp;#x27;one&amp;#x27;, &amp;#x27;two&amp;#x27;, &amp;#x27;three&amp;#x27;]

myNumbers.forEach((element, index) =&amp;gt; {
  console.log(element, index)
})
// Получим в консоли:
// one 0
// two 1
// three 2&lt;/pre&gt;
  &lt;p id=&quot;U9IG&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;Vfyg&quot;&gt;18.3. Циклы &lt;em&gt;while и do while&lt;/em&gt;&lt;/h3&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;yPC6&quot;&gt;&lt;em&gt;Цикл&lt;strong&gt; while&lt;/strong&gt;&lt;/em&gt; выполняет инструкцию пока условие правдиво (true)&lt;/p&gt;
  &lt;/section&gt;
  &lt;pre id=&quot;AuDx&quot; data-lang=&quot;javascript&quot;&gt;while (Условие) {
  // Блок кода, выполняемый при каждой итерации
}&lt;/pre&gt;
  &lt;p id=&quot;DgVN&quot;&gt;Мы должны сами контролировать изменение изначального условия внутри инструкции:&lt;/p&gt;
  &lt;pre id=&quot;hslZ&quot; data-lang=&quot;javascript&quot;&gt;let myNumber = 0

while (myNumber &amp;lt; 5) {
  console.log(myNumber)
  myNumber++
  // Меняем переменную, которое влияет на условие
  // позволяя выйти из цикла
}

// Получим в консоли:
//   0
//   1
//   2
//   3
//   4
// Когда myNumber станет равна 5 цикл закончится&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;ZzRq&quot;&gt;Цикл &lt;em&gt;&lt;strong&gt;do while&lt;/strong&gt;, в&lt;/em&gt; отличии от цикла &lt;em&gt;while&lt;/em&gt; всегда выполняется хотя бы 1 раз, т.к. инструкция выполняется до просмотра условия&lt;/p&gt;
  &lt;/section&gt;
  &lt;pre id=&quot;sDnI&quot; data-lang=&quot;javascript&quot;&gt;do {
  // Блок кода, выполняемый при каждой итерации
} while (Условие)&lt;/pre&gt;
  &lt;p id=&quot;Ahuo&quot;&gt;Мы также должны сами контролировать изменение изначального условия внутри инструкции:&lt;/p&gt;
  &lt;pre id=&quot;6m1t&quot; data-lang=&quot;javascript&quot;&gt;let myNumber = 0

do {
console.log(myNumber)
myNumber++
} while (myNumber &amp;lt; 5)&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;MMFK&quot;&gt;Если условие изначально ложно (false), то условие НЕ выполнится ни разу&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;zWLZ&quot;&gt;Если условие будет бесконечно правдиво (true), то цикл будет выполнятся &lt;strong&gt;бесконечно&lt;/strong&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;s9a9&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;ehhy&quot;&gt;18.4. Цикл &lt;em&gt;for in&lt;/em&gt; для объектов&lt;/h3&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;lEoM&quot;&gt;Блок инструкций &lt;em&gt;&lt;strong&gt;for in&lt;/strong&gt;&lt;/em&gt; выполняется для каждого свойства объекта или элемента массива&lt;/p&gt;
  &lt;/section&gt;
  &lt;pre id=&quot;xUVO&quot; data-lang=&quot;javascript&quot;&gt;for (key in Object) {
  // Действия с каждым свойством объекта
  // Значение свойства - Object[key]
}&lt;/pre&gt;
  &lt;p id=&quot;fTQc&quot;&gt;&lt;em&gt;Key&lt;/em&gt; будет представлять название свойства в объекте, а &lt;em&gt;Object&lt;/em&gt; это переменная указывающая на объект. Используя такой цикл можно перебрать все свойства объекта:&lt;/p&gt;
  &lt;pre id=&quot;DI7c&quot; data-lang=&quot;javascript&quot;&gt;const myObject = {
  x: 20,
  y: true,
  z: &amp;#x27;text&amp;#x27;
}

for (const key in myObject) {
  console.log(key, myObject[key])
  // key указывает на название свойства
  // myObject[key] указывает на значение свойств
}

// Получим в консоли:
//   x 20
//   y true
//   z text&lt;/pre&gt;
  &lt;p id=&quot;vT6P&quot;&gt;Точно также цикл &lt;em&gt;for in&lt;/em&gt; применяется к массивам:&lt;/p&gt;
  &lt;pre id=&quot;ULrX&quot; data-lang=&quot;javascript&quot;&gt;const myArray = [true, 20, &amp;#x27;text&amp;#x27;, null]

for (const key in myArray) {
  console.log(key, myArray[key])
}

// Получим в консоли:
//   true
//   20
//   text
//   null&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;UgaN&quot;&gt;Для массивов &lt;strong&gt;рекомендуется&lt;/strong&gt; применять метод &lt;em&gt;forEach()&lt;/em&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;kxGR&quot;&gt;Цикл &lt;em&gt;for in&lt;/em&gt; повторяется столько раз, сколько свойств в объекте или элементов в массиве&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;zYRO&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;RNpg&quot;&gt;18.5. Метод &lt;em&gt;forEach()&lt;/em&gt; для объектов&lt;/h3&gt;
  &lt;p id=&quot;Mv0K&quot;&gt;Можно применить метод массивов &lt;em&gt;forEach()&lt;/em&gt; для объектов, предварительно получив все имена свойств (ключи) этого объекта в вид массива с помощью метода &lt;em&gt;keys()&lt;/em&gt; глобального объекта &lt;em&gt;Object:&lt;/em&gt;&lt;/p&gt;
  &lt;pre id=&quot;G3nT&quot; data-lang=&quot;javascript&quot;&gt;const myObject = {
  x: 20,
  y: true,
  z: &amp;#x27;text&amp;#x27;
}

Object.keys(myObject).forEach(key =&amp;gt; {
  console.log(key, myObject[key])
})

// Получим в консоли:
//   x 20
//   y true
//   z text&lt;/pre&gt;
  &lt;p id=&quot;wa9D&quot;&gt;Аналогично, но используя метод &lt;em&gt;values()&lt;/em&gt; можно перебирать значения свойств:&lt;/p&gt;
  &lt;pre id=&quot;AI84&quot; data-lang=&quot;javascript&quot;&gt;const myObject = {
  x: 20,
  y: true,
  z: &amp;#x27;text&amp;#x27;
}

Object.values(myObject).forEach(value =&amp;gt; {
  console.log(value)
})

// Получим в консоли:
//   20
//   true
//   text&lt;/pre&gt;
  &lt;p id=&quot;yx4a&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;lAEG&quot;&gt;18.6. Цикл &lt;em&gt;for of&lt;/em&gt;&lt;/h3&gt;
  &lt;pre id=&quot;iI2W&quot; data-lang=&quot;javascript&quot;&gt;for (Element of Iterable) {
  // Действие с определенным элементом
}&lt;/pre&gt;
  &lt;p id=&quot;x7QS&quot;&gt;&lt;em&gt;&lt;strong&gt;Iterable&lt;/strong&gt;&lt;/em&gt; это любое значение по которому можно итерироваться (элементы которого можно перебирать):&lt;/p&gt;
  &lt;pre id=&quot;Z7tQ&quot; data-lang=&quot;javascript&quot;&gt;const myString = &amp;#x27;Hello&amp;#x27;

for (const letter of myString) {
  console.log(letter)
}
// Получим в консоли:
//   H
//   e
//   l
//   l
//   o&lt;/pre&gt;
  &lt;p id=&quot;jXNt&quot;&gt;Цикл &lt;em&gt;for of&lt;/em&gt; также подходит для массивов:&lt;/p&gt;
  &lt;pre id=&quot;rf0N&quot; data-lang=&quot;javascript&quot;&gt;const myArray = [true, 20, &amp;#x27;text&amp;#x27;, null]

for (const element of myArray) {
  console.log(element)
}
// Получим в консоли:
//   true
//   20
//   text
//   null&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;W4VF&quot;&gt;Для массивов &lt;strong&gt;рекомендуется&lt;/strong&gt; применять метод &lt;em&gt;forEach()&lt;/em&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;ntas&quot;&gt;&lt;em&gt; &lt;strong&gt;for of &lt;/strong&gt;д&lt;/em&gt;ля объектов НЕ подходит, т.к. объекты это НЕ итерируемые элементы&lt;/p&gt;
  &lt;/section&gt;
  &lt;blockquote id=&quot;Uew4&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;rU4w&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;RQm4&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;RyWC&quot;&gt;19. Модули&lt;/h2&gt;
  &lt;p id=&quot;aHYb&quot;&gt;Чтобы код был более читаемым используют модули. Один модуль это отдельный файл JS с частью кода и решающий какую-то одну задачу.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;BXft&quot;&gt;Модули должны быть одноцелевыми&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;rtM2&quot;&gt;В JS есть возможность экспорта и импорта переменных из модуля в модуль, для этого используется ключевые слова &lt;em&gt;&lt;strong&gt;export&lt;/strong&gt; &lt;strong&gt;default&lt;/strong&gt;&lt;/em&gt;, &lt;strong&gt;&lt;em&gt;export&lt;/em&gt;&lt;/strong&gt; и &lt;em&gt;&lt;strong&gt;import&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;w8m4&quot;&gt;Все экспортируемые переменные &lt;strong&gt;рекомендуется&lt;/strong&gt; всегда писать в самом конце файла, а импортируемые в самом начале&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;CCQn&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;nNiH&quot;&gt;&lt;strong&gt;Export default&lt;/strong&gt;&lt;/h3&gt;
  &lt;p id=&quot;FzNK&quot;&gt;Если нужно экспортировать из файла &lt;strong&gt;&lt;em&gt;file1.js&lt;/em&gt;&lt;/strong&gt; только одну переменную, лучше использовать &lt;em&gt;&lt;strong&gt;export default:&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
  &lt;pre id=&quot;jZmV&quot; data-lang=&quot;javascript&quot;&gt;// file1.js

const myName = () =&amp;gt; {
  console.log(&amp;#x27;Bob&amp;#x27;)
}
  
export default myName&lt;/pre&gt;
  &lt;p id=&quot;Bg5p&quot;&gt;В файле &lt;strong&gt;&lt;em&gt;file2.js&lt;/em&gt; &lt;/strong&gt;делаем импорт. Для этого используем ключевое слово import и указываем путь к файлу &lt;strong&gt;&lt;em&gt;file1.js&lt;/em&gt;&lt;/strong&gt; с помощью from:&lt;/p&gt;
  &lt;pre id=&quot;x25h&quot; data-lang=&quot;javascript&quot;&gt;// file2.js

import printMyName from &amp;#x27;./file1.js&amp;#x27;
// Укажем переменной новое имя printMyName

printMyName()
// Получим &amp;#x27;Bob&amp;#x27;&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;3NUO&quot;&gt;При импорте переменной, экспортируемой с помощью &lt;em&gt;export default,&lt;/em&gt; можно указать ей любое новое имя&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;C1Oo&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;8DTg&quot;&gt;Export&lt;/h3&gt;
  &lt;p id=&quot;dtBu&quot;&gt;При экспорте нескольких переменных из файла &lt;strong&gt;&lt;em&gt;file1.js&lt;/em&gt; &lt;/strong&gt;используем ключевое слово &lt;strong&gt;&lt;em&gt;export&lt;/em&gt;:&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;ATve&quot; data-lang=&quot;javascript&quot;&gt;const sum = (a, b) =&amp;gt; a + b
const mult = (a, b) =&amp;gt; a * b

export {sum, mult}&lt;/pre&gt;
  &lt;p id=&quot;8gOh&quot;&gt;В файле &lt;strong&gt;&lt;em&gt;file2.js&lt;/em&gt; &lt;/strong&gt;делаем импорт. Для этого используем ключевое слово import и {} фигурные скобки, в которых перечисляем имена импортируемых переменных:&lt;/p&gt;
  &lt;pre id=&quot;Jhog&quot; data-lang=&quot;javascript&quot;&gt;import {sum, mult} from &amp;#x27;./file1.js&amp;#x27;

console.log(sum(10, 2))
console.log(mult(10, 2))&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;FMRs&quot;&gt;При импорте нескольких переменных с помощью &lt;em&gt;export&lt;/em&gt;, нужно указывать те же самые имена переменных, что были при экспорте. &lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;Rvyb&quot;&gt;Но есть возможность переименовать переменную после экспорта:&lt;/p&gt;
  &lt;pre id=&quot;R8Se&quot; data-lang=&quot;javascript&quot;&gt;import {sum as sumRenamed, mult} from &amp;#x27;./file1.mjs&amp;#x27;
// Указываем переменной sum новое имя sumRenamed&lt;/pre&gt;
  &lt;blockquote id=&quot;uyRN&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;PF1V&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;3EbJ&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;k6X7&quot;&gt;20. Классы и прототипы&lt;/h2&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;4o9y&quot;&gt;&lt;strong&gt;Классы &lt;/strong&gt;позволяют создавать &lt;strong&gt;прототипы&lt;/strong&gt; для объектов&lt;/p&gt;
    &lt;p id=&quot;6OY5&quot;&gt;На основании &lt;strong&gt;прототипов&lt;/strong&gt; создаются &lt;strong&gt;экземпляры&lt;/strong&gt;&lt;/p&gt;
    &lt;p id=&quot;kLkh&quot;&gt;Экземпляры&lt;strong&gt; наследуют свойства и методы&lt;/strong&gt; прототипов&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;v8o1&quot;&gt;Для создания класса используется ключевое слово &lt;em&gt;&lt;strong&gt;class.&lt;/strong&gt;&lt;/em&gt; Название нового класса пишется с использованием &lt;em&gt;CamalCase&lt;/em&gt; нотации (с большой буквы)&lt;/p&gt;
  &lt;pre id=&quot;ZvOx&quot; data-lang=&quot;javascript&quot;&gt;class Comment {
// Пишем Comment с большой буквы т.к. это название класса
  constructor(a) {
  // Метод constructor вызывается только когда создается новый экземпляр
  // Его параметры, это аргументы заданые при создании экземпляра
    this.text = a
    this.votesQty = 0
    // Слово this указывает на будущий экземпляр класса.
    // То есть оно как бы замениться именем экземпляра,
    // который мы будем создавать 
  }
  upvote() {
  // Метод upvote будет доступен всем экземплярам нового класса Comment
  // Это называется наследованием
    this.votesQty += 1
  }
}
const firstComment = new Comment(&amp;#x27;First Comment&amp;#x27;)
// Оператор new вызывает функцию constructor с аргументом &amp;#x27;First Comment&amp;#x27;
console.log(firstComment)
// Получим объект firstComment {text: &amp;#x27;First Comment&amp;#x27;, votesQty: 0}
// Ему также доступны наследованные методы constructor и upvote&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;kijN&quot;&gt;Наследование происходит по цепочке:&lt;/p&gt;
    &lt;ul id=&quot;VoPf&quot;&gt;
      &lt;li id=&quot;EGmm&quot;&gt;&lt;strong&gt;Глобальный класс&lt;/strong&gt; &lt;em&gt;Object&lt;/em&gt; содержит методы доступные всем объектам в JavaScript.&lt;/li&gt;
      &lt;li id=&quot;wqvh&quot;&gt;&lt;strong&gt;Созданный нами класс&lt;/strong&gt; &lt;em&gt;Comment&lt;/em&gt; содержит созданные нами методы и наследует все методы глобального класса &lt;em&gt;Object&lt;/em&gt;.&lt;/li&gt;
      &lt;li id=&quot;KJJJ&quot;&gt;&lt;strong&gt;Экземпляр класса&lt;/strong&gt; &lt;em&gt;firstComment&lt;/em&gt; наследует все методы обоих родительских классов &lt;em&gt;Comment&lt;/em&gt; и &lt;em&gt;Object&lt;/em&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/section&gt;
  &lt;p id=&quot;U56G&quot;&gt;Чтобы проверить принадлежность &lt;strong&gt;объекта&lt;/strong&gt; к тому или иному &lt;strong&gt;классу&lt;/strong&gt; можно использовать оператор &lt;em&gt;instanceof:&lt;/em&gt;&lt;/p&gt;
  &lt;pre id=&quot;JVu2&quot; data-lang=&quot;javascript&quot;&gt;firstComment instanceof Comment
// Получим true т.к. firstComment экземпляр класса Comment
firstComment instanceof Object
// Получим true т.к. firstComment также является экземпляром
// глобального класса Object&lt;/pre&gt;
  &lt;p id=&quot;cmZr&quot;&gt;Чтобы проверить принадлежность &lt;strong&gt;свойства&lt;/strong&gt; к тому или иному &lt;strong&gt;объекту&lt;/strong&gt; можно использовать метод &lt;em&gt;hasOwnProperty()&lt;/em&gt;:&lt;/p&gt;
  &lt;pre id=&quot;l20f&quot; data-lang=&quot;javascript&quot;&gt;const firstComment = new Comment(&amp;#x27;First Comment&amp;#x27;)

firstComment.hasOwnProperty(&amp;#x27;text&amp;#x27;)
// Проверяем есть ли у объекта firstComment собственное свойство text
// Получаем true, такое свойство есть
firstComment.hasOwnProperty(&amp;#x27;votesQty&amp;#x27;)
// Получаем true, такое свойство тоже есть
firstComment.hasOwnProperty(&amp;#x27;upvote&amp;#x27;)
// Получаем false, такого свойства нет, это свойство родительского
// класса Comment
firstComment.hasOwnProperty(&amp;#x27;hasOwnProperty&amp;#x27;)
// Получаем false, такого свойства тоже нет, это свойство родительского
// глабального класса Object&lt;/pre&gt;
  &lt;p id=&quot;VAkG&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;EPqg&quot;&gt;20.1 Статический метод&lt;/h3&gt;
  &lt;p id=&quot;G9VZ&quot;&gt;С помощью ключевого слова &lt;em&gt;&lt;strong&gt;static&lt;/strong&gt;&lt;/em&gt; можно создавать методы, которые &lt;strong&gt;НЕ будут наследоваться&lt;/strong&gt; экземплярами классов:&lt;/p&gt;
  &lt;pre id=&quot;rFu4&quot; data-lang=&quot;javascript&quot;&gt;class Comment {
  constructor(text) {
    this.text = text
    this.votesQty = 0
  }
  upvote() {
    this.votesQty += 1
  }
  static mergeComments(first, second) {
    return &amp;#x60;${second} ${second}&amp;#x60;
}

Comment.mergeComments(&amp;#x27;First Comment&amp;#x27;, &amp;#x27;Second Comment&amp;#x27;)
// Метод будет доступен как свойство объекта Comment&lt;/pre&gt;
  &lt;p id=&quot;jjVz&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;9Wm3&quot;&gt;20.2 Расширение других классов&lt;/h3&gt;
  &lt;p id=&quot;AKoF&quot;&gt;С помощью ключевого слова &lt;em&gt;extends&lt;/em&gt; можно расширить существующий класс. Создастся новый класс с использованием конструктора из расширяемого класса, в данном случае класса массивов &lt;em&gt;Array&lt;/em&gt;:&lt;/p&gt;
  &lt;pre id=&quot;ARQj&quot; data-lang=&quot;javascript&quot;&gt;class NumbersArray extends Array {
  sum() {
    return this.reduce((el, acc) =&amp;gt; acc += el, 0)
  }
}

const myArray = new NumbersArray(2, 5, 7)
//
console.log(myArray)
myArray.sum()&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;OaRN&quot;&gt;Наследование происходит по цепочке:&lt;/p&gt;
    &lt;p id=&quot;8vAi&quot;&gt;myArray =&amp;gt; NumbersArray =&amp;gt; Array =&amp;gt; Object&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;h96e&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;A2da&quot;&gt;20.3 Примитивные значения&lt;/h3&gt;
  &lt;p id=&quot;Y5Sm&quot;&gt;Примитивные значения ведут себя как объекты и наследуют методы родительских классов:&lt;/p&gt;
  &lt;pre id=&quot;5ASb&quot; data-lang=&quot;javascript&quot;&gt;const myName = &amp;#x27;Vladimir&amp;#x27;
// Создадим переменную примитивного типа String
console.log(myName)
// Получим &amp;#x27;Vladimir&amp;#x27;
console.log(myName.toUpperCase())
// Получим &amp;#x27;VLADIMIR&amp;#x27;. Мы использовали метод класса String
const mySecondName = new String(&amp;#x27;Putin&amp;#x27;)
// Создадим новый экземпляр класса String
mySecondName
// Получим объект, экземпляр класса String:
// String {&amp;#x27;Putin&amp;#x27;}
//   0: &amp;quot;P&amp;quot;
//   1: &amp;quot;u&amp;quot;
//   2: &amp;quot;t&amp;quot;
//   3: &amp;quot;i&amp;quot;
//   4: &amp;quot;n&amp;quot;
//   length: 5&lt;/pre&gt;
  &lt;blockquote id=&quot;Mv4z&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;vrWS&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;lusm&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;Ez0U&quot;&gt;21. Промисы&lt;/h2&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;Iy42&quot;&gt;Промисы позволяют обрабатывать &lt;strong&gt;отложенные&lt;/strong&gt; во времени события&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;130J&quot;&gt;Промисы нужны чтобы иметь возможность обрабатывать другие запросы пока ждем ответа на предыдущие. Это возможно благодаря асинхронным запросам, ответ на которые JavaScript может получать не сразу, а через какое-то время&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;uCTy&quot;&gt;Промис может вернуть &lt;strong&gt;ошибку&lt;/strong&gt;, если результат предоставить &lt;strong&gt;невозможно&lt;/strong&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;hiyh&quot;&gt;У промиса может быть 3 состояния:&lt;/p&gt;
  &lt;ul id=&quot;6Ent&quot;&gt;
    &lt;li id=&quot;AYsO&quot;&gt;Ожидание (pending), когда промис создан;&lt;/li&gt;
    &lt;li id=&quot;XULL&quot;&gt;Исполнен (resolve), когда вернул результат;&lt;/li&gt;
    &lt;li id=&quot;X2XS&quot;&gt;Отклонен (reject), когда вернул ошибку.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;WazU&quot;&gt;Промис - это объект, глобальный класс в JS. &lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;Rie6&quot;&gt;Создаются промисы путем создания экземпляра класса &lt;em&gt;Promise&lt;/em&gt;:&lt;/p&gt;
  &lt;pre id=&quot;h5V1&quot; data-lang=&quot;javascript&quot;&gt;const myPromise = new Promise((resolve, reject) =&amp;gt; {
  // Выполнение асинхронных действий
  //
  // Внутри этой функции нужно в результате вызывать одну из функций
  // resolve или reject
})&lt;/pre&gt;
  &lt;p id=&quot;WsOU&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;b43K&quot;&gt;Получение результата промиса&lt;/h3&gt;
  &lt;pre id=&quot;X4HT&quot; data-lang=&quot;javascript&quot;&gt;myPromise
  .then(value =&amp;gt; {
    // Действия в случае успешного исполнения Промиса
    // Значение value - это значение, переданное в вызове функции
    // resove внутри промиса
  })
  .catch(error =&amp;gt; {
    // Действия в случае отклонения Промиса
    // Значение error - это значение, переданное в вызове функции
    // reject внутри промиса
  })&lt;/pre&gt;
  &lt;p id=&quot;EQzl&quot;&gt;Для тестирования отправки и получения запросов можно использовать сервис&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;FtRZ&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;https://jsonplaceholder.typicode.com/&quot; target=&quot;_blank&quot;&gt;jsonplaceholder.typicode.com&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;OfCa&quot;&gt;Когда мы отправляем &lt;em&gt;fetch&lt;/em&gt;-запрос, он отправляет назад промис.&lt;/p&gt;
  &lt;pre id=&quot;Urua&quot; data-lang=&quot;javascript&quot;&gt;fetch(&amp;#x27;https://jsonplaceholder.typicode.com/todos&amp;#x27;)
//
  .then(response =&amp;gt; response.json())
  // Получаем данные при исполнении промиса функцией fetch,
  // но т.к. там нет объектов и масивов JS мы присваиваем эти
  // данные переменной response и применяем к ней метод json()
  // Метод json() также возвращает промис
  .then(json =&amp;gt; console.log(json))
  // При возвращении промиса от метода json(), нужен еще один метод
  // then, который выводит его в консоль
  .catch(error =&amp;gt; console.error(error))
  // Если один из промисов отклонен, выводим ошибку в консоль

  &lt;/pre&gt;
  &lt;pre id=&quot;Urua&quot; data-lang=&quot;javascript&quot;&gt;fetch(&amp;#x27;https://jsonplaceholder.typicode.com/todos&amp;#x27;)
  .then(response =&amp;gt; {
    console.log(response)
    return response.json()
  }) 
// Такая функция позволит нам увидеть ответ от сервера в его исходном виде
  .then(json =&amp;gt; console.log(json))
  .catch(error =&amp;gt; console.error(error))&lt;/pre&gt;
  &lt;p id=&quot;pIHj&quot;&gt;Чтобы избежать двойного использования .then мы можем создать собственный промис, который будет получать данные, обрабатывать через JSON и вызвращать результат в виде переменной getData. Такой вариант кода можно поместить в модуль и обращаться к нему по мере необходимости:&lt;/p&gt;
  &lt;pre id=&quot;SLYy&quot; data-lang=&quot;javascript&quot;&gt;// Файл module1.js
const getData = (url) =&amp;gt; 
  new Promise((resolve, reject) =&amp;gt; 
    fetch(url)
      .then(response =&amp;gt; response.json())
      .then(json =&amp;gt; resolve(json))
      .catch(error =&amp;gt; reject(error))
  )

// Файл module2.js
getData(&amp;#x27;https://jsonplaceholder.typicode.com/todos&amp;#x27;)
  .then(data =&amp;gt; console.log(data))
  .catch(error =&amp;gt; console.log(error.massage))&lt;/pre&gt;
  &lt;blockquote id=&quot;tMKU&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;
  &lt;p id=&quot;0MHO&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;iOc1&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;dEYM&quot;&gt;22. Асинхронные функции&lt;/h2&gt;
  &lt;section style=&quot;background-color:hsl(hsl(170, 33%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;mkMK&quot;&gt;ASYNC/AWAIT - Специальный синтаксис для упрощения работы с промисами&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;kbWm&quot;&gt;Асинхронная функция - это функция которая всегда возвращает &lt;strong&gt;промис&lt;/strong&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;EK9a&quot;&gt;Для создания асинхронной функции используется слово async:&lt;/p&gt;
  &lt;pre id=&quot;hXah&quot; data-lang=&quot;javascript&quot;&gt;async function asyncFn() {
  // Стандартный синтаксис функции
}
const asyncFn = async () =&amp;gt; {
  // Стрелочная функция
}&lt;/pre&gt;
  &lt;p id=&quot;hXah&quot;&gt;!!!&lt;/p&gt;
  &lt;pre id=&quot;hXah&quot; data-lang=&quot;javascript&quot;&gt;const asyncFn = async () =&amp;gt; {
  throw new Error(&amp;#x27;There was an error!&amp;#x27;)
}

asyncFn()
  .then(value =&amp;gt; console.log(value))
  .catch(error =&amp;gt; console.log(error.massage))&lt;/pre&gt;
  &lt;p id=&quot;lDdb&quot;&gt;С помощью ключевого слова &lt;em&gt;await&lt;/em&gt; можно внутри асинхронной функции ожидать результата другого промиса:&lt;/p&gt;
  &lt;pre id=&quot;EhUi&quot; data-lang=&quot;javascript&quot;&gt;const timerPromise = () =&amp;gt;
  new Promise( (resolve, reject) =&amp;gt; setTimeout(() =&amp;gt; resolve(), 5000) )
  
const asyncFn = async () =&amp;gt; {
  console.log(&amp;#x27;Start&amp;#x27;)
  const start = performance.now()
  await timerPromise()
  const end = performance.now()
  console.log(&amp;#x27;Finish&amp;#x27;, end - start)
}

asyncFn()&lt;/pre&gt;
  &lt;p id=&quot;oCD7&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;tdzj&quot;&gt;22.1. Переход с промисов на ASYNC/AWAIT&lt;/h3&gt;
  &lt;p id=&quot;u2EL&quot;&gt;Возьмем предыдущий пример использования промисов:&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;pre id=&quot;WqvX&quot; data-lang=&quot;javascript&quot;&gt;// Первая часть
const getData = (url) =&amp;gt; 
  new Promise((resolve, reject) =&amp;gt; 
    fetch(url)
      .then(response =&amp;gt; response.json())
      .then(json =&amp;gt; resolve(json))
      .catch(error =&amp;gt; reject(error))
  )

// Вторая часть
getData(&amp;#x27;https://jsonplaceholder.typicode.com/todos&amp;#x27;)
  .then(data =&amp;gt; console.log(data))
  .catch(error =&amp;gt; console.log(error.massage))&lt;/pre&gt;
  &lt;/section&gt;
  &lt;p id=&quot;KeXQ&quot;&gt;Заменим первую часть:&lt;/p&gt;
  &lt;pre id=&quot;1DCh&quot; data-lang=&quot;javascript&quot;&gt;const getData = async (url) =&amp;gt; {
  const res = await fetch(url)
  const json = await res.json()
  return json
}&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;3DNa&quot;&gt;Если на каком этапе асинхронной функции возникнет ошибка промис будет &lt;strong&gt;автоматически&lt;/strong&gt; отклонен&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;bpKf&quot;&gt;Заменим вторую часть:&lt;/p&gt;
  &lt;pre id=&quot;TMK7&quot; data-lang=&quot;javascript&quot;&gt;const url = &amp;#x27;https://jsonplaceholder.typicode.com/todos&amp;#x27;)
const data = await getData(url)&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;mW6i&quot;&gt;Ключевое слово &lt;em&gt;await&lt;/em&gt; можно использовать в JS только внутри асинхронных функций, но браузеры позволяют обрабатывать такой код в консоли&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;U0vj&quot;&gt;Добавим во вторую часть обработчик ошибок с помощью &lt;a href=&quot;#hVjL&quot;&gt;try/catch&lt;/a&gt; блоков:&lt;/p&gt;
  &lt;pre id=&quot;Sgqm&quot; data-lang=&quot;javascript&quot;&gt;const url = &amp;#x27;https://jsonplaceholder.typicode.com/todos&amp;#x27;)

try {
  const data = await getData(url)
  console.log(data)
} catch (error) {
  console.log(error.message)
}&lt;/pre&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;jyuE&quot;&gt;ASYNC/AWAIT - это синтаксическая надстройка над промисами&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;J9RV&quot;&gt;&lt;em&gt;&lt;strong&gt;await&lt;/strong&gt;&lt;/em&gt; синтаксис возможен только внутри &lt;em&gt;&lt;strong&gt;async&lt;/strong&gt;&lt;/em&gt; функций&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;dnz0&quot;&gt;&lt;em&gt;&lt;strong&gt;async&lt;/strong&gt;&lt;/em&gt; функция всегда возвращает &lt;em&gt;Promise&lt;/em&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;S2S3&quot;&gt;&lt;em&gt;&lt;strong&gt;async&lt;/strong&gt;&lt;/em&gt; функция ожидает результата инструкции &lt;em&gt;&lt;strong&gt;await&lt;/strong&gt;&lt;/em&gt; и не выполняет последующие инструкции&lt;/p&gt;
  &lt;/section&gt;
  &lt;blockquote id=&quot;53Cr&quot; data-align=&quot;center&quot;&gt;&lt;a href=&quot;#TSUX&quot;&gt;Наверх&lt;/a&gt;&lt;/blockquote&gt;

</content></entry><entry><id>buninman:dLty8uA9oLZ</id><link rel="alternate" type="text/html" href="https://blog.buninman.ru/dLty8uA9oLZ?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=buninman"></link><title>Решил я, значит, стать программистом</title><published>2022-08-20T07:35:17.535Z</published><updated>2022-08-20T07:35:17.535Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/d0/17/d017fc60-141b-4e38-9aa4-a1910901ff33.png"></media:thumbnail><category term="myblog" label="Личный блог"></category><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/8d/42/8d42066b-977f-4e67-9ad2-2520a7556464.gif&quot;&gt;11 лет проработал дизайнером и вот так вот раз, и захотелось чего-то другого. Чего-то более математичного🙂</summary><content type="html">
  &lt;p id=&quot;LpIT&quot;&gt;11 лет проработал дизайнером и вот так вот раз, и захотелось чего-то другого. Чего-то более математичного🙂&lt;/p&gt;
  &lt;figure id=&quot;Vgn8&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/8d/42/8d42066b-977f-4e67-9ad2-2520a7556464.gif&quot; width=&quot;700&quot; /&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;sgnG&quot;&gt;Итак,&lt;/h3&gt;
  &lt;p id=&quot;E9ft&quot;&gt;Меня зовут Алексей и сейчас я занят изучением программирования на JavaScript. Выбор был сделан в пользу этого языка программирования просто потому, что я начал делать свой собственный сайт-портфолио по дизайну, частично используя чужой код. И чтоб разобраться в этом коде, мне нужно было знать HTML/CSS и JavaScript.&lt;/p&gt;
  &lt;p id=&quot;jDPX&quot;&gt;В процессе я заметил, что делать сайт мне намного интереснее, чем заниматься его наполнением и оформлять дизайн-проекты. В голову сразу залезли новые, но вполне достижимые цели. Например, у меня есть идея для приложения по учету финансов, а также есть желание повторить сайт-игру с машинкой от Бруно Саймона. Все это позволяет сделать JavaScript.&lt;/p&gt;
  &lt;p id=&quot;7bwr&quot;&gt;Если честно, я понятия не имею какую сферу программирования и какой язык стоит выбрать, чтоб быть программистом. Я просто захотел попробовать себя в какой-то новой сфере. Наверное, начался кризис среднего возраста😐 или что-то вроде того.&lt;/p&gt;
  &lt;p id=&quot;pVet&quot;&gt;Не уверен, что этот выбор правильный и даже не уверен, что меня на долго хватит, но пока все идет ништяк. Я уже немного подтянул знания HTML/CSS и начал проходить курс по JavaScript, который на удивление дается мне легко. Даже появилось какое-то неловкое чувство🤷‍♂️ будто изучаешь какую-то никому ненужную фигню.&lt;/p&gt;
  &lt;p id=&quot;uYmZ&quot;&gt;Если все получится, то буду пробовать устраиваться джуном и начинать карьеру программиста.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;hr /&gt;
  &lt;h3 id=&quot;upR4&quot;&gt;Зачем мне блог?&lt;/h3&gt;
  &lt;p id=&quot;4Zdd&quot;&gt;Изначально я завел его чтоб складывать полезные ссылки и конспекты, которые появляются по мере прохождения различных курсов. Я уже старый, поэтому конспектирую новые знания.. так меня научили еще более старые люди🙄&lt;/p&gt;
  &lt;p id=&quot;hbdg&quot;&gt;Но в этот раз я решил не тратить бумагу, а печать все в интернетах.. вдруг кому пригодится. Но нужно понимать, что это не истина, а всего-лишь моя интерпретация полученной информации, поэтому кроме конспектов тут будут и обычные человеческие посты.&lt;/p&gt;
  &lt;p id=&quot;RFB0&quot;&gt;Единственное, когда пишешь &amp;quot;в стол&amp;quot; приходит уныние, поэтому очень хочется чтоб кто-то этот блог читал, поддерживал или чморил в комментах, использовал конспекты. В общем, если вы тоже изучаете программирование, если вам интересно чем все закончится или есть еще какие-то неведомые причины, то подписывайтесь на меня тут или в &lt;a href=&quot;https://t.me/buninman&quot; target=&quot;_blank&quot;&gt;Телеграме&lt;/a&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h3 id=&quot;Tu9x&quot;&gt;Что дальше?&lt;/h3&gt;
  &lt;p id=&quot;8eTR&quot;&gt;На сегодняшний день, план изучения новых тем у меня такой:&lt;/p&gt;
  &lt;ul id=&quot;faqz&quot;&gt;
    &lt;li id=&quot;bin9&quot;&gt;HTML/CSS - без них никуда;&lt;/li&gt;
    &lt;li id=&quot;klOv&quot;&gt;JavaScript - основа моего план;&lt;/li&gt;
    &lt;li id=&quot;c5s9&quot;&gt;Vue или React - чтоб попробовать создать работающее приложение;&lt;/li&gt;
    &lt;li id=&quot;q3XD&quot;&gt;Blender - потому что хочу делать иллюстрации и модели для сайтов и приложений;&lt;/li&gt;
    &lt;li id=&quot;Kr12&quot;&gt;Three.js - чтоб сделать сайт как у Бруно Саймона;&lt;/li&gt;
    &lt;li id=&quot;Lfh9&quot;&gt;SQL - эта штука тоже много где всплывает, надо знать.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;Ybh3&quot;&gt;Этот план будет корректироваться по мере необходимости или по наличию интересного курса. Так, например, у меня уже есть курс по React, ждущий своей очереди.&lt;/p&gt;
  &lt;p id=&quot;AuJk&quot;&gt;Также надо не забывать следить за фондовым рынком, заниматься спортом, учить английский и между делом зарабатывать деньги🙂&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;dHhI&quot;&gt;А вот &lt;a href=&quot;https://bruno-simon.com/&quot; target=&quot;_blank&quot;&gt;сайт Бруно Саймана&lt;/a&gt;, о котором я говорил выше.&lt;/p&gt;
  &lt;figure id=&quot;HvD8&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/86/90/8690629d-8217-4adc-9eaf-255ad2216f15.png&quot; width=&quot;1920&quot; /&gt;
  &lt;/figure&gt;

</content></entry></feed>