<!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 18:50:27 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="uH0wb4c9MgTKS-rmg7ijIPSB2Apq7Hr6o2aQyGZo1mNXrPtYdUOfZHwIzn6Pt1NXNIj1oGLbhFgehgqcNG8xDQ";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-classes/lessons/late-binding/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-classes/lessons/late-binding/theory_unit">
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="wmiQu2pPAMatWsT-UfHtDts2SXQGKsrNAvOa9y46CCctuVuMmDGtphsZ4GZd_h15Gz9k3g4dNG-_EwCjfD3vSQ" />
<script src="/vite/assets/inertia-DfXos102.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-BrRXra1y.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-cb8xch9l.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/eyJfcmFpbHMiOnsiZGF0YSI6NDAxOSwicHVyIjoiYmxvYl9pZCJ9fQ==--84efd2b6854b7000046e9ce06e6be85d38af5ab8/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/JavaScript%20frameworks-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="/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-26T18:50:26.888Z","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":"9nGCrZmFmXDbuO0yGx8LuwMlo5PZvT_WEWw18Y49YsUZoEmaa_s0EG37yaoXEPvMwyyOOdGKwXSsjK-l3DqFqw","topics":[{"id":48962,"title":"Вопрос №3 теста крайне двусмысленный. Если буквально, то да - изменится. Как минимум получим ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor.\nНо верный ответ у вопроса \"Нет\", т.о. в вопросе имелось что-то другое, но это \"другое\" надо бы уточнить.","plain_title":"Вопрос №3 теста крайне двусмысленный. Если буквально, то да - изменится. Как минимум получим ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor. Но верный ответ у вопроса \"Нет\", т.о. в вопросе имелось что-то другое, но это \"другое\" надо бы уточнить. ","creator":{"public_name":"Alexey Yakovlev","id":87378,"is_tutor":false},"comments":[{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":105178,"body":"Ага спасибо. Поправил!","topic_id":48962}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Позднее связывание","entity_url":null,"active":true}},{"id":49928,"title":"а как же декларативный подход?\n\nhttps://ru.hexlet.io/code_reviews/346289","plain_title":"а как же декларативный подход? https://ru.hexlet.io/code_reviews/346289 ","creator":{"public_name":"Daniyar Zhanakhmetov","id":239134,"is_tutor":false},"comments":[{"creator":{"public_name":"Daniyar Zhanakhmetov","id":239134,"is_tutor":false},"id":107064,"body":"**Сергей Мелодин**, действительно. Так гораздо лучше. Спасибо!","topic_id":49928},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":107042,"body":"**Daniyar Zhanakhmetov**, приветствую.\n\nЭто два варианта решения одной задачи, только в вашем решении у функции внутренности попали во внешний интерфейс. Прочитайте эту статью: https://ru.hexlet.io/blog/posts/sovershennyy-kod-plohie-i-horoshie-praktiki-pri-proektirovanii-parametrov-funktsiy особенно текст под заголовком \"Параметры для внутренних нужд\", чтобы сделать данное решение правильным.","topic_id":49928}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Позднее связывание","entity_url":null,"active":true}},{"id":55013,"title":"Судя по всему в тексте упражнения ошибка:\n\n> текущая ошибка наследуется от errorInstance _И_ от одной из ошибок приложения;\n\nвместо _И_ должно быть _ИЛИ_ (по крайней мере у меня все тесты прошли именно с таким вариантом)","plain_title":"Судя по всему в тексте упражнения ошибка: текущая ошибка наследуется от errorInstance И от одной из ошибок приложения; вместо И должно быть ИЛИ (по крайней мере у меня все тесты прошли именно с таким вариантом) ","creator":{"public_name":"Алексей К","id":196174,"is_tutor":false},"comments":[{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":116976,"body":"Алексей, день добрый!\n\nУлучшил тесты, теперь такое решение не пройдёт. Также согласовал порядок функций в реализации с порядком в описании. Спасибо, что обратили внимание.","topic_id":55013},{"creator":{"public_name":"Алексей К","id":196174,"is_tutor":false},"id":116845,"body":"Пожалуйста: [review](https://ru.hexlet.io/code_reviews/411973)\nЯ понял в чем дело - я пробежался по списку кейсов из readme и в таком же порядке накидал условия в catchers. Сейчас внимательно прочитал названия функций и понял, что порядок другой. Должно быть _И_.","topic_id":55013},{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":116822,"body":"Алексей, приветствую!\n\nДолжно быть именно И. Вообще странно что тесты прошли с использованием ИЛИ. А можете отправить ваш код на ревью, а в сообщение вложить на него ссылку? Я посмотрю его, возможно нужно будет немного доработать тесты.","topic_id":55013}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Позднее связывание","entity_url":null,"active":true}},{"id":68873,"title":"Есть некоторые задания, которые настолько запутаны, что в них и разбираться не хочется. Это одно из них. Одно дело подтолкнуть ученика к решению - другое дело - запутать окончательно. Если над каждым заданием сидеть целый день для его решения, то и года не хватит, чтобы пройти курс на Хекслет, это при условии, что будешь скипать проекты. ","plain_title":"Есть некоторые задания, которые настолько запутаны, что в них и разбираться не хочется. Это одно из них. Одно дело подтолкнуть ученика к решению - другое дело - запутать окончательно. Если над каждым заданием сидеть целый день для его решения, то и года не хватит, чтобы пройти курс на Хекслет, это при условии, что будешь скипать проекты. ","creator":{"public_name":"Дмитрий Лось","id":400927,"is_tutor":false},"comments":[{"creator":{"public_name":"Ivan Gagarinov","id":75907,"is_tutor":true},"id":144633,"body":"Я подумаю как доработать это задание. С ним действительно возникает множество сложностей. Спасибо что обратили на это внимание.","topic_id":68873}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Позднее связывание","entity_url":null,"active":true}},{"id":59134,"title":"Доброго времен суток! \nПребываю в некоторой путанице, не проходит тест \"Throw not app error, check AppError instance\". Есть подозрение, что загвоздка кроется в функции appErrorCatcher файла \"catchers.js\", одна ее громоздкость и куча \"или\" вызывают мысли, что что-то делаю не так. Подскажите, в чем корень проблемы?\nРевью: https://ru.hexlet.io/code_reviews/468682","plain_title":"Доброго времен суток! Пребываю в некоторой путанице, не проходит тест \"Throw not app error, check AppError instance\". Есть подозрение, что загвоздка кроется в функции appErrorCatcher файла \"catchers.js\", одна ее громоздкость и куча \"или\" вызывают мысли, что что-то делаю не так. Подскажите, в чем корень проблемы? Ревью: https://ru.hexlet.io/code_reviews/468682 ","creator":{"public_name":"Кристина","id":354395,"is_tutor":false},"comments":[{"creator":{"public_name":"Кристина","id":354395,"is_tutor":false},"id":125088,"body":"Спасибо","topic_id":59134},{"creator":{"public_name":"Ivan Gagarinov","id":75907,"is_tutor":true},"id":125081,"body":"Здравствуйте! Для проверки что ошибка наследуется от одной из ошибок приложения вы можете использовать только `AppError` - все остальные ошибки приложения наследуются от неё. Таким образом вам достаточно просто убрать лишние проверки в `appErrorCatcher`","topic_id":59134}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Позднее связывание","entity_url":null,"active":true}},{"id":54903,"title":"Столкнулся с тем, что в тестах не проверяется вторая часть этого условия:\n> текущая ошибка наследуется от errorInstance И от одной из ошибок приложения;\n","plain_title":"Столкнулся с тем, что в тестах не проверяется вторая часть этого условия: текущая ошибка наследуется от errorInstance И от одной из ошибок приложения; ","creator":{"public_name":"Сергей","id":311079,"is_tutor":false},"comments":[{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":116622,"body":"Спасибо, принял. Проверю этот момент.","topic_id":54903}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Позднее связывание","entity_url":null,"active":true}},{"id":60562,"title":"Попался в ранее описанную ловушку \"знаю паттерн -> пытаюсь натянуть на задачу\" на этом задании.\nРешив на второй день борьбы всё-таки сделать ровно то, что от меня хотят в постановке задачи, написал идентичное с учителем решение. \nСпасибо за такие задания, Хекслет! Возвращение от паттернов к здравому смыслу очень освежает.\n","plain_title":"Попался в ранее описанную ловушку \"знаю паттерн -> пытаюсь натянуть на задачу\" на этом задании. Решив на второй день борьбы всё-таки сделать ровно то, что от меня хотят в постановке задачи, написал идентичное с учителем решение. Спасибо за такие задания, Хекслет! Возвращение от паттернов к здравому смыслу очень освежает. ","creator":{"public_name":"Егор Булгаков","id":392445,"is_tutor":false},"comments":[{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":127805,"body":"Добрый день, Егор! Рад, что вам понравилось задание. Здорово, что вы на собственном примере убедились, что не стоит идти от паттерна, который вам известен и пытаться применить его на ситуацию","topic_id":60562}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Позднее связывание","entity_url":null,"active":true}},{"id":54007,"title":"На мой взгляд в тексте задания в соответствии с предложенным решением есть неточность. \nА именно утверждение:\n\n> текущая ошибка не наследуется от ошибок приложения, но наследуется от `errorInstance`\n\nя склонен понимать, как:\n\n```js\n!(error instanceof AppError) && error instanceof errorInstance\n```\n\nно не как:\n\n```js\nerror instanceof errorInstance","plain_title":"На мой взгляд в тексте задания в соответствии с предложенным решением есть неточность. А именно утверждение: текущая ошибка не наследуется от ошибок приложения, но наследуется от errorInstance я склонен понимать, как: !(error instanceof AppError) && error instanceof errorInstance но не как: error instanceof errorInstance ","creator":{"public_name":"Pavel","id":340717,"is_tutor":false},"comments":[{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":114894,"body":"**Pavel**, улучшил формулировку, спасибо!","topic_id":54007}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Позднее связывание","entity_url":null,"active":true}},{"id":63110,"title":"Для тех, кто сломал мозг (как я) на этой части задания:\n\n> Реализуйте логику функций, подготовленных в файле. Каждая из них принимает обработчик ошибки и класс ошибки. В случае возникновения ошибки должны проверяться такие кейсы:\n> - текущая ошибка наследуется от errorInstance;\n> - текущая ошибка наследуется от errorInstance И от одной из ошибок приложения;\n> - errorInstance отсутствует, но ошибка содержит свойство isCustomError со значением true.\n\nКаждой функции из файла здесь соответствует 1 пункт из списка (по порядку).","plain_title":"Для тех, кто сломал мозг (как я) на этой часть задания: Реализуйте логику функций, подготовленных в файле. Каждая из них принимает обработчик ошибки и класс ошибки. В случае возникновения ошибки должны проверяться такие кейсы: - текущая ошибка наследуется от errorInstance; - текущая ошибка наследуется от errorInstance И от одной из ошибок приложения; - errorInstance отсутствует, но ошибка содержит свойство isCustomError со значением true. Каждой функции из файла здесь соответствует 1 пункт из списка, по порядку. ","creator":{"public_name":"Дмитрий","id":319563,"is_tutor":false},"comments":[{"creator":{"public_name":"Ivan Gagarinov","id":75907,"is_tutor":true},"id":132922,"body":"Спасибо за фидбек. Да, так и есть, имена файлов(и классов ошибок) указывают на тот или иной тип ошибки","topic_id":63110}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Позднее связывание","entity_url":null,"active":true}},{"id":50606,"title":"Всем добрый!\n\nПодскажите пожалуиста почему на первой итерации для теста есть равенство между **self.constructor.prototype**, **self.___proto __** и **Object.getPrototypeOf(self)**\na на второй итерации равенство уже проподает из за **self.constructor.prototype**?\n\nhttps://ru.hexlet.io/code_reviews/354553?submission_id=449835\n\n\n> Test : **expect(obj.isInstanceOf('FirstChild')).toBe(true)**;\n\n\n ####### **Iteration number 1** ########\n\n**self: ChildOfChild {}**\n\nconsole.log(self.constructor.prototype) // **FirstChild {}**\n\nconsole.log(Object.getPrototypeOf(self)) // **FirstChild {}**\n\nconsole.log((self. __ proto __) // **FirstChild {}**\n\n\n**равенство** : self.constructor.prototype **===** self. __proto __ **===** Object.getPrototypeOf(self)\n\n\n\n\n####### **Iteration number 2** ########\n\n**self: FirstChild {}**\n\nconsole.log(self.constructor.prototype) // **FirstChild {}**\n\nconsole.log(Object.getPrototypeOf(self)) // Base {}\n\nconsole.log((self.__ proto __) // Base {}\n\n**не равенство** self.constructor.prototype **!**= self.__ proto __\n\n\n","plain_title":"Всем добрый! Подскажите пожалуиста почему на первой итерации для теста есть равенство: теста : expect(obj.isInstanceOf('FirstChild')).toBe(true); ####### Iteration number 1 ######## console.log(self.constructor.prototype) // FirstChild {} console.log(Object.getPrototypeOf(self)) // FirstChild {} console.log((self.proto) // FirstChild {} *равенство *: self.constructor.prototype === self.proto === Object.getPrototypeOf(self) А на второй итерации равенство уже проподает : # Iteration number 2 console.log(self.constructor.prototype) // Base {} console.log(Object.getPrototypeOf(self)) // FirstChild {} console.log((self.proto) // FirstChild {} self.constructor.prototype != self.proto https://ru.hexlet.io/codereviews/354553?submissionid=449835 ","creator":{"public_name":"Vova","id":150672,"is_tutor":false},"comments":[{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":108554,"body":"Или напишите в нашем слаке в канале nodejs, там помогут подробнее разобраться с решением. Тут я не могу разбирать его детали, чтобы не спойлерить детали.","topic_id":50606},{"creator":{"public_name":"Vova","id":150672,"is_tutor":false},"id":108658,"body":"**Сергей**, cпасибо за ваше время и попытки объяснить но я разочарован.\n\nЗа **7 дней** переписки я сделал для себя некоторые выводы советую и вам.\n\nОтвет на мой вопрос очень простой когда понемаешь тему прототипов и наследования, но я так и **не дождался его от вас**.\n\nВместо чего:\n\n- Потому что такой дебаг. \n- Вы просто неправильно дебажите.\n- Легко отстрелить себе ногу, если допустить ошибку в коде.\n- Тут я не могу разбирать его детали, чтобы не спойлерить детали. (**Подсказка**: В ответе на мой \n вопрос **нету** спойлеров).\n- Используйте для начала базовые подходы, которым мы учим в теории курса, а \n когда освоитесь с ними, можете обратиться к книгам.\n\n\n\n","topic_id":50606},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":108660,"body":"**Vova**, возможно, проблема в вопросе. Я лично вижу, что вы называете итерациями разные вызовы функции и не можете разобраться с базовым использованием решения учителя, а уже полезли в прототипы.\n\nЕсли вам нужен человек, который будет разбираться с вами подробно в коде, то переходите на тариф с наставником: https://ru.hexlet.io/my/learning это как раз их задача. Опять же, есть слак, где есть люди, которые могут сказать что-то другими словами.","topic_id":50606},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":108357,"body":"**Vova**, не понял вопроса. У вас есть результат отладки, где на каждой итерации новый объект.","topic_id":50606},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":108629,"body":"**Vova**, это не итерации, а два вызова функции из тестов. Первый раз вызывается функция и в неё передаётся строка `'ChildOfChild'`, второй раз строка `'FirstChild'`. Поскольку класс `ChildOfChild` является верхним, то и при первом вызове, и при втором, поиск начинается с него.","topic_id":50606},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":108323,"body":"**Vova**, приветствую.\n\nПотому что в переменную перезаписываются текущие объекты. Это как если обходить массив в цикле и записывать в переменную текущий элемент.","topic_id":50606},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":108465,"body":"**Vova**, не выкладывайте решение учителя в комментарии. \n\n> Так скажите пожалуйста что пошло не так в решение учителя и почему\n\nВы просто неправильно дебажите. Создайте переменную condition и перенесите условие из while в неё, а затем смотрите в какой момент прерывается цикл. Также, посмотрите тесты, там вызов происходит с разными аргументами, поэтому где-то выполняется одна итерация, где-то несколько. Объект при этом корректно заменяется.\n\n> Если не согласны то скажите тогда пожалуйста в чем разница между\n\nУ proto более широкий класс задач, чем получение прототипа. Легко отстрелить себе ногу, если допустить ошибку в коде. Тут лучше почитать документацию: https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/proto\n\nПри обращении к конструктору и прототипу конструктора, фактически, идёт обращение к инициализирующему объекту и, по идее, там должен быть null. Функции-конструкторы рассматривались в этих уроках:\n* https://ru.hexlet.io/courses/js-introduction-to-oop/lessons/constructor/theory_unit\n* https://ru.hexlet.io/courses/js-introduction-to-oop/lessons/prototype/theory_unit\n\nЭто не значит, что вы не сможете решить данное упражнение, используя свойства и методы, описанные выше. Но мы в теории их не даём и здесь вам, как студенту по нашей учебной программе надо решить и разобраться теми способами, которые мы дали в теории.","topic_id":50606},{"creator":{"public_name":"Vova","id":150672,"is_tutor":false},"id":108501,"body":"Сергей, приветствую.\n\nДавайте я попробую спрость подругому.\n\nВот код учителя и я всего лишь добавил **console.log** нa **currentObject .constructor.name** в do {} while ().\nhttps://ru.hexlet.io/code_reviews/354553\n\nБежим тест: **expect(obj.isInstanceOf('Base')).toBe(true);**\n\nРезультат:\n\n- ChildOfChild\n- **ChildOfChild** ???\n- FirstChild\n- Base\n\nВопрос: Почему печатается 2 раза имя конструктора **ChildOfChild** ?\n","topic_id":50606},{"creator":{"public_name":"Vova","id":150672,"is_tutor":false},"id":108342,"body":"**Сергей**, приветствую.\n\nЕсли перезаписываются текущие объекты...\n\nТак почему именно:\n\n- на первой итерации:\n**self.constructor.prototype => FirstChild {}**\n\n- на второй итерации:\n**self.constructor.prototype => FirstChild {}**\n\n- на третий:\n**self.constructor.prototype => Base {}**","topic_id":50606},{"creator":{"public_name":"Vova","id":150672,"is_tutor":false},"id":108706,"body":"Дорогой **Сергей**, вы видете то что хотите видеть не разобравшись.\nА я лично вижу у вас избыточную самоуверенность которая на данный момент вредит (Надеюсь что только мне).\n\n1. Если всетаки захотите то могу подробно вам рассказать что именно происходит в коде и почему печатается как было сказано в вопросе, **без перехода на тариф с наставником**!\n\n2. Если я б не разбирался б в материале слегка то наверно на меня может и сработало все нижесказаное вами:\n\n- Если вам нужен человек, который будет разбираться с вами подробно в коде, то переходите на тариф с наставником.\n- Hе можете разобраться с базовым использованием решения учителя.\n- Потому что такой дебаг.\n- Вы просто неправильно дебажите.\n- Легко отстрелить себе ногу, если допустить ошибку в коде.\n- Тут я не могу разбирать его детали, чтобы не спойлерить детали. (Подсказка: В ответе на мой вопрос нету спойлеров).\n- Используйте для начала базовые подходы, которым мы учим в теории курса, а когда освоитесь с ними, можете обратиться к книгам.\n\n3. \n**Поповоду:**\n_Я лично вижу, что вы называете итерациями разные вызовы функции_.\n\n> Вы скидываете console.log не сказав какой тест вы бежали и где поставили console.log в коде и говорите вооооо видете у меня в console.log все ок. Как на мой взгляд не профессионально для ментора.\n\n**Поповоду:**\n_Hе можете разобраться с базовым использованием решения учителя_.\n\n> Если вы не заметили то я сначала решил задания (моё решение похоже на учительское) и потом уже спросил вопрос.\n\n**Поповоду:**\n_A уже полезли в прототипы_ \n\n> Полез потому что немножко понимаю, чего советуют и вам.\n\n**Поповоду:**\n_Если вам нужен человек, который будет разбираться с вами подробно в коде, то переходите на тариф с наставником._\n\n> Нет уж спасибо у меня с этим все ок.\n\n\n**С Наступающим!**","topic_id":50606},{"creator":{"public_name":"Vova","id":150672,"is_tutor":false},"id":108442,"body":"Сергей, приветствую.\n\n1) Если вы не заметили, то моё решение идентично решению учителя.\n Тут нет разницы **self** это или **currentObject**, тут важно на что эта переменная \n указывает на каждой итерации.\n\n2) \"Что угодно может пойти не так.\" - Так скажите пожалуйста что пошло не так в решение \n учителя и почему\n\n- на первой итерации:\n**currentObject.constructor.prototype => FirstChild {}**\n\n- на второй итерации:\n**currentObject.constructor.prototype => FirstChild {}**\n\n- на третий:\n**currentObject.constructor.prototype => Base {}**\n\n\n3) \"Hе согласен\" - Если не согласны то скажите тогда пожалуйста в чем разница между:\n\n (Если рассматривать решения учителя)\n\n- **currentObject.__ proto __**\n- **currentObject.constructor.prototype**\n- **Object.getPrototypeOf(currentObject)**","topic_id":50606},{"creator":{"public_name":"Vova","id":150672,"is_tutor":false},"id":108600,"body":"**Сергей Мелодин**, потому что такой дебаг?\n\nДавайте рассмотрим ваш дебаг.\nПодскажите пожалуиста по какой причине **в вашем** дебаге на первый и второй итерации **currentObject** равен **ChildOfChild {}**?\n\n```\n-------------------------------------1--------------------------------\n 1 { className: 'ChildOfChild' }\n\n console.log\n 2 { currentObject: ChildOfChild {} }\n\n console.log\n 3 { nextObject: FirstChild {} }\n\n-------------------------------------2--------------------------------\nconsole.log\n 1 { className: 'FirstChild' }\n\n console.log\n 2 { currentObject: ChildOfChild {} }\n\n console.log\n 3 { nextObject: FirstChild {} }\n```\n\n\n","topic_id":50606},{"creator":{"public_name":"Vova","id":150672,"is_tutor":false},"id":108392,"body":"Сергей, приветствую.\n\nВы согласны, что **self.constructor.prototype**, **self.__ proto __** и **Object.getPrototypeOf(self)** должны ссылаться на один и тот же объект?","topic_id":50606},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":108413,"body":"**Vova**, не согласен. Вы используете ключевое слово self и подменяете на нём данные. У self и this разное предназначение, у каждого вызова прототипа могут быть разные результаты. Что угодно может пойти не так. Используйте для начала базовые подходы, которым мы учим в теории курса, а когда освоитесь с ними, можете обратиться к книгам, вроде [You Don't Know JS](https://github.com/azat-io/you-dont-know-js-ru/blob/master/this%20%26%20object%20prototypes/ch5.md).","topic_id":50606},{"creator":{"public_name":"Vova","id":150672,"is_tutor":false},"id":108500,"body":"**Сергей**, приветствую.\n\nДавайте я попробую спросить подругому.\nВот учительский код:\n\nhttps://ru.hexlet.io/code_reviews/354553\n\nЯ всеголишь добавил в do {} while () console.log на **currentObject.constructor.name** и пробегаю один тест **expect(obj.isInstanceOf('Base')).toBe(true);**\n","topic_id":50606},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":113918,"body":"**Vova**, доброго дня. Судя по отзывам других студентов, упражнение оказалось сложнее, чем нужно и сегодня мы его поменяли на новую версию. Попробуйте вернуть по материалам этого курса и пройти уже новое упражнение.\n\nТакже, по теме прототипов я отвечал в топике выше, возможно, ранее поднятая тему получилось кому-то донести другими словами, если для вас вопрос прототипов ещё актуален.","topic_id":50606},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":108553,"body":"**Vova**, потому что такой дебаг. Сделайте для начала просто и по теоретической части. Вот пример вывода по решению учителя:\n\n```\n console.log\n 1 { className: 'ChildOfChild' }\n\n at ChildOfChild.isInstanceOf (Base.js:6:13)\n\n console.log\n 2 { currentObject: ChildOfChild {} }\n\n at ChildOfChild.isInstanceOf (Base.js:12:15)\n\n console.log\n 3 { nextObject: FirstChild {} }\n\n at ChildOfChild.isInstanceOf (Base.js:14:15)\n\n console.log\n\n\n at ChildOfChild.isInstanceOf (Base.js:15:15)\n\n console.log\n --------------------\n\n at ChildOfChild.isInstanceOf (Base.js:18:13)\n\n console.log\n 1 { className: 'FirstChild' }\n\n at ChildOfChild.isInstanceOf (Base.js:6:13)\n\n console.log\n 2 { currentObject: ChildOfChild {} }\n\n at ChildOfChild.isInstanceOf (Base.js:12:15)\n\n console.log\n 3 { nextObject: FirstChild {} }\n\n at ChildOfChild.isInstanceOf (Base.js:14:15)\n\n console.log\n\n\n at ChildOfChild.isInstanceOf (Base.js:15:15)\n\n console.log\n 2 { currentObject: FirstChild {} }\n\n at ChildOfChild.isInstanceOf (Base.js:12:15)\n\n console.log\n 3 { nextObject: Base {} }\n\n at ChildOfChild.isInstanceOf (Base.js:14:15)\n\n console.log\n\n\n at ChildOfChild.isInstanceOf (Base.js:15:15)\n\n console.log\n 2 { currentObject: Base {} }\n\n at ChildOfChild.isInstanceOf (Base.js:12:15)\n\n console.log\n 3 { nextObject: {} }\n\n at ChildOfChild.isInstanceOf (Base.js:14:15)\n\n// и так далее\n```","topic_id":50606},{"creator":{"public_name":"Vova","id":150672,"is_tutor":false},"id":114639,"body":"Спасибо Сергей за ответ. Всё решино, всё ок.","topic_id":50606}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Позднее связывание","entity_url":null,"active":true}}],"lesson":{"exercise":{"id":1415,"slug":"js_classes_late_binding_catchers_exercise","name":null,"state":"active","kind":"exercise","language":"javascript","locale":"ru","has_web_view":false,"has_test_view":false,"reviewable":true,"readme":"Исключения – один из немногих примеров удачного использования наследования. Мы познакомимся с ними в следующих уроках, а сейчас потренируемся проверять цепочку наследования.\n\nРеализация исключений через классы расширяет возможности обработки нестандартных ситуаций. Для каждого типа ошибки — свой класс. При этом каждый тип обладает общей логикой и интерфейсом. При создании исключения, в конструктор передается текст ошибки — это общая логика для всех типов наследуется от базового класса и работает благодаря позднему связыванию.\n\n## catchers.js\n\nРеализуйте логику функций, подготовленных в файле. Каждая из них принимает обработчик ошибки и класс ошибки. Каждая функция отлавливает особый тип ошибок:\n* Функция `anyErrorCatcher` проверяет, что текущая ошибка наследуется от `errorInstance`\n* Функция `appErrorCatcher` проверяет, что текущая ошибка наследуется от `errorInstance` **И** от одной из ошибок приложения\n* Функция `customErrorCatcher` проверяет, что ошибка содержит свойство `isCustomError` со значением `true` и `errorInstance` при этом отсутствует\n\nЕсли условие выполнено — ошибка передаётся в функцию `errorHandler` и возвращается результат этой функции. Если нет, то выбрасывается в исходном виде.\n\n## runCode.js\n\nРеализуйте и экспортируйте по умолчанию функцию, которая имеет следующие параметры:\n* `action` - функция, которую нужно выполнить. Обязательный\n* `catcher` - обработчик ошибки из `catcher.js`, в качестве параметра принимает ошибку. Необязательный\n\nОбщий принцип работы таков: функция принимает в себя экшен, пытается его выполнить и возвращает либо результат выполнения, либо передаёт ошибку в `catcher` и возвращает его результат (если `catcher` не задан, выбрасывает ошибку как есть).\n\n```javascript\nimport runCode from './runCode.js'\nimport { appErrorCatcher } from './catchers.js'\nimport AppNetworkError from './errors/AppNetworkError.js'\nimport NetworkError from './errors/NetworkError.js'\n\nconst successAction = () => 'Hello, Hexlet!'\nconst failedAction = () => {\n throw new AppNetworkError('Hexlet is unavailable!')\n}\nconst errorHandler = err => `\"Hello, Hexlet\" failed with error: \"${err.message}\"`\nconst catcher1 = appErrorCatcher(errorHandler, AppNetworkError)\n\nrunCode(successAction, catcher1) // 'Hello, Hexlet!';\n\n// Выброшена ошибка AppNetworkError, но перенаправлена в errorHandler\nrunCode(failedAction, catcher1) // '\"Hello, Hexlet\" failed with error: \"Hexlet is unavailable!\"';\n\nconst catcher2 = appErrorCatcher(errorHandler, NetworkError)\n// Выброшена ошибка AppNetworkError, но она не соответствует NetworkError\nrunCode(failedAction, catcher2) // Error: 'Hexlet is unavailable!'\n```\n\nБолее подробные кейсы использований смотрите в тестах.\n\n### Подсказки\n\nВсе кейсы, кроме CustomError легко проверить через [оператор проверки типа](https://ru.hexlet.io/courses/js-classes/lessons/inheritance/theory_unit#operator-proverki-tipa) `instanceof`. Для этого импортируйте необходимые ошибки самостоятельно из каталога *errors*.\n","prepared_readme":"Исключения – один из немногих примеров удачного использования наследования. Мы познакомимся с ними в следующих уроках, а сейчас потренируемся проверять цепочку наследования.\n\nРеализация исключений через классы расширяет возможности обработки нестандартных ситуаций. Для каждого типа ошибки — свой класс. При этом каждый тип обладает общей логикой и интерфейсом. При создании исключения, в конструктор передается текст ошибки — это общая логика для всех типов наследуется от базового класса и работает благодаря позднему связыванию.\n\n## catchers.js\n\nРеализуйте логику функций, подготовленных в файле. Каждая из них принимает обработчик ошибки и класс ошибки. Каждая функция отлавливает особый тип ошибок:\n* Функция `anyErrorCatcher` проверяет, что текущая ошибка наследуется от `errorInstance`\n* Функция `appErrorCatcher` проверяет, что текущая ошибка наследуется от `errorInstance` **И** от одной из ошибок приложения\n* Функция `customErrorCatcher` проверяет, что ошибка содержит свойство `isCustomError` со значением `true` и `errorInstance` при этом отсутствует\n\nЕсли условие выполнено — ошибка передаётся в функцию `errorHandler` и возвращается результат этой функции. Если нет, то выбрасывается в исходном виде.\n\n## runCode.js\n\nРеализуйте и экспортируйте по умолчанию функцию, которая имеет следующие параметры:\n* `action` - функция, которую нужно выполнить. Обязательный\n* `catcher` - обработчик ошибки из `catcher.js`, в качестве параметра принимает ошибку. Необязательный\n\nОбщий принцип работы таков: функция принимает в себя экшен, пытается его выполнить и возвращает либо результат выполнения, либо передаёт ошибку в `catcher` и возвращает его результат (если `catcher` не задан, выбрасывает ошибку как есть).\n\n```javascript\nimport runCode from './runCode.js'\nimport { appErrorCatcher } from './catchers.js'\nimport AppNetworkError from './errors/AppNetworkError.js'\nimport NetworkError from './errors/NetworkError.js'\n\nconst successAction = () => 'Hello, Hexlet!'\nconst failedAction = () => {\n throw new AppNetworkError('Hexlet is unavailable!')\n}\nconst errorHandler = err => `\"Hello, Hexlet\" failed with error: \"${err.message}\"`\nconst catcher1 = appErrorCatcher(errorHandler, AppNetworkError)\n\nrunCode(successAction, catcher1) // 'Hello, Hexlet!';\n\n// Выброшена ошибка AppNetworkError, но перенаправлена в errorHandler\nrunCode(failedAction, catcher1) // '\"Hello, Hexlet\" failed with error: \"Hexlet is unavailable!\"';\n\nconst catcher2 = appErrorCatcher(errorHandler, NetworkError)\n// Выброшена ошибка AppNetworkError, но она не соответствует NetworkError\nrunCode(failedAction, catcher2) // Error: 'Hexlet is unavailable!'\n```\n\nБолее подробные кейсы использований смотрите в тестах.\n\n### Подсказки\n\nВсе кейсы, кроме CustomError легко проверить через [оператор проверки типа](https://ru.hexlet.io/courses/js-classes/lessons/inheritance/theory_unit#operator-proverki-tipa) `instanceof`. Для этого импортируйте необходимые ошибки самостоятельно из каталога *errors*.\n","has_solution":true,"entity_name":"Позднее связывание"},"units":[{"id":4135,"name":"theory","url":"/courses/js-classes/lessons/late-binding/theory_unit"},{"id":4136,"name":"quiz","url":"/courses/js-classes/lessons/late-binding/quiz_unit"},{"id":4190,"name":"exercise","url":"/courses/js-classes/lessons/late-binding/exercise_unit"}],"links":[{"id":423177,"name":"Позднее связывание (Wiki)","url":"https://en.wikipedia.org/wiki/Late_binding"}],"ordered_units":[{"id":4135,"name":"theory","url":"/courses/js-classes/lessons/late-binding/theory_unit"},{"id":4136,"name":"quiz","url":"/courses/js-classes/lessons/late-binding/quiz_unit"},{"id":4190,"name":"exercise","url":"/courses/js-classes/lessons/late-binding/exercise_unit"}],"id":1866,"slug":"late-binding","state":"approved","name":"Позднее связывание","course_order":300,"goal":"Разбираемся, как между собой связаны части разных классов внутри объекта","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"Для понимания того, как соотносятся друг с другом внутренности классов, которые связаны наследованием, нужно разобраться с таким понятием как позднее связывание (late binding).\n\nВспомним базовый класс _HTMLElement_ из прошлого урока. Внутри него активно используется `this` для обращения к свойствам:\n\n```javascript\n// Базовый класс для всех тегов. Умеет работать с атрибутами.\nclass HTMLElement {\n constructor(attributes = {}) {\n this.attributes = attributes\n }\n\n getAttribute(key) {\n return this.attributes[key]\n }\n}\n```\n\nПредположим, что мы создаем объект класса _HTMLAnchorElement_ (который наследует _HTMLElement_). Тогда объектом какого класса будет `this` внутри методов родительского класса? Правильный ответ: _HTMLAnchorElement_, то есть того класса, объект которого мы прямо сейчас создаем. Посмотрите на пример:\n\n```javascript\nclass A {\n constructor() {\n this.name = 'From A'\n }\n\n getName() {\n console.log(this.constructor)\n return this.name\n }\n}\n\nclass B extends A {}\n\nconst b = new B()\nconsole.log(b.getName())\n// [class B extends A]\n// => From A\n```\n\nЭта особенность `this` называется поздним связыванием. Оно означает, что на момент определения класса, тип `this` неизвестен. В качестве текущего объекта может выступать объект любого класса, наследуемого от текущего. Все выглядит так, как будто весь код внутри базового класса скопировали и перенесли в каждый класс-наследник. Для позднего связывания не важно, насколько глубокая иерархия наследования. `this` всегда будет объектом того класса, который конструируется в коде.\n\nПозднее связывание — важный элемент в работе наследования. Без него взаимодействие классов стало бы значительно сложнее и ограниченнее. Каждый объект должен был бы наверняка знать, к какому классу конкретно относятся свойства и методы в цепочке наследования. Понадобился бы специальный синтаксис для доступа к ним.\n"},"lessonMember":null,"courseMember":null,"course":{"start_lesson":{"exercise":null,"units":[{"id":4118,"name":"theory","url":"/courses/js-classes/lessons/about/theory_unit"}],"links":[{"id":423175,"name":"Джо Армстронг об Elixir, Erlang, ФП и ООП","url":"https://habr.com/ru/post/450508/"}],"ordered_units":[{"id":4118,"name":"theory","url":"/courses/js-classes/lessons/about/theory_unit"}],"id":1857,"slug":"about","state":"approved","name":"О курсе","course_order":10,"goal":"Знакомимся с целями и задачами курса","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"JavaScript, как и любой другой классовый язык, уделяет очень много внимания организации классов. Все это делается ради возможности лучше переиспользовать код (в рамках классового подхода, без классов эти ухищрения не нужны) и допускать меньше ошибок.\n\nС одной стороны, это хорошо. Но с другой — текущих возможностей настолько много, что одну и ту же задачу можно реализовать десятками способов. Количество комбинаций разных подходов порождает целые школы и направления по тому, как надо писать код. Как часто нужно использовать наследование? Когда нужен принцип Лисков?\n\nВ этом курсе мы глубоко окунемся в организацию классов, познакомимся с концепцией наследования. Научимся строить иерархии классов правильно, с учетом принципа подстановки Лисков. Затем узнаем о том, почему наследование почти всегда плохой способ организации кода и почему лучше предпочитать композицию.\n\nНаследование тянет за собой много нового. Возникают шаблоны проектирования, специфичные только для наследования. Наследование влияет на то, как работает полиморфный код, но не является необходимым для него. Все это требует отдельного рассмотрения.\n\nВ конце концов, мы познакомимся с действительно интересной концепцией — миксинами.\n"},"id":218,"slug":"js-classes","challenges_count":3,"name":"JS: Погружаясь в классы","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"paid","description":"На этом курсе вы более подробно изучите наследование. Вы узнаете о принципе подстановки Лисков и паттерне «шаблонный метод». В итоге вы научитесь правильно применять наследование и узнаете, какие есть ограничения.","kind":"advanced","updated_at":"2026-01-20T11:41:54.641Z","language":"javascript","duration_cache":33900,"skills":["Грамотно выбирать между наследованием и композицией","Следовать принципу подстановки Лисков при построении иерархий классов","Реализовывать паттерн «шаблонный метод»","Познакомиться с иерархиями исключений"],"keywords":["позднее связывание","трейты","абстрактные классы"],"lessons_count":8,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NjQ4OSwicHVyIjoiYmxvYl9pZCJ9fQ==--270847b85b7e42d76aa1434be4e4407ffb506a6e/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":29,"slug":"js-oop","title":"ООП на Javascript","audience":"for_programmers","start_type":"anytime","pricing_model":"subscription","priority":"medium","kind":"track","state":"published","stack_state":"finished","order":4250,"duration_in_months":2},"id":46,"slug":"js-oop","title":"ООП на Javascript","subtitle":"Навык глубокого понимания архитектуры и написания чистого кода, позволяющий решать сложные задачи","subtitle_for_lists":"Изучите архитектуру и принципы чистого кода на JS","locale":"ru","current":true,"duration_in_months_text":"2 месяца","stack_slug":"js-oop","price_text":"от 3 900 ₽","duration_text":"2 месяца","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NDAxOSwicHVyIjoiYmxvYl9pZCJ9fQ==--84efd2b6854b7000046e9ce06e6be85d38af5ab8/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/JavaScript%20frameworks-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"}],"lessonMemberUnit":null,"accessToLearnUnitExists":false,"accessToCourseExists":false},"url":"/courses/js-classes/lessons/late-binding/theory_unit","version":"8f286f6358a90a7bef2263b3a6edf5a90a94fa42","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>Для понимания того, как соотносятся друг с другом внутренности классов, которые связаны наследованием, нужно разобраться с таким понятием как позднее связывание (late binding).</p>
<p>Вспомним базовый класс <em>HTMLElement</em> из прошлого урока. Внутри него активно используется <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">this</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">// Базовый класс для всех тегов. Умеет работать с атрибутами.
class HTMLElement {
constructor(attributes = {}) {
this.attributes = attributes
}
getAttribute(key) {
return this.attributes[key]
}
}</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>Предположим, что мы создаем объект класса <em>HTMLAnchorElement</em> (который наследует <em>HTMLElement</em>). Тогда объектом какого класса будет <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">this</code> внутри методов родительского класса? Правильный ответ: <em>HTMLAnchorElement</em>, то есть того класса, объект которого мы прямо сейчас создаем. Посмотрите на пример:</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">class A {
constructor() {
this.name = 'From A'
}
getName() {
console.log(this.constructor)
return this.name
}
}
class B extends A {}
const b = new B()
console.log(b.getName())
// [class B extends A]
// => From A</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">this</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">this</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">this</code> всегда будет объектом того класса, который конструируется в коде.</p>
<p>Позднее связывание — важный элемент в работе наследования. Без него взаимодействие классов стало бы значительно сложнее и ограниченнее. Каждый объект должен был бы наверняка знать, к какому классу конкретно относятся свойства и методы в цепочке наследования. Понадобился бы специальный синтаксис для доступа к ним.</p></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/js-oop?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">2 месяца</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">Изучите архитектуру и принципы чистого кода на JS</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/eyJfcmFpbHMiOnsiZGF0YSI6NDAxOSwicHVyIjoiYmxvYl9pZCJ9fQ==--84efd2b6854b7000046e9ce06e6be85d38af5ab8/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/JavaScript%20frameworks-cuate.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">от 3 900 ₽</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="/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-classes/lessons/late-binding/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 / 8</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-classes/lessons/late-binding/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-Bukl1lYy.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-BrRXra1y.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>