<!DOCTYPE html>
<html class="h-100" data-bs-theme="light" data-mantine-color-scheme="light" lang="ru" prefix="og: https://ogp.me/ns#">
<head>
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<link crossorigin="true" href="https://cdn.hexlet.io" rel="preconnect">
<link href="https://mc.yandex.ru" rel="preconnect">
<meta content="aa2vrdtq64dub8knuf83lwywit311w" name="facebook-domain-verification">
<link href="/favicon.ico" rel="icon" sizes="any">
<link href="/favicon.svg" rel="icon" type="image/svg+xml">
<link href="/apple-touch-icon.png" rel="apple-touch-icon">
<link href="/manifest.webmanifest" rel="manifest">
<script>
//<![CDATA[
window.gon={};gon.ym_counter="25559621";gon.is_bot=true;gon.applications={};gon.current_user={"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26 17:10:33 UTC","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false};gon.token="HAIgjvWyh6gwfym9SlVIKrJgKxnFTIG47i2QmIdNgKnz0-u5B8wqyIY8DSVGWrhdcmkGs817fxpTzQrM1Upnxw";gon.locale="ru";gon.language="ru";gon.theme="light";gon.rails_env="production";gon.mobile=false;gon.google={"analytics_key":"UA-1360700-51","optimize_key":"GTM-5QDVFPF"};gon.captcha={"google_v3_site_key":"6LenGbgZAAAAAM7HbrDbn5JlizCSzPcS767c9vaY","yandex_site_key":"ysc1_Vyob5ZPPUdPBsu0ykt8bVFdzsfpoVjQChLGl2b4g19647a89","verification_failed":null};gon.social_signin=false;gon.typoreporter_google_form_id="1FAIpQLSeibfGq-KvWQ2Fyru-zkFFRVTLBuzXAHAoEyN1p49FtDmNoNA";
//]]>
</script>
<meta charset="utf-8">
<title>Стек | JS: Массивы</title>
<meta name="description" content="Стек / JS: Массивы: Знакомимся с одной из самых фундаментальных структур данных">
<link rel="canonical" href="https://ru.hexlet.io/courses/js-arrays/lessons/stack/theory_unit">
<meta name="robots" content="noarchive">
<meta property="og:title" content="Стек">
<meta property="og:title" content="JS: Массивы">
<meta property="og:description" content="Стек / JS: Массивы: Знакомимся с одной из самых фундаментальных структур данных">
<meta property="og:url" content="https://ru.hexlet.io/courses/js-arrays/lessons/stack/theory_unit">
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="d7Cag-_2s_qgAk0jeKDJh2N9hdLG2V3GjexwK9bDrwiYYVG0HYgemhZBabt0rznwo3SoeM7uo2QwDOp_hMRIZg" />
<script src="/vite/assets/inertia-INZxX8jp.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/preload-helper-BJ4cLWpC.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-nkZBEvfU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ahoy-DrlRQ-1D.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/analytics-6pOtQ3OW.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Surface-DL2bpZA-.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/extends-C-EagtpE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/inheritsLoose-BBd-DCVI.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/objectWithoutPropertiesLoose-DRHXDhjp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/index.esm-DAqKOkZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Button-CGPUux8l.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/CloseButton-D1euiPao.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Group-BX48WcuU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Loader-BQEY8g6v.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Modal-Cy3HByv7.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/OptionalPortal-1Hza5P2w.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Stack-CtjJzfw4.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Textarea-Ck64llAy.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/DirectionProvider-Dc9zdUke.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/events-DJQOhap0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-reduced-motion-D2owz4wa.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-disclosure-zKtK5W1r.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-hotkeys-Cnc_Rwkb.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/random-id-DOQyszCZ.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/exports-C_MrNx_T.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<link rel="stylesheet" href="/vite/assets/application-BqhCP46M.js" />
<script src="/vite/assets/application-Df9RExpe.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/autocomplete-VMNbxKGl.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/createPopper-C3aM9r1M.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/js.cookie-D1-O8zkX.js" as="script" crossorigin="anonymous"><link rel="stylesheet" href="/vite/assets/application-C8HjmMaq.css" media="screen" />
<script>
window.ym = function(){(ym.a=ym.a||[]).push(arguments)};
window.addEventListener('load', function() {
setTimeout(function() {
ym.l = 1*new Date();
ym(window.gon.ym_counter, "init", {
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
webvisor: true
});
// Загружаем скрипт
var k = document.createElement('script');
k.async = 1;
k.src = 'https://mc.yandex.ru/metrika/tag.js';
document.head.appendChild(k);
ym(window.gon.ym_counter, 'getClientID', function(clientID) {
window.ymClientId = clientID;
});
}, 1500);
});
</script>
<!-- Google Tag Manager - deferred -->
<script>
// dataLayer stub сразу — пуши работают до загрузки скрипта
window.dataLayer = window.dataLayer || [];
// Сам скрипт — отложенно после load
window.addEventListener('load', function() {
setTimeout(function() {
dataLayer.push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
var j = document.createElement('script');
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-WK88TH';
document.head.appendChild(j);
}, 1500);
});
</script>
<!-- End Google Tag Manager -->
</head>
<body>
<noscript>
<div>
<img alt="" src="https://mc.yandex.ru/watch/25559621" style="position:absolute; left:-9999px;">
</div>
</noscript>
<header class="sticky-top bg-body">
<nav class="navbar navbar-expand-lg">
<div class="container-xxl">
<a class="navbar-brand" href="/"><img alt="Логотип Хекслета" height="24" src="https://ru.hexlet.io/vite/assets/logo_ru_light-BpiEA1LT.svg" width="96">
</a><button aria-controls="collapsable" aria-expanded="false" aria-label="Меню" class="navbar-toggler border-0 mb-0 mt-1" data-bs-target="#collapsable" data-bs-toggle="collapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsable">
<ul class="navbar-nav mb-lg-0 mt-lg-1">
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
Все курсы
<span class="bi bi-chevron-down align-middle ms-1"></span>
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item d-flex py-2" href="/courses"><div class="fw-bold me-auto">Все что есть</div>
<div class="text-muted">117</div>
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные категории</b>
</li>
<li>
<a class="dropdown-item py-2" href="/courses_devops">Курсы по DevOps
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_data_analytics">Курсы по аналитике данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_programming">Курсы по программированию
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_testing">Курсы по тестированию
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные курсы</b>
</li>
<li>
<a class="dropdown-item py-2" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/go">Go-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/java">Java-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/python">Python-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/qa-auto-engineer-java">Автоматизатор тестирования на Java
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/data-analytics">Аналитик данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/frontend">Фронтенд-разработчик
</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
О Хекслете
<span class="bi bi-chevron-down align-middle"></span>
</button>
<ul class="dropdown-menu bg-body">
<li>
<a class="dropdown-item py-2" href="/pages/about">О нас
</a></li>
<li>
<a class="dropdown-item py-2" href="/blog">Блог
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/hse-research" role="button">Результаты (Исследование)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://career.hexlet.io" role="button">Хекслет Карьера
</span></li>
<li>
<a class="dropdown-item py-2" href="/testimonials">Отзывы студентов
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://t.me/hexlet_help_bot" role="button">Поддержка (В ТГ)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/referal-program/?promo_creative=priglasite-druzei&promo_name=referal-program&promo_position=promo_position&promo_start=010724&promo_type=link" role="button">Реферальная программа
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/certificate" role="button">Подарочные сертификаты
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://hh.ru/employer/4307094" role="button">Вакансии
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://b2b.hexlet.io" data-target="_blank" role="button">Компаниям
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexly.ru/" data-target="_blank" role="button">Колледж
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexlyschool.ru/" data-target="_blank" role="button">Частная школа
</span></li>
</ul>
</li>
<li><a class="nav-link" href="/subscription/new">Подписка</a></li>
</ul>
<ul class="navbar-nav flex-lg-row align-items-lg-center gap-2 ms-auto">
<li>
<a class="nav-link" aria-label="Переключить тему" href="/theme/switch?new_theme=dark"><span aria-hidden="true" class="bi bi-moon"></span>
</a></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="/u/new" role="button"><span>Регистрация</span>
</span></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="https://ru.hexlet.io/session/new" role="button"><span>Вход</span>
</span></li>
</ul>
</div>
</div>
</nav>
</header>
<div class="x-container-xxxl">
</div>
<main class="mb-6 min-vh-100 h-100">
<link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzcyNywicHVyIjoiYmxvYl9pZCJ9fQ==--2d5cbbf5c3b4a73ae4b2c50632305d78f5872e4d/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Programmer-rafiki.png"/><link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzcyNSwicHVyIjoiYmxvYl9pZCJ9fQ==--2e84f5f94140ee4e22019ac479c290ef48c3fac8/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Static%20website-cuate.png"/><link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NDA0MywicHVyIjoiYmxvYl9pZCJ9fQ==--e2c6c0775e2308e42fbc5dc592ba2db0470632ca/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Programmer-rafiki.png"/><link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzk0MSwicHVyIjoiYmxvYl9pZCJ9fQ==--9a9cd0863661374e7c92ea27b1270ac3299c0979/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Usability%20testing-pana.png"/><link rel="preload" as="image" href="/vite/assets/development-BVihs_d5.png"/><div id="app" data-page="{"component":"web/courses/lessons/theory_unit","props":{"errors":{},"locale":"ru","language":"ru","httpsHost":"https://ru.hexlet.io","host":"ru.hexlet.io","colorScheme":"light","auth":{"user":{"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26T17:10:33.141Z","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false}},"cloudflareTurnstileSiteKey":"0x4AAAAAAA15KmeFXzd2H0Xo","vkIdClientId":"51586979","yandexIdClientId":"88d071f1d3384eb4bd1deb37910235c7","formAuthToken":"IkmdAcOGNa3xi9mSLJkiZqk53x9fUEYBhhZeWZT0I0zNmFY2MfiYzUfI_QogltIRaTDytVdnuKM79sQNxvPEIg","topics":[{"id":51715,"title":"https://ru.hexlet.io/code_reviews/368214 Подскажите, правильно ли я понимаю что в else if мне надо проверить что индекс closingSymbols === индексу openingSymbols?\nесли так, то никак не могу понять как мне подобраться к индексам openingSymbols, уже всё перепробовал. Либо же я совсем не правильно делаю. Сейчас я понимаю что ф-я у меня вообще всё из stack'а удаляет. Направьте пожалуйста.","plain_title":"https://ru.hexlet.io/code_reviews/368214 Подскажите, правильно ли я понимаю что в else if мне надо проверить что индекс closingSymbols === индексу openingSymbols? если так, то никак не могу понять как мне подобраться к индексам openingSymbols, уже всё перепробовал. Либо же я совсем не правильно делаю. Сейчас я понимаю что ф-я у меня вообще всё из stack'а удаляет. Направьте пожалуйста. ","creator":{"public_name":"Кирилл Кондратьев","id":337412,"is_tutor":false},"comments":[{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":110543,"body":"Приветствую, Кирилл!\n\nЗдорово, что вы не сдались и справились с заданием! А решения задач бывают разными, впрочем, как и сами задания.","topic_id":51715},{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":110493,"body":"Кирилл, приветствую!\n\n> правильно ли я понимаю что в else if мне надо проверить что индекс closingSymbols === индексу openingSymbols?\n\nТут всё зависит от логики которую вы используете для решения задачи. Любую задачу, как правило, можно решить разными способами и способ решения зависит конкретно от вас.\n\n> никак не могу понять как мне подобраться к индексам openingSymbols. если так, то никак не могу понять как мне подобраться к индексам openingSymbols, уже всё перепробовал.\n\nВ решении вижу, что вы используете метод indexOf, который возвращает индекс элемента в массиве, в том числе в else. Используйте полученный индекс, чтобы получить открывающуюся скобку из массива, которая соответствует полученной закрывающейся. Всё что останется - это сравнить открывающуюся скобку с той что хранится в стеке.","topic_id":51715},{"creator":{"public_name":"Кирилл Кондратьев","id":337412,"is_tutor":false},"id":110524,"body":"**Станислав Дзисяк**, О май гат, пятница 3 ночи и я решил сам!))) https://ru.hexlet.io/code_reviews/368214 Но с решением учителя надо разобраться ещё, немного запутанней чем я себе представлял (а я думал что сейчас откроешь решение учителя, а он там в три строки всё решил:)) ","topic_id":51715}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Стек","entity_url":null,"active":true}},{"id":44930,"title":"for (const symbol ... - когда в условии цикла пишется const а когда let ?","plain_title":"for (const symbol ... - когда в условии цикла пишется const а когда let ? ","creator":{"public_name":"Юрий","id":261846,"is_tutor":false},"comments":[{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":97211,"body":"Добрый день, Юрий!\n\nВадим правильно ответил на вопрос. Добавлю ссылки на документацию MDN по данным темам: [const](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/const), [let](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/let). Рекомендую ознакомиться с этими статьями, они очень подробные и там приводятся примеры использования данных директив.\n\nВадим, спасибо!","topic_id":44930},{"creator":{"public_name":"Вадим С.","id":154224,"is_tutor":false},"id":97204,"body":"**Юрий**, let - когда вы меняете значения переменных. К примеру, надо пройти по массиву от 1 до 10 и каждое число умножить на 2. Тогда только let, c const вы просто не сможете это сделать - будет ошибка. Во всех остальных случаях, когда менять ничего не надо - const. ","topic_id":44930}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Стек","entity_url":null,"active":true}},{"id":43522,"title":"Здравствуйте! можете подсказать что не так? https://ru.hexlet.io/code_reviews/274750 ","plain_title":"Здравствуйте! можете подсказать что не так? https://ru.hexlet.io/code_reviews/274750 ","creator":{"public_name":"Alexander Kim","id":182620,"is_tutor":false},"comments":[{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":94627,"body":"Добрый день!\n\nПопробуйте на каждую открывающую скобку, добавлять в стек соответствующую закрывающую, а когда встретится закрывающая извлекать из стека элемент и производить явное сравнение на соответствие. Если не равны, то скобки не сбалансированы. ","topic_id":43522}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Стек","entity_url":null,"active":true}},{"id":37977,"title":"Привет. Вот мое решение: https://ru.hexlet.io/code_reviews/210887. Мне кажется, или метод indexOf не давался ранее в материале профессии front-end? Долго ломал голову, как быть с идентификацией парности скобок, которые уже есть в стеке, и текущего проверяемого символа; в итоге написал функцию, которая возвращает открывающий символ на каждый закрывающий. Увидев решение учителя, пошел копаться в ранее пройденном материале в поисках метода indexOf, но найти его не смог.","plain_title":"Привет. Вот мое решение: https://ru.hexlet.io/code_reviews/210887. Мне кажется, или метод indexOf не давался ранее в материале профессии front-end? Долго ломал голову, как быть с идентификацией парности скобок, которые уже есть в стеке, и текущего проверяемого символа; в итоге написал функцию, которая возвращает открывающий символ на каждый закрывающий. Увидев решение учителя, пошел копаться в ранее пройденном материале в поисках метода indexOf, но найти его не смог. ","creator":{"public_name":"Dmitry Kiyko","id":215762,"is_tutor":false},"comments":[{"creator":{"public_name":"Roman Kozlov","id":231814,"is_tutor":false},"id":84220,"body":"Добрый день! \nДобавил подсказку в описании задачи. \nТеперь должно стать попроще :)","topic_id":37977},{"creator":{"public_name":"Влад Фом","id":182394,"is_tutor":false},"id":84144,"body":"**Roman Kozlov**, Тоже сталкивался с таким, только на другой ф-и. Как вижу, я совсем новичок, и понимаю, что в js тьма полезных готовых функций и библиотек для решения элементных заданий, и именно сейчас, думаю, что все задачи идут, что бы потренировать азы, поиграть с циклами, условиями и рекурсией. И потом бац ф-я. Было бы не плохо, что бы, был какой-то намек. Типа в подсказке, вы можете решить или посмотреть какая функция может помочь вам. Спасибо :)","topic_id":37977},{"creator":{"public_name":"Roman Kozlov","id":231814,"is_tutor":false},"id":83058,"body":"Приветствую! \nНекоторые функции или методы, которые используются в решении учителя вы можете изучить самостоятельно. \nНапример, если бы мы показали в теории как можно использовать метод `indexOf()` для сравнения элементов, то лишили бы вас замечательной возможности подумать над этим вопросом :)","topic_id":37977}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Стек","entity_url":null,"active":true}},{"id":45931,"title":"Добрый день! Не получается пройти тест ''({}}[]', решил не использовать indexOf(). \nhttps://ru.hexlet.io/code_reviews/298383\nПробовал отследить каждый шаг поэтапно и с помощью console.log. В итоге ни к чему не пришёл. Подскажите пожалуйста.\nАлгоритм действий следующий:\n1. Если скобка открывающая, то в result добавляется такая же, но закрывающая скобка.\n2. Если скобка закрывающая, то из result достается последний элемент и сравнивается с закрывающей скобкой (Если result пуст - вернуть false)\nВ общем я совсем запутался.\n","plain_title":"Добрый день! Не получается пройти тест ''({}}[]', решил не использовать indexOf(). https://ru.hexlet.io/code_reviews/298383 Пробовал отследить каждый шаг поэтапно и с помощью console.log. В итоге ни к чему не пришёл. Подскажите пожалуйста Алгоритм действий следующий: 1. Если скобка открывающая, то в result добавляется такая же, но закрывающая скобка. 2. Если скобка закрывающая, то из result достается последний элемент и сравнивается с закрывающей скобкой (Если result пуст - вернуть false) В общем я совсем запутался. ","creator":{"public_name":"Maxim Kalinchuk","id":288392,"is_tutor":false},"comments":[{"creator":{"public_name":"Maxim Kalinchuk","id":288392,"is_tutor":false},"id":99311,"body":"**Сергей Мелодин**, ясно, ну что могу сказать, бывает :D","topic_id":45931},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":99217,"body":"**Maxim Kalinchuk**, приветствую.\n\nАлгоритм верный, чтобы его осуществить, не обязательно так сильно проваливаться во вложенные циклы. Попробуйте упростить код, чтобы его было проще отлаживать","topic_id":45931},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":99309,"body":"**Maxim Kalinchuk**, выполните в консоли браузера `!5 === 5` ;)","topic_id":45931},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":99285,"body":"**Maxim Kalinchuk**, сейчас во втором ифе условие написано неправильно, отрицается элемент, который забирается из массива ;)","topic_id":45931},{"creator":{"public_name":"Maxim Kalinchuk","id":288392,"is_tutor":false},"id":99265,"body":"**Сергей Мелодин**, переписал код с использованием indexOf и без вложенного цикла. Выглядит и вправду легче, но суть не поменялась. '({}}[]' не проходит, как я понял из отладочных печатей, '({} =*}*= []' - когда этот элемент отделенный знаками равно попадает в else if, почему-то не выводится false. Но до сих пор не могу понять в чём проблема. Подскажите пожалуйста) https://ru.hexlet.io/code_reviews/298383\nНичего не понимаю\nhttps://ibb.co/hZn803B","topic_id":45931},{"creator":{"public_name":"Maxim Kalinchuk","id":288392,"is_tutor":false},"id":99308,"body":"**Сергей Мелодин**, Спасибо за помощь! Задачу решил. Но всё же не очень понял почему нельзя использовать такое условие *(!result.pop() === item)* . Мне казалось, что суть одна и таже. Потому что ! сразу же меняет значение из массива и только потом идёт сравнение? А на что он его меняет (true на false и т.д?) ? Просто не могу проследить как это происходит по этапно. Помогите пожалуйста разобраться)","topic_id":45931}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Стек","entity_url":null,"active":true}},{"id":46130,"title":"Народ, всем привет!\n\nНе прохожу следующий тест:\n> const str6 = '([)]';\n \nНиже ссылка на ревью\nhttps://ru.hexlet.io/code_reviews/300487\n\nПонимаю в чем проблема и в принципе могу попытаться написать код-многотомник, который бы решил проблему, но полагаю это не то. Также не хочу (потому что не представляю как) решать через indexOf()\n\nСпасибо\n","plain_title":"Народ, всем привет! Почти сдался. НЕ прохожу тест с const str6 = '([)]'; Весь день бьюсь, а толку? Вот ссылка на ревьюху https://ru.hexlet.io/code_reviews/300487 (http://https://ru.hexlet.io/code_reviews/300487) Понимаю в чем проблема и в принципе могу попытаться написать код-многотомник который бы решил проблему, но полагаю это не то. Также не хочу (потому что не представляю как) решать через indexOf() ","creator":{"public_name":"Msh Ker","id":231820,"is_tutor":false},"comments":[{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":101084,"body":"**Msh Ker**, тоже неплохо! Главное чтобы в дело 🤝","topic_id":46130},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":100916,"body":"**Msh Ker**, да, направление верное. Сокращайте количество if-else. Вам нужно забирать из стека скобку только в одном случае - если текущая скобка не открывающая.","topic_id":46130},{"creator":{"public_name":"Msh Ker","id":231820,"is_tutor":false},"id":99686,"body":"Сергей, приветствую!\n\nПереписал код:\n\nhttps://ru.hexlet.io/code_reviews/301313\n\nНе могу понять почему тесты выдают ошибки на строках '()' и '[()]'. Выводы ошибок не читабельны. Разбирал по кускам свой код в IDE, вроде как всё окей.","topic_id":46130},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":100810,"body":"**Msh Ker**, когда идёт движение по строке, то там получается всегда одно условие: следующий символ должен быть либо конкретной закрывающей скобкой, либо любой открывающей.","topic_id":46130},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":101057,"body":"**Msh Ker**, дело не в кейсах, а в алгоритме в целом:\n* читаем строку посимвольно;\n* если это *****, то записываем ***** в *****;\n* если нет, достаём из ***** последнюю записанную ***** и сравниваем;\n* если совпало, то *****, если нет, то *****.\n\nВы можете ввести две дополнительные функции для проверки на тип символа.","topic_id":46130},{"creator":{"public_name":"Msh Ker","id":231820,"is_tutor":false},"id":100888,"body":"**Сергей Мелодин**, \nпошел, как мне кажется, в верном направлении, но все же не получается все тесты пройти\nhttps://ru.hexlet.io/code_reviews/308523?submission_id=390363\n> когда идёт движение по строке, то там получается всегда одно условие: следующий символ должен быть либо конкретной закрывающей скобкой, либо любой открывающей.\n\nПредставить не могу как запоминать какие \"конктретно закрывающиеся скобки\" могут иметь место быть. То есть к примеру \"(({<..\" и на этом месте у меня в коде должен быть реализован контролер который говорит \"ага, значит из закрывающихся имеют право на существование \"))}>\", если да то как тогда их последовательность выстроить?","topic_id":46130},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":100795,"body":"**Msh Ker**, попробуйте ввести дополнительный массив, куда будете записывать один из символов и просто построчно обходить всю строку, а прерывать цикл только в том случае, если встретился неожиданный символ.","topic_id":46130},{"creator":{"public_name":"Msh Ker","id":231820,"is_tutor":false},"id":100999,"body":"**Сергей Мелодин**, \n\nХорошо. \nесли алгоритм действий такой:\n1. работаю построчно\n2. открывающие записываю в один массив\n3. единственное условие на удаление из стека - не открывающая\n\nто старые сложности (описанные пару комментов выше) никуда не исчезают. теперь если она (закр. скобка) любая \"не открывающая\", то такие тесты как этот ({}}[] не пройдут.\nhttps://ru.hexlet.io/code_reviews/308523\n","topic_id":46130},{"creator":{"public_name":"Msh Ker","id":231820,"is_tutor":false},"id":101077,"body":"**Сергей Мелодин**, \n\nкаароче. Видосики на ютубчике - это топчик :)\n\nЗаодно питон подтянул)","topic_id":46130},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":99550,"body":"**Msh Ker**, приветствую.\n\nСейчас в вашем решении сравниваются в лоб типы скобок и записываются в разные места. Попробуйте уйти от таких массивных условных конструкций и просто читать строку построчно, записывая ожидаемые закрывающие скобки в один массив.","topic_id":46130},{"creator":{"public_name":"Msh Ker","id":231820,"is_tutor":false},"id":100770,"body":"**Сергей Мелодин**, приветствую!\n\nПопытался решить задачу иным способом \nhttps://ru.hexlet.io/code_reviews/301316\n\nВстал в ступор увидев заваленные тесты \n```\nconst str3 = '({}[])';\n > 13 | expect(isBracketStructureBalanced(str3)).toBe(true);\n | ^\n 14 | \n 15 | const str4 = '(<><<{[()]}>>)';\n```\nНет представления решения задачи. То есть вложение скобок может идти до конца (напр. \"([<[{}]>)'), а также может произойти открытие и закрытие каких то отдельных скобок в начале строки (<><<{[()]}>>)'. \n\nПонимаю почему не прохожу тесты где строка начинается с закрывающей скобки, но вот тест '([)]' у себя в консоле прохожу, но тесты негодуют. \n\nКонечно можно было бы закидывать все 4 вида скобок последовательно в отдельные массивы, а потом перебрать как в теории, но сомневаюсь что от нас ожидается сей метод","topic_id":46130},{"creator":{"public_name":"Msh Ker","id":231820,"is_tutor":false},"id":101052,"body":"**Сергей Мелодин**, \n\nВ который раз пишу ну нет у меня алгоритма (даже словесного) для прохождения следующих тестов (<><<{[()]}>>), ‘([)]`","topic_id":46130},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":101007,"body":"**Msh Ker**, у вас алгоритм описан лишь частично. Попробуйте словами его описать, а потом выразить в коде. Код довольно точно отражает что куда записывается и как строятся условия.\n\n\nПро почту не понял. ","topic_id":46130},{"creator":{"public_name":"Msh Ker","id":231820,"is_tutor":false},"id":100802,"body":"**Сергей Мелодин**, \nНу а как я могу что то ожидать когда обрабатываемые скобки могут быть как симметричными так и открываться и тут же закрываться а потом продолжаться как тут <><<{[()]}>>?","topic_id":46130}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Стек","entity_url":null,"active":true}},{"id":41802,"title":"Добрый день, уважаемые менторы!\n\n3 день бьюсь над задачей. Прочитал все обсуждения, но так и не получилось ее закончить до конца.\n\n[Ревью](https://ru.hexlet.io/code_reviews/256335)\n\nЯ понимаю, что для определения баланса необходимо провести сравнение на соответствие открывающей скобки и закрывающей скобки, чтобы они были одного типа. Но у меня не получается это сделать. Прошу помощи, подсказки, хоть что-нибудь =)","plain_title":"Добрый день, уважаемые менторы! 3 день бьюсь над задачей. Прочитал все обсуждения, но так и не получилось ее закончить до конца. Ревью (https://ru.hexlet.io/code_reviews/256322) Я понимаю, что для определения баланса необходимо провести сравнение на соответствие открывающей скобки и закрывающей скобки, чтобы они были одного типа. Но у меня не получается это сделать. Прошу помощи, подсказки, хоть что-нибудь =) ","creator":{"public_name":"Иван Дис","id":104708,"is_tutor":false},"comments":[{"creator":{"public_name":"Иван Дис","id":104708,"is_tutor":false},"id":91073,"body":"Немного не дождался ментора и решил сам =)\n\n[Ревью 2](https://ru.hexlet.io/code_reviews/256335)\n\nМожно хотя бы пару слов о жизнеспособности данного кода?","topic_id":41802},{"creator":{"public_name":"Иван Дис","id":104708,"is_tutor":false},"id":91076,"body":"**Alexander Ismailov**, спасибо!\n\nВсе равно верное решение осталось со вложенными символами, однако получилось как вы и написали. Взял последний элемент стека и сравнил его с зеркальным отражением текущего элемента и код прошел все тесты.","topic_id":41802},{"creator":{"public_name":"Alexander Ismailov","id":252413,"is_tutor":false},"id":91074,"body":"**Иван Дис**, привет.\n\nСоветую отказаться от вложенного цикла, из-за него появляется много не соответствий.\nПопробуй в этой части своего алгоритма пойти несколько иначе. Если ` openingSymbols ` [содержит](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/includes) в себе ` elem `, то кладем его в стек, если же текущий элемент присутствует в ` closingSymbols `, то значит снимаем последний элемент из стека и сравниваем его с зеркальным отражением ` elem `.\n","topic_id":41802}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Стек","entity_url":null,"active":true}},{"id":41830,"title":"Добрый день! Скажите пожалуйста, почему это:\n const str6 = '([)]';\n expect(isBracketStructureBalanced(str6)).toBe(false);\nсчитается несбалансированным?\nСпасибо!\n","plain_title":"Добрый день! Скажите пожалуйста, почему это: const str6 = '([)]'; expect(isBracketStructureBalanced(str6)).toBe(false); считается несбалансированным? Спасибо! ","creator":{"public_name":"Andrei Khanau","id":245103,"is_tutor":false},"comments":[{"creator":{"public_name":"Alexander Ismailov","id":252413,"is_tutor":false},"id":91079,"body":"**Andrei Khanau**, привет.\n\n> Скобки — это парные структуры. У каждой открывающей скобки должна быть соответствующая ей закрывающая скобка.\nЗакрывающая скобка не должна идти впереди открывающей.\n\nЗдесь еще стоит учитывать порядок их следования, вот пример сбалансированных скобок:\n\n` ([{ ` открывающие скобки кончились дальше идут закрывающие ` }]) `, т.е. эта таже самая последовательность скобок, но в обратном порядке и в зеркальном отражении.\n\nОтсюда получается:\n\n` ([)] ` - Не сбалансированно\n\n` [()] ` - сбалансированно\n\nили ` ([]) ` - сбалансированно","topic_id":41830},{"creator":{"public_name":"Максим Чернов","id":255458,"is_tutor":false},"id":91639,"body":"([)] - не согласен с тем, что это несбалансированная конструкция. По кр. мере она соответствует вышеизложенному определению. Именно эта конструкция в тесте и заставляет нас мучиться.","topic_id":41830}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Стек","entity_url":null,"active":true}},{"id":45980,"title":"Ребята всем привет помогите пожалуйста решить у меня уже ступор https://ru.hexlet.io/code_reviews/299106","plain_title":"Ребята всем привет помогите пожалуйста решить у меня уже ступор https://ru.hexlet.io/code_reviews/299106 ","creator":{"public_name":"Serdar Gurbanmyradow","id":243713,"is_tutor":false},"comments":[{"creator":{"public_name":"Двоечник","id":297411,"is_tutor":false},"id":99351,"body":"**Serdar Gurbanmyradow**, Добрый день, ваш код не проходит тест `'(<><<{[()]}>>>)'`. Код возвращает значение true, а правильным ответом будет false т.к. эта часть `'(<`**>**`<<{[()]}>>>)'` делает пример **несбалансированным** (открывающих угловых скобок < три а закрывающих > четыре)","topic_id":45980},{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":99327,"body":"Добрый день. Опишите словами пошагово алгоритм действия, если в строке встречается закрывающий символ. Проблема у вас именно в этой части. ","topic_id":45980}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Стек","entity_url":null,"active":true}},{"id":46203,"title":"Второй день бьюсь над этой задачей\n\nЛицезреть до чего доводит безысходность можете по ссылке\n\nhttps://ru.hexlet.io/code_reviews/301316\n\nСлабонервным не смотреть. \n\nВ общем дайте наводку (желательно в виде готового решения).","plain_title":"Второй день бьюсь над этой задачей Лицезреть до чего доводит безысходность можете по ссылке https://ru.hexlet.io/code_reviews/301316 Слабонервным не смотреть. В общем дайте наводку (желательно в виде готового решения). ","creator":{"public_name":"Msh Ker","id":231820,"is_tutor":false},"comments":[{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":99723,"body":"**Msh Ker**, приветствую.\n\nВижу, с прошлого раза код не сильно изменился, хотя попытка была во второй версии. Готовые решения и даже описание алгоритма публиковать в обсуждениях, увы, не получится, чтобы его не спойлерить другим участникам. Попробуйте в нашем сообществе: https://slack-ru.hexlet.io/ в канале #nodejs **или** #frontend кинуть ссылку на данный пост с просьбой пояснить алгоритм, тогда есть шанс получить более спойлерные подсказки :)","topic_id":46203}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Стек","entity_url":null,"active":true}}],"lesson":{"exercise":{"id":1001,"slug":"js_arrays_stack_exercise","name":null,"state":"active","kind":"exercise","language":"javascript","locale":"ru","has_web_view":false,"has_test_view":false,"reviewable":true,"readme":"## strings.js\n\nРеализуйте и экспортируйте функцию по умолчанию, которая принимает на вход строку, состоящую только из открывающих и закрывающих скобок разных типов, и проверяет, является ли эта строка сбалансированной. Открывающие и закрывающие скобки должны быть одного вида. Пустая строка (отсутствие скобок) считается сбалансированной.\n\nСтрока считается корректной (сбалансированной), если содержащаяся в ней скобочная структура соответствует требованиям:\n\n* Скобки — это парные структуры. У каждой открывающей скобки должна быть соответствующая ей закрывающая скобка.\n* Скобки должны закрываться в правильном порядке:\n\n```javascript\nimport isBracketStructureBalanced from './strings.js'\n\n// Пример вложенности\nisBracketStructureBalanced('(>') // false\nisBracketStructureBalanced('()') // true\nisBracketStructureBalanced('[()]') // true\nisBracketStructureBalanced('({}[])') // true\nisBracketStructureBalanced('{<>}}') // false\nisBracketStructureBalanced('([)]') // false\n```\n\nФункция должна поддерживать, минимум, четыре вида скобок: круглые — `()`, квадратные — `[]`, фигурные — `{}` и угловые — `<>`.\n\n### Подсказки\n\n* Для решения вам может пригодиться метод [indexOf](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf). Подумайте, как его можно использовать для определения парного закрывающего символа\n","prepared_readme":"## strings.js\n\nРеализуйте и экспортируйте функцию по умолчанию, которая принимает на вход строку, состоящую только из открывающих и закрывающих скобок разных типов, и проверяет, является ли эта строка сбалансированной. Открывающие и закрывающие скобки должны быть одного вида. Пустая строка (отсутствие скобок) считается сбалансированной.\n\nСтрока считается корректной (сбалансированной), если содержащаяся в ней скобочная структура соответствует требованиям:\n\n* Скобки — это парные структуры. У каждой открывающей скобки должна быть соответствующая ей закрывающая скобка.\n* Скобки должны закрываться в правильном порядке:\n\n```javascript\nimport isBracketStructureBalanced from './strings.js'\n\n// Пример вложенности\nisBracketStructureBalanced('(>') // false\nisBracketStructureBalanced('()') // true\nisBracketStructureBalanced('[()]') // true\nisBracketStructureBalanced('({}[])') // true\nisBracketStructureBalanced('{<>}}') // false\nisBracketStructureBalanced('([)]') // false\n```\n\nФункция должна поддерживать, минимум, четыре вида скобок: круглые — `()`, квадратные — `[]`, фигурные — `{}` и угловые — `<>`.\n\n### Подсказки\n\n* Для решения вам может пригодиться метод [indexOf](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf). Подумайте, как его можно использовать для определения парного закрывающего символа\n","has_solution":true,"entity_name":"Стек"},"units":[{"id":3424,"name":"theory","url":"/courses/js-arrays/lessons/stack/theory_unit"},{"id":3425,"name":"quiz","url":"/courses/js-arrays/lessons/stack/quiz_unit"},{"id":3452,"name":"exercise","url":"/courses/js-arrays/lessons/stack/exercise_unit"}],"links":[{"id":422484,"name":"метод push","url":"https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/push"},{"id":422485,"name":"метод pop","url":"https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/pop"}],"ordered_units":[{"id":3424,"name":"theory","url":"/courses/js-arrays/lessons/stack/theory_unit"},{"id":3425,"name":"quiz","url":"/courses/js-arrays/lessons/stack/quiz_unit"},{"id":3452,"name":"exercise","url":"/courses/js-arrays/lessons/stack/exercise_unit"}],"id":1607,"slug":"stack","state":"approved","name":"Стек","course_order":600,"goal":"Знакомимся с одной из самых фундаментальных структур данных","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"Тема алгоритмов не существует сама по себе. Важно не только уметь составлять правильный алгоритм решения, но не менее важно использовать для работы с данными правильную структуру.\n\n**Структура данных** — это конкретный способ хранения и организации данных. В зависимости от решаемых задач удобным оказывается либо один способ организации данных, либо другой. Как минимум одну структуру данных вы уже знаете достаточно хорошо — это массив. С точки зрения организации массив представляет собой совокупность элементов, к которым имеется индексированный доступ (доступ по индексу), а вот с точки зрения физического хранения в памяти — все сложнее. Массивы бывают разные и внутри языка реализуются тоже [по-разному](https://ru.wikipedia.org/wiki/Массив_(тип_данных)).\n\nКроме массивов, существует множество других структур данных: списки, хеш-таблицы, деревья, графы, стек, очередь и другие. Использование структуры данных, подходящей под решаемую задачу, позволяет кардинально упростить код, устраняя запутанную логику.\n\nНекоторые из перечисленных структур данных мы рассмотрим в процессе прохождения курсов и проектов. Знания о других вам нужно будет подтянуть самостоятельно из книг. В любом случае алгоритмы и структуры данных (без фанатизма) составляют базу, на которую нанизывается все остальное в разработке.\n\nСтоит разделять три понятия:\n\n* Структура данных\n* Конкретный тип данных (или просто \"тип данных\")\n* Абстрактный тип данных (АТД)\n\nСо структурой данных все понятно, выше было определение. С типом данных тоже все просто. Например, *числа в JavaScript — это тип данных*. Понятие «тип данных» всегда привязано к конкретному языку и может быть абсолютно чем угодно в зависимости от предпочтений разработчиков языка. Другими словами, если бы разработчики JavaScript решили, что числа надо назвать типом данных String, то никто бы им этого не запретил, несмотря на абсурдность такого имени для чисел.\n\nА вот абстрактные типы данных — теоретическое понятие. АТД целиком и полностью определяется набором операций, которые можно выполнять над ним. АТД абстрактный потому, что он ничего не говорит о способе хранения и существует лишь на бумаге и в головах. А вот уже в конкретных языках существуют конкретные типы, реализующие АТД. АТД нередко путают с понятием «структура данных», более того, часто структуры данных и АТД имеют одно и то же название. Сильно погружаться в эти дебри не нужно, достаточно иметь общее представление.\n\nВ этом уроке мы разберем один из самых простых и важных абстрактных типов данных – стек (stack, переводится как стопка).\n\n## Стек\n\nСтек — упорядоченная коллекция элементов, в которой добавление новых и удаление старых элементов всегда происходит с одного конца коллекции. Обычно его называют вершиной стека.\n\n\n\nУ стека есть аналоги из реальной жизни. Например, пирамида колец. Кольца добавляются в пирамиду только друг за другом. Извлекаются тоже, только в обратном порядке. Последнее кольцо достается из пирамиды первым.\n\n\n\nПрактически любая стопка может рассматриваться как стек. Если не применять грубую физическую силу, то со стопками мы работаем двумя способами. Либо кладем новый элемент (например, книгу) на верхушку стопки, либо снимаем элемент с верхушки. Поэтому стек еще называют \"Last In First Out\" (LIFO), то есть \"последним зашел, первым вышел\".\n\nПеред тем, как разбирать конкретную задачу, посмотрим на роль, которую играет стек в программировании. Вспомните, как исполняется любая программа. Одни функции вызывают другие, которые, в свою очередь, вызывают третьи, и так далее. После того, как выполнение заходит в самую глубокую функцию, та возвращает значение, и начинается обратный процесс. Сначала идет выход из наиболее глубоких функций, затем из тех, что уровнем выше, и так далее до тех пор, пока не дойдет до самой внешней функции. Вызов функций — не что иное, как добавление элемента в стек, а возврат – извлечение из стека. Именно так все устроено на аппаратном уровне. К тому же, если в процессе выполнения программы происходит ошибка, то ее вывод часто называют _Stack Trace_ (трассировка стека).\n\nДругой пример, связанный с программированием — кнопка \"назад\" в браузере. История посещений представляет собой стек, каждый новый переход по ссылке добавляет ее в историю, а кнопка «назад» извлекает из стека последний элемент.\n\nРабота со стеком включает в себя следующие операции:\n\n* Добавить в стек (push)\n* Взять из стека (pop)\n* Вернуть элемент с вершины стека без удаления (peekBack)\n* Проверить на пустоту (isEmpty)\n* Вернуть размер (size)\n\nПервые две – базовые, остальные нужны время от времени. В JavaScript стек можно создать на основе массивов. Для этого используются методы `push()`, `pop()` и свойство `length`.\n\n```javascript\nconst stack = []\n\nstack.push(3)\nconsole.log(stack) // => [ 3 ]\nstack.push('Winterfall')\nconsole.log(stack) // => [ 3, 'Winterfall' ]\nstack.push(true)\nconsole.log(stack) // => [ 3, 'Winterfall', true ]\n\nconst element1 = stack.pop()\nconsole.log(element1) // => true\nconsole.log(stack) // => [ 3, 'Winterfall' ]\n\nconst element2 = stack.pop()\nconsole.log(element2) // => Winterfall\nconsole.log(stack) // => [ 3 ]\n```\n\nОбратите внимание, что методы `pop()` и `push()` изменяют исходный массив. `pop()` не только изменяет его, но и возвращает элемент, снятый со стека.\n\nРассмотрим задачку, решение которой тривиально при использовании стека. Кстати, ее нередко задают на собеседованиях, чтобы убедиться, хорошо ли вы знаете базовые структуры данных.\n\nЗадача:\n\nНеобходимо реализовать функцию, которая проверяет, что парные скобки сбалансированы. То есть каждая открывающая скобка имеет закрывающую: `()`, `((()()))`. А вот примеры несбалансированных скобок: `(`, `(()`, `)(`. Для проверки баланса недостаточно считать количество, важен так же порядок в котором они идут.\n\n_У этой задачи есть простое решение и без стека, но стек тоже хорошо подходит (и даже нагляднее)_\n\nРешение со стеком выглядит так:\n\n1. Если перед нами открывающий элемент, то заносим его в стек\n2. Если закрывающий, то достаем из стека элемент (очевидно, последний добавленный). Если стек пустой, то есть в нем нет открывающих скобок, значит выражение не соответствует требуемому формату.\n3. Если мы дошли до конца строки и стек пустой, то все хорошо. Если в стеке остались элементы, то проверка не прошла. Такое может быть, если в начале строки были открывающие элементы, но в конце не было закрывающих.\n\nРазберем его построчно:\n\n```javascript\nconst checkIsBalanced = (expression) => {\n // Инициализация стека\n const stack = []\n // Проходим по каждому символу в строке\n for (const symbol of expression) {\n // Смотрим, открывающий или закрывающий\n // Если символ открывающий\n if (symbol === '(') {\n // Добавляем его в стек\n stack.push(symbol)\n // Если символ закрывающий\n }\n else if (symbol === ')') {\n // Достаем из стека последний элемент\n // Если стек пуст, значит для закрывающего не нашлось открывающего\n // Значит баланса нет, возвращаем false\n if (!stack.pop()) {\n return false\n }\n }\n }\n\n // Проверяем, что стек пуст\n // Если в стеке остались элементы, то не все открывающие скобки закрыты,\n // а значит баланса нет\n return stack.length === 0\n}\n\nexport default checkIsBalanced\n```\nПредположим, что на вход функции попала следующая строка: `(()`. Ниже описание ключевых шагов при выполнении функции проверки:\n\n1. Первая скобка `(` заносится в стек, так как она открывающая\n1. Следующая скобка `(` также заносится в стек по той же самой причине\n1. Последняя `)` является закрывающей, из стека извлекается последняя добавленная скобка\n1. В стеке остался один элемент, значит баланса нет\n\n## Семантика\n\nМожет возникнуть соблазн использовать эти функции в повседневной практике. Например, чтобы извлечь из массива последний элемент. Несмотря на то, что метод `pop()` действительно позволяет это сделать, такой вариант использования крайне нежелателен по нескольким причинам:\n\n1. Побочный эффект данной операции — изменение исходного массива. Даже если массив потом не используется, такой код вносит потенциальные проблемы и заставляет его переписывать в будущем.\n\n2. Нарушается семантика. Инструменты нужно использовать по назначению, иначе рождается код, который декларирует одно, но в реальности делает другое. Любой опытный программист, который видит `pop()` сразу считает, что массив в данной части программы используется как стек. Если это не так, то понадобятся дополнительные умственные усилия для понимания происходящего.\n\nДля извлечения последнего элемента можно использовать метод массива [at()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at)\n\n```javascript\nconst items = ['first', 'second', 'third']\nitems.at(-1) // 'third'\n```\n"},"lessonMember":null,"courseMember":null,"course":{"start_lesson":{"exercise":null,"units":[{"id":3423,"name":"theory","url":"/courses/js-arrays/lessons/about/theory_unit"}],"links":[{"id":422437,"name":"Массивы","url":"https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array"}],"ordered_units":[{"id":3423,"name":"theory","url":"/courses/js-arrays/lessons/about/theory_unit"}],"id":1606,"slug":"about","state":"approved","name":"О курсе","course_order":1,"goal":"Знакомимся с целями и задачами курса","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"Программирование становится по-настоящему интересным, когда появляется возможность работать с наборами (коллекциями) элементов. Вот лишь некоторые примеры того, где они встречаются:\n\n* Постраничный вывод данных на сайте\n* Подсчет общей суммы в заказе на основании каждой из позиций\n* Вывод списка друзей, сообщений, фильмов и тому подобное\n* Обработка набора DOM-узлов (HTML, фронтенд разработка)\n\nЛюбые списки, которые окружают нас в реальном или виртуальном мире, являются коллекциями элементов с точки зрения программирования. В JavaScript для их хранения используется *массив* – структура данных, позволяющая работать с набором как с единым целым.\n\n```javascript\n// Определение массива друзей\nconst friends = ['petya', 'vasya', 'ivan']\n```\n\nВ отличие от примитивных типов данных, массивы в JavaScript могут изменяться. Причем, как по содержимому, так и по размеру самого массива. Это сильно влияет на работу с ними и добавляет с одной стороны больше возможностей, а с другой – ответственности. Используя массивы, одну и ту же задачу можно решить множеством разных способов. Только некоторые из них будут хорошими, остальные же — неэффективными, сложными в отладке и анализе.\n\nИменно поэтому массивам посвящено не несколько уроков, а целый и довольно большой курс. В этом курсе рассматривается множество ситуаций, которые традиционно решаются с помощью массивов. Знания, полученные в этом курсе, станут тем фундаментом, на котором основана вся дальнейшая разработка. Основные темы этого курса:\n\n* Манипуляции с массивами\n* Обработка массивов в циклах\n* Работа с вложенными массивами, используя вложенные циклы\n* Сортировка массивов\n* Работа со строками через массивы\n\nПомимо массивов, мы коснемся темы алгоритмов и структур данных. Вы познакомитесь с понятием алгоритмической сложности, узнаете, как реализовывать некоторые типичные алгоритмы, которые часто спрашивают на собеседованиях. Знание этих тем, хотя бы на базовом уровне, критично для написания эффективного кода.\n"},"id":199,"slug":"js-arrays","challenges_count":15,"name":"JS: Массивы","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"paid","description":"На этом курсе вы изучите массивы в JS. Вы узнаете больше о синтаксисе, вложенных массивах и ссылках. В итоге научитесь обходить массивы, извлекать из них значения с помощью деструктуризации и использовать spread-оператор. Массивы пригодятся для решения множества алгоритмических задач. Знания из этого курса помогают программистам грамотно объединять данные в коллекции.","kind":"additional","updated_at":"2026-01-20T11:37:25.919Z","language":"javascript","duration_cache":95940,"skills":["Определять массивы в коде и манипулировать ими","Формировать и обрабатывать массивы в циклах","Применять базовые алгоритмы и оценивать их сложность","Использовать spread, rest и деструктуризацию"],"keywords":["синтаксис","вложенные массивы","алгоритмическая сложность","сортировка","теория множеств","стек"],"lessons_count":22,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NTY3NywicHVyIjoiYmxvYl9pZCJ9fQ==--4d51e2f887ec929e8a1609900039863e3d6baa9e/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJqcGciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--39ba06fa99226096df9fc6bb31f84e1d29ea98e9/image.png"},"recommendedLandings":[{"stack":{"id":12,"slug":"frontend","title":"Фронтенд-разработчик","audience":"for_beginners","start_type":"weekly","pricing_model":"purchase","priority":"high","kind":"profession","state":"published","stack_state":"finished","order":20,"duration_in_months":10},"id":17,"slug":"frontend","title":"Фронтенд-разработчик","subtitle":"Изучите HTML, CSS, JavaScript и React","subtitle_for_lists":"Изучите HTML, CSS, JavaScript и React","locale":"ru","current":true,"duration_in_months_text":"10 месяцев","stack_slug":"frontend","price_text":"от 6 792 ₽","duration_text":"10 месяцев","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzcyNywicHVyIjoiYmxvYl9pZCJ9fQ==--2d5cbbf5c3b4a73ae4b2c50632305d78f5872e4d/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Programmer-rafiki.png"},{"stack":{"id":13,"slug":"backend","title":"Node.js-разработчик","audience":"for_beginners","start_type":"weekly","pricing_model":"purchase","priority":"high","kind":"profession","state":"published","stack_state":"finished","order":130,"duration_in_months":10},"id":19,"slug":"backend","title":"Node.js-разработчик","subtitle":"Изучите JavaScript, Node.js, Fastify и REST API","subtitle_for_lists":"Изучите JavaScript, Node.js, Fastify и REST API","locale":"ru","current":true,"duration_in_months_text":"10 месяцев","stack_slug":"backend","price_text":"от 4 755 ₽","duration_text":"10 месяцев","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzcyNSwicHVyIjoiYmxvYl9pZCJ9fQ==--2e84f5f94140ee4e22019ac479c290ef48c3fac8/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Static%20website-cuate.png"},{"stack":{"id":43,"slug":"fullstack-javascript","title":"Fullstack-разработчик на Node.js","audience":"for_beginners","start_type":"weekly","pricing_model":"purchase","priority":"high","kind":"profession","state":"published","stack_state":"finished","order":140,"duration_in_months":12},"id":74,"slug":"fullstack-javascript","title":"Fullstack-разработчик на Node.js","subtitle":"Освоите JavaScript, Node.js, Fastify и React для фронтенда и бэкенда.","subtitle_for_lists":"Освоите JavaScript, Node.js, Fastify и React для фронтенда и бэкенда.","locale":"ru","current":true,"duration_in_months_text":"12 месяцев","stack_slug":"fullstack-javascript","price_text":"от 7 934 ₽","duration_text":"12 месяцев","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NDA0MywicHVyIjoiYmxvYl9pZCJ9fQ==--e2c6c0775e2308e42fbc5dc592ba2db0470632ca/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Programmer-rafiki.png"},{"stack":{"id":47,"slug":"qa-auto-engineer-javascript","title":"Автоматизатор тестирования на JavaScript","audience":"for_programmers","start_type":"weekly","pricing_model":"purchase","priority":"high","kind":"profession","state":"published","stack_state":"finished","order":90,"duration_in_months":6},"id":82,"slug":"qa-auto-engineer-javascript","title":"Автоматизатор тестирования на JavaScript","subtitle":"Изучите: Git, JavaScript, Playwright, юнит-, API- и UI-тесты, Docker и SQL","subtitle_for_lists":"Изучите: Git, JavaScript, Playwright, юнит-, API- и UI-тесты, Docker и SQL","locale":"ru","current":true,"duration_in_months_text":"6 месяцев","stack_slug":"qa-auto-engineer-javascript","price_text":"от 4 281 ₽","duration_text":"6 месяцев","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzk0MSwicHVyIjoiYmxvYl9pZCJ9fQ==--9a9cd0863661374e7c92ea27b1270ac3299c0979/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Usability%20testing-pana.png"}],"lessonMemberUnit":null,"accessToLearnUnitExists":false,"accessToCourseExists":false},"url":"/courses/js-arrays/lessons/stack/theory_unit","version":"0b0c6d4ebbd40fd58630a0dd89cc25544ccdf24e","encryptHistory":false,"clearHistory":false}"><style data-mantine-styles="true">:root, :host{--mantine-font-family: Arial, sans-serif;--mantine-font-family-headings: Arial, sans-serif;--mantine-heading-font-weight: normal;--mantine-radius-default: 0rem;--mantine-primary-color-filled: var(--mantine-color-indigo-filled);--mantine-primary-color-filled-hover: var(--mantine-color-indigo-filled-hover);--mantine-primary-color-light: var(--mantine-color-indigo-light);--mantine-primary-color-light-hover: var(--mantine-color-indigo-light-hover);--mantine-primary-color-light-color: var(--mantine-color-indigo-light-color);--mantine-spacing-xxl: calc(4rem * var(--mantine-scale));--mantine-font-size-xs: 12px;--mantine-font-size-sm: 14px;--mantine-font-size-md: 16px;--mantine-font-size-lg: clamp(16.0000px, calc(15.2727px + 0.2273vw), 18.0000px);--mantine-font-size-xl: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-display-3: clamp(32.0000px, calc(26.1818px + 1.8182vw), 48.0000px);--mantine-font-size-display-2: clamp(36.0000px, calc(25.8182px + 3.1818vw), 64.0000px);--mantine-font-size-display-1: clamp(40.0000px, calc(25.4545px + 4.5455vw), 80.0000px);--mantine-font-size-h1: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-font-size-h2: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-font-size-h3: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-font-size-h4: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-font-size-h5: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-h6: 1rem;--mantine-primary-color-0: var(--mantine-color-indigo-0);--mantine-primary-color-1: var(--mantine-color-indigo-1);--mantine-primary-color-2: var(--mantine-color-indigo-2);--mantine-primary-color-3: var(--mantine-color-indigo-3);--mantine-primary-color-4: var(--mantine-color-indigo-4);--mantine-primary-color-5: var(--mantine-color-indigo-5);--mantine-primary-color-6: var(--mantine-color-indigo-6);--mantine-primary-color-7: var(--mantine-color-indigo-7);--mantine-primary-color-8: var(--mantine-color-indigo-8);--mantine-primary-color-9: var(--mantine-color-indigo-9);--mantine-color-red-0: #ffeaea;--mantine-color-red-1: #fed4d4;--mantine-color-red-2: #f4a7a8;--mantine-color-red-3: #ec7878;--mantine-color-red-4: #e55050;--mantine-color-red-5: #e03131;--mantine-color-red-6: #e02829;--mantine-color-red-7: #c71a1c;--mantine-color-red-8: #b21218;--mantine-color-red-9: #9c0411;--mantine-color-violet-0: #fce9ff;--mantine-color-violet-1: #f1cfff;--mantine-color-violet-2: #e09bff;--mantine-color-violet-3: #d16fff;--mantine-color-violet-4: #be37fe;--mantine-color-violet-5: #b51afe;--mantine-color-violet-6: #b009ff;--mantine-color-violet-7: #9b00e4;--mantine-color-violet-8: #8a00cc;--mantine-color-violet-9: #7800b3;--mantine-color-indigo-0: #edecff;--mantine-color-indigo-1: #d6d5fe;--mantine-color-indigo-2: #aaa9f4;--mantine-color-indigo-3: #7b79eb;--mantine-color-indigo-4: #5451e4;--mantine-color-indigo-5: #3b37e0;--mantine-color-indigo-6: #2d2adf;--mantine-color-indigo-7: #1f1ec7;--mantine-color-indigo-8: #1819b2;--mantine-color-indigo-9: #0c149e;--mantine-color-cyan-0: #dffdff;--mantine-color-cyan-1: #caf5ff;--mantine-color-cyan-2: #99e8ff;--mantine-color-cyan-3: #64daff;--mantine-color-cyan-4: #3ccffe;--mantine-color-cyan-5: #24c8fe;--mantine-color-cyan-6: #00c2ff;--mantine-color-cyan-7: #00ade4;--mantine-color-cyan-8: #009acd;--mantine-color-cyan-9: #0085b5;--mantine-color-green-0: #e9fdec;--mantine-color-green-1: #d7f6dc;--mantine-color-green-2: #b0eab9;--mantine-color-green-3: #86df94;--mantine-color-green-4: #62d574;--mantine-color-green-5: #4ccf5f;--mantine-color-green-6: #3fcc54;--mantine-color-green-7: #2fb344;--mantine-color-green-8: #25a03b;--mantine-color-green-9: #138a2e;--mantine-color-yellow-0: #fff7e2;--mantine-color-yellow-1: #ffeecd;--mantine-color-yellow-2: #ffdc9c;--mantine-color-yellow-3: #ffc966;--mantine-color-yellow-4: #feb93a;--mantine-color-yellow-5: #feae1e;--mantine-color-yellow-6: #ffa90f;--mantine-color-yellow-8: #ca8200;--mantine-color-yellow-9: #af7000;--mantine-h1-font-size: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-h1-font-weight: normal;--mantine-h2-font-size: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-h2-font-weight: normal;--mantine-h3-font-size: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-h3-font-weight: normal;--mantine-h4-font-size: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-h4-font-weight: normal;--mantine-h5-font-size: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-h5-font-weight: normal;--mantine-h6-font-size: 1rem;--mantine-h6-font-weight: normal;}
:root[data-mantine-color-scheme="dark"], :host([data-mantine-color-scheme="dark"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-dark-filled: var(--mantine-color-dark-5);--mantine-color-dark-filled-hover: var(--mantine-color-dark-6);--mantine-color-dark-light: rgba(105, 105, 105, 0.15);--mantine-color-dark-light-hover: rgba(105, 105, 105, 0.2);--mantine-color-dark-light-color: var(--mantine-color-dark-0);--mantine-color-dark-outline: var(--mantine-color-dark-1);--mantine-color-dark-outline-hover: rgba(184, 184, 184, 0.05);--mantine-color-gray-filled: var(--mantine-color-gray-5);--mantine-color-gray-filled-hover: var(--mantine-color-gray-6);--mantine-color-gray-light: rgba(222, 226, 230, 0.15);--mantine-color-gray-light-hover: rgba(222, 226, 230, 0.2);--mantine-color-gray-light-color: var(--mantine-color-gray-0);--mantine-color-gray-outline: var(--mantine-color-gray-1);--mantine-color-gray-outline-hover: rgba(241, 243, 245, 0.05);--mantine-color-red-filled: var(--mantine-color-red-5);--mantine-color-red-filled-hover: var(--mantine-color-red-6);--mantine-color-red-light: rgba(236, 120, 120, 0.15);--mantine-color-red-light-hover: rgba(236, 120, 120, 0.2);--mantine-color-red-light-color: var(--mantine-color-red-0);--mantine-color-red-outline: var(--mantine-color-red-1);--mantine-color-red-outline-hover: rgba(254, 212, 212, 0.05);--mantine-color-pink-filled: var(--mantine-color-pink-5);--mantine-color-pink-filled-hover: var(--mantine-color-pink-6);--mantine-color-pink-light: rgba(250, 162, 193, 0.15);--mantine-color-pink-light-hover: rgba(250, 162, 193, 0.2);--mantine-color-pink-light-color: var(--mantine-color-pink-0);--mantine-color-pink-outline: var(--mantine-color-pink-1);--mantine-color-pink-outline-hover: rgba(255, 222, 235, 0.05);--mantine-color-grape-filled: var(--mantine-color-grape-5);--mantine-color-grape-filled-hover: var(--mantine-color-grape-6);--mantine-color-grape-light: rgba(229, 153, 247, 0.15);--mantine-color-grape-light-hover: rgba(229, 153, 247, 0.2);--mantine-color-grape-light-color: var(--mantine-color-grape-0);--mantine-color-grape-outline: var(--mantine-color-grape-1);--mantine-color-grape-outline-hover: rgba(243, 217, 250, 0.05);--mantine-color-violet-filled: var(--mantine-color-violet-5);--mantine-color-violet-filled-hover: var(--mantine-color-violet-6);--mantine-color-violet-light: rgba(209, 111, 255, 0.15);--mantine-color-violet-light-hover: rgba(209, 111, 255, 0.2);--mantine-color-violet-light-color: var(--mantine-color-violet-0);--mantine-color-violet-outline: var(--mantine-color-violet-1);--mantine-color-violet-outline-hover: rgba(241, 207, 255, 0.05);--mantine-color-indigo-filled: var(--mantine-color-indigo-5);--mantine-color-indigo-filled-hover: var(--mantine-color-indigo-6);--mantine-color-indigo-light: rgba(123, 121, 235, 0.15);--mantine-color-indigo-light-hover: rgba(123, 121, 235, 0.2);--mantine-color-indigo-light-color: var(--mantine-color-indigo-0);--mantine-color-indigo-outline: var(--mantine-color-indigo-1);--mantine-color-indigo-outline-hover: rgba(214, 213, 254, 0.05);--mantine-color-blue-filled: var(--mantine-color-blue-5);--mantine-color-blue-filled-hover: var(--mantine-color-blue-6);--mantine-color-blue-light: rgba(116, 192, 252, 0.15);--mantine-color-blue-light-hover: rgba(116, 192, 252, 0.2);--mantine-color-blue-light-color: var(--mantine-color-blue-0);--mantine-color-blue-outline: var(--mantine-color-blue-1);--mantine-color-blue-outline-hover: rgba(208, 235, 255, 0.05);--mantine-color-cyan-filled: var(--mantine-color-cyan-5);--mantine-color-cyan-filled-hover: var(--mantine-color-cyan-6);--mantine-color-cyan-light: rgba(100, 218, 255, 0.15);--mantine-color-cyan-light-hover: rgba(100, 218, 255, 0.2);--mantine-color-cyan-light-color: var(--mantine-color-cyan-0);--mantine-color-cyan-outline: var(--mantine-color-cyan-1);--mantine-color-cyan-outline-hover: rgba(202, 245, 255, 0.05);--mantine-color-teal-filled: var(--mantine-color-teal-5);--mantine-color-teal-filled-hover: var(--mantine-color-teal-6);--mantine-color-teal-light: rgba(99, 230, 190, 0.15);--mantine-color-teal-light-hover: rgba(99, 230, 190, 0.2);--mantine-color-teal-light-color: var(--mantine-color-teal-0);--mantine-color-teal-outline: var(--mantine-color-teal-1);--mantine-color-teal-outline-hover: rgba(195, 250, 232, 0.05);--mantine-color-green-filled: var(--mantine-color-green-5);--mantine-color-green-filled-hover: var(--mantine-color-green-6);--mantine-color-green-light: rgba(134, 223, 148, 0.15);--mantine-color-green-light-hover: rgba(134, 223, 148, 0.2);--mantine-color-green-light-color: var(--mantine-color-green-0);--mantine-color-green-outline: var(--mantine-color-green-1);--mantine-color-green-outline-hover: rgba(215, 246, 220, 0.05);--mantine-color-lime-filled: var(--mantine-color-lime-5);--mantine-color-lime-filled-hover: var(--mantine-color-lime-6);--mantine-color-lime-light: rgba(192, 235, 117, 0.15);--mantine-color-lime-light-hover: rgba(192, 235, 117, 0.2);--mantine-color-lime-light-color: var(--mantine-color-lime-0);--mantine-color-lime-outline: var(--mantine-color-lime-1);--mantine-color-lime-outline-hover: rgba(233, 250, 200, 0.05);--mantine-color-yellow-filled: var(--mantine-color-yellow-5);--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-6);--mantine-color-yellow-light: rgba(255, 201, 102, 0.15);--mantine-color-yellow-light-hover: rgba(255, 201, 102, 0.2);--mantine-color-yellow-light-color: var(--mantine-color-yellow-0);--mantine-color-yellow-outline: var(--mantine-color-yellow-1);--mantine-color-yellow-outline-hover: rgba(255, 238, 205, 0.05);--mantine-color-orange-filled: var(--mantine-color-orange-5);--mantine-color-orange-filled-hover: var(--mantine-color-orange-6);--mantine-color-orange-light: rgba(255, 192, 120, 0.15);--mantine-color-orange-light-hover: rgba(255, 192, 120, 0.2);--mantine-color-orange-light-color: var(--mantine-color-orange-0);--mantine-color-orange-outline: var(--mantine-color-orange-1);--mantine-color-orange-outline-hover: rgba(255, 232, 204, 0.05);--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-9) 0%, var(--mantine-color-cyan-7) 100%);--app-color-surface: #2e2e2e;}
:root[data-mantine-color-scheme="light"], :host([data-mantine-color-scheme="light"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-red-light: rgba(224, 40, 41, 0.1);--mantine-color-red-light-hover: rgba(224, 40, 41, 0.12);--mantine-color-red-outline-hover: rgba(224, 40, 41, 0.05);--mantine-color-violet-light: rgba(176, 9, 255, 0.1);--mantine-color-violet-light-hover: rgba(176, 9, 255, 0.12);--mantine-color-violet-outline-hover: rgba(176, 9, 255, 0.05);--mantine-color-indigo-light: rgba(45, 42, 223, 0.1);--mantine-color-indigo-light-hover: rgba(45, 42, 223, 0.12);--mantine-color-indigo-outline-hover: rgba(45, 42, 223, 0.05);--mantine-color-cyan-light: rgba(0, 194, 255, 0.1);--mantine-color-cyan-light-hover: rgba(0, 194, 255, 0.12);--mantine-color-cyan-outline-hover: rgba(0, 194, 255, 0.05);--mantine-color-green-light: rgba(63, 204, 84, 0.1);--mantine-color-green-light-hover: rgba(63, 204, 84, 0.12);--mantine-color-green-outline-hover: rgba(63, 204, 84, 0.05);--mantine-color-yellow-light: rgba(255, 169, 15, 0.1);--mantine-color-yellow-light-hover: rgba(255, 169, 15, 0.12);--mantine-color-yellow-outline-hover: rgba(255, 169, 15, 0.05);--app-color-surface: #f1f3f5;--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-5) 100%);}</style><style data-mantine-styles="classes">@media (max-width: 35.99375em) {.mantine-visible-from-xs {display: none !important;}}@media (min-width: 36em) {.mantine-hidden-from-xs {display: none !important;}}@media (max-width: 47.99375em) {.mantine-visible-from-sm {display: none !important;}}@media (min-width: 48em) {.mantine-hidden-from-sm {display: none !important;}}@media (max-width: 61.99375em) {.mantine-visible-from-md {display: none !important;}}@media (min-width: 62em) {.mantine-hidden-from-md {display: none !important;}}@media (max-width: 74.99375em) {.mantine-visible-from-lg {display: none !important;}}@media (min-width: 75em) {.mantine-hidden-from-lg {display: none !important;}}@media (max-width: 87.99375em) {.mantine-visible-from-xl {display: none !important;}}@media (min-width: 88em) {.mantine-hidden-from-xl {display: none !important;}}</style><div style="position:absolute;top:0rem" class=""></div><div style="max-width:var(--container-size-xl);height:100%;min-height:0rem" class=""><style data-mantine-styles="inline">.__m__-_R_5ub_{--grid-gutter:0rem;}</style><div style="height:100%;min-height:0rem" class="m_410352e9 mantine-Grid-root __m__-_R_5ub_"><div class="m_dee7bd2f mantine-Grid-inner" style="height:100%"><style data-mantine-styles="inline">.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:91.66666666666667%;--col-max-width:91.66666666666667%;}@media(min-width: 48em){.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:83.33333333333334%;--col-max-width:83.33333333333334%;}}</style><div style="min-width:0rem;height:100%;min-height:0rem;display:flex" class="m_96bdd299 mantine-Grid-col __m__-_R_rdub_"><style data-mantine-styles="inline">.__m__-_R_6qrdub_{margin-top:0rem;padding-inline:var(--mantine-spacing-xs);width:100%;}@media(min-width: 48em){.__m__-_R_6qrdub_{margin-top:var(--mantine-spacing-xl);width:80%;}}@media(min-width: 62em){.__m__-_R_6qrdub_{padding-inline:var(--mantine-spacing-xl);}}</style><div style="margin-inline:auto;max-width:var(--mantine-breakpoint-xl)" class="__m__-_R_6qrdub_"><div style="color:var(--mantine-color-dimmed)" class="m_4451eb3a mantine-Center-root" data-inline="true"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:calc(0.125rem * var(--mantine-scale));color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-lock "><path d="M5 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-6"></path><path d="M11 16a1 1 0 1 0 2 0a1 1 0 0 0 -2 0"></path><path d="M8 11v-4a4 4 0 1 1 8 0v4"></path></svg></div><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">JS: Массивы</p></div><h1 style="--title-fw:var(--mantine-h1-font-weight);--title-lh:var(--mantine-h1-line-height);--title-fz:var(--mantine-h1-font-size);margin-bottom:var(--mantine-spacing-xl)" class="m_8a5d1357 mantine-Title-root" data-order="1">Теория: Стек</h1><script type="application/ld+json">{"@context":"https://schema.org","@type":"LearningResource","name":"Стек","inLanguage":"ru","isPartOf":{"@type":"LearningResource","name":"JS: Массивы"},"isAccessibleForFree":"False","hasPart":{"@type":"WebPageElement","isAccessibleForFree":"False","cssSelector":".paywalled"}}</script><div class=""><div style="--alert-color:var(--mantine-color-indigo-light-color);margin-bottom:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-lg)" class="m_66836ed3 mantine-Alert-root" id="mantine-_R_remqrdub_" role="alert" aria-describedby="mantine-_R_remqrdub_-body" aria-labelledby="mantine-_R_remqrdub_-title"><div class="m_a5d60502 mantine-Alert-wrapper"><div class="m_667f2a6a mantine-Alert-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-rocket "><path d="M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3 -5a9 9 0 0 0 6 -8a3 3 0 0 0 -3 -3a9 9 0 0 0 -8 6a6 6 0 0 0 -5 3"></path><path d="M7 14a6 6 0 0 0 -3 6a6 6 0 0 0 6 -3"></path><path d="M14 9a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path></svg></div><div class="m_667c2793 mantine-Alert-body"><div class="m_6a03f287 mantine-Alert-title"><span id="mantine-_R_remqrdub_-title" class="m_698f4f23 mantine-Alert-label">Полный доступ к материалам</span></div><div id="mantine-_R_remqrdub_-body" class="m_7fa78076 mantine-Alert-message"><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root"><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Зарегистрируйтесь и получите доступ к этому и десяткам других курсов</p><a style="--button-height:var(--button-height-xs);--button-padding-x:var(--button-padding-x-xs);--button-fz:var(--mantine-font-size-xs);--button-bg:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-hover:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-color:var(--mantine-color-white);--button-bd:none" class="mantine-focus-auto mantine-active m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root" data-variant="gradient" data-size="xs" href="/u/new"><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">Зарегистрироваться</span></span></a></div></div></div></div></div><div class="paywalled m_d08caa0 mantine-Typography-root"><p>Тема алгоритмов не существует сама по себе. Важно не только уметь составлять правильный алгоритм решения, но не менее важно использовать для работы с данными правильную структуру.</p>
<p><strong>Структура данных</strong> — это конкретный способ хранения и организации данных. В зависимости от решаемых задач удобным оказывается либо один способ организации данных, либо другой. Как минимум одну структуру данных вы уже знаете достаточно хорошо — это массив. С точки зрения организации массив представляет собой совокупность элементов, к которым имеется индексированный доступ (доступ по индексу), а вот с точки зрения физического хранения в памяти — все сложнее. Массивы бывают разные и внутри языка реализуются тоже <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D1%81%D1%81%D0%B8%D0%B2_(%D1%82%D0%B8%D0%BF_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85)" rel="noopener noreferrer" target="_blank">по-разному</a>.</p>
<p>Кроме массивов, существует множество других структур данных: списки, хеш-таблицы, деревья, графы, стек, очередь и другие. Использование структуры данных, подходящей под решаемую задачу, позволяет кардинально упростить код, устраняя запутанную логику.</p>
<p>Некоторые из перечисленных структур данных мы рассмотрим в процессе прохождения курсов и проектов. Знания о других вам нужно будет подтянуть самостоятельно из книг. В любом случае алгоритмы и структуры данных (без фанатизма) составляют базу, на которую нанизывается все остальное в разработке.</p>
<p>Стоит разделять три понятия:</p>
<ul>
<li>Структура данных</li>
<li>Конкретный тип данных (или просто "тип данных")</li>
<li>Абстрактный тип данных (АТД)</li>
</ul>
<p>Со структурой данных все понятно, выше было определение. С типом данных тоже все просто. Например, <em>числа в JavaScript — это тип данных</em>. Понятие «тип данных» всегда привязано к конкретному языку и может быть абсолютно чем угодно в зависимости от предпочтений разработчиков языка. Другими словами, если бы разработчики JavaScript решили, что числа надо назвать типом данных String, то никто бы им этого не запретил, несмотря на абсурдность такого имени для чисел.</p>
<p>А вот абстрактные типы данных — теоретическое понятие. АТД целиком и полностью определяется набором операций, которые можно выполнять над ним. АТД абстрактный потому, что он ничего не говорит о способе хранения и существует лишь на бумаге и в головах. А вот уже в конкретных языках существуют конкретные типы, реализующие АТД. АТД нередко путают с понятием «структура данных», более того, часто структуры данных и АТД имеют одно и то же название. Сильно погружаться в эти дебри не нужно, достаточно иметь общее представление.</p>
<p>В этом уроке мы разберем один из самых простых и важных абстрактных типов данных – стек (stack, переводится как стопка).</p>
<h2 id="heading-2-1">Стек</h2>
<p>Стек — упорядоченная коллекция элементов, в которой добавление новых и удаление старых элементов всегда происходит с одного конца коллекции. Обычно его называют вершиной стека.</p>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NTcyNiwicHVyIjoiYmxvYl9pZCJ9fQ==--4262f65b0e0899d41f62bb5f229c809ce9f1da77/stack_diagram.jpg" alt="Стек" loading="lazy"/></p>
<p>У стека есть аналоги из реальной жизни. Например, пирамида колец. Кольца добавляются в пирамиду только друг за другом. Извлекаются тоже, только в обратном порядке. Последнее кольцо достается из пирамиды первым.</p>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NTcyNywicHVyIjoiYmxvYl9pZCJ9fQ==--297ff678bfb509a30fa39fd5a5cbd0bbe2548e93/pyramid.png" alt="Пирамида" loading="lazy"/></p>
<p>Практически любая стопка может рассматриваться как стек. Если не применять грубую физическую силу, то со стопками мы работаем двумя способами. Либо кладем новый элемент (например, книгу) на верхушку стопки, либо снимаем элемент с верхушки. Поэтому стек еще называют "Last In First Out" (LIFO), то есть "последним зашел, первым вышел".</p>
<p>Перед тем, как разбирать конкретную задачу, посмотрим на роль, которую играет стек в программировании. Вспомните, как исполняется любая программа. Одни функции вызывают другие, которые, в свою очередь, вызывают третьи, и так далее. После того, как выполнение заходит в самую глубокую функцию, та возвращает значение, и начинается обратный процесс. Сначала идет выход из наиболее глубоких функций, затем из тех, что уровнем выше, и так далее до тех пор, пока не дойдет до самой внешней функции. Вызов функций — не что иное, как добавление элемента в стек, а возврат – извлечение из стека. Именно так все устроено на аппаратном уровне. К тому же, если в процессе выполнения программы происходит ошибка, то ее вывод часто называют <em>Stack Trace</em> (трассировка стека).</p>
<p>Другой пример, связанный с программированием — кнопка "назад" в браузере. История посещений представляет собой стек, каждый новый переход по ссылке добавляет ее в историю, а кнопка «назад» извлекает из стека последний элемент.</p>
<p>Работа со стеком включает в себя следующие операции:</p>
<ul>
<li>Добавить в стек (push)</li>
<li>Взять из стека (pop)</li>
<li>Вернуть элемент с вершины стека без удаления (peekBack)</li>
<li>Проверить на пустоту (isEmpty)</li>
<li>Вернуть размер (size)</li>
</ul>
<p>Первые две – базовые, остальные нужны время от времени. В JavaScript стек можно создать на основе массивов. Для этого используются методы <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">push()</code>, <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">pop()</code> и свойство <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">length</code>.</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">const stack = []
stack.push(3)
console.log(stack) // => [ 3 ]
stack.push('Winterfall')
console.log(stack) // => [ 3, 'Winterfall' ]
stack.push(true)
console.log(stack) // => [ 3, 'Winterfall', true ]
const element1 = stack.pop()
console.log(element1) // => true
console.log(stack) // => [ 3, 'Winterfall' ]
const element2 = stack.pop()
console.log(element2) // => Winterfall
console.log(stack) // => [ 3 ]</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Обратите внимание, что методы <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">pop()</code> и <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">push()</code> изменяют исходный массив. <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">pop()</code> не только изменяет его, но и возвращает элемент, снятый со стека.</p>
<p>Рассмотрим задачку, решение которой тривиально при использовании стека. Кстати, ее нередко задают на собеседованиях, чтобы убедиться, хорошо ли вы знаете базовые структуры данных.</p>
<p>Задача:</p>
<p>Необходимо реализовать функцию, которая проверяет, что парные скобки сбалансированы. То есть каждая открывающая скобка имеет закрывающую: <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">()</code>, <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">((()()))</code>. А вот примеры несбалансированных скобок: <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">(</code>, <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">(()</code>, <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">)(</code>. Для проверки баланса недостаточно считать количество, важен так же порядок в котором они идут.</p>
<p><em>У этой задачи есть простое решение и без стека, но стек тоже хорошо подходит (и даже нагляднее)</em></p>
<p>Решение со стеком выглядит так:</p>
<ol>
<li>Если перед нами открывающий элемент, то заносим его в стек</li>
<li>Если закрывающий, то достаем из стека элемент (очевидно, последний добавленный). Если стек пустой, то есть в нем нет открывающих скобок, значит выражение не соответствует требуемому формату.</li>
<li>Если мы дошли до конца строки и стек пустой, то все хорошо. Если в стеке остались элементы, то проверка не прошла. Такое может быть, если в начале строки были открывающие элементы, но в конце не было закрывающих.</li>
</ol>
<p>Разберем его построчно:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">const checkIsBalanced = (expression) => {
// Инициализация стека
const stack = []
// Проходим по каждому символу в строке
for (const symbol of expression) {
// Смотрим, открывающий или закрывающий
// Если символ открывающий
if (symbol === '(') {
// Добавляем его в стек
stack.push(symbol)
// Если символ закрывающий
}
else if (symbol === ')') {
// Достаем из стека последний элемент
// Если стек пуст, значит для закрывающего не нашлось открывающего
// Значит баланса нет, возвращаем false
if (!stack.pop()) {
return false
}
}
}
// Проверяем, что стек пуст
// Если в стеке остались элементы, то не все открывающие скобки закрыты,
// а значит баланса нет
return stack.length === 0
}
export default checkIsBalanced</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Предположим, что на вход функции попала следующая строка: <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">(()</code>. Ниже описание ключевых шагов при выполнении функции проверки:</p>
<ol>
<li>Первая скобка <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">(</code> заносится в стек, так как она открывающая</li>
<li>Следующая скобка <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">(</code> также заносится в стек по той же самой причине</li>
<li>Последняя <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">)</code> является закрывающей, из стека извлекается последняя добавленная скобка</li>
<li>В стеке остался один элемент, значит баланса нет</li>
</ol>
<h2 id="heading-2-2">Семантика</h2>
<p>Может возникнуть соблазн использовать эти функции в повседневной практике. Например, чтобы извлечь из массива последний элемент. Несмотря на то, что метод <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">pop()</code> действительно позволяет это сделать, такой вариант использования крайне нежелателен по нескольким причинам:</p>
<ol>
<li>
<p>Побочный эффект данной операции — изменение исходного массива. Даже если массив потом не используется, такой код вносит потенциальные проблемы и заставляет его переписывать в будущем.</p>
</li>
<li>
<p>Нарушается семантика. Инструменты нужно использовать по назначению, иначе рождается код, который декларирует одно, но в реальности делает другое. Любой опытный программист, который видит <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">pop()</code> сразу считает, что массив в данной части программы используется как стек. Если это не так, то понадобятся дополнительные умственные усилия для понимания происходящего.</p>
</li>
</ol>
<p>Для извлечения последнего элемента можно использовать метод массива <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at" rel="noopener noreferrer" target="_blank">at()</a></p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">const items = ['first', 'second', 'third']
items.at(-1) // 'third'</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div></div><div style="margin-block:var(--mantine-spacing-xl)" class=""><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size);margin-bottom:var(--mantine-spacing-md)" class="m_8a5d1357 mantine-Title-root" data-order="2">Рекомендуемые программы</h2><style data-mantine-styles="inline">.__m__-_R_2mremqrdub_{--carousel-slide-gap:var(--mantine-spacing-xs);--carousel-slide-size:70%;}@media(min-width: 36em){.__m__-_R_2mremqrdub_{--carousel-slide-gap:var(--mantine-spacing-xl);--carousel-slide-size:50%;}}</style><div style="--carousel-control-size:calc(2.5rem * var(--mantine-scale));--carousel-controls-offset:var(--mantine-spacing-sm);margin-bottom:var(--mantine-spacing-lg);padding-block:var(--mantine-spacing-sm);background:var(--app-color-surface)" class="m_17884d0f mantine-Carousel-root responsiveClassName" data-orientation="horizontal" data-include-gap-in-size="true"><div class="m_39bc3463 mantine-Carousel-controls" data-orientation="horizontal"><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="previous" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="next" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(-90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button></div><div class="m_a2dae653 mantine-Carousel-viewport" data-type="media"><div class="m_fcd81474 mantine-Carousel-container __m__-_R_2mremqrdub_" data-orientation="horizontal"><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/frontend?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">10 месяцев</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">С нуля</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Фронтенд-разработчик</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Изучите HTML, CSS, JavaScript и React</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzcyNywicHVyIjoiYmxvYl9pZCJ9fQ==--2d5cbbf5c3b4a73ae4b2c50632305d78f5872e4d/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Programmer-rafiki.png" alt="Фронтенд-разработчик" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 6 792 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/backend?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">10 месяцев</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">С нуля</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Node.js-разработчик</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Изучите JavaScript, Node.js, Fastify и REST API</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzcyNSwicHVyIjoiYmxvYl9pZCJ9fQ==--2e84f5f94140ee4e22019ac479c290ef48c3fac8/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Static%20website-cuate.png" alt="Node.js-разработчик" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 4 755 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/fullstack-javascript?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">12 месяцев</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">С нуля</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Fullstack-разработчик на Node.js</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Освоите JavaScript, Node.js, Fastify и React для фронтенда и бэкенда.</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NDA0MywicHVyIjoiYmxvYl9pZCJ9fQ==--e2c6c0775e2308e42fbc5dc592ba2db0470632ca/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Programmer-rafiki.png" alt="Fullstack-разработчик на Node.js" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 7 934 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/qa-auto-engineer-javascript?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">6 месяцев</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Для продвинутых</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Автоматизатор тестирования на JavaScript</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Изучите: Git, JavaScript, Playwright, юнит-, API- и UI-тесты, Docker и SQL</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzk0MSwicHVyIjoiYmxvYl9pZCJ9fQ==--9a9cd0863661374e7c92ea27b1270ac3299c0979/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Usability%20testing-pana.png" alt="Автоматизатор тестирования на JavaScript" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 4 281 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size);margin-bottom:var(--mantine-spacing-md);font-size:var(--mantine-font-size-h3)" class="m_8a5d1357 mantine-Title-root" data-order="2" data-responsive="true">Каталог</h2><p style="margin-bottom:auto" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Полный список доступных курсов по разным направлениям</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="/vite/assets/development-BVihs_d5.png" alt="Orientation"/></div></div></div></a></div></div></div></div></div></div></div></div></div><style data-mantine-styles="inline">.__m__-_R_1bdub_{--col-flex-grow:auto;--col-flex-basis:8.333333333333334%;--col-max-width:8.333333333333334%;}@media(min-width: 48em){.__m__-_R_1bdub_{--col-flex-grow:auto;--col-flex-basis:16.666666666666668%;--col-max-width:16.666666666666668%;}}</style><div style="min-width:0rem;height:100%;min-height:0rem" class="m_96bdd299 mantine-Grid-col __m__-_R_1bdub_"><div style="margin-inline:var(--mantine-spacing-xs)" class="mantine-visible-from-sm"><a style="--button-color:var(--mantine-color-white);margin-bottom:var(--mantine-spacing-lg);text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/js-arrays/lessons/stack/finish_unit?unit=theory" data-disabled="true" data-block="true" disabled=""><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label"><span style="margin-inline-end:var(--mantine-spacing-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Дальше</span>→</span></span></a><a style="padding-inline:0rem" class="mantine-focus-auto m_f0824112 mantine-NavLink-root m_87cf2631 mantine-UnstyledButton-root"><span class="m_690090b5 mantine-NavLink-section" data-position="left"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-list-numbers "><path d="M11 6h9"></path><path d="M11 12h9"></path><path d="M12 18h8"></path><path d="M4 16a2 2 0 1 1 4 0c0 .591 -.5 1 -1 1.5l-3 2.5h4"></path><path d="M6 10v-6l-2 2"></path></svg></div></span><div class="m_f07af9d2 mantine-NavLink-body"><span class="m_1f6ac4c4 mantine-NavLink-label">Навигация по теме</span><span class="m_57492dcc mantine-NavLink-description">Теория</span></div><span class="m_690090b5 mantine-NavLink-section" data-position="right"></span></a><div style="margin-block:var(--mantine-spacing-lg)" class="m_3eebeb36 mantine-Divider-root" data-orientation="horizontal" role="separator"></div><div style="margin-block:var(--mantine-spacing-lg)" class=""><div style="justify-content:space-between;margin-bottom:calc(0.1875rem * var(--mantine-scale));color:var(--mantine-color-dimmed);font-size:var(--mantine-font-size-xs)" class="m_8bffd616 mantine-Flex-root __m__-_R_qimrbdub_"><p style="font-size:var(--mantine-font-size-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Завершено</p><p style="font-size:var(--mantine-font-size-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">0 / 22</p></div><div style="--progress-size:var(--progress-size-sm)" class="m_db6d6462 mantine-Progress-root" data-size="sm"><div style="--progress-section-size:0%;--progress-section-color:var(--mantine-color-gray-filled)" class="m_2242eb65 mantine-Progress-section" role="progressbar" aria-valuemax="100" aria-valuemin="0" aria-valuenow="0" aria-valuetext="0%"></div></div></div><button style="padding-inline:0rem" class="mantine-focus-auto m_f0824112 mantine-NavLink-root m_87cf2631 mantine-UnstyledButton-root" type="button"><span class="m_690090b5 mantine-NavLink-section" data-position="left"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-message "><path d="M8 9h8"></path><path d="M8 13h6"></path><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"></path></svg></div></span><div class="m_f07af9d2 mantine-NavLink-body"><span class="m_1f6ac4c4 mantine-NavLink-label">Обсуждения (архив)</span><span class="m_57492dcc mantine-NavLink-description"></span></div></button><div style="--toc-bg:var(--mantine-color-blue-light);--toc-color:var(--mantine-color-blue-light-color);--toc-size:var(--mantine-font-size-sm);--toc-radius:var(--mantine-radius-sm);margin-top:var(--mantine-spacing-xl)" class="m_bcaa9990 mantine-TableOfContents-root" data-variant="light" data-size="sm"></div></div><div class="mantine-hidden-from-sm"><div style="--stack-gap:0rem;--stack-align:stretch;--stack-justify:flex-start" class="m_6d731127 mantine-Stack-root"><a style="--button-color:var(--mantine-color-white);margin-bottom:var(--mantine-spacing-xs);padding:0rem;text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/js-arrays/lessons/stack/finish_unit?unit=theory" data-disabled="true" data-block="true" disabled=""><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">→</span></span></a><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" data-disabled="true" type="button" disabled=""><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-list-numbers "><path d="M11 6h9"></path><path d="M11 12h9"></path><path d="M12 18h8"></path><path d="M4 16a2 2 0 1 1 4 0c0 .591 -.5 1 -1 1.5l-3 2.5h4"></path><path d="M6 10v-6l-2 2"></path></svg></span></button><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto mantine-active m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" type="button"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-message "><path d="M8 9h8"></path><path d="M8 13h6"></path><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"></path></svg></span></button></div></div></div></div></div></div></div>
</main>
<footer class="bg-dark fw-light text-light px-3 py-5">
<div class="row small">
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 mb-3">Хекслет</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/about">О нас</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/testimonials">Отзывы</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://b2b.hexlet.io" role="button">Корпоративное обучение</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/blog">Блог</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/qna">Вопросы и ответы</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/glossary">Глоссарий</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://help.hexlet.io" data-target="_blank" role="button">Справка</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" target="_blank" rel="noopener noreferrer" href="/map">Карта сайта</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 fw-normal mb-3">Направления</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_devops">DevOps
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_data_analytics">Аналитика
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_backend_development">Бэкенд
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_programming">Программирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_testing">Тестирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_front_end_dev">Фронтенд
</a></li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Профессии</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/go">Go-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/java">Java-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python">Python-разработчик </a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/data-analytics">Аналитик данных</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/qa-engineer">Инженер по ручному тестированию</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php">РНР-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/frontend">Фронтенд-разработчик</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Навыки</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python-django-developer">Django</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/docker">Docker</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php-laravel-developer">Laravel</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/postman">Postman</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-react-developer">React</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-rest-api">REST API в Node.js</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/spring-boot">Spring Boot</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/typescript">Typescript</a>
</li>
</ul>
</div>
</div>
<hr>
<div class="row">
<div class="col-12 col-sm-4 col-md-2">
<div class="fs-4">
<ul class="list-unstyled d-flex">
<li class="me-3">
<a aria-label="Telegram" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://t.me/hexlet_ru"><span class="bi bi-telegram"></span>
</a></li>
<li>
<a aria-label="Youtube" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://www.youtube.com/user/HexletUniversity"><span class="bi bi-youtube"></span>
</a></li>
</ul>
</div>
<div class="mb-2 d-flex flex-column">
<a class="link-light text-decoration-none" rel="nofollow" href="mailto:support@hexlet.io">support@hexlet.io</a>
<a class="link-light text-decoration-none py-2" target="_blank" href="https://t.me/hexlet_help_bot">t.me/hexlet_help_bot</a>
</div>
<ul class="list-unstyled d-flex">
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://hexlet.io/locale/switch?new_locale=en" data-target="_self" role="button"><span class="my-auto">EN</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 opacity-100 external-link" rel="nofollow" data-href="https://ru.hexlet.io/locale/switch?new_locale=ru" data-target="_self" role="button"><span class="my-auto">RU</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://kz.hexlet.io/locale/switch?new_locale=kz" data-target="_self" role="button"><span class="my-auto">KZ</span>
</span></li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<ul class="list-unstyled fs-4">
<li class="mb-3">
<a class="link-light text-decoration-none" href="tel:8%20800%20100%2022%2047">8 800 100 22 47</a>
<span class="d-block opacity-50 small">бесплатно по РФ</span>
</li>
<li>
<a class="link-light text-decoration-none" href="tel:%2B7%20495%20085%2021%2062">+7 495 085 21 62</a>
<span class="d-block opacity-50 small">бесплатно по Москве</span>
</li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<div class="small mb-3">Образовательные услуги оказываются на основании Л035-01298-77/01989008 от 14.03.2025</div>
<ul class="list-unstyled small">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/legal">Правовая информация</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/offer">Оферта</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/license">Лицензия</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/contacts">Контакты</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-12 col-md-4 small">
<div class="mb-2">
<div>ООО «<a href="/" class="text-decoration-none link-light">Хекслет Рус</a>»</div>
<div>108813 г. Москва, вн.тер.г. поселение Московский,</div>
<div>г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3</div>
<div>ОГРН 1217300010476</div>
<div>ИНН 7325174845</div>
</div>
<hr>
<div>АНО ДПО «<a href="/" class="text-decoration-none link-light">Учебный центр «Хекслет</a>»</div>
<div>119331 г. Москва, вн. тер. г. муниципальный округ</div>
<div>Ломоносовский, пр-кт Вернадского, д. 29</div>
<div>ОГРН 1247700712390</div>
<div>ИНН 7736364948</div>
</div>
</div>
</footer>
<div id="root-assistant-offcanvas"></div>
<script src="/vite/assets/assistant-CdBlNCiQ.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-nkZBEvfU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/MarkdownBlock-DbyKWoR_.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/shiki-V011pkdv.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-XR8Qr8kR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dist-GCHh59xr.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useIsomorphicEffect-HJ6VK0D3.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-KSp6QbZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/classnames-l6ipYlLR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/debounce-jMQ_Cf4f.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v67327c56f0bb4ef8b305cae61679db8f1769101564043" integrity="sha512-rdcWY47ByXd76cbCFzznIcEaCN71jqkWBBqlwhF1SY7KubdLKZiEGeP7AyieKZlGP9hbY/MhGrwXzJC/HulNyg==" data-cf-beacon='{"version":"2024.11.0","token":"d11015b65d11429ea6b4a2ef37dd7e0b","server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
</body>
</html>