<!DOCTYPE html>
<html class="h-100" data-bs-theme="light" data-mantine-color-scheme="light" lang="ru" prefix="og: https://ogp.me/ns#">
<head>
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<link crossorigin="true" href="https://cdn.hexlet.io" rel="preconnect">
<link href="https://mc.yandex.ru" rel="preconnect">
<meta content="aa2vrdtq64dub8knuf83lwywit311w" name="facebook-domain-verification">
<link href="/favicon.ico" rel="icon" sizes="any">
<link href="/favicon.svg" rel="icon" type="image/svg+xml">
<link href="/apple-touch-icon.png" rel="apple-touch-icon">
<link href="/manifest.webmanifest" rel="manifest">
<script>
//<![CDATA[
window.gon={};gon.ym_counter="25559621";gon.is_bot=true;gon.applications={};gon.current_user={"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26 17:13:50 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="R3BRHc4Q_s3QVjE3RxHHNDazr0wGutbaZYreMYbGTgSooZoqPG5TrWYVFa9LHjdD9rqC5g6NKHjYakRl1MGpag";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/ddp/lessons/objects/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/ddp/lessons/objects/theory_unit">
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="RKW_4idM9g5dDFg-gm9dOW1UD_f4TOM43sKKG0GqVu2rdHTV1TJbbutPfKaOYK1OrV0iXfB7HZpjIhBPE62xgw" />
<script src="/vite/assets/inertia-INZxX8jp.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/preload-helper-BJ4cLWpC.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-nkZBEvfU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ahoy-DrlRQ-1D.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/analytics-6pOtQ3OW.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Surface-DL2bpZA-.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/extends-C-EagtpE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/inheritsLoose-BBd-DCVI.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/objectWithoutPropertiesLoose-DRHXDhjp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/index.esm-DAqKOkZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Button-CGPUux8l.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/CloseButton-D1euiPao.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Group-BX48WcuU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Loader-BQEY8g6v.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Modal-Cy3HByv7.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/OptionalPortal-1Hza5P2w.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Stack-CtjJzfw4.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Textarea-Ck64llAy.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/DirectionProvider-Dc9zdUke.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/events-DJQOhap0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-reduced-motion-D2owz4wa.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-disclosure-zKtK5W1r.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-hotkeys-Cnc_Rwkb.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/random-id-DOQyszCZ.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/exports-C_MrNx_T.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<link rel="stylesheet" href="/vite/assets/application-BqhCP46M.js" />
<script src="/vite/assets/application-Df9RExpe.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/autocomplete-VMNbxKGl.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/createPopper-C3aM9r1M.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/js.cookie-D1-O8zkX.js" as="script" crossorigin="anonymous"><link rel="stylesheet" href="/vite/assets/application-C8HjmMaq.css" media="screen" />
<script>
window.ym = function(){(ym.a=ym.a||[]).push(arguments)};
window.addEventListener('load', function() {
setTimeout(function() {
ym.l = 1*new Date();
ym(window.gon.ym_counter, "init", {
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
webvisor: true
});
// Загружаем скрипт
var k = document.createElement('script');
k.async = 1;
k.src = 'https://mc.yandex.ru/metrika/tag.js';
document.head.appendChild(k);
ym(window.gon.ym_counter, 'getClientID', function(clientID) {
window.ymClientId = clientID;
});
}, 1500);
});
</script>
<!-- Google Tag Manager - deferred -->
<script>
// dataLayer stub сразу — пуши работают до загрузки скрипта
window.dataLayer = window.dataLayer || [];
// Сам скрипт — отложенно после load
window.addEventListener('load', function() {
setTimeout(function() {
dataLayer.push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
var j = document.createElement('script');
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-WK88TH';
document.head.appendChild(j);
}, 1500);
});
</script>
<!-- End Google Tag Manager -->
</head>
<body>
<noscript>
<div>
<img alt="" src="https://mc.yandex.ru/watch/25559621" style="position:absolute; left:-9999px;">
</div>
</noscript>
<header class="sticky-top bg-body">
<nav class="navbar navbar-expand-lg">
<div class="container-xxl">
<a class="navbar-brand" href="/"><img alt="Логотип Хекслета" height="24" src="https://ru.hexlet.io/vite/assets/logo_ru_light-BpiEA1LT.svg" width="96">
</a><button aria-controls="collapsable" aria-expanded="false" aria-label="Меню" class="navbar-toggler border-0 mb-0 mt-1" data-bs-target="#collapsable" data-bs-toggle="collapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsable">
<ul class="navbar-nav mb-lg-0 mt-lg-1">
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
Все курсы
<span class="bi bi-chevron-down align-middle ms-1"></span>
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item d-flex py-2" href="/courses"><div class="fw-bold me-auto">Все что есть</div>
<div class="text-muted">117</div>
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные категории</b>
</li>
<li>
<a class="dropdown-item py-2" href="/courses_devops">Курсы по DevOps
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_data_analytics">Курсы по аналитике данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_programming">Курсы по программированию
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_testing">Курсы по тестированию
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные курсы</b>
</li>
<li>
<a class="dropdown-item py-2" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/go">Go-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/java">Java-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/python">Python-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/qa-auto-engineer-java">Автоматизатор тестирования на Java
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/data-analytics">Аналитик данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/frontend">Фронтенд-разработчик
</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
О Хекслете
<span class="bi bi-chevron-down align-middle"></span>
</button>
<ul class="dropdown-menu bg-body">
<li>
<a class="dropdown-item py-2" href="/pages/about">О нас
</a></li>
<li>
<a class="dropdown-item py-2" href="/blog">Блог
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/hse-research" role="button">Результаты (Исследование)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://career.hexlet.io" role="button">Хекслет Карьера
</span></li>
<li>
<a class="dropdown-item py-2" href="/testimonials">Отзывы студентов
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://t.me/hexlet_help_bot" role="button">Поддержка (В ТГ)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/referal-program/?promo_creative=priglasite-druzei&promo_name=referal-program&promo_position=promo_position&promo_start=010724&promo_type=link" role="button">Реферальная программа
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/certificate" role="button">Подарочные сертификаты
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://hh.ru/employer/4307094" role="button">Вакансии
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://b2b.hexlet.io" data-target="_blank" role="button">Компаниям
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexly.ru/" data-target="_blank" role="button">Колледж
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexlyschool.ru/" data-target="_blank" role="button">Частная школа
</span></li>
</ul>
</li>
<li><a class="nav-link" href="/subscription/new">Подписка</a></li>
</ul>
<ul class="navbar-nav flex-lg-row align-items-lg-center gap-2 ms-auto">
<li>
<a class="nav-link" aria-label="Переключить тему" href="/theme/switch?new_theme=dark"><span aria-hidden="true" class="bi bi-moon"></span>
</a></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="/u/new" role="button"><span>Регистрация</span>
</span></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="https://ru.hexlet.io/session/new" role="button"><span>Вход</span>
</span></li>
</ul>
</div>
</div>
</nav>
</header>
<div class="x-container-xxxl">
</div>
<main class="mb-6 min-vh-100 h-100">
<link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc2MCwicHVyIjoiYmxvYl9pZCJ9fQ==--9348098e4053d798b6f34bee4ef66947540261e4/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Low%20code%20development-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-26T17:13:50.393Z","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":"8f575iu1HDfvSP8pd1boJcbkXS1MrHkKgD9znsea-Y0eL7DR2cuxV1kL27F7WRhSBu1wh0Sbh6g93-nKlZ0e4w","topics":[{"id":6019,"title":"застрял с пониманием алгоритма. \n1. Надо реализовать интерфейс типа `simpleCard`. Тут делаем по аналогии с `persent`, только `damage` считаем проще.\n2. Далее мы получаем два конструктора объекта `make` для двух типов карт и в `\nSolution.js`должны получить через методы этих объектов значение `cardName`. Как мне вызвать `make`, который соответствует типу текущей карты? К тому же у нас нет как в прошлом задании подгрузки методов `typeTag` для определения типа карты. Значит тут другая логика решения, которая не завязана на выбор нужного конструктора `make`?","plain_title":"застрял с пониманием алгоритма. 1. Надо реализовать интерфейс типа simpleCard. Тут делаем по аналогии с persent, только damage считаем проще. 2. Далее мы получаем два конструктора объекта make для двух типов карт и в Solution.jsдолжны получить через методы этих объектов значение cardName. Как мне вызвать make, который соответствует типу текущей карты? К тому же у нас нет как в прошлом задании подгрузки методов typeTag для определения типа карты. Значит тут другая логика решения, которая не завязана на выбор нужного конструктора make? ","creator":{"public_name":"Alexandr S","id":93661,"is_tutor":false},"comments":[{"creator":{"public_name":"Alexandr S","id":93661,"is_tutor":false},"id":10909,"body":"решил-таки после того как осознал что из себя представляет объект `card`.","topic_id":6019}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты","entity_url":null,"active":true}},{"id":17660,"title":"Что такое позднее / раннее связывание применительно к языкам программирования (статья к видео)?","plain_title":"Что такое позднее / раннее связывание применительно к языкам программирования (статья к видео)? ","creator":{"public_name":"Andrey Karamnoff","id":76205,"is_tutor":false},"comments":[{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":37298,"body":"Этот вопрос разбиратеся здесь https://ru.hexlet.io/courses/js_prototypes","topic_id":17660}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты","entity_url":null,"active":true}},{"id":7938,"title":"Удивлен, что абстракция данных не относится к концепции ООП","plain_title":"Удивлен, что абстракция данных не относится к концепции ООП ","creator":{"public_name":"Anton Platonov","id":120492,"is_tutor":false},"comments":[{"creator":{"public_name":"Aleksandr Zhuravlev","id":340,"is_tutor":false},"id":22082,"body":"Соглашусь с Антоном. На всякий случай продублирую вопрос: «Какие из концепций принято относить к теме объектно-ориентированного программирования?»\n\nАбстракция однозначно к нему относится. Но в тесте, почему-то, от нас ожидают другое. Вот цитата из вики: «Абстракция является основой объектно-ориентированного программирования и позволяет работать с объектами, не вдаваясь в особенности их реализации» [1].\n\nПонятно, что абстракция относится не только к ООП, но тогда к вопросу следует добавить слово «только к теме», хотя и это было бы не совсем точно.\n\nПоэтому, предлагаю абстракцию всё же считать за правильный ответ.\n\n[1]: https://ru.wikipedia.org/wiki/Абстракция_данных","topic_id":7938},{"creator":{"public_name":"Aleksandr Zhuravlev","id":340,"is_tutor":false},"id":22098,"body":"Спасибо.","topic_id":7938},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":15202,"body":"При этом вы буквально с первых курсов пользуетесь этой концепцией во все поля). Пары, точки, фигуры вот это все.","topic_id":7938},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":22085,"body":"Удалил пока вопросы, смысла от них мало. Позже поменяю на более интересные.","topic_id":7938},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":22084,"body":"Да точно, надо переформулировать в стиле \"встречается только в ооп\".","topic_id":7938}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты","entity_url":null,"active":true}},{"id":8647,"title":"Похоже, что не правильно возвращает damage от simplecard. Но не понимаю, что здесь может быть не так, если первый flow прошел.\n> FAIL __tests__/test.js\n> ● CardGame › #flow 2\n>\n> expect(received).toBe(expected)\n> \n> Expected value to be (using ===):\n> \"(5, 6)\"\n> Received:\n> \"(NaN, 6)\"\n> \n> at Object.it (__tests__/test.js:54:70)\n> at Promise.resolve.then.el (../../local/share/.config/yarn/global/node_modules/p->map/index.js:42:16)\n\nкод simplecard\n```\n// removed\n```\n","plain_title":"Похоже, что не правильно возвращает damage от simplecard. Но не понимаю, что здесь может быть не так, если первый flow прошел. FAIL tests/test.js ● CardGame › #flow 2 expect(received).toBe(expected) Expected value to be (using ===): \"(5, 6)\" Received: \"(NaN, 6)\" at Object.it (__tests__/test.js:54:70) at Promise.resolve.then.el (../../local/share/.config/yarn/global/node_modules/p->map/index.js:42:16) код simplecard // removed ","creator":{"public_name":"Андрей Стрельник","id":90847,"is_tutor":false},"comments":[{"creator":{"public_name":"","id":299,"is_tutor":false},"id":17098,"body":"> Похоже, что не правильно возвращает damage от simplecard. Но не понимаю, что здесь может быть не так, если первый flow прошел.\n\nНу так если в первом флоу проверялся бой на simplecard, то может быть дело в percentCard, а точнее в том как вы их используете?","topic_id":8647}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты","entity_url":null,"active":true}},{"id":20165,"title":"Маленькая придирочка) Задания ведь сохраняют приемственность от прошлых? На мой взгляд да, поэтому логичнее будет использовать в solution.js константу damage, а не points.","plain_title":"Маленькая придирочка) Задания ведь сохраняют приемственность от прошлых? На мой взгляд да, поэтому логичнее будет использовать в solution.js константу damage, а не points. ","creator":{"public_name":"Сергей Грабак","id":157986,"is_tutor":false},"comments":[{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":42731,"body":"В этом и следующих задания дополнительно вводятся сущности с таким же именем. Это задание я поправил (здесь используем одноимённое строковое сообщение `damage`), а в следующем уроке уже есть функция `damage`, поэтому приходится другое имя давать константе.","topic_id":20165}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты","entity_url":null,"active":true}},{"id":4526,"title":"> одна программа может использовать только одну парадигму программирования\n\nДа, может. А почему неверно?\nСкорее всего имелось в виду: \n\"одна программа должна использовать только одну парадигму программирования\"\nТогда согласен, неверно.","plain_title":"одна программа может использовать только одну парадигму программирования Да, может. А почему неверно? Скорее всего имелось в виду: \"одна программа должна использовать только одну парадигму программирования\" Тогда согласен, неверно. ","creator":{"public_name":"Anatoliy Ryabov","id":67988,"is_tutor":false},"comments":[{"creator":{"public_name":"Rakhim D.","id":42197,"is_tutor":false},"id":7799,"body":"Вы правы, ваша формулировка лучше. Исправил, спасибо.","topic_id":4526}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты","entity_url":null,"active":true}},{"id":12725,"title":"Я немного не понял это:\n```\n// removed\n```\nа точнее вот это\n```\n (message, health) => {\n switch (message) {\n\n```\nкак туда попадоют сообщение и хп? откуда они берутся? Да и вообще про весь этот код расскажите поалуйста, ну я вроде примерно догадываюсь как оно вроде работает, но расскажите пожалуйста. И еще вопрос, что именно нужно в ран дописать, то что имя и урон это понятно, в каком виде оно должно быть и какая логика?\n","plain_title":"Я немного не понял это: // removed а точнее вот это ``` (message, health) => { switch (message) { как туда попадоют сообщение и хп? откуда они берутся? Да и вообще про весь этот код расскажите поалуйста, ну я вроде примерно догадываюсь как оно вроде работает, но расскажите пожалуйста. И еще вопрос, что именно нужно в ран дописать, то что имя и урон это понятно, в каком виде оно должно быть и какая логика? ","creator":{"public_name":"Анатолий Р.","id":152675,"is_tutor":false},"comments":[{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":26511,"body":"Здесь используется обычный возврат функции из функции. Подробно эта тема разбиралась здесь https://ru.hexlet.io/courses/js-functions/lessons/return-function/theory_unit Вы ее не поняли?","topic_id":12725}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты","entity_url":null,"active":true}},{"id":19400,"title":"¯\\_(ツ)_/¯\n\nВозвращает (NaN, 6) — тут много таких вопросов ниже, но ответа я не нашёл.\n\nЕсли делать вот так:\n\n¯\\_(ツ)_/¯\n\nТо получаю (7, 6) — т.е у меня неправильно высчитывает урон карты, потому что я передаю не то значение хп, очевидно.\nА при таком коде:\n\n¯\\_(ツ)_/¯\n\nвывод тестов выглядит вот так:\n\n¯\\_(ツ)_/¯\n\nЯ не понимаю, почему я могу использовать _health1_ и не могу _health2_","plain_title":"¯_(ツ)_/¯ Возвращает (NaN, 6) — тут много таких вопросов ниже, но ответа я не нашёл. Если делать вот так: ¯_(ツ)_/¯ То получаю (7, 6) — т.е у меня неправильно высчитывает урон карты, потому что я передаю не то значение хп, очевидно. А при таком коде: ¯_(ツ)_/¯ вывод тестов выглядит вот так: ¯_(ツ)_/¯ Я не понимаю, почему я могу использовать health1 и не могу health2 ","creator":{"public_name":"Руслан Командышко","id":158574,"is_tutor":false},"comments":[{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":41001,"body":"Добрый день!\n\nВ константу `cardName` вы зачем-то создаёте и записываете новую функцию, вместо того, чтобы сделать простой, но правильный вызов `card`.","topic_id":19400},{"creator":{"public_name":"Руслан Командышко","id":158574,"is_tutor":false},"id":41023,"body":"Спасибо, так сначала и делал, но выдавало ошибку в simpleCard.js, проверил снова и нашел там ошибочку с именами.","topic_id":19400}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты","entity_url":null,"active":true}},{"id":21630,"title":"Было бы неплохо наверно как то обобщить данный курс. \nЧто я имею ввиду - чем дальше мы заходим, тем сложнее становится видеть общую картину создания карт, вызова функций, что, зачем, куда, и от этого теряется какая то доля понимания зачем всё это, и как в целом работает.\nБудет круто, если в какой нибудь теме курса появится, допустим, картинка с чисто схематическим представлением всех вызовов и т.д., можно даже без аргументов, ну или в какой нибудь другой форме представить это свё.","plain_title":"Было бы неплохо наверно как то обобщить данный курс. Что я имею ввиду - чем дальше мы заходим, тем сложнее становится видеть общую картину создания карт, вызова функций, что, зачем, куда, и от этого теряется какая то доля понимания зачем всё это, и как в целом работает. Будет круто, если в какой нибудь теме курса появится, допустим, картинка с чисто схематическим представлением всех вызовов и т.д., можно даже без аргументов, ну или в какой нибудь другой форме представить это свё. ","creator":{"public_name":"Александр Елахов","id":180236,"is_tutor":false},"comments":[{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":45951,"body":"Ага, спасибо за идею!","topic_id":21630},{"creator":{"public_name":"Dmitry Rakov","id":181256,"is_tutor":false},"id":47543,"body":"Согласен, весь курс думал об схематичном представении, дабы уложить все это в голове и структурировать. ","topic_id":21630}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты","entity_url":null,"active":true}},{"id":22248,"title":"Добрый вечер! Линтер не дремлет.\n\n>/usr/src/app/solution.js\n 4:8 error Unexpected line break after this opening brace object-curly-newline\n 6:1 error Unexpected line break before this closing brace object-curly-newline","plain_title":"Добрый вечер! Линтер не дремлет. /usr/src/app/solution.js 4:8 error Unexpected line break after this opening brace object-curly-newline 6:1 error Unexpected line break before this closing brace object-curly-newline ","creator":{"public_name":"Сергей Синицын","id":105179,"is_tutor":false},"comments":[{"creator":{"public_name":"Юрий Чернышев","id":182794,"is_tutor":false},"id":47409,"body":"Спасибо за наводку!","topic_id":22248}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты","entity_url":null,"active":true}}],"lesson":{"exercise":{"id":470,"slug":"js_ddp_objects_exercise","name":null,"state":"active","kind":"exercise","language":"javascript","locale":"ru","has_web_view":false,"has_test_view":false,"reviewable":true,"readme":"## simpleCard.js\n\nРеализуйте интерфейс типа `simpleCard` по аналогии с типом `percentCard`.\n\n## solution.js\n\nДопишите недостающую логику работы с картами в функции игрового движка `run()`.\n\n### Подсказки\n\n* При необходимости вы можете самостоятельно импортировать функцию `toString()` из библиотеки `@hexlet/pairs` и использовать её для отладки решений. Эта функция возвращает строковое представление пары.\n* При необходимости вы можете самостоятельно импортировать функцию `toString()` из библиотеки `@hexlet/pairs-data` и использовать её для отладки решений. Эта функция возвращает строковое представление списка.\n* Для разрешения противоречий в случае импорта нескольких функций с одинаковыми именами используйте псевдонимы (aliases).\n","prepared_readme":"## simpleCard.js\n\nРеализуйте интерфейс типа `simpleCard` по аналогии с типом `percentCard`.\n\n## solution.js\n\nДопишите недостающую логику работы с картами в функции игрового движка `run()`.\n\n### Подсказки\n\n* При необходимости вы можете самостоятельно импортировать функцию `toString()` из библиотеки `@hexlet/pairs` и использовать её для отладки решений. Эта функция возвращает строковое представление пары.\n* При необходимости вы можете самостоятельно импортировать функцию `toString()` из библиотеки `@hexlet/pairs-data` и использовать её для отладки решений. Эта функция возвращает строковое представление списка.\n* Для разрешения противоречий в случае импорта нескольких функций с одинаковыми именами используйте псевдонимы (aliases).\n","has_solution":true,"entity_name":"Объекты"},"units":[{"id":1390,"name":"theory","url":"/courses/ddp/lessons/objects/theory_unit"},{"id":13353,"name":"quiz","url":"/courses/ddp/lessons/objects/quiz_unit"},{"id":1391,"name":"exercise","url":"/courses/ddp/lessons/objects/exercise_unit"}],"links":[],"ordered_units":[{"id":1390,"name":"theory","url":"/courses/ddp/lessons/objects/theory_unit"},{"id":13353,"name":"quiz","url":"/courses/ddp/lessons/objects/quiz_unit"},{"id":1391,"name":"exercise","url":"/courses/ddp/lessons/objects/exercise_unit"}],"id":703,"slug":"objects","state":"approved","name":"Объекты","course_order":600,"goal":"Познакомиться с объектами в контексте современного, общепринятого понятия объектно-ориентированного программирования. Понять, как динамическая диспетчеризация дала возможность работать с объектами в ООП.","self_study":null,"theory_video_provider":"vimeo","theory_video_uid":"172395951","theory":"Динамическая диспетчеризация – очень мощный механизм, который лёг в основу подхода называемым **объектно-ориентированное программирование**.\nИзначально само понятие ООП имело совершенно другой смысл и идеи человека, который придумал ООП, совершенно не похожи на то, что под этим подразумевают сегодня. Его зовут Алан Кэй, обязательно [прочитайте](https://habr.com/ru/company/hexlet/blog/303754/) о нём. Поэтому когда мы говорим про ООП, мы в первую очередь будем подразумевать современное представление и понимание, и в голове мы у себя будем держать и вспоминать о том, что на самом деле существует несколько пониманий этого слова и они зависят от того, в каком контексте мы об этом говорим.\n\n## Объект\n\nВ объектном программировании мы оперируем не структурами данных, которые спрятаны за какие-то абстракции, а объектами.\nОбъект – это такая умная структура данных, которая помимо того, что работает просто как некое состояние, с которым можно что-то делать и как-то манипулировать, но он еще определяет то, какие операции над ним применяются.\n\nРассмотрим этот код:\n\n```javascript\nconst card = percentCard.make('percent card', 60)\ncard('getName') // percent card\ncard('damage', 10) // 6\n```\n\nСпособ работы с сущностью `card` называется **передача сообщений**. Мы это делали когда работали с парами. Наши пары, а также `card` – это самый настоящий объект, который внутри себя содержит какое-то состояние.\n> Кстати, объект изолирует к нему доступ, но не всегда и не везде языки предлагают такой вариант работы, в которых объекты встроены в сам язык. Иногда вы можете получить все внутренности, как в JS, но вот здесь более защищённый способ работы.\n\nФункция, которая будет работать, выбирается в зависимости от переданного сообщения и диспетчеризация внутри идёт по имени. То есть объект сам отвечает за то, какой код будет выполняться в случае вызова того или иного метода (в данном случае в зависимости от переданного сообщения).\n\n## Реализация\n\nРеализация простая и повторяет полностью то, что было с парами. Если хотите узнать больше про пары, то попробуйте наш курс [JS: Составные данные](https://ru.hexlet.io/courses/compound_data)\n\n```javascript\nexport const make = (name, percent) =>\n (message, health) => {\n switch (message) {\n case 'getName':\n return name\n case 'damage':\n return Math.round(health * (percent / 100))\n default:\n return 'undefined method'\n }\n }\n```\n\nВнутри определяется новая функция, которая возвращается наружу. Она принимает на вход `message`, по которому делается свич и в зависимости от того, что происходит делает ту или иную задачу. Функция содержит какое-то состояние, но в данном случае оно неизменяемо (хотя это может быть не так).\n\nЯ надеюсь, что к текущем моменту вы уже поняли, что ООП и функциональное программирование – это вещи разных порядков. Их нельзя сравнивать, потому что функциональное программирование противопоставляется императивному программированию, то есть изменяемое состояние или неизменяемое состояние. В свою очередь ООП про диспетчеризацию, про возможность выбирать реализацию и это прекрасно существует в функциональных языках при функциональном подходе, поэтому эти концепции целиком и полностью дополняют друг друга.\nТак уж сложилось, что чаще всего объектно-ориентированные языки сами по себе являются императивными. Но при этом, как видите, на JS мы спокойно пишем функциональный код и в будущем мы будем писать его еще больше.\n\n## Характеристика ООП\n\n[Бенджамин Пирс](https://en.wikipedia.org/wiki/Benjamin_C._Pierce) – известный учёный, который занимается теорией типов написал следующую вещь в своей книге, которая называется Types and Programming Languages, знаменитая книга о типах в языках программирования:\n> Вероятно самая фундаментальная характеристика объектно-ориентированного стиля – это то, что когда по отношению к объекту применяется некоторая операция, объект сам определяет, какой код её осуществляет.\n\nНебольшое замечание. То что объект сам определяет, какой код её осуществляет – это то, как оно выглядит снаружи, как мы видим это и какая семантика у этой всей истории, но в реальности с точки зрения имплементации это определяет не объект и это может быть сделано гораздо хитрее, как мы себе не можем это представить. Это очень сильно зависит от конкретной имплементации конкретного языка и его особенностей.\n\n## Передача сообщений\n\nС точки зрения Алана Кэя, который придумал ООП, передача сообщений является ключевым фактором и вообще ключевой идеей в ООП. При этом некоторые современные объектно-ориентированные языки взяли всё таки эту идею немножко в себя и используют. В JS, кстати, передача сообщений не используется, но мы её самостоятельно реализовали и теперь, как минимум вы знаете про это. Например, у таких языков как Ruby или PHP есть такая возможность, но она немножко ограничена. С одной стороны там передача сообщений, с другой стороны есть методы и получился такой микс между двумя способами работы.\n\nВ нашем случае объект, который мы создали и с которым до сих пор работали, действительно работает с помощью передачи сообщений.\n\n```javascript\nconst card = percentCard.make('percent card', 60)\ncard('getName')\ncard('damage', 10) // 6\n```\n\nВ чём отличие от вызова функции?\n\nВо-первых гораздо более **гибкая обработка**. Если не существует какой-то функции, то ваш код однозначно будет падать с ошибкой и вы ничего не сможете с этим сделать, только если вы снаружи не обработаете ошибку. Но когда идёт передача сообщений, обработка может идти внутри и сам объект может достаточно хитро реагировать на различные сообщения.\nБолее того, могут интересно использоваться техники когда имя сообщения внутри себя содержит определённые параметры, то есть строится определённым способом. Это позволяет нам распарсив его, то есть извлекая из него определённые куски, понять, что нам нужно.\n\nКлассный пример – `getName`.\n\n```javascript\ncard('getName')\n```\n\nПредположим, что у нашего объекта был бы не только `getName`, но и `getSurname`, `getLastname` и много других параметров. Так вот вместо того, чтобы определять множество различных сообщений, которые делают одно и тоже – просто извлекают разные куски нашего внутреннего состояния, мы могли бы внутри определить такой обработчик, который проверял бы, что переданное сообщение начинается с `get` и после этого идёт какое-то название. Затем он бы его разбирал и использовал это название для того, чтобы определить, а что собственно вернуть и тогда мы бы очень сильно сократили код. Это очень крутая возможность. Например, она активно используется в Ruby и в частности в Ruby On Rails.\n\nНу и второе – это **адаптация в работающем коде**. Это означает, что объект со временем может менять своё поведение: как он отвечает на сообщение, на какие сообщения он отвечает. Использование сообщений открывает достаточно широкие возможности. В JavaScript, существуют *прокси объекты*, которые позволяют имитировать передачу сообщений, что открывает путь к большому количеству возможностей. С помощью такого подхода можно строить гораздо более гибкие приложения и делать фишки, которые без этого недоступны.\n"},"lessonMember":null,"courseMember":null,"course":{"start_lesson":{"exercise":null,"units":[{"id":1378,"name":"theory","url":"/courses/ddp/lessons/intro/theory_unit"}],"links":[],"ordered_units":[{"id":1378,"name":"theory","url":"/courses/ddp/lessons/intro/theory_unit"}],"id":698,"slug":"intro","state":"approved","name":"Введение","course_order":100,"goal":"Познакомиться с курсом и с проектом карточной игры, над которым мы будем работать в течение всего курса, по ходу знакомясь с важными концепциями программирования.","self_study":null,"theory_video_provider":"vimeo","theory_video_uid":"172391980","theory":"<figure>\n <blockquote class=\"blockquote\">\n <p>Я изобрел понятие «объектно-ориентированный», но могу заявить, что не имел в виду C++ при этом.</p>\n </blockquote>\n <figcaption class=\"blockquote-footer\">\n Alan Kay\n </figcaption>\n</figure>\n\nНа текущий момент мы уже достаточно много знаем, как строить модульные программы и теперь пришло время поговорить о том, как строить расширяемые программы. В программировании существует понятие аддитивность, и эта тема будет центральной в нашем курсе.\n**Аддитивность** – это расширение возможности вашей программы без переписывания исходного кода.\n\n## Какие темы будут разобраны?\n\n- Пользовательские типы\n- Динамическая диспетчеризация (по типу)\n- Полиморфизм\n- Передача сообщений\n- Объектно-ориентированное программирование\n\nВо-первых, это пользовательские типы (типы данных, которые мы можем создавать самостоятельно).\nМы поговорим про такое важное понятие, как диспетчеризация и конкретно о динамической диспетчеризации (по типу). Разберём понятие полиморфизма. О нём многие слышали, но очень не многие понимают, что оно по-настоящему обозначает. Эту интересную тему мы разберём в одном из последних уроков. Также мы поговорим про передачу сообщений. И, наконец, придём к пониманию объектно-ориентированного программирования: что это такое, как с ним работать и почему, например, JavaScript считается объектно-ориентированным языком.\n\n## Новый синтаксис\n\n- Свойства\n- Тип Данных: Объект\n- Классы\n\nВ этом курсе появится новый синтаксис, который включает в себя несколько понятий.\nПервое – это **свойства**, которые используются в JavaScript даже для самых базовых вещей. Мы избегали этой темы, чтобы не отвлекаться от модульности. Теперь пришло время начать с ними работать.\n\nВо-вторых, мы разберём тип данных, который называется **объект**. Это не то же самое, что объект в объектно-ориентированном программировании, но иногда названия, которые используются в языках программирования несут свой смысл, и к этому нужно будет просто привыкнуть.\n\nИ последнее, с чем мы познакомимся – это **классы**. Ниже приведён небольшой пример класса, который будет использоваться в нашей программе. Мы подробно разберем его в нашем курсе.\n\n```javascript\nexport default class PercentCard {\n constructor(name, percent) {\n this.name = name\n this.percent = percent\n }\n\n damage(health) {\n return Math.round(health * (this.percent / 100))\n }\n}\n```\n\n## Проект: Карточная игра\n\n\n\nВ этом курсе мы будем работать над своей **карточной игрой**. Она будет без графического интерфейса. Мы будем выводит процесс игры в виде текста.\n\nЭта карточная игра необычная и не такая, как все привыкли видеть, играя в обычные карты. Игра будет про волшебников, в процессе которой происходит нападение друг на друга. Каждая карта описывает атаку, урон юнита и так далее. В нашем случае она будет простая, но на ней будет хорошо видна проблематика, которую мы собираемся отрабатывать.\n\n## Процесс игры\n\nДавайте посмотрим на процесс без кода. Как будет происходить вывод нашей игры:\n\n```\nНачинаем бой!\n\nИгрок 'John' применил 'Прохладный чыонг-бонг рыка'\nпротив 'Ada' и нанес урон '3'\n\nИгрок 'Ada' применил 'Воздушный змей клеветы'\nпротив 'John' и нанес урон '1'\n\nИгрок 'John' применил 'Проказливый рубитель крови'\nпротив 'Ada' и нанес урон '2'\n\nAda был убит\n```\n\nДля карт, которые представляют собой оружие, используются названия позаимствованные из Diablo. В сети существует множество генераторов названий предметов из этой игры. Они довольно прикольные, поэтому будет здорово здесь ими воспользоваться.\n\nГлядя на процесс, очевидно, что игра рассчитана на двух игроков, которые по очереди делают ходы. Сначала один игрок наносит урон, потом второй, затем снова первый и так по кругу. Урон зависит от текущей карты. И она не всегда наносит конкретный урон. Он может зависеть от текущего здоровья (например, снимать 50% здоровья) и других характеристик.\n\nПредположим, что стартовый уровень жизни у каждого игрока 10. А тот, у кого уровень жизни дойдёт до нуля или станет отрицательным, считается убитым. В примере видно, что игрок с именем Ada был убит первым.\n\n## Разработка через тесты\n\nНаш курс будет примером разработки через так называемый Test Driven Development. Это означает, что тесты пишутся до кода.\n\n```\nДизайн кода определяется тестами.\n\nВместо того, чтобы сосредотачиваться на\nвнутреннем представлении, сначала прорабатываются\nварианты использования этого кода.\n```\n\nЗачем это нужно?\n\n **Test Driven Development** – это такая методология, которая существует уже достаточно много лет. Она входит в концепцию экстремального программирования. Её главная фишка, что мы не фокусируемся на том, как будет устроен код внутри. Гораздо важнее, как им пользоваться. Именно дизайн кода (так называемый API), интерфейс, который вы отдаёте другим для использования и является определяющим. Если вы делаете хорошую абстракцию, то внутреннее содержимое не так важно. Вы всегда можете его переписать.\n\nОчень часто бывает так (это касается не только программирования), что люди делают что-то, но пользоваться этим невозможно. Это касается всего в нашей жизни: любого производства, продукта, процесса и так далее. Test Driven Development в первую очередь, заставляет нас думать о дизайне кода, о том, как его использовать, а затем строить внутреннюю структуру.\n\n## Обучение на Хекслете\n\nПовторим аспекты, которые мы используем для того, чтобы обучение было лучше и была проработка правильных вещей.\n\n- Неизменяемость (функциональный стиль)\n- СИКП\n- Обучение через рефакторинг\n- Разработка через тесты\n- Знания, которые не устаревают\n\nМы продолжаем использовать функциональный стиль. При этом постепенно начинаем вводить изменяемость.\n\nКурс также продолжает традицию основ на СИКП.\n\nМы делаем обучение через рефакторинг, то есть мы не рассказываем сразу, как правильно что-то сделать. Чтобы понять достаточно сложные темы по-настоящему, нужно пережить опыт и самостоятельно упереться в сложности. Поэтому уроки будут построены следующим образом: мы делаем какое-то решение, которое у вас (по нашей задумке) будет вызывать вопросы «А почему так?» и будете видеть, что здесь есть какие-то недоработки. В свою очередь следующий урок будет говорить об этом подробно и уже показывать следующий шаг для решения возникших проблем, и так далее. Постепенно мы будем приходить к общему решению, которое исправляет все недостатки предыдущих. Это так называемое обучение через рефакторинг.\n\nТакже напоминаю, что в этом курсе разработка будет происходить через тесты (о чём мы уже с вами говорили).\n\nЗнания текущего курса являются универсальными. Будет совсем чуть-чуть JavaScript специфики, но в основном всё, что здесь рассказывается — это ключ к пониманию, как устроены все современные языки, и какие проблемы они решают.\n"},"id":121,"slug":"ddp","challenges_count":3,"name":"JS: Программирование, управляемое данными","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"paid","description":"На этом курсе вы познакомитесь с программированием, управляемым данными. Вы узнаете, как использовать данные для управления логикой программы. Вы научитесь создавать динамические приложения и работать с классами, узнаете о полиморфизме и его типах, познакомитесь с диспетчеризацией по типу и аддитивностью. Знания из этого курса помогут создавать мощные и гибкие приложения, которые легко адаптируются к изменениям данных.","kind":"additional","updated_at":"2026-01-20T11:53:13.077Z","language":"javascript","duration_cache":39000,"skills":["Делать свое ООП с типами и диспетчеризацией","Использовать инверсию зависимостей для изменения поведения кода без его переписывания","Создавать классы и использовать их в JavaScript","Применять полиморфизм для уменьшения количества условных конструкций и дублирования"],"keywords":["ООП","Динамическая диспетчеризация","Типы данных","Объекты"],"lessons_count":9,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6ODkwOSwicHVyIjoiYmxvYl9pZCJ9fQ==--8d6ae873c203221995a5f2afe08cdb3b594e095f/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJqcGciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--39ba06fa99226096df9fc6bb31f84e1d29ea98e9/image.png"},"recommendedLandings":[{"stack":{"id":20,"slug":"js-sicp","title":"СИКП на JS","audience":"for_programmers","start_type":"anytime","pricing_model":"subscription","priority":"medium","kind":"track","state":"published","stack_state":"finished","order":4050,"duration_in_months":1},"id":28,"slug":"js-sicp","title":"СИКП на JS","subtitle":"Навык понимать программы на фундаментальном уровне, уверенно проходить собеседования и решать сложные задачи","subtitle_for_lists":"Навык фундаментального программирования","locale":"ru","current":true,"duration_in_months_text":"1 месяц","stack_slug":"js-sicp","price_text":"от 3 900 ₽","duration_text":"1 месяц","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc2MCwicHVyIjoiYmxvYl9pZCJ9fQ==--9348098e4053d798b6f34bee4ef66947540261e4/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Low%20code%20development-rafiki.png"}],"lessonMemberUnit":null,"accessToLearnUnitExists":false,"accessToCourseExists":false},"url":"/courses/ddp/lessons/objects/theory_unit","version":"0b0c6d4ebbd40fd58630a0dd89cc25544ccdf24e","encryptHistory":false,"clearHistory":false}"><style data-mantine-styles="true">:root, :host{--mantine-font-family: Arial, sans-serif;--mantine-font-family-headings: Arial, sans-serif;--mantine-heading-font-weight: normal;--mantine-radius-default: 0rem;--mantine-primary-color-filled: var(--mantine-color-indigo-filled);--mantine-primary-color-filled-hover: var(--mantine-color-indigo-filled-hover);--mantine-primary-color-light: var(--mantine-color-indigo-light);--mantine-primary-color-light-hover: var(--mantine-color-indigo-light-hover);--mantine-primary-color-light-color: var(--mantine-color-indigo-light-color);--mantine-spacing-xxl: calc(4rem * var(--mantine-scale));--mantine-font-size-xs: 12px;--mantine-font-size-sm: 14px;--mantine-font-size-md: 16px;--mantine-font-size-lg: clamp(16.0000px, calc(15.2727px + 0.2273vw), 18.0000px);--mantine-font-size-xl: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-display-3: clamp(32.0000px, calc(26.1818px + 1.8182vw), 48.0000px);--mantine-font-size-display-2: clamp(36.0000px, calc(25.8182px + 3.1818vw), 64.0000px);--mantine-font-size-display-1: clamp(40.0000px, calc(25.4545px + 4.5455vw), 80.0000px);--mantine-font-size-h1: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-font-size-h2: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-font-size-h3: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-font-size-h4: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-font-size-h5: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-h6: 1rem;--mantine-primary-color-0: var(--mantine-color-indigo-0);--mantine-primary-color-1: var(--mantine-color-indigo-1);--mantine-primary-color-2: var(--mantine-color-indigo-2);--mantine-primary-color-3: var(--mantine-color-indigo-3);--mantine-primary-color-4: var(--mantine-color-indigo-4);--mantine-primary-color-5: var(--mantine-color-indigo-5);--mantine-primary-color-6: var(--mantine-color-indigo-6);--mantine-primary-color-7: var(--mantine-color-indigo-7);--mantine-primary-color-8: var(--mantine-color-indigo-8);--mantine-primary-color-9: var(--mantine-color-indigo-9);--mantine-color-red-0: #ffeaea;--mantine-color-red-1: #fed4d4;--mantine-color-red-2: #f4a7a8;--mantine-color-red-3: #ec7878;--mantine-color-red-4: #e55050;--mantine-color-red-5: #e03131;--mantine-color-red-6: #e02829;--mantine-color-red-7: #c71a1c;--mantine-color-red-8: #b21218;--mantine-color-red-9: #9c0411;--mantine-color-violet-0: #fce9ff;--mantine-color-violet-1: #f1cfff;--mantine-color-violet-2: #e09bff;--mantine-color-violet-3: #d16fff;--mantine-color-violet-4: #be37fe;--mantine-color-violet-5: #b51afe;--mantine-color-violet-6: #b009ff;--mantine-color-violet-7: #9b00e4;--mantine-color-violet-8: #8a00cc;--mantine-color-violet-9: #7800b3;--mantine-color-indigo-0: #edecff;--mantine-color-indigo-1: #d6d5fe;--mantine-color-indigo-2: #aaa9f4;--mantine-color-indigo-3: #7b79eb;--mantine-color-indigo-4: #5451e4;--mantine-color-indigo-5: #3b37e0;--mantine-color-indigo-6: #2d2adf;--mantine-color-indigo-7: #1f1ec7;--mantine-color-indigo-8: #1819b2;--mantine-color-indigo-9: #0c149e;--mantine-color-cyan-0: #dffdff;--mantine-color-cyan-1: #caf5ff;--mantine-color-cyan-2: #99e8ff;--mantine-color-cyan-3: #64daff;--mantine-color-cyan-4: #3ccffe;--mantine-color-cyan-5: #24c8fe;--mantine-color-cyan-6: #00c2ff;--mantine-color-cyan-7: #00ade4;--mantine-color-cyan-8: #009acd;--mantine-color-cyan-9: #0085b5;--mantine-color-green-0: #e9fdec;--mantine-color-green-1: #d7f6dc;--mantine-color-green-2: #b0eab9;--mantine-color-green-3: #86df94;--mantine-color-green-4: #62d574;--mantine-color-green-5: #4ccf5f;--mantine-color-green-6: #3fcc54;--mantine-color-green-7: #2fb344;--mantine-color-green-8: #25a03b;--mantine-color-green-9: #138a2e;--mantine-color-yellow-0: #fff7e2;--mantine-color-yellow-1: #ffeecd;--mantine-color-yellow-2: #ffdc9c;--mantine-color-yellow-3: #ffc966;--mantine-color-yellow-4: #feb93a;--mantine-color-yellow-5: #feae1e;--mantine-color-yellow-6: #ffa90f;--mantine-color-yellow-8: #ca8200;--mantine-color-yellow-9: #af7000;--mantine-h1-font-size: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-h1-font-weight: normal;--mantine-h2-font-size: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-h2-font-weight: normal;--mantine-h3-font-size: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-h3-font-weight: normal;--mantine-h4-font-size: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-h4-font-weight: normal;--mantine-h5-font-size: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-h5-font-weight: normal;--mantine-h6-font-size: 1rem;--mantine-h6-font-weight: normal;}
:root[data-mantine-color-scheme="dark"], :host([data-mantine-color-scheme="dark"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-dark-filled: var(--mantine-color-dark-5);--mantine-color-dark-filled-hover: var(--mantine-color-dark-6);--mantine-color-dark-light: rgba(105, 105, 105, 0.15);--mantine-color-dark-light-hover: rgba(105, 105, 105, 0.2);--mantine-color-dark-light-color: var(--mantine-color-dark-0);--mantine-color-dark-outline: var(--mantine-color-dark-1);--mantine-color-dark-outline-hover: rgba(184, 184, 184, 0.05);--mantine-color-gray-filled: var(--mantine-color-gray-5);--mantine-color-gray-filled-hover: var(--mantine-color-gray-6);--mantine-color-gray-light: rgba(222, 226, 230, 0.15);--mantine-color-gray-light-hover: rgba(222, 226, 230, 0.2);--mantine-color-gray-light-color: var(--mantine-color-gray-0);--mantine-color-gray-outline: var(--mantine-color-gray-1);--mantine-color-gray-outline-hover: rgba(241, 243, 245, 0.05);--mantine-color-red-filled: var(--mantine-color-red-5);--mantine-color-red-filled-hover: var(--mantine-color-red-6);--mantine-color-red-light: rgba(236, 120, 120, 0.15);--mantine-color-red-light-hover: rgba(236, 120, 120, 0.2);--mantine-color-red-light-color: var(--mantine-color-red-0);--mantine-color-red-outline: var(--mantine-color-red-1);--mantine-color-red-outline-hover: rgba(254, 212, 212, 0.05);--mantine-color-pink-filled: var(--mantine-color-pink-5);--mantine-color-pink-filled-hover: var(--mantine-color-pink-6);--mantine-color-pink-light: rgba(250, 162, 193, 0.15);--mantine-color-pink-light-hover: rgba(250, 162, 193, 0.2);--mantine-color-pink-light-color: var(--mantine-color-pink-0);--mantine-color-pink-outline: var(--mantine-color-pink-1);--mantine-color-pink-outline-hover: rgba(255, 222, 235, 0.05);--mantine-color-grape-filled: var(--mantine-color-grape-5);--mantine-color-grape-filled-hover: var(--mantine-color-grape-6);--mantine-color-grape-light: rgba(229, 153, 247, 0.15);--mantine-color-grape-light-hover: rgba(229, 153, 247, 0.2);--mantine-color-grape-light-color: var(--mantine-color-grape-0);--mantine-color-grape-outline: var(--mantine-color-grape-1);--mantine-color-grape-outline-hover: rgba(243, 217, 250, 0.05);--mantine-color-violet-filled: var(--mantine-color-violet-5);--mantine-color-violet-filled-hover: var(--mantine-color-violet-6);--mantine-color-violet-light: rgba(209, 111, 255, 0.15);--mantine-color-violet-light-hover: rgba(209, 111, 255, 0.2);--mantine-color-violet-light-color: var(--mantine-color-violet-0);--mantine-color-violet-outline: var(--mantine-color-violet-1);--mantine-color-violet-outline-hover: rgba(241, 207, 255, 0.05);--mantine-color-indigo-filled: var(--mantine-color-indigo-5);--mantine-color-indigo-filled-hover: var(--mantine-color-indigo-6);--mantine-color-indigo-light: rgba(123, 121, 235, 0.15);--mantine-color-indigo-light-hover: rgba(123, 121, 235, 0.2);--mantine-color-indigo-light-color: var(--mantine-color-indigo-0);--mantine-color-indigo-outline: var(--mantine-color-indigo-1);--mantine-color-indigo-outline-hover: rgba(214, 213, 254, 0.05);--mantine-color-blue-filled: var(--mantine-color-blue-5);--mantine-color-blue-filled-hover: var(--mantine-color-blue-6);--mantine-color-blue-light: rgba(116, 192, 252, 0.15);--mantine-color-blue-light-hover: rgba(116, 192, 252, 0.2);--mantine-color-blue-light-color: var(--mantine-color-blue-0);--mantine-color-blue-outline: var(--mantine-color-blue-1);--mantine-color-blue-outline-hover: rgba(208, 235, 255, 0.05);--mantine-color-cyan-filled: var(--mantine-color-cyan-5);--mantine-color-cyan-filled-hover: var(--mantine-color-cyan-6);--mantine-color-cyan-light: rgba(100, 218, 255, 0.15);--mantine-color-cyan-light-hover: rgba(100, 218, 255, 0.2);--mantine-color-cyan-light-color: var(--mantine-color-cyan-0);--mantine-color-cyan-outline: var(--mantine-color-cyan-1);--mantine-color-cyan-outline-hover: rgba(202, 245, 255, 0.05);--mantine-color-teal-filled: var(--mantine-color-teal-5);--mantine-color-teal-filled-hover: var(--mantine-color-teal-6);--mantine-color-teal-light: rgba(99, 230, 190, 0.15);--mantine-color-teal-light-hover: rgba(99, 230, 190, 0.2);--mantine-color-teal-light-color: var(--mantine-color-teal-0);--mantine-color-teal-outline: var(--mantine-color-teal-1);--mantine-color-teal-outline-hover: rgba(195, 250, 232, 0.05);--mantine-color-green-filled: var(--mantine-color-green-5);--mantine-color-green-filled-hover: var(--mantine-color-green-6);--mantine-color-green-light: rgba(134, 223, 148, 0.15);--mantine-color-green-light-hover: rgba(134, 223, 148, 0.2);--mantine-color-green-light-color: var(--mantine-color-green-0);--mantine-color-green-outline: var(--mantine-color-green-1);--mantine-color-green-outline-hover: rgba(215, 246, 220, 0.05);--mantine-color-lime-filled: var(--mantine-color-lime-5);--mantine-color-lime-filled-hover: var(--mantine-color-lime-6);--mantine-color-lime-light: rgba(192, 235, 117, 0.15);--mantine-color-lime-light-hover: rgba(192, 235, 117, 0.2);--mantine-color-lime-light-color: var(--mantine-color-lime-0);--mantine-color-lime-outline: var(--mantine-color-lime-1);--mantine-color-lime-outline-hover: rgba(233, 250, 200, 0.05);--mantine-color-yellow-filled: var(--mantine-color-yellow-5);--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-6);--mantine-color-yellow-light: rgba(255, 201, 102, 0.15);--mantine-color-yellow-light-hover: rgba(255, 201, 102, 0.2);--mantine-color-yellow-light-color: var(--mantine-color-yellow-0);--mantine-color-yellow-outline: var(--mantine-color-yellow-1);--mantine-color-yellow-outline-hover: rgba(255, 238, 205, 0.05);--mantine-color-orange-filled: var(--mantine-color-orange-5);--mantine-color-orange-filled-hover: var(--mantine-color-orange-6);--mantine-color-orange-light: rgba(255, 192, 120, 0.15);--mantine-color-orange-light-hover: rgba(255, 192, 120, 0.2);--mantine-color-orange-light-color: var(--mantine-color-orange-0);--mantine-color-orange-outline: var(--mantine-color-orange-1);--mantine-color-orange-outline-hover: rgba(255, 232, 204, 0.05);--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-9) 0%, var(--mantine-color-cyan-7) 100%);--app-color-surface: #2e2e2e;}
:root[data-mantine-color-scheme="light"], :host([data-mantine-color-scheme="light"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-red-light: rgba(224, 40, 41, 0.1);--mantine-color-red-light-hover: rgba(224, 40, 41, 0.12);--mantine-color-red-outline-hover: rgba(224, 40, 41, 0.05);--mantine-color-violet-light: rgba(176, 9, 255, 0.1);--mantine-color-violet-light-hover: rgba(176, 9, 255, 0.12);--mantine-color-violet-outline-hover: rgba(176, 9, 255, 0.05);--mantine-color-indigo-light: rgba(45, 42, 223, 0.1);--mantine-color-indigo-light-hover: rgba(45, 42, 223, 0.12);--mantine-color-indigo-outline-hover: rgba(45, 42, 223, 0.05);--mantine-color-cyan-light: rgba(0, 194, 255, 0.1);--mantine-color-cyan-light-hover: rgba(0, 194, 255, 0.12);--mantine-color-cyan-outline-hover: rgba(0, 194, 255, 0.05);--mantine-color-green-light: rgba(63, 204, 84, 0.1);--mantine-color-green-light-hover: rgba(63, 204, 84, 0.12);--mantine-color-green-outline-hover: rgba(63, 204, 84, 0.05);--mantine-color-yellow-light: rgba(255, 169, 15, 0.1);--mantine-color-yellow-light-hover: rgba(255, 169, 15, 0.12);--mantine-color-yellow-outline-hover: rgba(255, 169, 15, 0.05);--app-color-surface: #f1f3f5;--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-5) 100%);}</style><style data-mantine-styles="classes">@media (max-width: 35.99375em) {.mantine-visible-from-xs {display: none !important;}}@media (min-width: 36em) {.mantine-hidden-from-xs {display: none !important;}}@media (max-width: 47.99375em) {.mantine-visible-from-sm {display: none !important;}}@media (min-width: 48em) {.mantine-hidden-from-sm {display: none !important;}}@media (max-width: 61.99375em) {.mantine-visible-from-md {display: none !important;}}@media (min-width: 62em) {.mantine-hidden-from-md {display: none !important;}}@media (max-width: 74.99375em) {.mantine-visible-from-lg {display: none !important;}}@media (min-width: 75em) {.mantine-hidden-from-lg {display: none !important;}}@media (max-width: 87.99375em) {.mantine-visible-from-xl {display: none !important;}}@media (min-width: 88em) {.mantine-hidden-from-xl {display: none !important;}}</style><div style="position:absolute;top:0rem" class=""></div><div style="max-width:var(--container-size-xl);height:100%;min-height:0rem" class=""><style data-mantine-styles="inline">.__m__-_R_5ub_{--grid-gutter:0rem;}</style><div style="height:100%;min-height:0rem" class="m_410352e9 mantine-Grid-root __m__-_R_5ub_"><div class="m_dee7bd2f mantine-Grid-inner" style="height:100%"><style data-mantine-styles="inline">.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:91.66666666666667%;--col-max-width:91.66666666666667%;}@media(min-width: 48em){.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:83.33333333333334%;--col-max-width:83.33333333333334%;}}</style><div style="min-width:0rem;height:100%;min-height:0rem;display:flex" class="m_96bdd299 mantine-Grid-col __m__-_R_rdub_"><style data-mantine-styles="inline">.__m__-_R_6qrdub_{margin-top:0rem;padding-inline:var(--mantine-spacing-xs);width:100%;}@media(min-width: 48em){.__m__-_R_6qrdub_{margin-top:var(--mantine-spacing-xl);width:80%;}}@media(min-width: 62em){.__m__-_R_6qrdub_{padding-inline:var(--mantine-spacing-xl);}}</style><div style="margin-inline:auto;max-width:var(--mantine-breakpoint-xl)" class="__m__-_R_6qrdub_"><div style="color:var(--mantine-color-dimmed)" class="m_4451eb3a mantine-Center-root" data-inline="true"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:calc(0.125rem * var(--mantine-scale));color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-lock "><path d="M5 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-6"></path><path d="M11 16a1 1 0 1 0 2 0a1 1 0 0 0 -2 0"></path><path d="M8 11v-4a4 4 0 1 1 8 0v4"></path></svg></div><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">JS: Программирование, управляемое данными</p></div><h1 style="--title-fw:var(--mantine-h1-font-weight);--title-lh:var(--mantine-h1-line-height);--title-fz:var(--mantine-h1-font-size);margin-bottom:var(--mantine-spacing-xl)" class="m_8a5d1357 mantine-Title-root" data-order="1">Теория: Объекты</h1><script type="application/ld+json">{"@context":"https://schema.org","@type":"LearningResource","name":"Объекты","inLanguage":"ru","isPartOf":{"@type":"LearningResource","name":"JS: Программирование, управляемое данными"},"isAccessibleForFree":"False","hasPart":{"@type":"WebPageElement","isAccessibleForFree":"False","cssSelector":".paywalled"}}</script><div class=""><div style="--alert-color:var(--mantine-color-indigo-light-color);margin-bottom:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-lg)" class="m_66836ed3 mantine-Alert-root" id="mantine-_R_remqrdub_" role="alert" aria-describedby="mantine-_R_remqrdub_-body" aria-labelledby="mantine-_R_remqrdub_-title"><div class="m_a5d60502 mantine-Alert-wrapper"><div class="m_667f2a6a mantine-Alert-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-rocket "><path d="M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3 -5a9 9 0 0 0 6 -8a3 3 0 0 0 -3 -3a9 9 0 0 0 -8 6a6 6 0 0 0 -5 3"></path><path d="M7 14a6 6 0 0 0 -3 6a6 6 0 0 0 6 -3"></path><path d="M14 9a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path></svg></div><div class="m_667c2793 mantine-Alert-body"><div class="m_6a03f287 mantine-Alert-title"><span id="mantine-_R_remqrdub_-title" class="m_698f4f23 mantine-Alert-label">Полный доступ к материалам</span></div><div id="mantine-_R_remqrdub_-body" class="m_7fa78076 mantine-Alert-message"><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root"><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Зарегистрируйтесь и получите доступ к этому и десяткам других курсов</p><a style="--button-height:var(--button-height-xs);--button-padding-x:var(--button-padding-x-xs);--button-fz:var(--mantine-font-size-xs);--button-bg:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-hover:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-color:var(--mantine-color-white);--button-bd:none" class="mantine-focus-auto mantine-active m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root" data-variant="gradient" data-size="xs" href="/u/new"><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">Зарегистрироваться</span></span></a></div></div></div></div></div><div class="paywalled m_d08caa0 mantine-Typography-root"><p>Динамическая диспетчеризация – очень мощный механизм, который лёг в основу подхода называемым <strong>объектно-ориентированное программирование</strong>.
Изначально само понятие ООП имело совершенно другой смысл и идеи человека, который придумал ООП, совершенно не похожи на то, что под этим подразумевают сегодня. Его зовут Алан Кэй, обязательно <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://habr.com/ru/company/hexlet/blog/303754/" rel="noopener noreferrer" target="_blank">прочитайте</a> о нём. Поэтому когда мы говорим про ООП, мы в первую очередь будем подразумевать современное представление и понимание, и в голове мы у себя будем держать и вспоминать о том, что на самом деле существует несколько пониманий этого слова и они зависят от того, в каком контексте мы об этом говорим.</p>
<h2 id="heading-2-1">Объект</h2>
<p>В объектном программировании мы оперируем не структурами данных, которые спрятаны за какие-то абстракции, а объектами.
Объект – это такая умная структура данных, которая помимо того, что работает просто как некое состояние, с которым можно что-то делать и как-то манипулировать, но он еще определяет то, какие операции над ним применяются.</p>
<p>Рассмотрим этот код:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">const card = percentCard.make('percent card', 60)
card('getName') // percent card
card('damage', 10) // 6</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">card</code> называется <strong>передача сообщений</strong>. Мы это делали когда работали с парами. Наши пары, а также <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">card</code> – это самый настоящий объект, который внутри себя содержит какое-то состояние.</p>
<blockquote>
<p>Кстати, объект изолирует к нему доступ, но не всегда и не везде языки предлагают такой вариант работы, в которых объекты встроены в сам язык. Иногда вы можете получить все внутренности, как в JS, но вот здесь более защищённый способ работы.</p>
</blockquote>
<p>Функция, которая будет работать, выбирается в зависимости от переданного сообщения и диспетчеризация внутри идёт по имени. То есть объект сам отвечает за то, какой код будет выполняться в случае вызова того или иного метода (в данном случае в зависимости от переданного сообщения).</p>
<h2 id="heading-2-2">Реализация</h2>
<p>Реализация простая и повторяет полностью то, что было с парами. Если хотите узнать больше про пары, то попробуйте наш курс <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://ru.hexlet.io/courses/compound_data" rel="noopener noreferrer" target="_blank">JS: Составные данные</a></p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">export const make = (name, percent) =>
(message, health) => {
switch (message) {
case 'getName':
return name
case 'damage':
return Math.round(health * (percent / 100))
default:
return 'undefined method'
}
}</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">message</code>, по которому делается свич и в зависимости от того, что происходит делает ту или иную задачу. Функция содержит какое-то состояние, но в данном случае оно неизменяемо (хотя это может быть не так).</p>
<p>Я надеюсь, что к текущем моменту вы уже поняли, что ООП и функциональное программирование – это вещи разных порядков. Их нельзя сравнивать, потому что функциональное программирование противопоставляется императивному программированию, то есть изменяемое состояние или неизменяемое состояние. В свою очередь ООП про диспетчеризацию, про возможность выбирать реализацию и это прекрасно существует в функциональных языках при функциональном подходе, поэтому эти концепции целиком и полностью дополняют друг друга.
Так уж сложилось, что чаще всего объектно-ориентированные языки сами по себе являются императивными. Но при этом, как видите, на JS мы спокойно пишем функциональный код и в будущем мы будем писать его еще больше.</p>
<h2 id="heading-2-3">Характеристика ООП</h2>
<p><a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://en.wikipedia.org/wiki/Benjamin_C._Pierce" rel="noopener noreferrer" target="_blank">Бенджамин Пирс</a> – известный учёный, который занимается теорией типов написал следующую вещь в своей книге, которая называется Types and Programming Languages, знаменитая книга о типах в языках программирования:</p>
<blockquote>
<p>Вероятно самая фундаментальная характеристика объектно-ориентированного стиля – это то, что когда по отношению к объекту применяется некоторая операция, объект сам определяет, какой код её осуществляет.</p>
</blockquote>
<p>Небольшое замечание. То что объект сам определяет, какой код её осуществляет – это то, как оно выглядит снаружи, как мы видим это и какая семантика у этой всей истории, но в реальности с точки зрения имплементации это определяет не объект и это может быть сделано гораздо хитрее, как мы себе не можем это представить. Это очень сильно зависит от конкретной имплементации конкретного языка и его особенностей.</p>
<h2 id="heading-2-4">Передача сообщений</h2>
<p>С точки зрения Алана Кэя, который придумал ООП, передача сообщений является ключевым фактором и вообще ключевой идеей в ООП. При этом некоторые современные объектно-ориентированные языки взяли всё таки эту идею немножко в себя и используют. В JS, кстати, передача сообщений не используется, но мы её самостоятельно реализовали и теперь, как минимум вы знаете про это. Например, у таких языков как Ruby или PHP есть такая возможность, но она немножко ограничена. С одной стороны там передача сообщений, с другой стороны есть методы и получился такой микс между двумя способами работы.</p>
<p>В нашем случае объект, который мы создали и с которым до сих пор работали, действительно работает с помощью передачи сообщений.</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">const card = percentCard.make('percent card', 60)
card('getName')
card('damage', 10) // 6</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>В чём отличие от вызова функции?</p>
<p>Во-первых гораздо более <strong>гибкая обработка</strong>. Если не существует какой-то функции, то ваш код однозначно будет падать с ошибкой и вы ничего не сможете с этим сделать, только если вы снаружи не обработаете ошибку. Но когда идёт передача сообщений, обработка может идти внутри и сам объект может достаточно хитро реагировать на различные сообщения.
Более того, могут интересно использоваться техники когда имя сообщения внутри себя содержит определённые параметры, то есть строится определённым способом. Это позволяет нам распарсив его, то есть извлекая из него определённые куски, понять, что нам нужно.</p>
<p>Классный пример – <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">getName</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">card('getName')</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">getName</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">getSurname</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">getLastname</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">get</code> и после этого идёт какое-то название. Затем он бы его разбирал и использовал это название для того, чтобы определить, а что собственно вернуть и тогда мы бы очень сильно сократили код. Это очень крутая возможность. Например, она активно используется в Ruby и в частности в Ruby On Rails.</p>
<p>Ну и второе – это <strong>адаптация в работающем коде</strong>. Это означает, что объект со временем может менять своё поведение: как он отвечает на сообщение, на какие сообщения он отвечает. Использование сообщений открывает достаточно широкие возможности. В JavaScript, существуют <em>прокси объекты</em>, которые позволяют имитировать передачу сообщений, что открывает путь к большому количеству возможностей. С помощью такого подхода можно строить гораздо более гибкие приложения и делать фишки, которые без этого недоступны.</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/js-sicp?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">1 месяц</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">СИКП на JS</p><p 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="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc2MCwicHVyIjoiYmxvYl9pZCJ9fQ==--9348098e4053d798b6f34bee4ef66947540261e4/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Low%20code%20development-rafiki.png" alt="СИКП на 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">от 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="/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/ddp/lessons/objects/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 / 9</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/ddp/lessons/objects/finish_unit?unit=theory" data-disabled="true" data-block="true" disabled=""><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">→</span></span></a><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" data-disabled="true" type="button" disabled=""><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-list-numbers "><path d="M11 6h9"></path><path d="M11 12h9"></path><path d="M12 18h8"></path><path d="M4 16a2 2 0 1 1 4 0c0 .591 -.5 1 -1 1.5l-3 2.5h4"></path><path d="M6 10v-6l-2 2"></path></svg></span></button><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto mantine-active m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" type="button"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-message "><path d="M8 9h8"></path><path d="M8 13h6"></path><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"></path></svg></span></button></div></div></div></div></div></div></div>
</main>
<footer class="bg-dark fw-light text-light px-3 py-5">
<div class="row small">
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 mb-3">Хекслет</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/about">О нас</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/testimonials">Отзывы</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://b2b.hexlet.io" role="button">Корпоративное обучение</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/blog">Блог</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/qna">Вопросы и ответы</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/glossary">Глоссарий</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://help.hexlet.io" data-target="_blank" role="button">Справка</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" target="_blank" rel="noopener noreferrer" href="/map">Карта сайта</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 fw-normal mb-3">Направления</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_devops">DevOps
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_data_analytics">Аналитика
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_backend_development">Бэкенд
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_programming">Программирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_testing">Тестирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_front_end_dev">Фронтенд
</a></li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Профессии</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/go">Go-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/java">Java-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python">Python-разработчик </a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/data-analytics">Аналитик данных</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/qa-engineer">Инженер по ручному тестированию</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php">РНР-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/frontend">Фронтенд-разработчик</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Навыки</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python-django-developer">Django</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/docker">Docker</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php-laravel-developer">Laravel</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/postman">Postman</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-react-developer">React</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-rest-api">REST API в Node.js</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/spring-boot">Spring Boot</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/typescript">Typescript</a>
</li>
</ul>
</div>
</div>
<hr>
<div class="row">
<div class="col-12 col-sm-4 col-md-2">
<div class="fs-4">
<ul class="list-unstyled d-flex">
<li class="me-3">
<a aria-label="Telegram" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://t.me/hexlet_ru"><span class="bi bi-telegram"></span>
</a></li>
<li>
<a aria-label="Youtube" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://www.youtube.com/user/HexletUniversity"><span class="bi bi-youtube"></span>
</a></li>
</ul>
</div>
<div class="mb-2 d-flex flex-column">
<a class="link-light text-decoration-none" rel="nofollow" href="mailto:support@hexlet.io">support@hexlet.io</a>
<a class="link-light text-decoration-none py-2" target="_blank" href="https://t.me/hexlet_help_bot">t.me/hexlet_help_bot</a>
</div>
<ul class="list-unstyled d-flex">
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://hexlet.io/locale/switch?new_locale=en" data-target="_self" role="button"><span class="my-auto">EN</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 opacity-100 external-link" rel="nofollow" data-href="https://ru.hexlet.io/locale/switch?new_locale=ru" data-target="_self" role="button"><span class="my-auto">RU</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://kz.hexlet.io/locale/switch?new_locale=kz" data-target="_self" role="button"><span class="my-auto">KZ</span>
</span></li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<ul class="list-unstyled fs-4">
<li class="mb-3">
<a class="link-light text-decoration-none" href="tel:8%20800%20100%2022%2047">8 800 100 22 47</a>
<span class="d-block opacity-50 small">бесплатно по РФ</span>
</li>
<li>
<a class="link-light text-decoration-none" href="tel:%2B7%20495%20085%2021%2062">+7 495 085 21 62</a>
<span class="d-block opacity-50 small">бесплатно по Москве</span>
</li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<div class="small mb-3">Образовательные услуги оказываются на основании Л035-01298-77/01989008 от 14.03.2025</div>
<ul class="list-unstyled small">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/legal">Правовая информация</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/offer">Оферта</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/license">Лицензия</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/contacts">Контакты</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-12 col-md-4 small">
<div class="mb-2">
<div>ООО «<a href="/" class="text-decoration-none link-light">Хекслет Рус</a>»</div>
<div>108813 г. Москва, вн.тер.г. поселение Московский,</div>
<div>г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3</div>
<div>ОГРН 1217300010476</div>
<div>ИНН 7325174845</div>
</div>
<hr>
<div>АНО ДПО «<a href="/" class="text-decoration-none link-light">Учебный центр «Хекслет</a>»</div>
<div>119331 г. Москва, вн. тер. г. муниципальный округ</div>
<div>Ломоносовский, пр-кт Вернадского, д. 29</div>
<div>ОГРН 1247700712390</div>
<div>ИНН 7736364948</div>
</div>
</div>
</footer>
<div id="root-assistant-offcanvas"></div>
<script src="/vite/assets/assistant-CdBlNCiQ.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-nkZBEvfU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/MarkdownBlock-DbyKWoR_.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/shiki-V011pkdv.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-XR8Qr8kR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dist-GCHh59xr.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useIsomorphicEffect-HJ6VK0D3.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-KSp6QbZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/classnames-l6ipYlLR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/debounce-jMQ_Cf4f.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v67327c56f0bb4ef8b305cae61679db8f1769101564043" integrity="sha512-rdcWY47ByXd76cbCFzznIcEaCN71jqkWBBqlwhF1SY7KubdLKZiEGeP7AyieKZlGP9hbY/MhGrwXzJC/HulNyg==" data-cf-beacon='{"version":"2024.11.0","token":"d11015b65d11429ea6b4a2ef37dd7e0b","server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
</body>
</html>