Важное примечание
Изначально в начале конспекта и урока речь шла о глобальном и локальном окружении, но объяснялась фактически глобальная и локальная область видимости. В видео эта тема до сих пор называется «глобальное и локальное окружение», текстовая версия урока исправлена.
Прежде, чем приступить к уроку, разберёмся с терминологией:
- Область видимости (scope) — это широкое понятие, означающее, грубо говоря, «интерпретатор в разных местах кода видит разные штуки».
- Лексическая область видимости (Lexical scoping) — это конкретный механизм, одно из правил для области видимости. Этот механизм применяется в JavaScript и большинстве других языков. Под лексической областью видимости можно понимать просто механизм поиска значений: смотрим в текущей области, если нет — идём на уровень выше, и так далее. Слово «лексический» означает, что видимость задаётся исключительно текстом программы, исходным кодом. То есть можно смотреть на программу, не запуская её, и понять область видимости в любой точке. В других языках может быть не лексический механизм, а динамический (dynamic scope).
- Окружение (environment) - это область памяти, где записываются идентификаторы и значения из областей видимости. Не путайте с окружением, как средой исполнения.
Путаница возникает ещё потому, что в разделе про Область видимости мы смотрим на примеры, которые работают по правилу «лексическая область видимости». От этого никуда не деться, так как язык JavaScript работает именно так.
Транскрипт урока
Часть I. Окружение
Давайте поговорим об окружении. Наша планета огромна, но мы все делим её. Если вы построите химический завод, неплохо бы изолировать его от окружающего мира, чтобы то, что в нём происходит оставалось внутри. Вы можете сказать, что в этом здании своё окружение, микроклимат, изолированный от внешней окружающей среды. В программировании такая изоляция называется областью видимости.
Ваша программа имеет подобную структуру по похожим причинам. То, что вы создаёте снаружи — снаружи функций, инструкций if, циклов и других блоков кода — находится во внешней, глобальной области видимости.
Константа age , функция multiplier и переменная result — имеют "глобальную область видимости". Область видимости означает "область, где компоненты доступны".
Внутри функции multiplier есть константа x. Поскольку она внутри блока кода, это локальная константа, а не глобальная. Она видна только внутри этой функции, но не снаружи. У неё локальная область видимости.
В функции multiplier есть ещё один компонент из локальной области видимости — аргумент num. Он не задан так же чётко, как константы или переменные, но ведёт себя почти как локальная переменная.
У нас нет доступа к x снаружи, как будто её там не существует:
console.log вызывается в глобальном окружении, а x не задан в этом глобальном окружении. Поэтому мы получаем Reference Error.
Мы можем задать x глобально:
Теперь существует глобальный x и его значение было выведено на экран, но локальный x внутри функции multiplier по-прежнему виден только внутри этой функции. Эти два x не имеют ничего общего друг с другом, они находятся в разных областях видимости. Они не схлопываются в одно целое, несмотря на то, что у них одно и то же имя.
Любой блок кода между фигурными скобками имеет локальную область видимости. Вот пример с блоком if:
То же работает для циклов while и for.
Ок, локальное не доступно снаружи. Но глобальное доступно везде. Даже внутри чего-то? Да!
Эта глобальная переменная a изменилась внутри функции changer. Функция вообще выполняет что-то только когда её вызывают, а не когда её определяют, так что вначале a это 0, но после того как вызывается changer, a становится 1.
Хоть это и заманчиво всё помещать в глобальную область видимости и забыть о сложностях областей видимости — это ужасная практика. Глобальные переменные делают ваш код невероятно хрупким. В таком случае что угодно может сломать что угодно. Поэтому избегайте глобальной области видимости, храните вещи там, где им место.
Часть II. Лексическая область видимости
Взгляните на эту программу:
Функция multiplier возвращает произведение a и b. a задано внутри, а b — нет.
Пытаясь решить умножение a * b, JavaScript ищет значения a и b. Он начинает искать локально и выходит наружу, по одной области видимости за шаг, пока он не найдёт то, что ему нужно или пока не поймёт, что это невозможно найти.
Поэтому в данном примере JavaScript начинает с поиска a внутри локальной области видимости — внутри функции multiplier. Он находит значение сразу и переходит к b. Невозможно найти значение b в локальной области видимости, поэтому он переходит к наружной области. Тут он находит b — это 10. a * b превращается в 5 * 10, а затем в 50.
Весь этот кусок кода мог бы быть внутри другой функции, и ещё внутри другой функции. И если бы b не нашлась здесь, JavaScript продолжил бы искать b за пределами функции, слой за слоем.
Заметьте, что a = 7 не затронула вычисления, a была найдена внутри, поэтому внешняя a не сыграла роли.
Этот механизм называется лексической областью видимости. Область видимости любого компонента определяется местом расположения этого компонента внутри кода. И вложенные блоки имеют доступ к их внешним областям видимости.
Часть III. Замыкания
Большинство языков программирования имеют что-то вроде области видимости или окружения, и этот механизм позволяет существовать замыканиям. Замыкание — это всего лишь модное название функции, которая запоминает внешние штуки, используемые внутри.
Перед тем, как мы продолжим, давайте вспомним, как функции создаются и используются:
f — довольно бесполезная функция, она всегда возвращает 0. Весь этот набор состоит из двух частей: константы и самой функции.
Важно помнить, что эти два компонента раздельны. Первый — константа с именем f. Её значение могло бы быть числом или строкой. Но в данном случае её значение — функция.
Мы использовали аналогию в предыдущих уроках: константы как листы бумаги — имя на одной стороне, значение на другой. Следовательно, f — лист бумаги с f на одной стороне и описанием запускаемой функции на другой.
Когда вы вызываете эту функцию, вот так:
… создаётся новый ящик, основываясь на описании на этом листе бумаги.
Ок, вернёмся к замыканиям. Рассмотрим следующий код:
Функция createPrint создаёт константу name и затем функцию с именем printName. Обе они локальные для функции createPrint, и доступны только внутри createPrint.
У самой printName нет локальных компонентов, но у неё есть доступ к области видимости, где она сама находится, внешней области, где задана константа name.
Затем функция createPrint возвращает функцию printName. Помните, определения функций — это описания запущенных функций, просто фрагменты информации, как числа или строки. Поэтому мы можем вернуть определение функции, как мы возвращаем число.
Во внешней области видимости мы создаём константу myPrint и задаём ей значение, которое возвращает вызов функции createPrint(). Этот вызов возвращает функцию, так что теперь myPrint — это функция. Вызовите её, и на экран выведется "King".
Тут есть странная штука: эта константа name была создана внутри функции createPrint. Функция была вызвана и исполнена. Как мы знаем, когда функция заканчивает работу, она больше не существует. Этот магический ящик исчезает со всеми своими внутренностями.
НО он возвратил другую функцию, и уже она как-то запомнила константу name. Поэтому когда мы вызывали myPrint(), она вывела "King" — запомненное значение, при том, что область видимости, где оно было задано больше не существует.
Функция, которая была возвращена из createPrint, называется замыканием. Замыкание — это сочетание функции и окружения, где она была задана. Функция "замкнула" в себе некоторую информацию из области видимости.
Это может выглядеть как JavaScript-фокус, но замыкания, когда их используют разумно, могут сделать код приятней, чище и проще для чтения. И сама идея возврата функций тем же способом, которым можно возвращать числа и строки, даёт больше возможностей и гибкости.
Вы заметите, как часто эти идеи используются в программировании, и мы рассмотрим их мощь в следующих курсах.
Выводы
-
Область видимости (scope) компонентов — это местоположение, где эти компоненты доступны.
- Компоненты, созданные снаружи функций, инструкций с if, циклов и так далее, находятся в глобальной области видимости
- Фигурные скобки { } задают новую локальную область видимости
Глобальная против локальной
Локальные константы и переменные не видимы снаружи их области видимости:
Но если x представлен глобально, то он доступен:
Возможен доступ к внешней области видимости:
Функция фактически производит что-то, только когда она вызывается, а не задаётся, поэтому изначально a это 0, но после того, как вызвана changer, a становится 1.
Лексическая область видимости
JavaScript пытается найти значение в текущем окружении. Но значение не находится и JavaScript выходит наружу, на один уровень за попытку, пока не найдёт значение или не поймет, что значение невозможно найти.
Здесь, в выражении a * b , функция multiplier использует локальную a (потому что она обнаружена локально), и наружную b (потому что локально b найдена не была).
Замыкания
myPrint — это функция, которая была возвращена createPrint. Несмотря на то, что вызов createPrint окончен и константы name больше не существует, значение запомнено в myPrint.
Это замыкание: сочетание функции и окружения, где она была заявлена.
<!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:19:18 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="LH_VzKWRFmU7324yjysreWnZUZJ0pO20C8bpY6NKWorDrh77V--7BY2cSqqDJNsOqdB8OHyTExa2JnM38U295A";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/env/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/env/theory_unit">
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="EM_7MbX6nIViQXPcP3uWc9l5KLkdqBc9soi8T_sJ4Tn_HjAGR4Qx5dQCV0QzdGYEGXAFExWf6Z8PaCYbqQ4GVw" />
<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:19:18.080Z","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":"DvzhljweSq_1hTWgZDTiU43BQiQwUwyXFHWD-JD4IunhLSqhzmDnz0PGEThoOxIkTchvjjhk8jWplRmswv_Fhw","topics":[{"id":17988,"title":"Блиииин, уже 5 часов сижу над этим заданием! Принципиально не хочу смотреть решение. В общем, написал такой код\n\n`// removed`\n\nВ общем - Я написал функцию-счетчик, которая определяет , сколько букв в строке (функция **\"schet\"**) .Далее я написал функцию **\"g\"** - которая сравнивает буквы Заглавные и строчные. Далее я написал цикл , где с помощью функции **schet** цикл сравнивал каждую букву строки в обратном порядке и в случае если буква заглавная , то в **result** прибавлялось +1 ,а если буква строчная, то прибавлялось +0.... но в этом месте функция работает некорректно и выдает неправельные результаты... хотя по отдельности , каждая часть кода работает как надо(будь то счетчик букв или определение заглавной буквы). Я уже отчаялся. Я конечно понимаю ,что мой код малочитабельный, но я надеюсь на помощь!!","plain_title":"Блиииин, уже 5 часов сижу над этим заданием! Принципиально не хочу смотреть решение. В общем, написал такой код // removed В общем - Я написал функцию-счетчик, которая определяет , сколько букв в строке (функция \"schet\") .Далее я написал функцию \"g\" - которая сравнивает буквы Заглавные и строчные. Далее я написал цикл , где с помощью функции schet цикл сравнивал каждую букву строки в обратном порядке и в случае если буква заглавная , то в result прибавлялось +1 ,а если буква строчная, то прибавлялось +0.... но в этом месте функция работает некорректно и выдает неправельные результаты... хотя по отдельности , каждая часть кода работает как надо(будь то счетчик букв или определение заглавной буквы). Я уже отчаялся. Я конечно понимаю ,что мой код малочитабельный, но я надеюсь на помощь!! ","creator":{"public_name":"Александр Чеботарёв","id":186615,"is_tutor":false},"comments":[{"creator":{"public_name":"Александр Чеботарёв","id":186615,"is_tutor":false},"id":37950,"body":"Это просто взрыв мозга! Было не легко, особенно в той части , где надо было дописать код функции , которая находит количество заглавных букв в строке. Я не использовал уже готовые функции, а написал все с нуля (просто захотелось проверить себя). Убил весь вчерашний вечер и сегодняшнее утро на это... но я это сделал! Уххх, как это классно! ","topic_id":17988},{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":37989,"body":"> Убил весь вчерашний вечер и сегодняшнее утро на это... но я это сделал!\n\nНе убили, а плодотворно провели время! :)\n\n> Уххх, как это классно!\n\n:))","topic_id":17988}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Окружение","entity_url":null,"active":true}},{"id":20084,"title":"Ничего же непонятно. Почему так много стрелок? Можете, пожалуйста, расписать функцию по аналогии с ES5 синтаксисом?\nИ почему так много скобок в конце вызова функции? ( . )( . )\n\n```\nЧто будет выведено на экран?\n\nconst x = 7;\nconst f = (x) => () => () => x;\nconsole.log(f(10)()());\n```","plain_title":"Ничего же непонятно. Почему так много стрелок? Можете, пожалуйста, расписать функцию по аналогии с ES5 синтаксисом? И почему так много скобок в конце вызова функции? ( . )( . ) Что будет выведено на экран? const x = 7; const f = (x) => () => () => x; console.log(f(10)()()); ","creator":{"public_name":"Pavel Sokolov","id":191547,"is_tutor":false},"comments":[{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":42590,"body":"Кстати, здесь вы можете смотреть, как код, написанный на новом синтаксисе, выглядел бы в старом формате: https://babeljs.io/repl","topic_id":20084},{"creator":{"public_name":"Pavel Sokolov","id":191547,"is_tutor":false},"id":42556,"body":"Круто, спасибо за разъяснение! \nЯ то пытался вложить функции друг в друга без **return**a, вот и не получалось.","topic_id":20084},{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":42545,"body":"Добрый день!\n\n> Можете, пожалуйста, расписать функцию по аналогии с ES5 синтаксисом?\n\n```javascript\nconst f = function(x) {\n return function() {\n return function() {\n return x;\n }\n }\n}\n```\n\n> И почему так много скобок в конце вызова функции? ( . )( . )\n\nПотому что несколько вложенных друг в друга функций (как матрёшка), вызываем одну - результатом получем другую и следом её вызываем и т.д. пока не дойдём до последней функции, вызов которой возвращает значение `x`.","topic_id":20084}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Окружение","entity_url":null,"active":true}},{"id":20895,"title":"Добрый день.\nПопробовал решить данное задание, но к сожалению выдает ошибку. Попробовал данный код в песочнице, вроде отрабатывает. Подскажите в чем ошибка:\n`//removed`","plain_title":"Добрый день. Попробовал решить данное задание, но к сожалению выдает ошибку. Попробовал данный код в песочнице, вроде отрабатывает. Подскажите в чем ошибка: //removed ","creator":{"public_name":"Igor Morozov","id":190815,"is_tutor":false},"comments":[{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":44183,"body":"Приветствую!\n\n> Попробовал решить данное задание, но к сожалению выдает ошибку. \n> Подскажите в чем ошибка:\n\nОшибка обычно прямо или косвенно обозначается в выводе тестов? Вы его пробовали анализировать?","topic_id":20895}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Окружение","entity_url":null,"active":true}},{"id":36476,"title":"Моя дурная голова не может сообразить, почему не запускается https://ru.hexlet.io/code_reviews/193457.\n\nВидимо при построении функции bigLettersCount я ошибся в задании условия цикла - при проверке на repl.it количество заглавных букв всегда равно 0. \nТакое ощущение, что до \"result = result + 1\" никогда не доходит, т.к. ниодно из условий не выполняется. Получается у меня ошибка в сравнении строк и определении наличия пробела?\nНо как ее исправить я не пойму, вроде все верно.","plain_title":"Моя дурная голова не может сообразить, почему не запускается https://ru.hexlet.io/code_reviews/193457. Видимо при построении функции bigLettersCount я ошибся в задании условия цикла - при проверке на repl.it количество заглавных букв всегда равно 0. Такое ощущение, что до \"result = result + 1\" никогда не доходит, т.к. ниодно из условий не выполняется. Получается у меня ошибка в сравнении строк и определении наличия пробела? Но как ее исправить я не пойму, вроде все верно. ","creator":{"public_name":"Aleksey Aleksey","id":259083,"is_tutor":false},"comments":[{"creator":{"public_name":"Дмитрий Темин","id":202664,"is_tutor":false},"id":80362,"body":"`copyStr[a] === str[a] || a === ' '`\nВаш цикл работатает пока это утверждение верно. На незаглавной букве всё заканчивается.","topic_id":36476},{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":80527,"body":"**Aleksey Tagaev**, приветствую!\n\nПроблема в том, что, если условие не выполняется, цикл завершает свою работу, а нужно что бы он независимо ни от чего обошел все символы строки. Данное условное выражение нужно использовать внутри цикла в инструкции if. Таким образом цикл пройдётся по всем символам строки, а при выполнении условия к переменной result будет добавляться единица.","topic_id":36476},{"creator":{"public_name":"Aleksey Aleksey","id":259083,"is_tutor":false},"id":80319,"body":"Избавился от зацикливания, теперь образовалась проблема: bigLettersCount почему-то работает неправильно - после первого не заглавного символа счетчик останавливается и не видит последующие заглавные символы: https://ru.hexlet.io/code_reviews/197074","topic_id":36476},{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":79712,"body":"**Aleksey Tagaev**, приветствую!\n\nДело в том, что в коде происходит зацикливание. Проверьте, срабатывают ли условия выхода из циклов. Возьмите простую строку и проверьте работу функции bigLettersCount. Например, проанализируйте такой вызов bigLettersCount('AA');","topic_id":36476},{"creator":{"public_name":"Дмитрий Темин","id":202664,"is_tutor":false},"id":79620,"body":"Привет! Можно на любом этапе проверить какие значения принимают переменные использовав `concole.log`. Тогда станет ясно в какой момент что-то пошло не так. Например вот так:\n```\n while (a < length(str)) { // условие - \"а\" меньше длины строки\n for (; copyStr[a] === str[a] || a === ' '; a = a + 1) { // условие цикла - символ скопированной строки равен символу исходной строки, или символ пробел\n result = result + 1;\n console.log(a, result)\n }\n return result;\n }\n\n```\nА вообще можно обойтись и одним циклом.","topic_id":36476}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Окружение","entity_url":null,"active":true}},{"id":30160,"title":"Не понимаю, зачем переводить строку в верхний регистр, если мне нужно просто посчитать количество символов в верхнем регистре. Видимо, я совсем дуб","plain_title":"Не понимаю, зачем переводить строку в верхний регистр, если мне нужно просто посчитать количество символов в верхнем регистре. Видимо, я совсем дуб ","creator":{"public_name":"Amanzhol Umurzakov","id":237350,"is_tutor":false},"comments":[{"creator":{"public_name":"Игорь Седнев","id":231634,"is_tutor":false},"id":65365,"body":"Для того чтобы посчитать символы в верхнем регистре их сначала нужно отобрать, в ридми есть подсказка как проверить находится ли символ в верхнем регистре. ","topic_id":30160},{"creator":{"public_name":"Сергей К.","id":5174,"is_tutor":false},"id":65399,"body":"**Amanzhol**, функция `toUpperCase` может принимать на вход как строку так и отдельный символ. Выбирайте тот способ, который необходим для решения. Воспользуйтесь подсказкой из условия задачи, о которой говорит Игорь.","topic_id":30160},{"creator":{"public_name":"Сергей К.","id":5174,"is_tutor":false},"id":65438,"body":"Отлично!","topic_id":30160},{"creator":{"public_name":"Amanzhol Umurzakov","id":237350,"is_tutor":false},"id":65425,"body":"я уже разобрался, но не нашел, как удалить комментарий) Все равно спасибо)","topic_id":30160},{"creator":{"public_name":"Amanzhol Umurzakov","id":237350,"is_tutor":false},"id":65427,"body":"я уже разобрался, а шестеренку, через которую можно удалить комментарий увидел только сейчас) Но все равно спасибо)","topic_id":30160}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Окружение","entity_url":null,"active":true}},{"id":39611,"title":"https://ru.hexlet.io/code_reviews/231405\nНемного не понял момент связанный с символом пробела, судя по описанию задания я подумал, что именно я должен считать пробел, как заглавный символ(сейчас уже понял, что довольно не логично было), но в решении учителя такой проверки не было. Я правильно понял, что вне зависимости от регистра проблем всегда будет равен сам себе, так? И получается я просто лишнее условие вписал в цикл?","plain_title":"https://ru.hexlet.io/code_reviews/231405 Немного не понял момент связанный с символом пробела, судя по описанию задания я подумал, что именно я должен считать пробел, как заглавный символ(сейчас уже понял, что довольно не логично было), но в решении учителя такой проверки не было. Я правильно понял, что вне зависимости от регистра проблем всегда будет равен сам себе, так? И получается я просто лишнее условие вписал в цикл? ","creator":{"public_name":"Вадим Бодянский","id":270578,"is_tutor":false},"comments":[{"creator":{"public_name":"Roman Kozlov","id":231814,"is_tutor":false},"id":86761,"body":"Вадим, приветствую! \nДа, всё верно. В решении учителя производится подсчёт пробелов. Если к пробелу применить метод `toUpperCase` получим тот же самый пробел ;) \nВы можете попробовать проверить это, например, на ресурсе [repl.it](https://repl.it/).","topic_id":39611},{"creator":{"public_name":"Roman Kozlov","id":231814,"is_tutor":false},"id":89278,"body":"**spbtne**, добрый день! \nДа, решение учителя обрабатывает пробелы. В цикле проверяется каждый символ из строки, пробел, в том числе является символом. Попробуйте посмотреть, что выводится в консоль с помощью выражения: `console.log(' '.toUpperCase() === ' ');` \nДолжно стать понятно, как именно происходит подсчёт пробелов.","topic_id":39611},{"creator":{"public_name":"Nikita Tushin","id":276184,"is_tutor":false},"id":89177,"body":"**Roman Kozlov**, Роман, добрый день! Поддерживаю вопрос Вадима. В условии задачи есть пункт про подсчет пробелов, но в решении учителя подсчета нет, либо я вместе с Вадимом его не увидел. Можете уточнить есть в решении подсчет или нет?","topic_id":39611}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Окружение","entity_url":null,"active":true}},{"id":47366,"title":"Добрый)\nМоё решение имеет мало общего с решением ментора, но тест пройден\nhttps://ru.hexlet.io/code_reviews/315209\n\nВопрос:почему так? И правильно ли я понимаю, что при других вводных данных при проверке кода мой вариант не сработал бы?","plain_title":"Добрый) Моё решение имеет мало общего с решением ментора, но тест пройден https://ru.hexlet.io/code_reviews/315209 Вопрос:почему так? И правильно ли я понимаю, что при других вводных данных при проверке кода мой вариант не сработал бы? ","creator":{"public_name":"Надежда Аксенюк","id":290171,"is_tutor":false},"comments":[{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":102002,"body":"**Надежда Аксенюк**, приветствую.\n\nВаше решение, в общем-то и не прошло, если вы посмотрите вывод тестов, то увидите что там вывод ошибки. А открытое решение учителя - это баг, мы его исправляем. Так что вам стоит ещё поработать над кодом и добиться именно успешного выполнения тестов.","topic_id":47366},{"creator":{"public_name":"Надежда Аксенюк","id":290171,"is_tutor":false},"id":102380,"body":"Поэтому и написала)","topic_id":47366}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Окружение","entity_url":null,"active":true}},{"id":30628,"title":"Parsing error: 'import' and 'export' may only appear at the top level\n\nпочему линтер ругается на экспорты, которые прописаны в задании?\nhttps://ru.hexlet.io/code_reviews/135868","plain_title":"Parsing error: 'import' and 'export' may only appear at the top level почему линтер ругается на экспорты, которые прописаны в задании? ","creator":{"public_name":"Nikolay Polyanskiy","id":235303,"is_tutor":false},"comments":[{"creator":{"public_name":"Nikolay Polyanskiy","id":235303,"is_tutor":false},"id":66459,"body":"**Igor Zelenov**, сори, добавил ревью","topic_id":30628},{"creator":{"public_name":"Igor Zelenov","id":237430,"is_tutor":false},"id":66462,"body":"**Nikolay Polyanskiy**, Не нашел у вас закрывающей скобки `}` в первом блоке кода, возможно туда обратить внимание.","topic_id":30628},{"creator":{"public_name":"Igor Zelenov","id":237430,"is_tutor":false},"id":66450,"body":"**Nikolay Polyanskiy**, Добрый день! Без [ревью](https://help.hexlet.io/article/40-code-review) сложно сказать. Могу предположить, что вы писали код ниже этого блока: \n\n`// removed`\n\nТ.е. не между //BEGIN и //END","topic_id":30628}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Окружение","entity_url":null,"active":true}},{"id":42392,"title":"Здравствуйте!\nПомогите разобраться с функцией bigLettersCount. Как сделать так, чтобы цикл не прерывался, пока не будет проверен каждый символ в строке. Я понимаю, что ошибка в блоке с if, но не совсем ясно, каким образом увеличивать result в случае, когда символ в верхнем регистре.\nhttps://ru.hexlet.io/code_reviews/259800","plain_title":"Здравствуйте! Помогите разобраться с функцией bigLettersCount. Как сделать так, чтобы цикл не прерывался, пока не будет проверен каждый символ в строке. Я понимаю, что ошибка в блоке с if, но не совсем ясно, каким образом увеличивать result в случае, когда символ в верхнем регистре. https://ru.hexlet.io/code_reviews/259800 ","creator":{"public_name":"Виолетта Сувви","id":272158,"is_tutor":false},"comments":[{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":92321,"body":"Приветствую, Виолетта!\n\nДавайте разбираться.\n\n> Как сделать так, чтобы цикл не прерывался, пока не будет проверен каждый символ в строке. \n\nЦикл прерывается потому, что вы используете `return` внутри него. Вернуть результат ведь нужно в самом конце, верно? Попробуйте просто увеличивать `result`, если встречен символ в верхнем регистре.\n\nПоясните, пожалуйста, зачем вы делаете вот это:\n\n let newstr = str.toUpperCase();\n\nПопробуйте не создавать дополнительной переменной. Работайте непосредственно с входящей строкой `str`.\n\nВ текущем виде условие `str[i].toUpperCase() === newstr[i].toUpperCase()` всегда будет возвращать `true`. `newstr` ведь таже самая строка, только все буквы в ней большие. Подумайте, каким должно быть это условие? Вам нужно узнать, в верхнем ли регистре текущий символ в строке и увеличить `result`. ","topic_id":42392},{"creator":{"public_name":"Виолетта Сувви","id":272158,"is_tutor":false},"id":92382,"body":"**Роман Ашиков**, Разобралась. Спасибо большое!","topic_id":42392}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Окружение","entity_url":null,"active":true}},{"id":46292,"title":"Чет я уже несколько дней в этом задании копаюсь. \nверной ли я дорогой иду товарищи? - https://ru.hexlet.io/code_reviews/302244","plain_title":"Чет я уже несколько дней в этом задании копаюсь. верной ли я дорогой иду товарищи? - https://ru.hexlet.io/code_reviews/302244 ","creator":{"public_name":"Артем Артемьев","id":269101,"is_tutor":false},"comments":[{"creator":{"public_name":"Артем Артемьев","id":269101,"is_tutor":false},"id":100018,"body":"Это я понял. я не понимаю чего цикл не работает. \nну.. i перебирается с 0 до < length","topic_id":46292},{"creator":{"public_name":"Артем Артемьев","id":269101,"is_tutor":false},"id":100012,"body":"**aotea**, \nну длина строки, она ведь импортируется. \n a 'i' с нуля до (length - 1) , чтобы перебрать str[0],str[1],str[2],str[до length]","topic_id":46292},{"creator":{"public_name":"Vasiliy Boldurean","id":296346,"is_tutor":false},"id":100015,"body":"**Артем Артемьев**, \nВсё правильно. Разница в том, что за i кроется та самая буква, которую Вы перебираете в цикле. То есть когда i доходит до заглавной, её не надо передавать в результат. А просто увеличить результат на +1. \n> str[0],str[1],str[2],str[до length] ... до length -1","topic_id":46292},{"creator":{"public_name":"Артем Артемьев","id":269101,"is_tutor":false},"id":100021,"body":"так уже делал не работало \n(в трех предыдущих версиях ревью было такое условие i < length, поэтому да разумеется я пробовал), возможно причина в чем-то еще. (str.length тоже и она ведь импортируется из strings как length не?, вы ведь не на неё намекали?)\n\nвсе что в принципе советовали я делал во второй версии ревью (до того как просить помощи) \nresult 0 , +1 , length > i ...","topic_id":46292},{"creator":{"public_name":"Vasiliy Boldurean","id":296346,"is_tutor":false},"id":99908,"body":"**Артем Артемьев**, \n\nПравильно объявили переменную результат. Только ей не надо присваивать пустую строку, присвойте ноль, а потом увеличивайте её на +1 каждый раз когда цикл находит заглавную букву. \nP.S. У вас в цикле i < length (читается как i меньше длины). Задайте себе вопрос, длины чего? i не должно быть больше длинны переданной строки. Тогда цикл будет проверять каждую букву начиная с индекса 0 и заканчивая последним. У вас результату присваивается значение i, выведете в console.log(i), чтобы просмотреть какое значение присваивается i в каждой итерации :) Функция должна возвращать результат т.е. конечное число заглавных букв.","topic_id":46292},{"creator":{"public_name":"Артем Артемьев","id":269101,"is_tutor":false},"id":100023,"body":"слишком жирно намекаете)), писал же что понял и _Я ТАК УЖЕ ДЕЛАЛ_\n\nвот на всякий- https://ru.hexlet.io/code_reviews/302244 \n\nможет в \"compare\" что.. \nесли сравнивать first.length и second.length - **isEqual** и **lessThan** только проходят в тестах. \nПоменял на firstCount и secondCount - теперь наоборот проходит только **greaterThan**\n","topic_id":46292},{"creator":{"public_name":"Vasiliy Boldurean","id":296346,"is_tutor":false},"id":100019,"body":"**Артем Артемьев**, \nВам нужно пересмотреть синтаксис циклов :)\n\n(let i = 0; length - 1 > i; i += 1) - попробуйте прочитать что в цикле? \n\n(объявим i которая принимает значение 0; длина минус 1 больше i; i ровно i плюс 1) \nКак вы себе представляете это будет работать? Условия предиката непонятны. А должно быть так: (объявим i которая принимает значение 0; i меньше длины строки; i ровно i плюс 1)\n\nЯ уже не знаю как намекнуть вам на правильность написания, кроме как попросить вас посмотреть внимательно решение учителя и сделать выводы, почему так работает. Или пересмотреть теорию. ","topic_id":46292},{"creator":{"public_name":"Артем Артемьев","id":269101,"is_tutor":false},"id":99906,"body":"Про счетчик не совсем понял как осуществить, поэтому складываю заглавные буквы,\nтесты только 2 из 3 прошли. https://ru.hexlet.io/code_reviews/302244 \n\n","topic_id":46292},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":99950,"body":"**Артем Артемьев**, приветствую.\n\nНе забывайте смотреть на тесты и использовать отладочную печать, чтобы помогать себе в решении задачи ;)","topic_id":46292},{"creator":{"public_name":"Vasiliy Boldurean","id":296346,"is_tutor":false},"id":99880,"body":"Добрый день Артём. \n\nОбратите внимание на первую функцию, и задайте себе вопрос \"Что она делает?\" bigLettersCount (Счетчик больших букв). Давайте представим как будет работать функция и попробуем расписать её на бумаге.\n\nсчетчикБольшихБукв принимает в аргумент строку, в которой, в последствии высчитывает заглавные буквы и выдает конечный результат.\nПосле объявления функции нам нужна будет переменная, значение которой будет изменяться как только в строке будет найдена заглавная буква, её значение для начала может быть 0(нулевым). Затем, нам нужен будет цикл. (кстати не забывайте что цикл for выглядит следующим образом) \nfor (<объявляем переменную>;<считаем до?>; <увеличиваем переменную на нужное нам кол-во>)\nЦикл с каждой итерацией просматривает все индексы в строке. начиная с 0 ... последнего. Внутри цикла, надо создать условие: Если найденая в итерации буква === ЗАГЛАВНОЙ букве, то увеличим счетчик на 1, и не забываем, что результат функции нужно возвращать. \n\nТеперь, когда у нас есть функция вычисляющая количество заглавных бук, грех ею не воспользоваться в следующей функции compare. \n\nКладём аргументы функции compare внутрь нами написанной функции выше и сравниваем результаты, в условиях прописываем, что вернуть в разных результатах) \n\n","topic_id":46292},{"creator":{"public_name":"Vasiliy Boldurean","id":296346,"is_tutor":false},"id":100022,"body":"**Артем Артемьев**, \n\nfor (let i = 0; i < str.length; i += 1) {\nнужный вам код.\n}","topic_id":46292},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":100035,"body":"**Артем Артемьев**, вы пробовали использовать отладочную печать? Код у вас написан правильно для решения задачи, однако при выполнении можно найти место, где он завершается раньше, чем нужно.","topic_id":46292}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Окружение","entity_url":null,"active":true}}],"lesson":{"exercise":null,"units":[{"id":1903,"name":"theory","url":"/courses/introduction_to_programming/lessons/env/theory_unit"}],"links":[{"id":427091,"name":"Variables and scoping / Exploring JS","url":"https://exploringjs.com/es6/ch_variables.html"},{"id":427092,"name":"Scope / Wikipedia","url":"https://en.wikipedia.org/wiki/Scope_(computer_science)"},{"id":427093,"name":"Closure / Wikipedia","url":"https://en.wikipedia.org/wiki/Closure_(computer_programming)"},{"id":427094,"name":"Замыкания в JS / Mozilla Developer Network","url":"https://developer.mozilla.org/ru/docs/Web/JavaScript/Closures"}],"ordered_units":[{"id":1903,"name":"theory","url":"/courses/introduction_to_programming/lessons/env/theory_unit"}],"id":927,"slug":"env","state":"approved","name":"Окружение","course_order":170,"goal":"Изучаем три важные концепции: окружение, область видимости и замыкания. Выясняем, каким образом происходит поиск значений.","self_study":null,"theory_video_provider":"youtube","theory_video_uid":"o-8bXkiNdeE","theory":"## Важное примечание\n\nИзначально в начале конспекта и урока речь шла о глобальном и локальном окружении, но объяснялась фактически глобальная и локальная область видимости. В видео эта тема до сих пор называется «глобальное и локальное окружение», текстовая версия урока исправлена.\n\nПрежде, чем приступить к уроку, разберёмся с терминологией:\n- Область видимости (scope) — это широкое понятие, означающее, грубо говоря, «интерпретатор в разных местах кода видит разные штуки».\n- Лексическая область видимости (Lexical scoping) — это конкретный механизм, одно из правил для области видимости. Этот механизм применяется в JavaScript и большинстве других языков. Под лексической областью видимости можно понимать просто механизм поиска значений: смотрим в текущей области, если нет — идём на уровень выше, и так далее. Слово «лексический» означает, что видимость задаётся исключительно текстом программы, исходным кодом. То есть можно смотреть на программу, не запуская её, и понять область видимости в любой точке. В других языках может быть не лексический механизм, а динамический ([dynamic scope](https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scope_vs._dynamic_scope)).\n- Окружение (environment) - это область памяти, где записываются идентификаторы и значения из областей видимости. Не путайте с окружением, как средой исполнения.\n\n\n\nПутаница возникает ещё потому, что в разделе про Область видимости мы смотрим на примеры, которые работают по правилу «лексическая область видимости». От этого никуда не деться, так как язык JavaScript работает именно так.\n\n## Транскрипт урока\n\n### Часть I. Окружение\n\nДавайте поговорим об окружении. Наша планета огромна, но мы все делим её. Если вы построите химический завод, неплохо бы изолировать его от окружающего мира, чтобы то, что в нём происходит оставалось внутри. Вы можете сказать, что в этом здании своё окружение, микроклимат, изолированный от внешней окружающей среды. В программировании такая изоляция называется областью видимости.\n\nВаша программа имеет подобную структуру по похожим причинам. То, что вы создаёте снаружи — снаружи функций, инструкций if, циклов и других блоков кода — находится во внешней, глобальной области видимости.\n\n```javascript\nconst age = 29\n\nconst multiplier = (num) => {\n const x = 10\n return num * x\n}\n\nlet result = true\n```\n\nКонстанта `age` , функция `multiplier` и переменная `result` — имеют \"глобальную область видимости\". Область видимости означает \"область, где компоненты доступны\".\n\nВнутри функции `multiplier` есть константа `x`. Поскольку она внутри блока кода, это локальная константа, а не глобальная. Она видна только внутри этой функции, но не снаружи. У неё локальная область видимости.\n\nВ функции `multiplier` есть ещё один компонент из локальной области видимости — аргумент `num`. Он не задан так же чётко, как константы или переменные, но ведёт себя почти как локальная переменная.\n\nУ нас нет доступа к `x` снаружи, как будто её там не существует:\n\n```javascript\nconst multiplier = (num) => {\n const x = 10\n return num * x\n}\n\nconsole.log(x) // ReferenceError: x is not defined\n```\n\n`console.log` вызывается в глобальном окружении, а `x` не задан в этом глобальном окружении. Поэтому мы получаем Reference Error.\n\nМы можем задать `x` глобально:\n\n```javascript\nconst x = 55\n\nconst multiplier = (num) => {\n const x = 10\n return num * x\n}\n\nconsole.log(x) // 55\n```\n\nТеперь существует глобальный `x` и его значение было выведено на экран, но локальный `x` внутри функции `multiplier` по-прежнему виден только внутри этой функции. Эти два `x` не имеют ничего общего друг с другом, они находятся в разных областях видимости. Они не схлопываются в одно целое, несмотря на то, что у них одно и то же имя.\n\nЛюбой блок кода между фигурными скобками имеет локальную область видимости. Вот пример с блоком `if`:\n\n```javascript\nlet a = 0\n\nif (a === 0) {\n const local = 10\n}\n\nconsole.log(local) // => ReferenceError: local is not defined\n```\n\nТо же работает для циклов `while` и `for`.\n\nОк, локальное не доступно снаружи. Но глобальное доступно везде. Даже внутри чего-то? Да!\n\n```javascript\nlet a = 0\n\nconst changer = () => {\n a++\n}\n\nconsole.log(a) // 0\nchanger()\nconsole.log(a) // 1\n```\n\nЭта глобальная переменная `a` изменилась внутри функции `changer`. Функция вообще выполняет что-то только когда её вызывают, а не когда её определяют, так что вначале `a` это `0`, но после того как вызывается `changer`, `a` становится `1`.\n\nХоть это и заманчиво всё помещать в глобальную область видимости и забыть о сложностях областей видимости — это ужасная практика. Глобальные переменные делают ваш код невероятно хрупким. В таком случае что угодно может сломать что угодно. Поэтому избегайте глобальной области видимости, храните вещи там, где им место.\n\n### Часть II. Лексическая область видимости\n\nВзгляните на эту программу:\n\n```javascript\nlet a = 7\nlet b = 10\n\nconst multiplier = () => {\n let a = 5\n return a * b\n}\n\nmultiplier() // 50\n```\n\nФункция `multiplier` возвращает произведение `a` и `b`. `a` задано внутри, а `b` — нет.\n\nПытаясь решить умножение `a * b`, JavaScript ищет значения `a` и `b`. Он начинает искать локально и выходит наружу, по одной области видимости за шаг, пока он не найдёт то, что ему нужно или пока не поймёт, что это невозможно найти.\n\nПоэтому в данном примере JavaScript начинает с поиска `a` внутри локальной области видимости — внутри функции `multiplier`. Он находит значение сразу и переходит к `b`. Невозможно найти значение `b` в локальной области видимости, поэтому он переходит к наружной области. Тут он находит `b` — это 10. `a * b` превращается в `5 * 10`, а затем в `50`.\n\nВесь этот кусок кода мог бы быть внутри другой функции, и ещё внутри другой функции. И если бы `b` не нашлась здесь, JavaScript продолжил бы искать `b` за пределами функции, слой за слоем.\n\nЗаметьте, что `a = 7` не затронула вычисления, `a` была найдена внутри, поэтому внешняя `a` не сыграла роли.\n\nЭтот механизм называется лексической областью видимости. Область видимости любого компонента определяется местом расположения этого компонента внутри кода. И вложенные блоки имеют доступ к их внешним областям видимости.\n\n### Часть III. Замыкания\n\nБольшинство языков программирования имеют что-то вроде области видимости или окружения, и этот механизм позволяет существовать замыканиям. Замыкание — это всего лишь модное название функции, которая запоминает внешние штуки, используемые внутри.\n\nПеред тем, как мы продолжим, давайте вспомним, как функции создаются и используются:\n\n```javascript\nconst f = () => {\n return 0\n}\n```\n\n`f` — довольно бесполезная функция, она всегда возвращает 0. Весь этот набор состоит из двух частей: константы и самой функции.\n\nВажно помнить, что эти два компонента раздельны. Первый — константа с именем `f`. Её значение могло бы быть числом или строкой. Но в данном случае её значение — функция.\n\nМы использовали аналогию в предыдущих уроках: константы как листы бумаги — имя на одной стороне, значение на другой. Следовательно, `f` — лист бумаги с `f` на одной стороне и описанием запускаемой функции на другой.\n\nКогда вы вызываете эту функцию, вот так:\n\n```javascript\nf()\n```\n\n… создаётся новый ящик, основываясь на описании на этом листе бумаги.\n\nОк, вернёмся к замыканиям. Рассмотрим следующий код:\n\n```javascript\nconst createPrint = () => {\n const name = 'King'\n\n const printName = () => {\n console.log(name)\n }\n\n return printName\n}\n\nconst myPrint = createPrint()\nmyPrint() // King\n```\n\nФункция `createPrint` создаёт константу `name` и затем функцию с именем `printName`. Обе они локальные для функции `createPrint`, и доступны только внутри `createPrint`.\n\nУ самой `printName` нет локальных компонентов, но у неё есть доступ к области видимости, где она сама находится, внешней области, где задана константа `name`.\n\nЗатем функция `createPrint` возвращает функцию `printName`. Помните, определения функций — это описания запущенных функций, просто фрагменты информации, как числа или строки. Поэтому мы можем вернуть определение функции, как мы возвращаем число.\n\nВо внешней области видимости мы создаём константу `myPrint` и задаём ей значение, которое возвращает вызов функции `createPrint()`. Этот вызов возвращает функцию, так что теперь `myPrint` — это функция. Вызовите её, и на экран выведется \"King\".\n\nТут есть странная штука: эта константа `name` была создана внутри функции `createPrint`. Функция была вызвана и исполнена. Как мы знаем, когда функция заканчивает работу, она больше не существует. Этот магический ящик исчезает со всеми своими внутренностями.\n\nНО он возвратил другую функцию, и уже она как-то запомнила константу `name`. Поэтому когда мы вызывали `myPrint()`, она вывела \"King\" — запомненное значение, при том, что область видимости, где оно было задано больше не существует.\n\nФункция, которая была возвращена из `createPrint`, называется замыканием. Замыкание — это сочетание функции и окружения, где она была задана. Функция \"замкнула\" в себе некоторую информацию из области видимости.\n\nЭто может выглядеть как JavaScript-фокус, но замыкания, когда их используют разумно, могут сделать код приятней, чище и проще для чтения. И сама идея возврата функций тем же способом, которым можно возвращать числа и строки, даёт больше возможностей и гибкости.\n\nВы заметите, как часто эти идеи используются в программировании, и мы рассмотрим их мощь в следующих курсах.\n\n\n## Выводы\n\n- **Область видимости** (scope) компонентов — это местоположение, где эти компоненты доступны.\n- Компоненты, созданные снаружи функций, инструкций с if, циклов и так далее, находятся в **глобальной области видимости**\n- Фигурные скобки `{ }` задают новую **локальную область видимости**\n\n### Глобальная против локальной\n\nЛокальные константы и переменные не видимы снаружи их области видимости:\n\n```javascript\nconst multiplier = (num) => {\n const x = 10\n return num * x\n}\n\nconsole.log(x) // ReferenceError: x is not defined\n```\n\nНо если `x` представлен глобально, то он доступен:\n\n```javascript\nconst x = 55\n\nconst multiplier = (num) => {\n const x = 10\n return num * x\n}\n\nconsole.log(x) // 55\n```\n\nВозможен доступ к внешней области видимости:\n\n```javascript\nlet a = 0\n\nconst changer = () => {\n a++\n}\n\nconsole.log(a) // 0\nchanger()\nconsole.log(a) // 1\n```\n\nФункция фактически производит что-то, только когда она вызывается, а не задаётся, поэтому изначально `a` это `0`, но после того, как вызвана `changer`, `a` становится `1`.\n\n### Лексическая область видимости\n\nJavaScript пытается найти значение в текущем окружении. Но значение не находится и JavaScript выходит наружу, на один уровень за попытку, пока не найдёт значение или не поймет, что значение невозможно найти.\n\n```javascript\nlet a = 7\nlet b = 10\n\nconst multiplier = () => {\n let a = 5\n return a * b\n}\n\nmultiplier() // 50\n```\n\nЗдесь, в выражении `a * b` , функция `multiplier` использует локальную `a` (потому что она обнаружена локально), и наружную `b` (потому что локально `b` найдена не была).\n\n### Замыкания\n\n```javascript\nconst createPrint = () => {\n const name = 'King'\n\n const printName = () => {\n console.log(name)\n }\n\n return printName\n}\n\nconst myPrint = createPrint()\nmyPrint() // King\n```\n\nmyPrint — это функция, которая была возвращена `createPrint`. Несмотря на то, что вызов `createPrint` окончен и константы `name` больше не существует, значение запомнено в `myPrint`.\n\nЭто **замыкание**: сочетание функции и окружения, где она была заявлена.\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/env/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/o-8bXkiNdeE" loading="lazy" allowFullScreen="" title="video"></iframe></div></div><div class="paywalled m_d08caa0 mantine-Typography-root"><h2 id="heading-2-1">Важное примечание</h2>
<p>Изначально в начале конспекта и урока речь шла о глобальном и локальном окружении, но объяснялась фактически глобальная и локальная область видимости. В видео эта тема до сих пор называется «глобальное и локальное окружение», текстовая версия урока исправлена.</p>
<p>Прежде, чем приступить к уроку, разберёмся с терминологией:</p>
<ul>
<li>Область видимости (scope) — это широкое понятие, означающее, грубо говоря, «интерпретатор в разных местах кода видит разные штуки».</li>
<li>Лексическая область видимости (Lexical scoping) — это конкретный механизм, одно из правил для области видимости. Этот механизм применяется в JavaScript и большинстве других языков. Под лексической областью видимости можно понимать просто механизм поиска значений: смотрим в текущей области, если нет — идём на уровень выше, и так далее. Слово «лексический» означает, что видимость задаётся исключительно текстом программы, исходным кодом. То есть можно смотреть на программу, не запуская её, и понять область видимости в любой точке. В других языках может быть не лексический механизм, а динамический (<a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scope_vs._dynamic_scope" rel="noopener noreferrer" target="_blank">dynamic scope</a>).</li>
<li>Окружение (environment) - это область памяти, где записываются идентификаторы и значения из областей видимости. Не путайте с окружением, как средой исполнения.</li>
</ul>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTI1ODEsInB1ciI6ImJsb2JfaWQifX0=--be8f93dcc88171a32c937183773f32b80108db7c/env_and_scope.png" alt="Упрощённая визуализация областей видимости и окружений в javascript" loading="lazy"/></p>
<p>Путаница возникает ещё потому, что в разделе про Область видимости мы смотрим на примеры, которые работают по правилу «лексическая область видимости». От этого никуда не деться, так как язык JavaScript работает именно так.</p>
<h2 id="heading-2-2">Транскрипт урока</h2>
<h3 id="heading-3-3">Часть I. Окружение</h3>
<p>Давайте поговорим об окружении. Наша планета огромна, но мы все делим её. Если вы построите химический завод, неплохо бы изолировать его от окружающего мира, чтобы то, что в нём происходит оставалось внутри. Вы можете сказать, что в этом здании своё окружение, микроклимат, изолированный от внешней окружающей среды. В программировании такая изоляция называется областью видимости.</p>
<p>Ваша программа имеет подобную структуру по похожим причинам. То, что вы создаёте снаружи — снаружи функций, инструкций if, циклов и других блоков кода — находится во внешней, глобальной области видимости.</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 age = 29
const multiplier = (num) => {
const x = 10
return num * x
}
let result = 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>
<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">age</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">multiplier</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">result</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">multiplier</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">x</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">multiplier</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">num</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">x</code> снаружи, как будто её там не существует:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">const multiplier = (num) => {
const x = 10
return num * x
}
console.log(x) // ReferenceError: x is not defined</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">console.log</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">x</code> не задан в этом глобальном окружении. Поэтому мы получаем Reference Error.</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">x</code> глобально:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">const x = 55
const multiplier = (num) => {
const x = 10
return num * x
}
console.log(x) // 55</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">x</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">x</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">multiplier</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">x</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">if</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 = 0
if (a === 0) {
const local = 10
}
console.log(local) // => ReferenceError: local is not defined</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">while</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">for</code>.</p>
<p>Ок, локальное не доступно снаружи. Но глобальное доступно везде. Даже внутри чего-то? Да!</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">let a = 0
const changer = () => {
a++
}
console.log(a) // 0
changer()
console.log(a) // 1</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">a</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">changer</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">a</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">0</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">changer</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">a</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">1</code>.</p>
<p>Хоть это и заманчиво всё помещать в глобальную область видимости и забыть о сложностях областей видимости — это ужасная практика. Глобальные переменные делают ваш код невероятно хрупким. В таком случае что угодно может сломать что угодно. Поэтому избегайте глобальной области видимости, храните вещи там, где им место.</p>
<h3 id="heading-3-4">Часть II. Лексическая область видимости</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">let a = 7
let b = 10
const multiplier = () => {
let a = 5
return a * b
}
multiplier() // 50</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">multiplier</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">a</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">b</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">a</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">b</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">a * b</code>, 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">a</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">b</code>. Он начинает искать локально и выходит наружу, по одной области видимости за шаг, пока он не найдёт то, что ему нужно или пока не поймёт, что это невозможно найти.</p>
<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">a</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">multiplier</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">b</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">b</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">b</code> — это 10. <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">a * b</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">5 * 10</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">50</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">b</code> не нашлась здесь, 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">b</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">a = 7</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">a</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">a</code> не сыграла роли.</p>
<p>Этот механизм называется лексической областью видимости. Область видимости любого компонента определяется местом расположения этого компонента внутри кода. И вложенные блоки имеют доступ к их внешним областям видимости.</p>
<h3 id="heading-3-5">Часть III. Замыкания</h3>
<p>Большинство языков программирования имеют что-то вроде области видимости или окружения, и этот механизм позволяет существовать замыканиям. Замыкание — это всего лишь модное название функции, которая запоминает внешние штуки, используемые внутри.</p>
<p>Перед тем, как мы продолжим, давайте вспомним, как функции создаются и используются:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">const f = () => {
return 0
}</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">f</code> — довольно бесполезная функция, она всегда возвращает 0. Весь этот набор состоит из двух частей: константы и самой функции.</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">f</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">f</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">f</code> на одной стороне и описанием запускаемой функции на другой.</p>
<p>Когда вы вызываете эту функцию, вот так:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">f()</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>Ок, вернёмся к замыканиям. Рассмотрим следующий код:</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 createPrint = () => {
const name = 'King'
const printName = () => {
console.log(name)
}
return printName
}
const myPrint = createPrint()
myPrint() // King</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">createPrint</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">name</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">printName</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">createPrint</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">createPrint</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">printName</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">name</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">createPrint</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">printName</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">myPrint</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">createPrint()</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">myPrint</code> — это функция. Вызовите её, и на экран выведется "King".</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">name</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">createPrint</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">name</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">myPrint()</code>, она вывела "King" — запомненное значение, при том, что область видимости, где оно было задано больше не существует.</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">createPrint</code>, называется замыканием. Замыкание — это сочетание функции и окружения, где она была задана. Функция "замкнула" в себе некоторую информацию из области видимости.</p>
<p>Это может выглядеть как JavaScript-фокус, но замыкания, когда их используют разумно, могут сделать код приятней, чище и проще для чтения. И сама идея возврата функций тем же способом, которым можно возвращать числа и строки, даёт больше возможностей и гибкости.</p>
<p>Вы заметите, как часто эти идеи используются в программировании, и мы рассмотрим их мощь в следующих курсах.</p>
<h2 id="heading-2-6">Выводы</h2>
<ul>
<li><strong>Область видимости</strong> (scope) компонентов — это местоположение, где эти компоненты доступны.</li>
<li>Компоненты, созданные снаружи функций, инструкций с if, циклов и так далее, находятся в <strong>глобальной области видимости</strong></li>
<li>Фигурные скобки <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">{ }</code> задают новую <strong>локальную область видимости</strong></li>
</ul>
<h3 id="heading-3-7">Глобальная против локальной</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">const multiplier = (num) => {
const x = 10
return num * x
}
console.log(x) // ReferenceError: x is not defined</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">x</code> представлен глобально, то он доступен:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">const x = 55
const multiplier = (num) => {
const x = 10
return num * x
}
console.log(x) // 55</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>
<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 = 0
const changer = () => {
a++
}
console.log(a) // 0
changer()
console.log(a) // 1</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">a</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">0</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">changer</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">a</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">1</code>.</p>
<h3 id="heading-3-8">Лексическая область видимости</h3>
<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">let a = 7
let b = 10
const multiplier = () => {
let a = 5
return a * b
}
multiplier() // 50</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">a * b</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">multiplier</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">a</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">b</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">b</code> найдена не была).</p>
<h3 id="heading-3-9">Замыкания</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">const createPrint = () => {
const name = 'King'
const printName = () => {
console.log(name)
}
return printName
}
const myPrint = createPrint()
myPrint() // King</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>myPrint — это функция, которая была возвращена <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">createPrint</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">createPrint</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">name</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">myPrint</code>.</p>
<p>Это <strong>замыкание</strong>: сочетание функции и окружения, где она была заявлена.</p></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/env/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/env/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>