HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-03-10
1 <ul><li><a>Оператор Map</a><ul><li><a>Практическое применение</a></li>
1 <ul><li><a>Оператор Map</a><ul><li><a>Практическое применение</a></li>
2 <li><a>Разница между подходами</a></li>
2 <li><a>Разница между подходами</a></li>
3 <li><a>О трудностях</a></li>
3 <li><a>О трудностях</a></li>
4 </ul></li>
4 </ul></li>
5 <li><a>Метод Filter</a><ul><li><a>Проблемы реализации</a></li>
5 <li><a>Метод Filter</a><ul><li><a>Проблемы реализации</a></li>
6 </ul></li>
6 </ul></li>
7 <li><a>Метод reduce</a><ul><li><a>Наглядный пример</a></li>
7 <li><a>Метод reduce</a><ul><li><a>Наглядный пример</a></li>
8 <li><a>Особенности написания</a></li>
8 <li><a>Особенности написания</a></li>
9 <li><a>Применение на практике</a><ul><li><a>ES5 версия</a></li>
9 <li><a>Применение на практике</a><ul><li><a>ES5 версия</a></li>
10 <li><a>Среднее число</a></li>
10 <li><a>Среднее число</a></li>
11 <li><a>Учет данных</a></li>
11 <li><a>Учет данных</a></li>
12 <li><a>Соединение воедино</a></li>
12 <li><a>Соединение воедино</a></li>
13 </ul></li>
13 </ul></li>
14 </ul></li>
14 </ul></li>
15 <li><a>Курсы для быстрого освоения</a></li>
15 <li><a>Курсы для быстрого освоения</a></li>
16 </ul><p>Функциональное программирование становится все более популярным. Такая парадигма поддерживается достаточно известным и распространенным языком - JavaScript. Нужен JS для того, чтобы создавать веб-приложения, а также иное программное обеспечение, базирующееся на скриптах. В основном применяется для интернет-разработки.</p>
16 </ul><p>Функциональное программирование становится все более популярным. Такая парадигма поддерживается достаточно известным и распространенным языком - JavaScript. Нужен JS для того, чтобы создавать веб-приложения, а также иное программное обеспечение, базирующееся на скриптах. В основном применяется для интернет-разработки.</p>
17 <p>Функциональное программирование имеет одну особенность - использование списков, а также разнообразных операторов для работы с ними. Говоря проще - массивы вещей и возможность взаимодействия с ними.</p>
17 <p>Функциональное программирование имеет одну особенность - использование списков, а также разнообразных операторов для работы с ними. Говоря проще - массивы вещей и возможность взаимодействия с ними.</p>
18 <p>В данной статье будут рассмотрены ключевые операторы списков в JavaScript. Они помогут быстрее создавать функциональные коды, получая на выходе достаточно мощные утилиты. А еще - позволят избавиться от постоянного применения цикла for.</p>
18 <p>В данной статье будут рассмотрены ключевые операторы списков в JavaScript. Они помогут быстрее создавать функциональные коды, получая на выходе достаточно мощные утилиты. А еще - позволят избавиться от постоянного применения цикла for.</p>
19 <h2>Оператор Map</h2>
19 <h2>Оператор Map</h2>
20 <p>При создании ПО приходится достаточно часто модифицировать каждый элемент имеющегося массива при помощи одних и тех же подходов. Типичные примеры - возведение каждого компонента массива чисел в квадрат, получение имен из списка пользователей, обработка строк регулярными выражениями.</p>
20 <p>При создании ПО приходится достаточно часто модифицировать каждый элемент имеющегося массива при помощи одних и тех же подходов. Типичные примеры - возведение каждого компонента массива чисел в квадрат, получение имен из списка пользователей, обработка строк регулярными выражениями.</p>
21 <p>Map - встроенный метод JS, который используется для соответствующих задач. Он определен в Array.prototype. Его можно вызвать на любом массиве, а затем передать коллбек в виде первого аргумента.</p>
21 <p>Map - встроенный метод JS, который используется для соответствующих задач. Он определен в Array.prototype. Его можно вызвать на любом массиве, а затем передать коллбек в виде первого аргумента.</p>
22 <p>При вызове map для массива, callback выполняется для каждого его элемента. После - возвращается новый массив со значениями, которые обработаны каллбеком.</p>
22 <p>При вызове map для массива, callback выполняется для каждого его элемента. После - возвращается новый массив со значениями, которые обработаны каллбеком.</p>
23 <p>Данная функция (оператор) передает три аргумента:</p>
23 <p>Данная функция (оператор) передает три аргумента:</p>
24 <ul><li>текущий элемент массива;</li>
24 <ul><li>текущий элемент массива;</li>
25 <li>индекс;</li>
25 <li>индекс;</li>
26 <li>весь массив, для которого был вызван изначально map.</li>
26 <li>весь массив, для которого был вызван изначально map.</li>
27 </ul><p>Лучше разобраться с этими моментами JavaScript помогут наглядные примеры.</p>
27 </ul><p>Лучше разобраться с этими моментами JavaScript помогут наглядные примеры.</p>
28 <h3>Практическое применение</h3>
28 <h3>Практическое применение</h3>
29 <p>Надо сделать программу, которая имеет массив с задачами для выполнения на день. Каждый task - это объект. Он имеет свои собственные свойства name и duration. В редакторе фрагмент кода выглядит так:</p>
29 <p>Надо сделать программу, которая имеет массив с задачами для выполнения на день. Каждый task - это объект. Он имеет свои собственные свойства name и duration. В редакторе фрагмент кода выглядит так:</p>
30 <p>Теперь требуется создать новый массив только с "именем" для каждого "таска". Этот прием позволяет посмотреть на все задачи, выполненные за день. Необходимо использовать цикл for. Тогда код будет выглядеть так:</p>
30 <p>Теперь требуется создать новый массив только с "именем" для каждого "таска". Этот прием позволяет посмотреть на все задачи, выполненные за день. Необходимо использовать цикл for. Тогда код будет выглядеть так:</p>
31 <p>В JS есть цикл forEach. Он работает так же, как и for, но в нем не требуется проводить сравнение индекса элемента с длиной массива. Процессы проводятся автоматически:</p>
31 <p>В JS есть цикл forEach. Он работает так же, как и for, но в нем не требуется проводить сравнение индекса элемента с длиной массива. Процессы проводятся автоматически:</p>
32 <p>Если же нужно использовать "метод" map, код получит следующее представление:</p>
32 <p>Если же нужно использовать "метод" map, код получит следующее представление:</p>
33 <p>Здесь добавлены параметры index и array. Это поможет не забыть о том, что ими можно пользоваться при необходимости. А вот - реализация на MDN:</p>
33 <p>Здесь добавлены параметры index и array. Это поможет не забыть о том, что ими можно пользоваться при необходимости. А вот - реализация на MDN:</p>
34 <p>Перед тем, как его протестировать, нужно инициализировать task. Отлично работает с mdn MozillaFirefox.</p>
34 <p>Перед тем, как его протестировать, нужно инициализировать task. Отлично работает с mdn MozillaFirefox.</p>
35 <h3>Разница между подходами</h3>
35 <h3>Разница между подходами</h3>
36 <p>Программист может использовать любой метод из предложенных. Главное - понимать разницу между ними:</p>
36 <p>Программист может использовать любой метод из предложенных. Главное - понимать разницу между ними:</p>
37 <ol><li>Map нужен для того, чтобы избавиться от состояния цикла for.</li>
37 <ol><li>Map нужен для того, чтобы избавиться от состояния цикла for.</li>
38 <li>Позволяет взаимодействовать с компонентами массива напрямую. Индексировать его не придется.</li>
38 <li>Позволяет взаимодействовать с компонентами массива напрямую. Индексировать его не придется.</li>
39 <li>Не придется создавать массив пустой и добавлять в него компоненты. Map вернет конечный результат за один подход. Останется добавить возвращаемое значение новой переменной.</li>
39 <li>Не придется создавать массив пустой и добавлять в него компоненты. Map вернет конечный результат за один подход. Останется добавить возвращаемое значение новой переменной.</li>
40 <li>Нужно не забывать добавлять return коллбеку. Если им пренебречь, на выходе получится новый массив, который заполнен undefined.</li>
40 <li>Нужно не забывать добавлять return коллбеку. Если им пренебречь, на выходе получится новый массив, который заполнен undefined.</li>
41 </ol><p>Все эти характеристики имеют иные рассматриваемые далее функции. Map имеет несколько преимуществ перед forEach:</p>
41 </ol><p>Все эти характеристики имеют иные рассматриваемые далее функции. Map имеет несколько преимуществ перед forEach:</p>
42 <ol><li>ForEach возвращает undefined. Его не получится связать с другими методами массива. Map от этого недостатка уберегает.</li>
42 <ol><li>ForEach возвращает undefined. Его не получится связать с другими методами массива. Map от этого недостатка уберегает.</li>
43 <li>Функция (оператор) Map поможет вернуть массив с конечным результатом. Корректировать "набор данных" внутри цикла больше нет необходимости.</li>
43 <li>Функция (оператор) Map поможет вернуть массив с конечным результатом. Корректировать "набор данных" внутри цикла больше нет необходимости.</li>
44 </ol><p>Все это приводит к тому, что функциональный код становится максимально емким, понятным и простым. Это - верный путь к реактивной разработке.</p>
44 </ol><p>Все это приводит к тому, что функциональный код становится максимально емким, понятным и простым. Это - верный путь к реактивной разработке.</p>
45 <h3>О трудностях</h3>
45 <h3>О трудностях</h3>
46 <p>В коллбеке, передаваемом оператору, должен быть явный return. В противном случае функция вернет массив, который принимает компоненты типа undefined.</p>
46 <p>В коллбеке, передаваемом оператору, должен быть явный return. В противном случае функция вернет массив, который принимает компоненты типа undefined.</p>
47 <p>Также стоит запомнить - данный вариант не указывает на ошибки. Вместо этого происходит возврат пустого массива. Тихие ошибки подобного плана достаточно тяжело искать, особенно если исходный код объемный.</p>
47 <p>Также стоит запомнить - данный вариант не указывает на ошибки. Вместо этого происходит возврат пустого массива. Тихие ошибки подобного плана достаточно тяжело искать, особенно если исходный код объемный.</p>
48 <h2>Метод Filter</h2>
48 <h2>Метод Filter</h2>
49 <p>Основные methods для работы со списками в функциональном программировании на JS предусматривают метод Filter. Он отвечает за фильтрацию массива. Отсеивает ненужные компоненты.</p>
49 <p>Основные methods для работы со списками в функциональном программировании на JS предусматривают метод Filter. Он отвечает за фильтрацию массива. Отсеивает ненужные компоненты.</p>
50 <p>Определяется в array prototype. Method доступен для любого массива. Начальное значение (аргумент) - каллбек. Работает так:</p>
50 <p>Определяется в array prototype. Method доступен для любого массива. Начальное значение (аргумент) - каллбек. Работает так:</p>
51 <ol><li>Filter вызывает callback для каждого компонента "множества данных".</li>
51 <ol><li>Filter вызывает callback для каждого компонента "множества данных".</li>
52 <li>Проводится обработка информации.</li>
52 <li>Проводится обработка информации.</li>
53 <li>Возвращается новый массив, который содержит только компоненты, для которых callback вернул значение "истина".</li>
53 <li>Возвращается новый массив, который содержит только компоненты, для которых callback вернул значение "истина".</li>
54 </ol><p>Передает при работе три аргумента: текущий компонент, индекс и весь массив.</p>
54 </ol><p>Передает при работе три аргумента: текущий компонент, индекс и весь массив.</p>
55 <h3>Проблемы реализации</h3>
55 <h3>Проблемы реализации</h3>
56 <p>Каждый раз, когда разработчик использует Filter, он должен помнить, что:</p>
56 <p>Каждый раз, когда разработчик использует Filter, он должен помнить, что:</p>
57 <ol><li>Обязательно использовать return. Это нужно для того, чтобы убедиться в возврате булевого значения.</li>
57 <ol><li>Обязательно использовать return. Это нужно для того, чтобы убедиться в возврате булевого значения.</li>
58 <li>Если забыть о return, коллбек вернет undefined. Результат метода всегда будет "ложью".</li>
58 <li>Если забыть о return, коллбек вернет undefined. Результат метода всегда будет "ложью".</li>
59 <li>Если возвращается что-то, что отличается от "истины" и "лжи", система использует правила приведения JS. Это помогает понять, чего хочет добиться разработчик. Это часто влечет ошибки.</li>
59 <li>Если возвращается что-то, что отличается от "истины" и "лжи", система использует правила приведения JS. Это помогает понять, чего хочет добиться разработчик. Это часто влечет ошибки.</li>
60 </ol><p>Запомнив эти простые правила и принципы того, как работает Filter, программист сможет эффективно использовать его в функциональном программировании.</p>
60 </ol><p>Запомнив эти простые правила и принципы того, как работает Filter, программист сможет эффективно использовать его в функциональном программировании.</p>
61 <h2>Метод reduce</h2>
61 <h2>Метод reduce</h2>
62 <p>Reduce - метод массива, позволяющий превращать "множество данных" в любое другое значение при помощи переданной функции коллбека и начального значения. Используется тогда, когда есть массив чисел, которые необходимо сложить.</p>
62 <p>Reduce - метод массива, позволяющий превращать "множество данных" в любое другое значение при помощи переданной функции коллбека и начального значения. Используется тогда, когда есть массив чисел, которые необходимо сложить.</p>
63 <p>Reduce - к первому значению прибавляет второе, потом к результату - третье и так далее. Это - аналог "суммы" (sum). Определяется в array prototype. Доступен для любого массива. Коллбек передается в виде первого аргумента. Дополнительно можно передать второй аргумент - значение, индекс с которого предусматривает сложение.</p>
63 <p>Reduce - к первому значению прибавляет второе, потом к результату - третье и так далее. Это - аналог "суммы" (sum). Определяется в array prototype. Доступен для любого массива. Коллбек передается в виде первого аргумента. Дополнительно можно передать второй аргумент - значение, индекс с которого предусматривает сложение.</p>
64 <p>Имеет четыре arg:</p>
64 <p>Имеет четыре arg:</p>
65 <ul><li>текущее значение (acc);</li>
65 <ul><li>текущее значение (acc);</li>
66 <li>предыдущее значение (item);</li>
66 <li>предыдущее значение (item);</li>
67 <li>нынешний индекс (index);</li>
67 <li>нынешний индекс (index);</li>
68 <li>массив, для которого вызывается reduce (arr).</li>
68 <li>массив, для которого вызывается reduce (arr).</li>
69 </ul><p>Callback будет иметь доступ к предыдущим "параметрам" на каждой очередной итерации. На первом "проходе" его нет. Именно поэтому reduce требует передачи начального "параметра" на усмотрение пользователя. В противном случае предыдущее окажется 0. Reduce в JavaScript возвращает один arr (arg), а не все "множество" из одной составляющей.</p>
69 </ul><p>Callback будет иметь доступ к предыдущим "параметрам" на каждой очередной итерации. На первом "проходе" его нет. Именно поэтому reduce требует передачи начального "параметра" на усмотрение пользователя. В противном случае предыдущее окажется 0. Reduce в JavaScript возвращает один arr (arg), а не все "множество" из одной составляющей.</p>
70 <h3>Наглядный пример</h3>
70 <h3>Наглядный пример</h3>
71 <p>Соответствующий метод встречается на практике чаще остальных. Поэтому его стоит рассмотреть более подробно. Вот - пример кода:</p>
71 <p>Соответствующий метод встречается на практике чаще остальных. Поэтому его стоит рассмотреть более подробно. Вот - пример кода:</p>
72 <p>Так будет выглядеть reduce на практике.</p>
72 <p>Так будет выглядеть reduce на практике.</p>
73 <h3>Особенности написания</h3>
73 <h3>Особенности написания</h3>
74 <p>Reduce принимает два параметра object - функцию-коллбек и начальный arr-параметр для аккумулятора.</p>
74 <p>Reduce принимает два параметра object - функцию-коллбек и начальный arr-параметр для аккумулятора.</p>
75 <p>Операция обязательно возвращает тот или иной результат. Связно это с тем, что при следующей итерации в acc object отобразится результат, который вернулся на предыдущем этапе. На начале обработки первый элемент - это "параметр", который передается вторым из arr в метод reduce.</p>
75 <p>Операция обязательно возвращает тот или иной результат. Связно это с тем, что при следующей итерации в acc object отобразится результат, который вернулся на предыдущем этапе. На начале обработки первый элемент - это "параметр", который передается вторым из arr в метод reduce.</p>
76 <p>"Точку старта" для аккумулятора можно не указывать явно. Для этого случае первый компонент в arr встречается на первой итерации:</p>
76 <p>"Точку старта" для аккумулятора можно не указывать явно. Для этого случае первый компонент в arr встречается на первой итерации:</p>
77 <p>В этом example:</p>
77 <p>В этом example:</p>
78 <ol><li>Acc на первом проходе - это "единица", val - 2.</li>
78 <ol><li>Acc на первом проходе - это "единица", val - 2.</li>
79 <li>К полученному результату objects прибавляется 3.</li>
79 <li>К полученному результату objects прибавляется 3.</li>
80 <li>Осуществляется возврат результата через reduce.</li>
80 <li>Осуществляется возврат результата через reduce.</li>
81 </ol><p>Есть и краевой example. Если arr пуст, JS выдаст соответствующую ошибку с сообщением "Reduce of empty arrays with no initial value. Ситуация требует отдельной обработки. Example - обернуть reduce в try…catch. Но лучше всегда задавать function "изначальный параметр".</p>
81 </ol><p>Есть и краевой example. Если arr пуст, JS выдаст соответствующую ошибку с сообщением "Reduce of empty arrays with no initial value. Ситуация требует отдельной обработки. Example - обернуть reduce в try…catch. Но лучше всегда задавать function "изначальный параметр".</p>
82 <h3>Применение на практике</h3>
82 <h3>Применение на практике</h3>
83 <p>Reduce - это object (функция), которая широко распространена в функциональном программировании. Особенно на JS. Далее будут рассмотрены ситуации, при которых нужен соответствующий метод. Все это поможет лучше разобраться в принципах его работы.</p>
83 <p>Reduce - это object (функция), которая широко распространена в функциональном программировании. Особенно на JS. Далее будут рассмотрены ситуации, при которых нужен соответствующий метод. Все это поможет лучше разобраться в принципах его работы.</p>
84 <h4>ES5 версия</h4>
84 <h4>ES5 версия</h4>
85 <p>При работе с node и mdn код может выглядеть громоздко. Часто программисты начинают с ES5. Элементарный код будет выглядеть так:</p>
85 <p>При работе с node и mdn код может выглядеть громоздко. Часто программисты начинают с ES5. Элементарный код будет выглядеть так:</p>
86 <p>Остальные примеры - это ES6. Его синтаксис более краткий и оставляет меньше пространства для возникновения тех или иных ошибок.</p>
86 <p>Остальные примеры - это ES6. Его синтаксис более краткий и оставляет меньше пространства для возникновения тех или иных ошибок.</p>
87 <h4><em>Среднее число</em></h4>
87 <h4><em>Среднее число</em></h4>
88 <p>In order требуется не просто вывести сумму, а разделить ее на длину arr перед тем, как отображать итог. Для этого можно задействовать index. Он покажет, сколько раз редюсер прошел по "множеству".</p>
88 <p>In order требуется не просто вывести сумму, а разделить ее на длину arr перед тем, как отображать итог. Для этого можно задействовать index. Он покажет, сколько раз редюсер прошел по "множеству".</p>
89 <p>Последний "параметр" - это и его сам arr. Выше - пример обнаружения среднего заданных объектов.</p>
89 <p>Последний "параметр" - это и его сам arr. Выше - пример обнаружения среднего заданных объектов.</p>
90 <h4><em>Учет данных</em></h4>
90 <h4><em>Учет данных</em></h4>
91 <p>А вот order, который помогает вести учет информации через reduce. Он помогает if есть коллекция информации, но требуется узнать, сколько типов каждого компонента содержится во множестве:</p>
91 <p>А вот order, который помогает вести учет информации через reduce. Он помогает if есть коллекция информации, но требуется узнать, сколько типов каждого компонента содержится во множестве:</p>
92 <p>Чтобы посчитать каждый объект в arr, требуется сначала задать пустой object, а не все множество. Далее действовать необходимо следующим образом:</p>
92 <p>Чтобы посчитать каждый объект в arr, требуется сначала задать пустой object, а не все множество. Далее действовать необходимо следующим образом:</p>
93 <ol><li>Сохранить пару ключ-значение в total: .</li>
93 <ol><li>Сохранить пару ключ-значение в total: .</li>
94 <li>Выдать имя первому ключу. Это - первый параметр.</li>
94 <li>Выдать имя первому ключу. Это - первый параметр.</li>
95 <li>Присваиваемое значение - "единица". Такой подход позволяет получить объект, где все названия фруктов - это ключи. Каждый имеет значение 1.</li>
95 <li>Присваиваемое значение - "единица". Такой подход позволяет получить объект, где все названия фруктов - это ключи. Каждый имеет значение 1.</li>
96 <li>Увеличение length (параметра каждого "фрукта") необходимо, если происходит повторение.</li>
96 <li>Увеличение length (параметра каждого "фрукта") необходимо, если происходит повторение.</li>
97 <li>На втором цикле требуется проверить, есть ли в total ключ с соответствующей "пищей". Если нет - создать ключ. В противном случае - увеличить на +1: .</li>
97 <li>На втором цикле требуется проверить, есть ли в total ключ с соответствующей "пищей". Если нет - создать ключ. В противном случае - увеличить на +1: .</li>
98 </ol><p>Теперь можно запустить программу и посмотреть, что вышло. Пример - через node.</p>
98 </ol><p>Теперь можно запустить программу и посмотреть, что вышло. Пример - через node.</p>
99 <h4><em>Соединение воедино</em></h4>
99 <h4><em>Соединение воедино</em></h4>
100 <p>Reduce помогает сливать друг с другом вложенные значения. Они in order обретают форму единого arr (множества). Выглядит это так:</p>
100 <p>Reduce помогает сливать друг с другом вложенные значения. Они in order обретают форму единого arr (множества). Выглядит это так:</p>
101 <ol><li>Сначала нужно выставить изначальное значение на пустое множество. Далее - конкатенировать его с total: .</li>
101 <ol><li>Сначала нужно выставить изначальное значение на пустое множество. Далее - конкатенировать его с total: .</li>
102 <li>Для более сложной ситуации - получить все цвета с переменной data, которая находится ниже: .</li>
102 <li>Для более сложной ситуации - получить все цвета с переменной data, которая находится ниже: .</li>
103 <li>Пройтись по каждому объекту (push) и взять оттуда нужные цвета. Для этого на помощь придет reduce. Но можно воспользоваться forEach и использовать amount.c. При каждой итерации здесь происходит добавление вложенного arr в total: .</li>
103 <li>Пройтись по каждому объекту (push) и взять оттуда нужные цвета. Для этого на помощь придет reduce. Но можно воспользоваться forEach и использовать amount.c. При каждой итерации здесь происходит добавление вложенного arr в total: .</li>
104 <li>Если нужно только уникальные "параметры", требуется провести проверку на него в total. Делается это перед тем, как отправить соответствующий компонент в arr: .</li>
104 <li>Если нужно только уникальные "параметры", требуется провести проверку на него в total. Делается это перед тем, как отправить соответствующий компонент в arr: .</li>
105 </ol><p>Это - основы работы со списками и уникальными функциями JS. Освоить их сможет как новичок, так и продвинутый разработчик. Наглядные примеры помогут не запутаться и лучше разобраться в выбранном направлении.</p>
105 </ol><p>Это - основы работы со списками и уникальными функциями JS. Освоить их сможет как новичок, так и продвинутый разработчик. Наглядные примеры помогут не запутаться и лучше разобраться в выбранном направлении.</p>
106 <h2>Курсы для быстрого освоения</h2>
106 <h2>Курсы для быстрого освоения</h2>
107 <p>Чтобы лучше изучить метод reduce в JavaScript, а также выяснить, что такое node и функциональное программирование, подойдут специализированные компьютерные курсы. Они намного лучше самообразования.</p>
107 <p>Чтобы лучше изучить метод reduce в JavaScript, а также выяснить, что такое node и функциональное программирование, подойдут специализированные компьютерные курсы. Они намного лучше самообразования.</p>
108 <p>Рассчитаны программы на срок от нескольких месяцев до года. Пользователи могут выбрать одно или пару направлений одновременно. Каждому гарантировано кураторство опытными специалистами, интересные домашние задания и практика с формированием портфолио. При успешном завершении курсов пользователь получит сертификат, подтверждающий навыки и умения в выбранной области. </p>
108 <p>Рассчитаны программы на срок от нескольких месяцев до года. Пользователи могут выбрать одно или пару направлений одновременно. Каждому гарантировано кураторство опытными специалистами, интересные домашние задания и практика с формированием портфолио. При успешном завершении курсов пользователь получит сертификат, подтверждающий навыки и умения в выбранной области. </p>
109 <a></a>
109 <a></a>