Транскрипт урока
В одном из прошлых уроков мы говорили об ошибках и как с ними справляться. Есть несколько видов ошибок, и я хочу напомнить об одном конкретном виде. Вот небольшой фрагмент того урока:
Взгляните на этот код:
Сначала мы создали константу. Помните, что это как давать чему-то название: в нашем случае — числу 12 даётся название length. В следующей строке мы вызываем функцию length и передаём ей аргумент — число 54. Но подождите! length — это не функция! Это всего лишь число. Числа — это не функции, не ящики, которые производят какие-то действия. И JavaScript пожалуется именно на это:
Это Ошибка типизации: тип объекта, который вы использовали, неверный. Интерпретатор JavaScript не скажет чем что-то является, но точно скажет чем оно не является. length — это не функция.
Ошибка типизации — это как просить кошку постирать бельё. Возможно, вы хотели попросить об этом вашего друга.
В программировании "типизация" — это классификация информации. Это общий термин и разные языки программирования справляются с типизацией по-разному. Как вы уже знаете, JavaScript умеет отличать типы. Функция — это один тип, Число — другой, и вы не можете просто использовать число как функцию.
typeof — это специальный оператор, который возвращает строку, в которой написан тип.
42 и 3.14, очевидно, числа, несколько комбинаций букв в кавычках — строка, а true и false — булево значение. Всё это — типы в JavaScript — число, строка и булево значение.
NaN означает — "не число", но тип NaN — это "число". Да, я знаю. Еще одна странность JavaScript. Такие правила в этом языке.
Типизация полезна. Когда мы попытаемся запустить число, как будто это функция, JavaScript начнёт жаловаться и мы увидим ошибку и починим её. Если бы никакого обозначения типов в JavaScript не было, мы бы сталкивались либо с каким-нибудь аномальным поведением, либо с мистической ошибкой. Вместо чёткого "length — это не функция", мы бы видели что-то вроде "I'm sorry Dave, I'm afraid I can't do that".
А что, если создать переменную, но не задать ей никакого значения? Какой в этом случае будет тип? Это ни число, ни строка, ничто... Потому что нет значения, правильно?
JavaScript в этом случае кое-что делает в тайне от вас. Переменная без значения на самом деле имеет специальное значение — "undefined". И тип такой переменной называется "undefined".
Например, тип number имеет множество потенциальных значений: 1, 2, -10, 69000 и другие числа. А тип undefined только одно — undefined.
Когда дело касается типизации в программировании, важно различать две концепции: динамическая против статической и слабая против сильной.
Чтобы понимать разницу между динамической и статической типизацией, нам сначала нужно посмотреть как написанные программы становятся запущенными программами.
Код, который вы пишете, обычно конвертируется в понятную для запуска компьютером форму. Этот процесс называется компиляцией, а промежуток времени, за который это происходит — "стадией компиляции" или compile time.
После того, как компиляция закончена и программа запущена, начинается отсчёт времени, который называется "стадией исполнения" или run time.
Некоторые языки проверяют типы и ищут ошибки типизации на стадии компиляции. У них статическая типизация.
Другие языки проверяют типы и ищут ошибки типизации на стадии исполнения. Такая типизация — динамическая.
Иными словами: статическая типизация означает проверку типов перед запуском программы, динамическая — проверку типов, когда программа запущена.
C#, C++, Java, Go — статически типизированные языки. Если в одном из этих языков вы создадите число и попытаетесь проводить с ним операции, как с функцией, вы получите ошибку во время компиляции, а программа не станет запускаться — она даже не дойдёт до этой стадии, потому что ошибка типизации будет обнаружена перед исполнением, в период компиляции.
JavaScript, Ruby, PHP — динамически типизированные языки. Как вы видели раньше, если использовать неверную типизацию, ваша программа запустится, а ошибка обнаружится только когда будет исполняться конкретная строчка кода. Здесь типы проверяются в период исполнения.
Вообще-то, в JavaScript обычно нет никакой компиляции, но это тема другого урока.
Динамическая типизация не хуже и не лучше статической. Оба способа имеют свои преимущества и недостатки. Динамически типизированные языки обычно проще изучать и писать на них программы, но, как вы можете представить, это потенциально увеличивает ошибки.
Теперь давайте поговорим о слабой и сильной типизации. Посмотрите на этот JavaScript код:
М-да… Это… Ок, что тут происходит? Сложение числа 4 со строкой "7" даёт нам строку "47". JavaScript конвертирует число 4 в строку "4" и конкатенирует две строки — склеивает их друг с другом. JavaScript просто берёт на себя ответственность предположить, что это то, что мы хотели. Глупо обвинять его — чего мы действительно хотели? Складывать число со строкой не имеет никакого смысла. Какой-нибудь другой язык, вроде Ruby или Python просто бы пожаловался и ничего не сделал.
Произведение числа 4 со строкой "7", это, как видите, 28, по мнению JavaScript. В этом случае он сконвертировал строку "7" в число 7 и произвёл обычное умножение.
JavaScript постоянно так делает. Он знает о типах разных значений, но когда типы не соответствуют, он пытается предположить и сконвертировать один тип в другой, не предупреждая вас. Иногда это полезно, иногда мозгодробяще. Такое происходит потому что JavaScript — язык со слабой типизацией. У него есть представление о типах, но он типа "это всего лишь игра, чего ты злишься?"
У этой концепции нет ничего общего с динамической и статической типизацией, смысл которых — КОГДА проверять типы. Сильная против слабой — это НАСКОЛЬКО СЕРЬЁЗНО проверять типы.
Вы можете считать, что слабая — это нестрогая типизация, а сильная — это требовательная.
В отличие от динамичности-статичности, сила типизации это спектр. У PHP типизация немного сильнее. У Python ещё сильнее. И все они динамически типизированные языки.
JavaScript делает множество неявных конвертаций, но он так же даёт нам инструменты, чтобы мы могли делать явные конвертации сами. Мы можем конвертировать строки в числа, числа в строки, булевы значения в строки и так далее:
Можно предположить, что неявная конверсия из типа в тип — не самая лучшая идея. Неявный, значит скрытый, а скрытый — значит трудно понимаемый и предрасположенный к ошибкам. Поведение программы становится менее очевидным. Вы пишете меньше кода, да, но код более хрупкий и менее понятный.
Дополнение к уроку
null
В JavaScript кроме undefined существует null. Оно означает, что «значение отсутствует». Например, если создать переменную, но не задавать ей значения, то у нее будет значение undefined:
Тут значения не оказалось ненамеренно. Видимо, просто еще не пришло время дать этой переменной значение.
null нужен для явного, намеренного указания, что значения нет. Можно сказать let a = null;. Например, вы попросили пользователя ввести информацию, но он ничего не ввел. В таком случае уместно записать в результат null.
null, в отличие от undefined, можно задавать вручную, передавать как аргумент в функцию и в целом использовать как любое другое явное значение.
(undefined тоже можно задавать вручную, но никогда не нужно этого делать: это значение семантически создано только для того, чтобы его генерировал компьютер, а не программист).
При сравнении null и undefined нужно быть осторожным:
Сравнение
В этом курсе мы сравниваем данные, используя три знака равенства:
Это сравнение прямое: являются ли эти данные абсолютно идентичными?
В JavaScript есть расслабленное сравнение, с двумя знаками равенства. Оно показывает, что происходит внутри JavaScript, при сравнении значений разных типов:
Выводы
Типизация в JavaScript
JavaScript имеет представление о типах: числах, строках, функциях, логических значениях и так далее. typeof возвращает строку, в которой записан тип:
NaN означает "не число", но тип этого значения — number.
Переменная без значения имеет специальное значение undefined. Тип такой переменной — undefined:
Динамическая и статическая типизация
Код конвертируется в другую форму, которую компьютер может запустить. Этот процесс называется компиляцией, а период времени, за который этот процесс происходит — стадией компиляции (compile time).
После того, как компиляция закончена, запускается программа и период, пока она запущена, называется стадией исполнения (run time).
Статически типизированные языки проверяют типы и ищут ошибки типизации на стадии компиляции.
Динамически типизированные языки проверяют типы и ищут ошибки типизации на стадии исполнения.
Иными словами: статическое типизирование означает проверку типов перед запуском программы; динамическое — проверку типов пока программа запущена.
Слабая и сильная типизация
JavaScript часто конвертирует типы автоматически:
JavaScript — это язык со слабой типизацией. У него есть представление о типах, но он расслаблено к ним относится и может оперировать значениями, можно сказать, произвольно. Чем сильнее система типизации, тем строже правила.
Явные конверсии в JavaScript
<!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:22:00 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="Owu6c9yBb-3Pn1bLYP8JJTNsoMu4flW2AbdQkqWsRTfU2nFELv_CjXncclNs8PlS82WNYbBJqxS8V8rG96uiWQ";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>Типизация | Введение в программирование</title>
<meta name="description" content="Типизация / Введение в программирование: Знакомимся с идеей типизации. Ищем разницу между динамической и статической типизацией, а также разницу между сильной и слабой типизацией.">
<link rel="canonical" href="https://ru.hexlet.io/courses/introduction_to_programming/lessons/types/theory_unit">
<meta name="robots" content="noarchive">
<meta property="og:title" content="Типизация">
<meta property="og:title" content="Введение в программирование">
<meta property="og:description" content="Типизация / Введение в программирование: Знакомимся с идеей типизации. Ищем разницу между динамической и статической типизацией, а также разницу между сильной и слабой типизацией.">
<meta property="og:url" content="https://ru.hexlet.io/courses/introduction_to_programming/lessons/types/theory_unit">
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="PKXOftOZ0Ofms1dGI-TuGPbAQRu6y_dgYhd_PAUx5IXTdAVJIed9h1Dwc94v6x5vNslssbL8CcLf9-VoVzYD6w" />
<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">
<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:22:00.703Z","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":"pIpUZMqFnZpUD9Pr_c6BBpdi1rjILbzBjq5H5T27mMZLW59TOPsw-uJM93PxwXFxV2v7EsAaQmMzTt2xb7x_qA","topics":[{"id":50532,"title":"Всем добрый вечер. Сделал один круг. Но никак не могу понять как мой результат еще раз запустить и получить окончательный ответ. Уже всю голову сломал. Заранее спасибо. https://ru.hexlet.io/code_reviews/353892","plain_title":"Всем добрый вечер. Сделал один круг. Но никак не могу понять как мой результат еще раз запустить и получить окончательный ответ. Уже всю голову сломал. Заранее спасибо. https://ru.hexlet.io/code_reviews/353892 ","creator":{"public_name":"Timur Ermeshev","id":310131,"is_tutor":false},"comments":[{"creator":{"public_name":"Timur Ermeshev","id":310131,"is_tutor":false},"id":108297,"body":"**Максим Литвинов**, Максим, так я это понимаю и поэтому ввел условие, чтобы результат был меньше 10. Но оно почему-то выполняется только один раз.","topic_id":50532},{"creator":{"public_name":"Timur Ermeshev","id":310131,"is_tutor":false},"id":108292,"body":"**Станислав Дзисяк**, Станислав, к сожалению не получилось. Не мог сначала понять, как вызывать отдельно данную функцию и ее результат проверить. Сейчас же происходит вычисление в 2 круга. Третий не делает. https://ru.hexlet.io/code_reviews/353892","topic_id":50532},{"creator":{"public_name":"Timur Ermeshev","id":310131,"is_tutor":false},"id":108397,"body":"**Станислав Дзисяк**, Станислав, спасибо большое за подробный ответ. Действительно нужно было поставить цикл. Все получилось.","topic_id":50532},{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":108294,"body":"Вы почти у цели, осталось совсем немного. Подумайте, ведь количество \"кругов\" заранее не известно и вам нужно вызывать функцию и обновлять результат до тех пор, **пока** число не станет состоять из одной цифры.","topic_id":50532},{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":108301,"body":"Потому что у вас условная конструкция, она выполняется только один раз. Замените на цикл и он будет выполняться до тех пор, пока истинно его условие","topic_id":50532},{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":108262,"body":"Приветствую, Тимур!\n\nПолучилось ли у вас продвинуться в решении упражнения? Если нет, отправляйте новую версию кода на ревью, будем вместе разбираться дальше.","topic_id":50532},{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":108387,"body":"Приветствую, Тимур!\n\nМаксим вам верно подсказывает: необходимо в функции finalresult заменить if на while. Также обратите внимание, что нужно экспортировать по умолчанию вашу функцию `export default finalresult;`. Сейчас именно по этой причине при запуске тестов возникает синтаксическая ошибка `SyntaxError: The requested module '../addDigits.js' does not provide an export named 'default'`.","topic_id":50532},{"creator":{"public_name":"Timur Ermeshev","id":310131,"is_tutor":false},"id":108293,"body":"**Максим Литвинов**, Максим, спасибо большое за подсказку. К сожалению не получилось. Не мог сначала понять, как вызывать отдельно данную функцию и ее результат проверить. Сейчас же происходит вычисление в 2 круга. Третий не делает. https://ru.hexlet.io/code_reviews/353892","topic_id":50532},{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":108170,"body":"Добрый день. Загляните в раздел Подсказки:\n>Выделите процесс суммирования цифр в числе в отдельную функцию\n\nСейчас вы написали именно эту отдельную функцию, которая просто один раз суммирует все цифры в числе. Теперь вам нужна основная функция, которая будет вызывать уже написанную функцию до тех пор, пока в числе не останется одна цифра. Из числа 1259 у вас получилось число 17. Теперь вам просто нужно еще раз вызвать написанную функцию, но уже с числом 17 и получить 8","topic_id":50532},{"creator":{"public_name":"Timur Ermeshev","id":310131,"is_tutor":false},"id":108396,"body":"**Максим Литвинов**, Максим, спасибо за помощь. Все получилось.","topic_id":50532}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Типизация","entity_url":null,"active":true}},{"id":12537,"title":"По факту сделанного задания получила прохождение теста. Но были сомнения, что моя программа делает только два прохода, поэтому добавила в тест такую строчку:\nexpect(addDigits(99999999999)).toBe(9);\nИ таки да, теперь моя программа тест не проходит. Советую добавить такую строчку для всех, а над своей программой подумаю ещё.\n(В выводе ошибки пишет, что получено значение 18 вместо ожидаемого 9.)","plain_title":"По факту сделанного задания получила прохождение теста. Но были сомнения, что моя программа делает только два прохода, поэтому добавила в тест такую строчку: expect(addDigits(99999999999)).toBe(9); И таки да, теперь моя программа тест не проходит. Советую добавить такую строчку для всех, а над своей программой подумаю ещё. (В выводе ошибки пишет, что получено значение 18 вместо ожидаемого 9.) ","creator":{"public_name":"Vita Chistyakova","id":163107,"is_tutor":false},"comments":[{"creator":{"public_name":"Vita Chistyakova","id":163107,"is_tutor":false},"id":27439,"body":"Не очень поняла. Мой код в ревью выложить?","topic_id":12537},{"creator":{"public_name":"Дмитрий Храпонов","id":145876,"is_tutor":false},"id":26173,"body":"Покажите пожалуйста код, который проходит все тесты, кроме `addDigits(99999999999)`. Я проанализирую и добавлю ещё тестов, если потребуется. Спасибо вам за фидбэк.","topic_id":12537},{"creator":{"public_name":"Дмитрий Храпонов","id":145876,"is_tutor":false},"id":27453,"body":"Не, спасибо, тест уже добавлен в упражнение :)","topic_id":12537}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Типизация","entity_url":null,"active":true}},{"id":46078,"title":"Добрый день! Получаю правильный результат только когда при первом сложении цифр num получается одна цифра. А как сложить дальше (повторить цикл) что-то не соображу. Подскажите пожалуйста. ","plain_title":"Добрый день! Получаю правильный результат только когда при первом сложении цифр num получается одна цифра. А как сложить дальше (повторить цикл) что-то не соображу. Подскажите пожалуйста. ","creator":{"public_name":"Юлия Андрианова","id":282817,"is_tutor":false},"comments":[{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":99494,"body":"Приветствую, Юлия!\n\nМаксим правильно посоветовал разбить решение на две небольшие функции. Попробуйте описать в коде предложенный алгоритм. Напишите, пожалуйста, удалось ли вам разобраться и победить задачу.\n\nЕсли вопрос решён и вам помог ответ участника сообщества, нажмите \"Отметить как решение\" в его комментарии. Это хороший способ выразить благодарность и поможет другим ученикам в поисках ответов на похожие вопросы.","topic_id":46078},{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":99431,"body":"Добрый день. Попробуйте воспользоваться советом в подсказках к заданию. Разделите весь код на две функции. Первая функция будет считать сумму цифр в переданном числе (только один раз). Вторая будет проверять, является ли число однозначным. Если нет, вызывать первую функцию с этим числом. И так до тех пор, пока число не станет однозначным ","topic_id":46078},{"creator":{"public_name":"Юлия Андрианова","id":282817,"is_tutor":false},"id":99393,"body":"https://ru.hexlet.io/code_reviews/299781","topic_id":46078}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Типизация","entity_url":null,"active":true}},{"id":46356,"title":"Здравствуйте, объясните пожалуйста зачем в решение учителя вторая функция? Я понимаю что она отсекает все числа которые не требуется складывать, но зачем? Первая итак сделает все что нужно.\nhttps://ru.hexlet.io/code_reviews/303006\n","plain_title":"Здравствуйте, объясните пожалуйста зачем в решение учителя вторая функция? Я понимаю что она отсекает все числа которые не требуется складывать, но зачем? Первая итак сделает все что нужно. https://ru.hexlet.io/code_reviews/303006 ","creator":{"public_name":"Глеб Манов","id":306928,"is_tutor":false},"comments":[{"creator":{"public_name":"Глеб Манов","id":306928,"is_tutor":false},"id":100065,"body":"**Сергей Мелодин**, но без второй функции ответ будет также верен, семантика не меняется, то есть она излишняя. Разве нет?","topic_id":46356},{"creator":{"public_name":"Глеб Манов","id":306928,"is_tutor":false},"id":100064,"body":"Но без второй функции ответ будет также верен, семантика не меняется, то есть она излишняя. ","topic_id":46356},{"creator":{"public_name":"Глеб Манов","id":306928,"is_tutor":false},"id":100068,"body":"**Сергей Мелодин**, спасибо","topic_id":46356},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":100055,"body":"**glebs**, приветствую.\n\nФункции выполняют разные функции, как бы это не звучало. Одна занимается непосредственно сложением, а другая решает до каких пор это сложение выполнять. Верхнюю функцию можно переиспользовать отдельно от нижней.","topic_id":46356},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":100067,"body":"**glebs**, простое правило для написания читаемого кода - если что-то можно вынести в хорошую абстракцию, то выносите. Декларативность достигается когда код читается через вопрос \"что нужно сделать\".","topic_id":46356}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Типизация","entity_url":null,"active":true}},{"id":12335,"title":"\n\n> \n> \n> 1. const addDigits = (num ) =>{\n> 1. if (num < 10){\n> 1. return num;\n> 1. }\n> 1. for (let numz = String(num) ; numz.length = 2; ){\n> 1. const SummuNumz = (numz) => {\n> 1. let nn = 1;\n> 1. nn = Number (numz[0])+ Number ( numz[1])\n> 1. return nn;\n> 1. }\n> 1. numz = SummuNumz;\n> 1. }\n> 1. return Number (numz);\nЧто не так ?\n","plain_title":"const addDigits = (num ) =>{ if (num < 10){ return num; } for (let numz = String(num) ; numz.length = 2; ){ const SummuNumz = (numz) => { let nn = 1; nn = Number (numz[0])+ Number ( numz[1]) return nn; } numz = SummuNumz; } return Number (numz); Что не так ? ","creator":{"public_name":"Ислам Энгиноев","id":128102,"is_tutor":false},"comments":[{"creator":{"public_name":"Ислам Энгиноев","id":128102,"is_tutor":false},"id":25671,"body":"где 11 я изменил на numz = String(SummuNumz).","topic_id":12335}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Типизация","entity_url":null,"active":true}},{"id":75293,"title":"Откуда в решении учителя нижняя функция addDigits берет аргумент num ? \n\nЕсли этот аргумент приходит, как возвращенное значение верхней функции sumDigits, то как это понять и где это указано в коде ?\n\nДопустим, в качестве аргумента задано число 598997686567. Куда оно будет передано ? Сразу в обе функции в параметр num ? Или только в ф-цию sumDigits ?","plain_title":"Откуда в решении учителя нижняя функция addDigits берет аргумент num ? Если этот аргумент приходит, как возвращенное значение верхней функции sumDigits, то как это понять и где это указано в коде ? Допустим, в качестве аргумента задано число 598997686567. Куда оно будет передано ? Сразу в обе функции в параметр num ? Или только в ф-цию sumDigits ? ","creator":{"public_name":"Станислав","id":494154,"is_tutor":false},"comments":[{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":156914,"body":"> Откуда в решении учителя нижняя функция addDigits берет аргумент num ?\n\nОн передаётся в качестве параметра при вызове функции. Например: `addDigits(1234)`. \n\n> Если этот аргумент приходит, как возвращенное значение верхней функции sumDigits, то как это понять и где это указано в коде ?\n\nМы определили две функции: `sumDigits()` и `addDigits()`. Вторая функция внутри использует первую функцию. Она вызывает её с параметром `result `. А в начале определения `addDigits()` мы присваиваем:\n\n let result = num;\n\nИнтерпретатор двигается сверху вниз по определению функции `addDigits()` и выполняет все инструкции. Как только он доходит до вызова функции `sumDigits()`, он перемещается в определение этой функции и выполняет её код, также построчно. ","topic_id":75293},{"creator":{"public_name":"Станислав","id":494154,"is_tutor":false},"id":156938,"body":"Так все таки, куда первоначально попадает аргумент в качестве параметра ? \n\nВ какую ф-цию ? sumDigits() или addDigits() ?","topic_id":75293},{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":156960,"body":"По условиям задачи нам нужно реализовать функцию `addDigits()` и аргумент приходит именно в эту функцию.","topic_id":75293}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Типизация","entity_url":null,"active":true}},{"id":9374,"title":"Подскажите пожалуйста. Я уже принудительно ставлю, чтобы функция возвращала тип Number, а проверка выдает, что возвращается тип String.\n====================================================\n const addDigits = (num) => {\n num = (typeof num !== 'string') ? String(num) : num;\n let sum = num;\n let j = sum.length;\n // alert(\"length(Digitsum) = \" + sum.length);\n if (j === 1) return num;\n while(j > 1) {\n \n // alert(\"sum = \" + sum);\n sumd = Number(sumDigid(sum));\n sum = sumd;\n sum = (typeof sum !== 'string') ? String(sum) : sum;\n j = sum.length;\n // alert(\"j (в циклe while) = \" + j);\n }\n // alert(\"sum (в цикле addDigits) = \" + sum);\n return Number(sumd);\n };\n\n const sumDigid = (sumnum) => {\n let sumd = 0;\n //alert(\"length(sumnum) = \" + length(sumnum));\n sumnum = (typeof sumnum !== 'string') ? String(sumnum) : sumnum;\n // alert(\"sumnum = \" + sumnum);\n // alert(\"length(sumnum) = \" + sumnum.length);\n for (let i = 0; i < sumnum.length; i += 1) {\n sumd = sumd + Number(sumnum[i]);\n // alert(\"i = \" + i);\n // alert(\"Number(sumnum[\"+i+\"]) = \" + Number(sumnum[i]));\n // alert(\"sumd (в цикле) = \" + sumd);\n \n }\n sum = sumd;\n // alert(\"sumd (вне цикла) = \" + sumd);\n return Number(sum);\n };\n \n export default addDigits;","plain_title":"Подскажите пожалуйста. Я уже принудительно ставлю, чтобы функция возвращала тип Number, а проверка выдает, что возвращается тип String. const addDigits = (num) => { num = (typeof num !== 'string') ? String(num) : num; let sum = num; let j = sum.length; // alert(\"length(Digitsum) = \" + sum.length); if (j === 1) return num; while(j > 1) { // alert(\"sum = \" + sum); sumd = Number(sumDigid(sum)); sum = sumd; sum = (typeof sum !== 'string') ? String(sum) : sum; j = sum.length; // alert(\"j (в циклe while) = \" + j); } // alert(\"sum (в цикле addDigits) = \" + sum); return Number(sumd); }; const sumDigid = (sumnum) => { let sumd = 0; //alert(\"length(sumnum) = \" + length(sumnum)); sumnum = (typeof sumnum !== 'string') ? String(sumnum) : sumnum; // alert(\"sumnum = \" + sumnum); // alert(\"length(sumnum) = \" + sumnum.length); for (let i = 0; i < sumnum.length; i += 1) { sumd = sumd + Number(sumnum[i]); // alert(\"i = \" + i); // alert(\"Number(sumnum[\"+i+\"]) = \" + Number(sumnum[i])); // alert(\"sumd (в цикле) = \" + sumd); } sum = sumd; // alert(\"sumd (вне цикла) = \" + sumd); return Number(sum); }; export default addDigits; ","creator":{"public_name":"Рамиль Хамзин","id":131086,"is_tutor":false},"comments":[{"creator":{"public_name":"Рамиль Хамзин","id":131086,"is_tutor":false},"id":19097,"body":"Сорри, это у меня случайно такой шрифт выдало","topic_id":9374},{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":19104,"body":"Здравствуйте! Как вы сами заметили, ваше сообщение неудачно сформатировано. Поэтому его достаточно тяжело читать и воспринимать. Отредактируйте, пожалуйста, это сообщение, чтобы привести его в удобочитаемый вид, как это делается можно подсмотреть здесь: http://help.hexlet.io/article/10-markdown","topic_id":9374}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Типизация","entity_url":null,"active":true}},{"id":28653,"title":"Подскажите, почему у меня получается NaN при вызове вот такого числа:\nconsole.log(addDigits(1111111111111111111111));\n\nМой код: https://ru.hexlet.io/code_reviews/117675\n\nЕсли убрать из числа одну единицу, то выведет нормально","plain_title":"Подскажите, почему у меня получается NaN при вызове вот такого числа: console.log(addDigits(1111111111111111111111)); Мой код: https://ru.hexlet.io/code_reviews/117675 Если убрать из числа одну единицу, то выведет нормально ","creator":{"public_name":"","id":230609,"is_tutor":false},"comments":[{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":61885,"body":"Слишком большое число, в js есть ограничение на размер чисел, например, вы сами можете проверить, что число `1111111111111111111111` будет представлено в [экспоненциальной записи](https://ru.wikipedia.org/wiki/%D0%AD%D0%BA%D1%81%D0%BF%D0%BE%D0%BD%D0%B5%D0%BD%D1%86%D0%B8%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D1%8C) `1.1111111111111111e+21`.","topic_id":28653}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Типизация","entity_url":null,"active":true}},{"id":43273,"title":"Добрый день. Не смог разобраться сам. Воспользовался решением учителя. \n[Ревью тут.](https://ru.hexlet.io/code_reviews/271820#)Не смог понять следующую строчку:\n`\\\\ removed`\nКто может обьяснить что это значит и откуда взялось? Спасибо.","plain_title":"Добрый день. Не смог разобраться сам. Воспользовался решением учителя. Ревью тут. (https://ru.hexlet.io/code_reviews/271820#)Не смог понять следующую строчку: result += Number(str[i]); Кто может обьяснить что это значит и откуда взялось? Спасибо. ","creator":{"public_name":"Александр Лежнин","id":253776,"is_tutor":false},"comments":[{"creator":{"public_name":"Александр Лежнин","id":253776,"is_tutor":false},"id":94113,"body":"Хорошо, напишу более конкретно. Откуда взялось Number?","topic_id":43273},{"creator":{"public_name":"Nikolai Gagarinov","id":104929,"is_tutor":true},"id":94112,"body":"Привет, могут помочь разобраться вот эти уроки\nhttps://ru.code-basics.com/languages/javascript/modules/variables/lessons/symbols\n\n`result +=` - это сокращение в котором к этой переменной что-то складывается. Например\n```\nlet a = 5;\na += 1; // a === 6\n```","topic_id":43273},{"creator":{"public_name":"Евгений Подгаецкий","id":194196,"is_tutor":false},"id":94115,"body":"**Александр Лежнин**, Более явное преобразования в число [https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Number](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Number)","topic_id":43273}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Типизация","entity_url":null,"active":true}},{"id":27393,"title":"Помогите, ребят, жестко туплю. Упражнение раздела типизация. ожидаемый 5 - выдает 0.\n\n```\nlet i = 0;\nlet result = 0;\n\nconst addDigits=(num)=>{ if (num===0) {return 0;}\n else while (i<num.length) {\n\nresult= result + Number(str[i]);\ni=i+1;}\nif (result.length===1) {\nreturn result; \n} \n\nelse return addDigits(result);\n};\n\nexport default addDigits;\n``` \n\n\n\n\n","plain_title":"Помогите, ребят, жестко туплю. Упражнение раздела типизация. ожидаемый 5 - выдает 0. let i = 0; let result = 0; const addDigits=(num)=>{ if (num===0) {return 0;} else while (i<num.length) { result= result + Number(str[i]); i=i+1;} if (result.length===1) { return result; } else return addDigits(result); }; export default addDigits; ","creator":{"public_name":"Герман Нинько","id":212214,"is_tutor":false},"comments":[{"creator":{"public_name":"Сергей К.","id":5174,"is_tutor":false},"id":58729,"body":"Герман, доброе утро! Вы использовали отладочную печать для того, чтобы отследить изменения значений переменных? Также обратите внимание на замечания линтера. При их исправлении читать код станет намного легче.","topic_id":27393}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Типизация","entity_url":null,"active":true}}],"lesson":{"exercise":null,"units":[{"id":1906,"name":"theory","url":"/courses/introduction_to_programming/lessons/types/theory_unit"}],"links":[{"id":427095,"name":"Wat by Gary Bernhardt (video)","url":"https://www.destroyallsoftware.com/talks/wat"},{"id":427096,"name":"typeof","url":"https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/typeof"},{"id":427097,"name":"Data type / Wikipedia","url":"https://en.wikipedia.org/wiki/Data_type"},{"id":427098,"name":"Dynamic typing (WikiWikiWeb)","url":"https://wiki.c2.com/?DynamicTyping"},{"id":427099,"name":"Weak And Strong Typing (WikiWikiWeb)","url":"https://wiki.c2.com/?WeakAndStrongTyping"}],"ordered_units":[{"id":1906,"name":"theory","url":"/courses/introduction_to_programming/lessons/types/theory_unit"}],"id":928,"slug":"types","state":"approved","name":"Типизация","course_order":180,"goal":"Знакомимся с идеей типизации. Ищем разницу между динамической и статической типизацией, а также разницу между сильной и слабой типизацией.","self_study":null,"theory_video_provider":"youtube","theory_video_uid":"1dwJvRw_h7A","theory":"## Транскрипт урока\n\nВ одном из прошлых уроков мы говорили об ошибках и как с ними справляться. Есть несколько видов ошибок, и я хочу напомнить об одном конкретном виде. Вот небольшой фрагмент того урока:\n\n---\n\nВзгляните на этот код:\n\n```javascript\nconst length = 12\nconst num = length(54)\n```\n\nСначала мы создали константу. Помните, что это как давать чему-то название: в нашем случае — числу 12 даётся название `length`. В следующей строке мы вызываем функцию `length` и передаём ей аргумент — число 54. Но подождите! `length` — это не функция! Это всего лишь число. Числа — это не функции, не ящики, которые производят какие-то действия. И JavaScript пожалуется именно на это:\n\n```bash\n→ node test.js\n/Users/rakhim/test.js:2\nconst num = length(-54);\n ^\n\nTypeError: length is not a function\n at Object.<anonymous> (/Users/rakhim/test.js:2:13)\n at Module._compile (module.js:571:32)\n at Object.Module._extensions..js (module.js:580:10)\n at Module.load (module.js:488:32)\n at tryModuleLoad (module.js:447:12)\n at Function.Module._load (module.js:439:3)\n at Module.runMain (module.js:605:10)\n at run (bootstrap_node.js:420:7)\n at startup (bootstrap_node.js:139:9)\n at bootstrap_node.js:535:3\n```\n\nЭто **Ошибка типизации**: тип объекта, который вы использовали, неверный. Интерпретатор JavaScript не скажет **чем что-то является**, но точно скажет **чем оно не является**. `length` — это не функция.\n\n> Ошибка типизации — это как просить кошку постирать бельё. Возможно, вы хотели попросить об этом вашего друга.\n\n---\n\nВ программировании \"типизация\" — это классификация информации. Это общий термин и разные языки программирования справляются с типизацией по-разному. Как вы уже знаете, JavaScript умеет отличать типы. Функция — это один тип, Число — другой, и вы не можете просто использовать число как функцию.\n\n`typeof` — это специальный оператор, который возвращает строку, в которой написан тип.\n\n```javascript\ntypeof 42 // 'number'\ntypeof 3.14 // 'number'\ntypeof NaN // 'number'\n\ntypeof 'Berry' // 'string'\ntypeof true // 'boolean'\ntypeof false // 'boolean'\n```\n\n42 и 3.14, очевидно, числа, несколько комбинаций букв в кавычках — строка, а true и false — булево значение. Всё это — типы в JavaScript — число, строка и булево значение.\n\nNaN означает — \"не число\", но тип NaN — это \"число\". Да, я знаю. Еще одна странность JavaScript. Такие правила в этом языке.\n\nТипизация полезна. Когда мы попытаемся запустить число, как будто это функция, JavaScript начнёт жаловаться и мы увидим ошибку и починим её. Если бы никакого обозначения типов в JavaScript не было, мы бы сталкивались либо с каким-нибудь аномальным поведением, либо с мистической ошибкой. Вместо чёткого \"length — это не функция\", мы бы видели что-то вроде \"I'm sorry Dave, I'm afraid I can't do that\".\n\nА что, если создать переменную, но не задать ей никакого значения? Какой в этом случае будет тип? Это ни число, ни строка, ничто... Потому что нет значения, правильно?\n\nJavaScript в этом случае кое-что делает в тайне от вас. Переменная без значения на самом деле имеет специальное значение — \"undefined\". И тип такой переменной называется \"undefined\".\n\n```javascript\nlet a\nconsole.log(a) // undefined\ntypeof a // 'undefined'\n```\n\nНапример, тип `number` имеет множество потенциальных значений: 1, 2, -10, 69000 и другие числа. А тип `undefined` только одно — `undefined`.\n\nКогда дело касается типизации в программировании, важно различать две концепции: динамическая против статической и слабая против сильной.\n\nЧтобы понимать разницу между динамической и статической типизацией, нам сначала нужно посмотреть как написанные программы становятся запущенными программами.\n\nКод, который вы пишете, обычно конвертируется в понятную для запуска компьютером форму. Этот процесс называется компиляцией, а промежуток времени, за который это происходит — \"стадией компиляции\" или compile time.\n\nПосле того, как компиляция закончена и программа запущена, начинается отсчёт времени, который называется \"стадией исполнения\" или run time.\n\nНекоторые языки проверяют типы и ищут ошибки типизации на стадии компиляции. У них статическая типизация.\n\nДругие языки проверяют типы и ищут ошибки типизации на стадии исполнения. Такая типизация — динамическая.\n\nИными словами: статическая типизация означает проверку типов перед запуском программы, динамическая — проверку типов, когда программа запущена.\n\nC#, C++, Java, Go — статически типизированные языки. Если в одном из этих языков вы создадите число и попытаетесь проводить с ним операции, как с функцией, вы получите ошибку во время компиляции, а программа не станет запускаться — она даже не дойдёт до этой стадии, потому что ошибка типизации будет обнаружена перед исполнением, в период компиляции.\n\nJavaScript, Ruby, PHP — динамически типизированные языки. Как вы видели раньше, если использовать неверную типизацию, ваша программа запустится, а ошибка обнаружится только когда будет исполняться конкретная строчка кода. Здесь типы проверяются в период исполнения.\n\nВообще-то, в JavaScript *обычно* нет никакой компиляции, но это тема другого урока.\n\nДинамическая типизация не хуже и не лучше статической. Оба способа имеют свои преимущества и недостатки. Динамически типизированные языки обычно проще изучать и писать на них программы, но, как вы можете представить, это потенциально увеличивает ошибки.\n\nТеперь давайте поговорим о слабой и сильной типизации. Посмотрите на этот JavaScript код:\n\n```javascript\n4 + '7' // '47'\n4 * '7' // 28\n2 + true // 3\nfalse - 3 // -3\n```\n\nМ-да… Это… Ок, что тут происходит? Сложение числа 4 со строкой \"7\" даёт нам строку \"47\". JavaScript конвертирует число 4 в строку \"4\" и конкатенирует две строки — склеивает их друг с другом. JavaScript просто берёт на себя ответственность предположить, что это то, что мы хотели. Глупо обвинять его — чего мы действительно хотели? Складывать число со строкой не имеет никакого смысла. Какой-нибудь другой язык, вроде Ruby или Python просто бы пожаловался и ничего не сделал.\n\nПроизведение числа 4 со строкой \"7\", это, как видите, 28, по мнению JavaScript. В этом случае он сконвертировал строку \"7\" в число 7 и произвёл обычное умножение.\n\nJavaScript постоянно так делает. Он знает о типах разных значений, но когда типы не соответствуют, он пытается предположить и сконвертировать один тип в другой, не предупреждая вас. Иногда это полезно, иногда мозгодробяще. Такое происходит потому что JavaScript — язык со слабой типизацией. У него есть представление о типах, но он типа \"это всего лишь игра, чего ты злишься?\"\n\nУ этой концепции нет ничего общего с динамической и статической типизацией, смысл которых — КОГДА проверять типы. Сильная против слабой — это НАСКОЛЬКО СЕРЬЁЗНО проверять типы.\n\nВы можете считать, что слабая — это нестрогая типизация, а сильная — это требовательная.\n\nВ отличие от динамичности-статичности, сила типизации это спектр. У PHP типизация немного сильнее. У Python ещё сильнее. И все они динамически типизированные языки.\n\nJavaScript делает множество неявных конвертаций, но он так же даёт нам инструменты, чтобы мы могли делать явные конвертации сами. Мы можем конвертировать строки в числа, числа в строки, булевы значения в строки и так далее:\n\n```javascript\n// Конвертация числа в строку\nString(44843) // '44843'\n\n// Конвертация строки в число\nNumber('590') // 590\nNumber('aaa!!') // NaN\n\n// Конвертация числа в булево значение\nBoolean(1) // true\nBoolean(0) // false\n\n// Конвертация булева значения в строку\nString(true) // 'true'\nString(false) // 'false'\n```\n\nМожно предположить, что неявная конверсия из типа в тип — не самая лучшая идея. Неявный, значит скрытый, а скрытый — значит трудно понимаемый и предрасположенный к ошибкам. Поведение программы становится менее очевидным. Вы пишете меньше кода, да, но код более хрупкий и менее понятный.\n\n## Дополнение к уроку\n\n### null\n\nВ JavaScript кроме `undefined` существует `null`. Оно означает, что «значение отсутствует». Например, если создать переменную, но не задавать ей значения, то у нее будет значение undefined:\n\n```javascript\nlet a\nconsole.log(a) // undefined\n```\n\nТут значения не оказалось ненамеренно. Видимо, просто еще не пришло время дать этой переменной значение.\n\n`null` нужен для явного, намеренного указания, что значения нет. Можно сказать `let a = null;`. Например, вы попросили пользователя ввести информацию, но он ничего не ввел. В таком случае уместно записать в результат `null`.\n\n`null`, в отличие от `undefined`, можно задавать вручную, передавать как аргумент в функцию и в целом использовать как любое другое явное значение.\n\n(`undefined` тоже можно задавать вручную, но никогда не нужно этого делать: это значение семантически создано только для того, чтобы его генерировал компьютер, а не программист).\n\nПри сравнении null и undefined нужно быть осторожным:\n\n```javascript\ntypeof null // \"object\" (не \"null\" по историческим причинам)\ntypeof undefined // \"undefined\"\nnull === undefined // false\n\nnull == undefined // true\nnull === null // true\nnull == null // true\n!null // true\n\nisNaN(1 + null) // false\nisNaN(1 + undefined) // true\n```\n\n### Сравнение\n\nВ этом курсе мы сравниваем данные, используя три знака равенства:\n\n```javascript\na === b\n12 === 12\n```\n\nЭто сравнение прямое: являются ли эти данные абсолютно идентичными?\n\nВ JavaScript есть расслабленное сравнение, с двумя знаками равенства. Оно показывает, что происходит внутри JavaScript, при сравнении значений разных типов:\n\n```javascript\n1 === '1' // false\n1 == '1' // true\n\ntrue === 1 // false\ntrue == 1 // true\n```\n\n\n\n## Выводы\n\n### Типизация в JavaScript\n\nJavaScript имеет представление о типах: числах, строках, функциях, логических значениях и так далее. `typeof` возвращает строку, в которой записан тип:\n\n```javascript\ntypeof 42 // 'number'\ntypeof 3.14 // 'number'\ntypeof NaN // 'number'\n\ntypeof 'Berry' // 'string'\ntypeof true // 'boolean'\ntypeof false // 'boolean'\n```\n\n`NaN` означает \"не число\", но тип этого значения — `number`.\n\nПеременная без значения имеет специальное значение `undefined`. Тип такой переменной — `undefined`:\n\n```javascript\nlet a\nconsole.log(a) // undefined\ntypeof a // 'undefined'\n```\n\n### Динамическая и статическая типизация\n\n\n\nКод конвертируется в другую форму, которую компьютер может запустить. Этот процесс называется компиляцией, а период времени, за который этот процесс происходит — **стадией компиляции** (compile time).\n\nПосле того, как компиляция закончена, запускается программа и период, пока она запущена, называется **стадией исполнения** (run time).\n\n**Статически типизированные** языки проверяют типы и ищут ошибки типизации на стадии компиляции.\n\n**Динамически типизированные** языки проверяют типы и ищут ошибки типизации на стадии исполнения.\n\nИными словами: статическое типизирование означает проверку типов перед запуском программы; динамическое — проверку типов пока программа запущена.\n\n### Слабая и сильная типизация\n\nJavaScript часто конвертирует типы автоматически:\n\n```javascript\n4 + '7' // '47'\n4 * '7' // 28\n2 + true // 3\nfalse - 3 // -3\n```\n\nJavaScript — это язык со слабой типизацией. У него есть представление о типах, но он расслаблено к ним относится и может оперировать значениями, можно сказать, произвольно. Чем сильнее система типизации, тем строже правила.\n\n\n\n### Явные конверсии в JavaScript\n\n```javascript\nNumber('590') // 590\nNumber('aaa!!') // NaN\n\nBoolean(1) // true\nBoolean(0) // false\n\nString(true) // 'true'\nString(false) // 'false'\n\nString(44843) // '44843'\n```\n"},"lessonMember":null,"courseMember":null,"course":{"start_lesson":{"exercise":null,"units":[{"id":1801,"name":"theory","url":"/courses/introduction_to_programming/lessons/intro/theory_unit"}],"links":[{"id":427047,"name":"Inside your computer - Bettina Bair","url":"https://www.youtube.com/watch?v=AkFi90lZmXA"},{"id":427048,"name":"Punch Card Programming - Computerphile","url":"https://www.youtube.com/watch?v=KG2M4ttzBnY"},{"id":427049,"name":"The Future of Computer Intelligence Is Everything but Artificial","url":"https://www.wired.com/2014/06/the-future-of-computer-intelligence-is-everything-but-artificial/"}],"ordered_units":[{"id":1801,"name":"theory","url":"/courses/introduction_to_programming/lessons/intro/theory_unit"}],"id":876,"slug":"intro","state":"approved","name":"Что такое компьютер?","course_order":10,"goal":"Первый урок посвящен знакомству с Тотой – главным персонажем Хекслета. Вместе с нашим героем отвечаем на простые, но важные вопросы: Что такое компьютер? Умный ли он? Говорит ли он на языке программирования?","self_study":null,"theory_video_provider":"youtube","theory_video_uid":"rrRZZ_3licM","theory":"## Транскрипт урока\n\nЭто Тота.\n\nТота - пещерный человек.\n\nОднажды он шёл по лесу и неожиданно перед ним из ниоткуда возник большой, шумный сферический объект, поблескивая и мерцая.\n\n\"Прямо как в Терминаторе\", - сказал бы Тота, если бы видел фильм Терминатор.\n\nОбъект быстро исчез, оставив на траве чёрный дымящийся ящик.\n\nТоту захватило любопытство, и он ждал, пока дым рассеется, чтобы изучить непонятную штуку.\n\nЭто была тяжёлая коробка с двумя кнопками сбоку, на одной из кнопок было написано Х, на другой О. Наверху была щель, а сбоку торчал рычаг. Как настоящий пещерный человек, Тота пытался щупать её, пинать, нюхать и валять по земле. Ящик определённо не был живым, но кнопки интриговали его.\n\nТота обнаружил интересное свойство: если нажать Х и О последовательно, а потом опустить рычаг, то на короткое время вначале загорится кнопка О, а потом Х.\n\nЯ вам говорил, что Тота был невероятно умным? Самым умным в своей пещере.\n\nОн решил нажать кнопки в том порядке, в котором они загорались, а потом снова опустить рычаг.\n\nТеперь отклик был другой — кнопки загорелись по новой схеме. Когда Тота ввел в коробку последнюю схему, ящик издал звук и изверг молнию, безумно напугал Тоту и поджёг стоящие впереди деревья. \n\nТеперь у Тоты было что-то подобное оружию. Он убил им много животных и часто наслаждался горячей пищей, сидя у костра.\n\nВскоре он открыл другие схемы: одна из них производила ненавистный Тоте звук, после другой выплевывался лист с какими-то пометками, а некоторые комбинации вообще ни к чему не приводили.\n\nОднажды Тота обнаружил ещё более продвинутую особенность этого прибора. Он хотел снова сделать костёр, но вместо того, чтобы просто нажать на рычаг один раз, он нажал и подержал его. После того, как он отпустил его несколько моментов спустя, пламени не возникло, но и Х и О стали мигать. Он отчаянно нажал О и мигание прекратилось. С того момента нажатия О и опускания рычага было достаточно, чтобы произвести огонь, намного проще и быстрее, чем раньше!\n\nОн понял, что натренировал этого зверя, точно так же, как однажды натренировал волчонка.\n\nТак что это за штука?\n\nКонечно, Тота называет её Бум-вум, но мы можем придумать что-то получше. Изначально можно подумать, что это какое-то чрезмерно усложнённое оружие. Но оно производит и другие странные вещи, вроде музыки... и даже печати. Оно не похоже на бытовой прибор, хотя, некоторые стиральные машины намного сложнее в эксплуатации.\n\nДавайте начнём с кнопок. Похоже машина \"понимает\" определённые комбинации и не понимает другие. Мы не знаем назначения кнопок и комбинации, поэтому я хочу назвать это \"кодом\", вроде \"я понятия не имею что это, но, наверное, это что-то значит\". Некоторые коды работают, некоторые — нет, так же как в речи некоторые звуки означают что-то, а другие — нет. \"Язык\", кажется, подходящее слово. Эта машина понимает определенный язык кодов.\n\nХорошо, как тогда мы назовём эту машину? Пониматель языка кода? \"Понимать\" звучит важно, но основная задача машины не в том, чтобы понимать, а в том, чтобы выдавать какой-то результат. Она понимает код - \"огненная вспышка\" и немедленно эту вспышку создаёт. Поэтому, можно назвать её... выполнитель языка кода? Она выполняет некоторые действия. \n\nТот, кто послал эту штуку из будущего в каменный век, возможно называл её иначе, но мы, определённо, называем эту машину компьютером. Именно такие машины принимают код и выполняют какие-то действия.\n\nВам может показаться, что это ужасный компьютер с ужасным кодом. Сегодня у нас есть магические устройства с фантастическими особенностями и языки программирования с кодами, которые легко читать, вроде этого:\n\n```javascript\nconst factorial = (n) => {\n const iter = (current, acc) => {\n if (current === 0) {\n return acc\n }\n return iter(current - 1, acc * current)\n }\n\n return iter(n, 1)\n}\n```\n\nКстати, в конце курса, вы сможете писать и понимать подобный код с лёгкостью.\n\nДа, современные компьютеры отличаются от тех, что были раньше. Но... не слишком. Мы еще не исследовали эту машину досконально, но, поверьте - по сути они одинаковы. Так же как это... сильно отличается от этого... оба объекта работают по одинаковому принципу и выполняют одинаковую функцию, в разной степени.\n\nПродолжая рассматривать эту странную машину, мы можем понять кое-что важное в компьютерах в целом: \n\nПервое: компьютер понимает определённый, строгий язык. Случайные нажатия не приводят к результату, работают только конкретные комбинации. Крошечная ошибка в схеме ломает всё. \n\nИ второе: компьютеры по-настоящему тупы.\n\nВозможно, вы подумаете, что последнее высказывание касается этого конкретного компьютера, странного и маломощного, но я говорю о компьютерах вообще. Они очень мощные, но одновременно тупые. Не сомневайтесь - всё, что они делают, это выполняют действия, которые мы им задаём. Никакой магии. Но, безусловно, для Тоты - это магия, так же как современные устройства кажутся нам магическими, если только мы не изучим программирование. К счастью, именно этим мы и собираемся заняться в этом курсе.\n\n## Выводы\n\n- Компьютер принимает код и выполняет действия\n- Компьютер понимает определённый язык кодов:\n - Некоторые коды работают\n - Некоторые коды не работают\n - В коде жёсткие правила \n- Компьютеры по существу не такие умные, как люди, они только выполняют наши указания. А указания для компьютеров выражаются в виде кода.\n- Все компьютеры фундаментально одинаковы. Примитивный, старый, маломощный компьютер и современный ноутбук используют одинаковые принципы и способны на одинаковые операции, в разной степени.\n"},"id":143,"slug":"introduction_to_programming","challenges_count":0,"name":"Введение в программирование","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"free","description":"В этом курсе вы изучите основы программирования. Вы узнаете больше о языках программирования, их синтаксисе и правильном выборе языка для обучения. В итоге вы научитесь использовать функции, условия и циклы, а также напишите свои первые программы на JavaScript. Знания из этого курса пригодятся, если вы решите заниматься программированием и познакомиться с ключевыми принципами написания хорошего кода.","kind":"sandbox","updated_at":"2026-02-06T11:25:43.725Z","language":"javascript","duration_cache":18000,"skills":["Использовать основные языковые конструкции: условия, циклы, функции и другие","Разделять код на модули для повторного использования и отсутствия конфликта имён","Понимать ключевые концепции для написания хорошего кода, такие как чистота и детерминированность"],"keywords":["основы javascript","чистый код","алгоритмы","логика"],"lessons_count":20,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTI1NzIsInB1ciI6ImJsb2JfaWQifX0=--3444a6a2b32ba0a1b370387ae75d0c63f10ad54f/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJwbmciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--6067466c2912ca31a17eddee04b8cf2a38c6ad17/image.png"},"recommendedLandings":[],"lessonMemberUnit":null,"accessToLearnUnitExists":true,"accessToCourseExists":true},"url":"/courses/introduction_to_programming/lessons/types/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">Введение в программирование</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":"Введение в программирование"},"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 style="margin-bottom:var(--mantine-spacing-xl)" class=""><div class="ratio ratio-16x9"><iframe width="100%" height="auto" src="//www.youtube.com/embed/1dwJvRw_h7A" loading="lazy" allowFullScreen="" title="video"></iframe></div></div><div class="paywalled m_d08caa0 mantine-Typography-root"><h2 id="heading-2-1">Транскрипт урока</h2>
<p>В одном из прошлых уроков мы говорили об ошибках и как с ними справляться. Есть несколько видов ошибок, и я хочу напомнить об одном конкретном виде. Вот небольшой фрагмент того урока:</p>
<hr/>
<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 length = 12
const num = length(54)</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>Сначала мы создали константу. Помните, что это как давать чему-то название: в нашем случае — числу 12 даётся название <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">length</code>. В следующей строке мы вызываем функцию <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">length</code> и передаём ей аргумент — число 54. Но подождите! <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">length</code> — это не функция! Это всего лишь число. Числа — это не функции, не ящики, которые производят какие-то действия. И JavaScript пожалуется именно на это:</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">→ node test.js
/Users/rakhim/test.js:2
const num = length(-54);
^
TypeError: length is not a function
at Object.<anonymous> (/Users/rakhim/test.js:2:13)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.runMain (module.js:605:10)
at run (bootstrap_node.js:420:7)
at startup (bootstrap_node.js:139:9)
at bootstrap_node.js:535:3</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Это <strong>Ошибка типизации</strong>: тип объекта, который вы использовали, неверный. Интерпретатор JavaScript не скажет <strong>чем что-то является</strong>, но точно скажет <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">length</code> — это не функция.</p>
<blockquote>
<p>Ошибка типизации — это как просить кошку постирать бельё. Возможно, вы хотели попросить об этом вашего друга.</p>
</blockquote>
<hr/>
<p>В программировании "типизация" — это классификация информации. Это общий термин и разные языки программирования справляются с типизацией по-разному. Как вы уже знаете, JavaScript умеет отличать типы. Функция — это один тип, Число — другой, и вы не можете просто использовать число как функцию.</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">typeof</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">typeof 42 // 'number'
typeof 3.14 // 'number'
typeof NaN // 'number'
typeof 'Berry' // 'string'
typeof true // 'boolean'
typeof false // 'boolean'</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>42 и 3.14, очевидно, числа, несколько комбинаций букв в кавычках — строка, а true и false — булево значение. Всё это — типы в JavaScript — число, строка и булево значение.</p>
<p>NaN означает — "не число", но тип NaN — это "число". Да, я знаю. Еще одна странность JavaScript. Такие правила в этом языке.</p>
<p>Типизация полезна. Когда мы попытаемся запустить число, как будто это функция, JavaScript начнёт жаловаться и мы увидим ошибку и починим её. Если бы никакого обозначения типов в JavaScript не было, мы бы сталкивались либо с каким-нибудь аномальным поведением, либо с мистической ошибкой. Вместо чёткого "length — это не функция", мы бы видели что-то вроде "I'm sorry Dave, I'm afraid I can't do that".</p>
<p>А что, если создать переменную, но не задать ей никакого значения? Какой в этом случае будет тип? Это ни число, ни строка, ничто... Потому что нет значения, правильно?</p>
<p>JavaScript в этом случае кое-что делает в тайне от вас. Переменная без значения на самом деле имеет специальное значение — "undefined". И тип такой переменной называется "undefined".</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">let a
console.log(a) // undefined
typeof a // 'undefined'</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">number</code> имеет множество потенциальных значений: 1, 2, -10, 69000 и другие числа. А тип <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">undefined</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">undefined</code>.</p>
<p>Когда дело касается типизации в программировании, важно различать две концепции: динамическая против статической и слабая против сильной.</p>
<p>Чтобы понимать разницу между динамической и статической типизацией, нам сначала нужно посмотреть как написанные программы становятся запущенными программами.</p>
<p>Код, который вы пишете, обычно конвертируется в понятную для запуска компьютером форму. Этот процесс называется компиляцией, а промежуток времени, за который это происходит — "стадией компиляции" или compile time.</p>
<p>После того, как компиляция закончена и программа запущена, начинается отсчёт времени, который называется "стадией исполнения" или run time.</p>
<p>Некоторые языки проверяют типы и ищут ошибки типизации на стадии компиляции. У них статическая типизация.</p>
<p>Другие языки проверяют типы и ищут ошибки типизации на стадии исполнения. Такая типизация — динамическая.</p>
<p>Иными словами: статическая типизация означает проверку типов перед запуском программы, динамическая — проверку типов, когда программа запущена.</p>
<p>C#, C++, Java, Go — статически типизированные языки. Если в одном из этих языков вы создадите число и попытаетесь проводить с ним операции, как с функцией, вы получите ошибку во время компиляции, а программа не станет запускаться — она даже не дойдёт до этой стадии, потому что ошибка типизации будет обнаружена перед исполнением, в период компиляции.</p>
<p>JavaScript, Ruby, PHP — динамически типизированные языки. Как вы видели раньше, если использовать неверную типизацию, ваша программа запустится, а ошибка обнаружится только когда будет исполняться конкретная строчка кода. Здесь типы проверяются в период исполнения.</p>
<p>Вообще-то, в JavaScript <em>обычно</em> нет никакой компиляции, но это тема другого урока.</p>
<p>Динамическая типизация не хуже и не лучше статической. Оба способа имеют свои преимущества и недостатки. Динамически типизированные языки обычно проще изучать и писать на них программы, но, как вы можете представить, это потенциально увеличивает ошибки.</p>
<p>Теперь давайте поговорим о слабой и сильной типизации. Посмотрите на этот JavaScript код:</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">4 + '7' // '47'
4 * '7' // 28
2 + true // 3
false - 3 // -3</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>М-да… Это… Ок, что тут происходит? Сложение числа 4 со строкой "7" даёт нам строку "47". JavaScript конвертирует число 4 в строку "4" и конкатенирует две строки — склеивает их друг с другом. JavaScript просто берёт на себя ответственность предположить, что это то, что мы хотели. Глупо обвинять его — чего мы действительно хотели? Складывать число со строкой не имеет никакого смысла. Какой-нибудь другой язык, вроде Ruby или Python просто бы пожаловался и ничего не сделал.</p>
<p>Произведение числа 4 со строкой "7", это, как видите, 28, по мнению JavaScript. В этом случае он сконвертировал строку "7" в число 7 и произвёл обычное умножение.</p>
<p>JavaScript постоянно так делает. Он знает о типах разных значений, но когда типы не соответствуют, он пытается предположить и сконвертировать один тип в другой, не предупреждая вас. Иногда это полезно, иногда мозгодробяще. Такое происходит потому что JavaScript — язык со слабой типизацией. У него есть представление о типах, но он типа "это всего лишь игра, чего ты злишься?"</p>
<p>У этой концепции нет ничего общего с динамической и статической типизацией, смысл которых — КОГДА проверять типы. Сильная против слабой — это НАСКОЛЬКО СЕРЬЁЗНО проверять типы.</p>
<p>Вы можете считать, что слабая — это нестрогая типизация, а сильная — это требовательная.</p>
<p>В отличие от динамичности-статичности, сила типизации это спектр. У PHP типизация немного сильнее. У Python ещё сильнее. И все они динамически типизированные языки.</p>
<p>JavaScript делает множество неявных конвертаций, но он так же даёт нам инструменты, чтобы мы могли делать явные конвертации сами. Мы можем конвертировать строки в числа, числа в строки, булевы значения в строки и так далее:</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">// Конвертация числа в строку
String(44843) // '44843'
// Конвертация строки в число
Number('590') // 590
Number('aaa!!') // NaN
// Конвертация числа в булево значение
Boolean(1) // true
Boolean(0) // false
// Конвертация булева значения в строку
String(true) // 'true'
String(false) // 'false'</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>
<h2 id="heading-2-2">Дополнение к уроку</h2>
<h3 id="heading-3-3">null</h3>
<p>В JavaScript кроме <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">undefined</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">null</code>. Оно означает, что «значение отсутствует». Например, если создать переменную, но не задавать ей значения, то у нее будет значение undefined:</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">let a
console.log(a) // undefined</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><code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">null</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">let a = null;</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">null</code>.</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">null</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">undefined</code>, можно задавать вручную, передавать как аргумент в функцию и в целом использовать как любое другое явное значение.</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">undefined</code> тоже можно задавать вручную, но никогда не нужно этого делать: это значение семантически создано только для того, чтобы его генерировал компьютер, а не программист).</p>
<p>При сравнении null и undefined нужно быть осторожным:</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">typeof null // "object" (не "null" по историческим причинам)
typeof undefined // "undefined"
null === undefined // false
null == undefined // true
null === null // true
null == null // true
!null // true
isNaN(1 + null) // false
isNaN(1 + undefined) // true</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>
<h3 id="heading-3-4">Сравнение</h3>
<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">a === b
12 === 12</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>В JavaScript есть расслабленное сравнение, с двумя знаками равенства. Оно показывает, что происходит внутри JavaScript, при сравнении значений разных типов:</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">1 === '1' // false
1 == '1' // true
true === 1 // false
true == 1 // true</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>
<h2 id="heading-2-5">Выводы</h2>
<h3 id="heading-3-6">Типизация в JavaScript</h3>
<p>JavaScript имеет представление о типах: числах, строках, функциях, логических значениях и так далее. <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">typeof</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">typeof 42 // 'number'
typeof 3.14 // 'number'
typeof NaN // 'number'
typeof 'Berry' // 'string'
typeof true // 'boolean'
typeof false // 'boolean'</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">NaN</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">number</code>.</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">undefined</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">undefined</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">let a
console.log(a) // undefined
typeof a // 'undefined'</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>
<h3 id="heading-3-7">Динамическая и статическая типизация</h3>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTI1ODIsInB1ciI6ImJsb2JfaWQifX0=--76062552a48d319b5dd6c21a41421335f0af30ed/dynamic_vs_static.png" alt="Динамическая и статичекая типизация" loading="lazy"/></p>
<p>Код конвертируется в другую форму, которую компьютер может запустить. Этот процесс называется компиляцией, а период времени, за который этот процесс происходит — <strong>стадией компиляции</strong> (compile time).</p>
<p>После того, как компиляция закончена, запускается программа и период, пока она запущена, называется <strong>стадией исполнения</strong> (run time).</p>
<p><strong>Статически типизированные</strong> языки проверяют типы и ищут ошибки типизации на стадии компиляции.</p>
<p><strong>Динамически типизированные</strong> языки проверяют типы и ищут ошибки типизации на стадии исполнения.</p>
<p>Иными словами: статическое типизирование означает проверку типов перед запуском программы; динамическое — проверку типов пока программа запущена.</p>
<h3 id="heading-3-8">Слабая и сильная типизация</h3>
<p>JavaScript часто конвертирует типы автоматически:</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">4 + '7' // '47'
4 * '7' // 28
2 + true // 3
false - 3 // -3</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>JavaScript — это язык со слабой типизацией. У него есть представление о типах, но он расслаблено к ним относится и может оперировать значениями, можно сказать, произвольно. Чем сильнее система типизации, тем строже правила.</p>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTI1ODMsInB1ciI6ImJsb2JfaWQifX0=--98778af107f49a12890a09628a0532ccf1a562bb/weak_strong_typing.png" alt="Слабая и сильная типизация" loading="lazy"/></p>
<h3 id="heading-3-9">Явные конверсии в JavaScript</h3>
<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">Number('590') // 590
Number('aaa!!') // NaN
Boolean(1) // true
Boolean(0) // false
String(true) // 'true'
String(false) // 'false'
String(44843) // '44843'</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div></div></div></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/introduction_to_programming/lessons/types/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 / 20</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/introduction_to_programming/lessons/types/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>