<!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 19:53:35 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="9YuGmW9KZg2-vxlgMvxv0ALKCPF83QHAkAWhxSh-qoIaWk2unTTLbQj8Pfg-85-nwsMlW3Tq_2It5TuRenlN7A";gon.locale="ru";gon.language="ru";gon.theme="light";gon.rails_env="production";gon.mobile=false;gon.google={"analytics_key":"UA-1360700-51","optimize_key":"GTM-5QDVFPF"};gon.captcha={"google_v3_site_key":"6LenGbgZAAAAAM7HbrDbn5JlizCSzPcS767c9vaY","yandex_site_key":"ysc1_Vyob5ZPPUdPBsu0ykt8bVFdzsfpoVjQChLGl2b4g19647a89","verification_failed":null};gon.social_signin=false;gon.typoreporter_google_form_id="1FAIpQLSeibfGq-KvWQ2Fyru-zkFFRVTLBuzXAHAoEyN1p49FtDmNoNA";
//]]>
</script>
<meta charset="utf-8">
<title>Объекты первого класса | JS: Функциональное программирование</title>
<meta name="description" content="Объекты первого класса / JS: Функциональное программирование: Выясняем, что функции – это данные">
<link rel="canonical" href="https://ru.hexlet.io/courses/js-functions-hard-way/lessons/first-class-citizen/theory_unit">
<meta name="robots" content="noarchive">
<meta property="og:title" content="Объекты первого класса">
<meta property="og:title" content="JS: Функциональное программирование">
<meta property="og:description" content="Объекты первого класса / JS: Функциональное программирование: Выясняем, что функции – это данные">
<meta property="og:url" content="https://ru.hexlet.io/courses/js-functions-hard-way/lessons/first-class-citizen/theory_unit">
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="mRJxKjPrL3WgDJ9lwI_-_P6o5TR9GVNGH5NRIa_Q5Px2w7odwZWCFRZPu_3MgA6LPqHInnUureSic8t1_dcDkg" />
<script src="/vite/assets/inertia-DfXos102.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/preload-helper-BJ4cLWpC.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-BrRXra1y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ahoy-DrlRQ-1D.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/analytics-cb8xch9l.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Surface-DL2bpZA-.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/extends-C-EagtpE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/inheritsLoose-BBd-DCVI.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/objectWithoutPropertiesLoose-DRHXDhjp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/index.esm-DAqKOkZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Button-CGPUux8l.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/CloseButton-D1euiPao.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Group-BX48WcuU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Loader-BQEY8g6v.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Modal-Cy3HByv7.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/OptionalPortal-1Hza5P2w.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Stack-CtjJzfw4.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Textarea-Ck64llAy.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/DirectionProvider-Dc9zdUke.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/events-DJQOhap0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-reduced-motion-D2owz4wa.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-disclosure-zKtK5W1r.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-hotkeys-Cnc_Rwkb.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/random-id-DOQyszCZ.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/exports-C_MrNx_T.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<link rel="stylesheet" href="/vite/assets/application-BqhCP46M.js" />
<script src="/vite/assets/application-Df9RExpe.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/autocomplete-VMNbxKGl.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/createPopper-C3aM9r1M.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/js.cookie-D1-O8zkX.js" as="script" crossorigin="anonymous"><link rel="stylesheet" href="/vite/assets/application-C8HjmMaq.css" media="screen" />
<script>
window.ym = function(){(ym.a=ym.a||[]).push(arguments)};
window.addEventListener('load', function() {
setTimeout(function() {
ym.l = 1*new Date();
ym(window.gon.ym_counter, "init", {
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
webvisor: true
});
// Загружаем скрипт
var k = document.createElement('script');
k.async = 1;
k.src = 'https://mc.yandex.ru/metrika/tag.js';
document.head.appendChild(k);
ym(window.gon.ym_counter, 'getClientID', function(clientID) {
window.ymClientId = clientID;
});
}, 1500);
});
</script>
<!-- Google Tag Manager - deferred -->
<script>
// dataLayer stub сразу — пуши работают до загрузки скрипта
window.dataLayer = window.dataLayer || [];
// Сам скрипт — отложенно после load
window.addEventListener('load', function() {
setTimeout(function() {
dataLayer.push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
var j = document.createElement('script');
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-WK88TH';
document.head.appendChild(j);
}, 1500);
});
</script>
<!-- End Google Tag Manager -->
</head>
<body>
<noscript>
<div>
<img alt="" src="https://mc.yandex.ru/watch/25559621" style="position:absolute; left:-9999px;">
</div>
</noscript>
<header class="sticky-top bg-body">
<nav class="navbar navbar-expand-lg">
<div class="container-xxl">
<a class="navbar-brand" href="/"><img alt="Логотип Хекслета" height="24" src="https://ru.hexlet.io/vite/assets/logo_ru_light-BpiEA1LT.svg" width="96">
</a><button aria-controls="collapsable" aria-expanded="false" aria-label="Меню" class="navbar-toggler border-0 mb-0 mt-1" data-bs-target="#collapsable" data-bs-toggle="collapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsable">
<ul class="navbar-nav mb-lg-0 mt-lg-1">
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
Все курсы
<span class="bi bi-chevron-down align-middle ms-1"></span>
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item d-flex py-2" href="/courses"><div class="fw-bold me-auto">Все что есть</div>
<div class="text-muted">117</div>
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные категории</b>
</li>
<li>
<a class="dropdown-item py-2" href="/courses_devops">Курсы по DevOps
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_data_analytics">Курсы по аналитике данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_programming">Курсы по программированию
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_testing">Курсы по тестированию
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные курсы</b>
</li>
<li>
<a class="dropdown-item py-2" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/go">Go-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/java">Java-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/python">Python-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/qa-auto-engineer-java">Автоматизатор тестирования на Java
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/data-analytics">Аналитик данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/frontend">Фронтенд-разработчик
</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
О Хекслете
<span class="bi bi-chevron-down align-middle"></span>
</button>
<ul class="dropdown-menu bg-body">
<li>
<a class="dropdown-item py-2" href="/pages/about">О нас
</a></li>
<li>
<a class="dropdown-item py-2" href="/blog">Блог
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/hse-research" role="button">Результаты (Исследование)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://career.hexlet.io" role="button">Хекслет Карьера
</span></li>
<li>
<a class="dropdown-item py-2" href="/testimonials">Отзывы студентов
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://t.me/hexlet_help_bot" role="button">Поддержка (В ТГ)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/referal-program/?promo_creative=priglasite-druzei&promo_name=referal-program&promo_position=promo_position&promo_start=010724&promo_type=link" role="button">Реферальная программа
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/certificate" role="button">Подарочные сертификаты
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://hh.ru/employer/4307094" role="button">Вакансии
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://b2b.hexlet.io" data-target="_blank" role="button">Компаниям
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexly.ru/" data-target="_blank" role="button">Колледж
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexlyschool.ru/" data-target="_blank" role="button">Частная школа
</span></li>
</ul>
</li>
<li><a class="nav-link" href="/subscription/new">Подписка</a></li>
</ul>
<ul class="navbar-nav flex-lg-row align-items-lg-center gap-2 ms-auto">
<li>
<a class="nav-link" aria-label="Переключить тему" href="/theme/switch?new_theme=dark"><span aria-hidden="true" class="bi bi-moon"></span>
</a></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="/u/new" role="button"><span>Регистрация</span>
</span></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="https://ru.hexlet.io/session/new" role="button"><span>Вход</span>
</span></li>
</ul>
</div>
</div>
</nav>
</header>
<div class="x-container-xxxl">
</div>
<main class="mb-6 min-vh-100 h-100">
<link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc2MCwicHVyIjoiYmxvYl9pZCJ9fQ==--9348098e4053d798b6f34bee4ef66947540261e4/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Low%20code%20development-rafiki.png"/><link rel="preload" as="image" href="/vite/assets/development-BVihs_d5.png"/><div id="app" data-page="{"component":"web/courses/lessons/theory_unit","props":{"errors":{},"locale":"ru","language":"ru","httpsHost":"https://ru.hexlet.io","host":"ru.hexlet.io","colorScheme":"light","auth":{"user":{"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26T19:53:34.882Z","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":"ENxsbgNAZJFyDaeI-QEdQlTmFzd35yu-4sZ_NY19Q3D_DadZ8T7J8cROgxD1Du01lO86nX_Q1RxfJuVh33qkHg","topics":[{"id":23651,"title":"Всем привет! Пытаясь разобраться в том, как работает код:\n\n```\nconst halfSquare = f => z => f(z)\nconsole.log(halfSquare(10));\n```\n\n**//[Function]**\n\nпопытался переписать эквивалентный этому коду код:\n\n```\nconst halfSquare = (f)=> {\n\treturn z = () => {\n\t\treturn f(z)\n\t}\n}\nconsole.log(halfSquare(10));\n```\n\n**//{ [Function: z] toString: [Function] }**\n\nИ увидел, что интерпретатор JS возвращает разные значения. Значит, коды не эквивалентны. Значит - я неправильно понимаю синтаксис первого кода. Но вот ошибку в понимании устранить не удается. **Как я интерпретирую первый код:** мы задаем функцию halfSquare с параметром f (f-функция). Вызывается функция f (у нее нет входного параметра), которая возвращает функцию z, которая, в свою очередь, вызывается и возвращает значение f(z)...","plain_title":"Всем привет! Пытаясь разобраться в том, как работает код: const halfSquare = f => z => f(z) console.log(halfSquare(10)); //[Function] попытался переписать эквивалентный этому коду код: const halfSquare = (f)=> { return z = () => { return f(z) } } console.log(halfSquare(10)); //{ [Function: z] toString: [Function] } И увидел, что интерпретатор JS возвращает разные значения. Значит, коды не эквивалентны. Значит - я неправильно понимаю синтаксис первого кода. Но вот ошибку в понимании устранить не удается. Как я интерпретирую первый код: мы задаем функцию halfSquare с параметром f (f-функция). Вызывается функция f (у нее нет входного параметра), которая возвращает функцию z, которая, в свою очередь, вызывается и возвращает значение f(z)... ","creator":{"public_name":"Александр Мельчаков","id":198299,"is_tutor":false},"comments":[{"creator":{"public_name":"Максим А.","id":186811,"is_tutor":false},"id":50438,"body":"Функция halfSquare принимает на вход функцию F, которая возвращает функцию Z, которая принимает на вход один параметр и возвращает функцию F от этого параметра.\n```\nconst half = (func) => {\n const z = (arg) => {\n return func(arg);\n }\n return z;\n};\n```\n\n","topic_id":23651},{"creator":{"public_name":"Александр Мельчаков","id":198299,"is_tutor":false},"id":50463,"body":"Максим, но ведь в записи const halfSquare = f => z => f(z) у функции Z никаких параметров нет. А в вашей записи у функции Z появляется параметр. Как это объяснить? Я думаю, что эквивалентная запись подразумевает одинаковое количество функций и параметров функций. Или это не так?","topic_id":23651},{"creator":{"public_name":"Александр Мельчаков","id":198299,"is_tutor":false},"id":50581,"body":"Александр, Максим, спасибо! С кодом разбирался пошагово через визуализацию кода. Чтобы не флудить здесь: закрою этот топик и создам вверху новый. Причина: адаптировал код, но разобраться в нем не смог.","topic_id":23651},{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":50512,"body":"Всем привет!\n\n> попытался переписать эквивалентный этому коду код:\n\nhttps://babeljs.io/repl/\n\nПопробуйте этот сервис. Он показывает, как выгядит написанный на \"новом синтаксисе\" код, если его переписать на старый синтаксис.","topic_id":23651},{"creator":{"public_name":"Максим А.","id":186811,"is_tutor":false},"id":50474,"body":"Александр разве функция z => f(z), не принимает ни одного аргумента? Или если ещё упростить z => z.","topic_id":23651},{"creator":{"public_name":"Максим Гурьянов","id":206528,"is_tutor":false},"id":103378,"body":"Здравствуйте! Уважаемые менторы, правильно ли я понял, что вот этот код (который обсуждался автором топика):\n\n```\nconst halfSquare = f => z => f(z)\nconsole.log(halfSquare(10));\n```\nвыведет в консоль анонимную функцию `z => f(z)` ввиде строки, применив к ней метод `toString()`.\nЧтобы вызвать эту анонимную функцию, необходимо написать `halfSquare()(10)`. И этот вызов уже вернет вызов функции `f(10)`, которая уже что-то сделает с аргументом и вернет результат вычисления.\n\nПоправьте меня, пожалуйста, если я ошибаюсь.","topic_id":23651},{"creator":{"public_name":"Александр Мельчаков","id":198299,"is_tutor":false},"id":50544,"body":"Александр, Максим: спасибо! С этим вопросом я пока разбираюсь: сегодня около 2 часов потратил на разбор данного кода, пока не осилил его. Голова устала. Перерыв! Вопрос пока оставляю открытым: думаю, по этому топику еще появятся вопросы","topic_id":23651},{"creator":{"public_name":"Максим А.","id":186811,"is_tutor":false},"id":103385,"body":"Вроде правильно","topic_id":23651},{"creator":{"public_name":"Максим Гурьянов","id":206528,"is_tutor":false},"id":103391,"body":"Или все же вызов `console.log(halfSquare(10));` вернет анонимную функцию `z => 10(z)` ? И вот если ее вызвать `console.log(halfSquare(10)(10));`, то получим ошибку, потому что 10- это не функция? Ведь в итого получится `(z => 10(z))(10)`, отсюда получаем `10(10)`","topic_id":23651}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты первого класса","entity_url":null,"active":true}},{"id":36430,"title":"Приветствую! Возьмём для примера такие строчки кода:\n\nconst identity = (v) => v;\n\nidentity((v) => v)('run');\n\nВсё ок и работает. Но, если мы добавим в тело функции хотя бы один оператор ( например так const identity = (v) => - v; или так: const identity = (v) => v + v;\nто после вызова identity((v) => v)('run'); всё ломается, и выскакивает ошибка TypeError. identity(...) is not a function. Мне не совсем понятна причина такого поведения. Почему функции не отработать так: 'run' + 'run'? \nПрошу прощения, если тупой вопрос, но не доходит.","plain_title":"Приветствую! Возьмём для примера такие строчки кода: const identity = (v) => v; identity((v) => v)('run'); Всё ок и работает. Но, если мы добавим в тело функции хотя бы один оператор ( например так const identity = (v) => - v; или так: const identity = (v) => v + v; то после вызова identity((v) => v)('run'); всё ломается, и выскакивает ошибка TypeError. identity(...) is not a function. Мне не совсем понятна причина такого поведения. Почему функции не отработать так: 'run' + 'run'? Прошу прощения, если тупой вопрос, но не доходит. ","creator":{"public_name":"Дмитрий Крук","id":129204,"is_tutor":false},"comments":[{"creator":{"public_name":"Cross Minder","id":153568,"is_tutor":false},"id":79525,"body":"**Дмитрий Крук**, Привет. Выполни вызовы последовательно и поймёшь почему так. Например. \n`const identity = (v) => -v;` \nФункция принимает аргумент и возвращает его применяя к нему оператор унарный минус (он меняет знак на противоположный). Вызовем с числом \n`identity(5); // -5` \n`identity(-5); // 5` \nВызовем с вашей функцией \n`identity(v => v); // NaN` \nФункция не число, поэтому такой результат. Другой пример попробуй разобрать также самостоятельно.","topic_id":36430},{"creator":{"public_name":"Дмитрий Крук","id":129204,"is_tutor":false},"id":79538,"body":"Гм, т.е. вариант \"-f\" невозможен в принципе? Т.к. мы не можем применить унарный операнд к функции?\nПо поводу второго варианта: \n\nconst identity = v => v + v;\n\nПри подстановке: identity((v) => v); \n\nREPL выдаёт такой ответ: (v) => v(v) => v;\n\nЧёт я запутался. Куда делось тело функции v + v ?","topic_id":36430},{"creator":{"public_name":"Cross Minder","id":153568,"is_tutor":false},"id":79543,"body":"**Дмитрий Крук**, С минусом сработает, если за ним будет вызов функции, а не определение и функция должна возвращать число. \nТо есть `-f(5)` будет `5`. \nЛюбая математическая операция, которая не может быть вычислена приведёт к NaN. \n`5 / ‘hello’ -> NaN`. \nВ случае сложения функция возвращает `v + v`, ты передал функцию и получил результат `(v) => v(v) => v;` \nСогласен он странный, я если честно никогда не пробовал так делать поэтому не объясню почему определения так сложились) Может «особенности js», потому что если произвести вычитание будет NaN. Предполагаю, что дело в «+» ведь он может производить конкатенацию в отличии от других мат. операторов. ","topic_id":36430},{"creator":{"public_name":"Cross Minder","id":153568,"is_tutor":false},"id":79544,"body":"Если попробовать сложить эти функции без передачи в другую функцию, то результат тот же самый `console.log((v => v) + (v => v));` \n// (v) => v(v) => v; \nТак что наверно все дело в плюсе)","topic_id":36430},{"creator":{"public_name":"Дмитрий Крук","id":129204,"is_tutor":false},"id":79574,"body":"Хех, забавно. \n> Так что наверно все дело в плюсе)\n\nДа, я тоже пришёл к такому выводу. Спасибо за ответы :)","topic_id":36430}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты первого класса","entity_url":null,"active":true}},{"id":32616,"title":"Добрый день!\nhttps://ru.hexlet.io/code_reviews/155390\n\nУ меня получилось решить и пройти задание, но осталось много вопросов в своей компетенции после того, как я увидела решение учителя в три строчки. Что нужно проверить, повторить, чтобы суметь также решать задачи. Логики не хватает?","plain_title":"Добрый день! https://ru.hexlet.io/code_reviews/155390 У меня получилось решить и пройти задание, но осталось много вопросов в своей компетенции после того, как я увидела решение учителя в три строчки. Что нужно проверить, повторить, чтобы суметь также решать задачи. Логики не хватает? ","creator":{"public_name":"Anna Burley","id":235400,"is_tutor":false},"comments":[{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":70900,"body":"Здравствуйте!\n\n> Что нужно проверить, повторить, чтобы суметь также решать задачи.\n\nПрежде всего, нужно нарабатывать опыт написания кода, решения различных задачек, сразу \"нахрапом\" в любом случае не получится.\n\nСамое главное, что у вас получилось самостоятельно решить упражнение (и не важно каким способом). Может быть, ваше решение не идеальное, но оно рабочее и его дальше уже можно рефакторить (улучшать) — для этого можете проанализировать решение учителя, разобтрать его, сопоставить со своим кодом. И, чуть позже, попробовать самостоятельно переписать свой прежний вариант решения. Так надо поступать в каждой практике.\n\nЕсли же вы не знаете как решить упражнение или не понимаете решения учителя, тогда в этом надо разбираться, пишите в комьюнити, задавайте вопросы.\n\nP.S. Вижу, что вы используете \"устаревший\" синтаксис при определении функции с ключевым словом `function`, хотя нигде до сих пор в наших курсах он не использовался и не демонстрировался, у нас везде \"стрелочный\" синтаксис и мы рекомендуем его использовать, как более практичный и лаконичный (\"устаревший\" синтаксис важен только при определённых случаях, которые в будущем мы обговорим). Возможно, всё это свидетельствует о том, что в целом вы пишите код так, как \"привыкли\" это делать ранее, но всё же стоит более открыться к изменениям :)","topic_id":32616}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты первого класса","entity_url":null,"active":true}},{"id":35133,"title":"Теперь после проверки кода возвращается надпись:\nLinter status: finished → Проверка линтером завершена. Стилистических ошибок не найдено.\nА где же \"Осом!\"?)))","plain_title":"Теперь после проверки кода возвращается надпись: Linter status: finished → Проверка линтером завершена. Стилистических ошибок не найдено. А где же \"Осом!\"?))) ","creator":{"public_name":"Lenri Rodionova","id":194087,"is_tutor":false},"comments":[{"creator":{"public_name":"Lenri Rodionova","id":194087,"is_tutor":false},"id":76782,"body":"**Максим Литвинов**, вот именно! Потрясающе! Как без этой фразы справляться с вредным линтером?)))) Кстати, заметьте, слово \"линтер\" знают все)))))","topic_id":35133},{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":76727,"body":"**Lenri Rodionova**, приветствую!\n\nНе всем было понятно, что это значит, поэтому теперь без Сома :)","topic_id":35133},{"creator":{"public_name":"Lenri Rodionova","id":194087,"is_tutor":false},"id":76781,"body":"**Станислав Дзисяк**, респект тому, кто придумал Сома))) было весело каждый раз видеть эту фразу. Жаль, что теперь включили стрикт.","topic_id":35133},{"creator":{"public_name":"Александр Некрасов","id":244158,"is_tutor":false},"id":76700,"body":"**Lenri Rodionova**, Привет!\n\nКто в слаке пожаловался что не знает что такое \"Осом\"(я тоже не знал ) и его пообещали убрать. Видимо убрали. \n\nЕсли вас еще нет с нами, обязательно приходите в уютный слак!;)","topic_id":35133},{"creator":{"public_name":"Maksim Litvinov","id":198906,"is_tutor":true},"id":76701,"body":"Это видимо транскрипция английского слова awesome - потрясающе)","topic_id":35133}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты первого класса","entity_url":null,"active":true}},{"id":10633,"title":"У меня при старте задания уже есть какой-то код между begin и end, так задумано ?)","plain_title":"У меня при старте задания уже есть какой-то код между begin и end, так задумано ?) ","creator":{"public_name":"Андрей Волосников","id":128150,"is_tutor":false},"comments":[{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":22045,"body":"Добрый день! Нет, никакого кода быть не должно, это какие-то артефакты) Нажмите кнопку \"Сбросить\" для работы с последней версией практики.","topic_id":10633}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты первого класса","entity_url":null,"active":true}},{"id":11190,"title":"Не очень понимаю такую запись в тестах `v => v ** 2` . Как она срабатывает? Что подставляется в \"v\"?","plain_title":"Не очень понимаю такую запись в тестах v => v ** 2 . Как она срабатывает? Что подставляется в \"v\"? ","creator":{"public_name":"Vladimir Gavrilov","id":152807,"is_tutor":false},"comments":[{"creator":{"public_name":"Vladimir Gavrilov","id":152807,"is_tutor":false},"id":23279,"body":"А, все, разобрался.","topic_id":11190},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":23309,"body":"Отлично)","topic_id":11190}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты первого класса","entity_url":null,"active":true}},{"id":17445,"title":" Добрый день!\n Никак не могу начать эффективно применять на практике рекурсию. Вроде бы и теорию всю понимаю (но это не точно) и задания с испытаниями выполнил. Замечаю моменты, когда рекурсия в решении зайдет лучше цикла (как, например, в этом упражнении). Но, как только дело доходит до практического применения, сразу впадаю в какой-то ступор. Решение с циклом реализовал за считанные минуты:\n\n`// removed`\n\n А к решению рекурсивным методом не пришел и за полчаса попыток. При этом, когда увидел решение учителя, то сразу все показалось таким простым и очевидным, что даже стыдно стало. Но по себе знаю, что это всего лишь иллюзия понимания.\nОпасаюсь упустить эту тему, так как вижу в итеративном методе использования рекурсии мощный и гибкий инструмент, с которым качество кода выходит на совершенно иной уровень, нежели простое использование циклов.\n Порекомендуйте, пожалуйста, способы преодоления данной проблемы. Заранее благодарен за помощь.\n P. S. Извиняюсь, что создал топик не в том уроке. Просто только сейчас пришло понимание того, что упускаю важную тему.","plain_title":" Добрый день! Никак не могу начать эффективно применять на практике рекурсию. Вроде бы и теорию всю понимаю (но это не точно) и задания с испытаниями выполнил. Замечаю моменты, когда рекурсия в решении зайдет лучше цикла (как, например, в этом упражнении). Но, как только дело доходит до практического применения, сразу впадаю в какой-то ступор. Решение с циклом реализовал за считанные минуты: // removed А к решению рекурсивным методом не пришел и за полчаса попыток. При этом, когда увидел решение учителя, то сразу все показалось таким простым и очевидным, что даже стыдно стало. Но по себе знаю, что это всего лишь иллюзия понимания. Опасаюсь упустить эту тему, так как вижу в итеративном методе использования рекурсии мощный и гибкий инструмент, с которым качество кода выходит на совершенно иной уровень, нежели простое использование циклов. Порекомендуйте, пожалуйста, способы преодоления данной проблемы. Заранее благодарен за помощь. P. S. Извиняюсь, что создал топик не в том уроке. Просто только сейчас пришло понимание того, что упускаю важную тему. ","creator":{"public_name":"Алексей Слюнявчиков","id":183447,"is_tutor":false},"comments":[{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":36832,"body":"Здравствуйте!\n\nЕсли хотите поделиться готовым решением (прошедшим тесты), то его лучше отправить на код-ревью, а здесь оставить ссылку на него.\n\n> При этом, когда увидел решение учителя, то сразу все показалось таким простым и очевидным\n\nПо вашему описанию очень похоже, что вы действительно понимаете рекурсию, но вам не хватает практики её использования. В таком случае способ очевиден: надо практиковаться как можно больше. Например, в задании проанализируйте решение учителя, использование рекурсии, а затем через некоторое время попробуйте вернуться снова к практике и самостоятельно реализовать функцию с применением рекурсии.","topic_id":17445},{"creator":{"public_name":"Михаил Кацупко","id":182980,"is_tutor":false},"id":37272,"body":"Не хочу создавать новый топик, схожий вопрос.\nКак можно сравнении решение с рекурсией и решении с циклом? Если можем решить с рекурсией то всегда нужно решать с помощью рекурсии? Почему рекурсия > цикла? Я понимаю _вроде_ рекурсию, часто очень изящьно, но циклы такая же часть языка. Как выбрать инструмент для решения задачи?","topic_id":17445},{"creator":{"public_name":"Алексей Слюнявчиков","id":183447,"is_tutor":false},"id":36848,"body":"> Если хотите поделиться готовым решением (прошедшим тесты), то его лучше отправить на код-ревью, а здесь оставить ссылку на него.\n\nПонял, учту при следующих публикациях.\n\nБлагодарю за наставление, побежал искать задачки по рекурсии!","topic_id":17445}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты первого класса","entity_url":null,"active":true}},{"id":31695,"title":"Линтер ругается на файл тестов, проверьте пожалуйста.\nЗадание далось просто, возможно, это уже результат :)\nhttps://ru.hexlet.io/code_reviews/146469","plain_title":"Линтер ругается на файл тестов, проверьте пожалуйста. Задание далось просто, возможно, это уже результат :) https://ru.hexlet.io/code_reviews/146469 ","creator":{"public_name":"Николай Макаров","id":232254,"is_tutor":false},"comments":[{"creator":{"public_name":"Сергей К.","id":5174,"is_tutor":false},"id":68927,"body":"Спасибо! Пофиксил файл с тестами.","topic_id":31695}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты первого класса","entity_url":null,"active":true}},{"id":13822,"title":"Добрый день! Подскажите пожалуйста, почему этот код не работает? const apply = (howmany, func, argument) => {\n if (howmany = 0) { return argument; }\n else { return apply(howmany - 1, func, func(argument)); }\n };\nВижу в отчете ошибку связанную с бесконечной рекурсией, но не как не могу понять где ошибка((. Полностью уверен в том, что это должно работать(.","plain_title":"Добрый день! Подскажите пожалуйста, почему этот код не работает? const apply = (howmany, func, argument) => { if (howmany = 0) { return argument; } else { return apply(howmany - 1, func, func(argument)); } }; Вижу в отчете ошибку связанную с бесконечной рекурсией, но не как не могу понять где ошибка((. Полностью уверен в том, что это должно работать(. ","creator":{"public_name":"Бельнов Иван","id":163226,"is_tutor":false},"comments":[{"creator":{"public_name":"Бельнов Иван","id":163226,"is_tutor":false},"id":29054,"body":"Так, поскольку тут ответ, пожалуй удалю код)","topic_id":13822},{"creator":{"public_name":"Бельнов Иван","id":163226,"is_tutor":false},"id":29053,"body":"О боже, через 4 часа 43 минуты я все таки смог разглядеть ошибку, howmany = 0, howmany === 0 !!!!! \n","topic_id":13822}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты первого класса","entity_url":null,"active":true}},{"id":32205,"title":"Здравствуйте :)\n\n_Насколько мне известно, Chrome DevTools Console при вводе в нее выражения возвращает результат выражения. Т.е., если в консоль ввести просто 2, то консоль выведет эту двойку как результат выражения 2. Если ввести 2+3, то консоль выведет результат этого выражения - 5._\n\nПрочитав, что объявление функции - это выражение, мне захотелось это проверить. Я ввел в браузерную консоль выражение **() => {}**. Вау! Действительно! Консоль возвращает эту же функцию в качестве значения выражения. Затем я пробую объявить функцию через ключевое слово **function** и неожиданно получаю в ответ **undefined**. Т.е., выходит, значением выражения\n\n function doSomething () {}\n\nбудет undefined? Ок, я присваиваю ссылку на мою только что созданную функцию переменной и, о чудо, она присваивается без проблем. Подскажите, пожалуйста, почему консоль в качестве значения выражения \n\n function doSomething () {}\n\nвозвращает **undefined**? \nСпасибо!","plain_title":"Здравствуйте :) Насколько мне известно, Chrome DevTools Console при вводе в нее выражения возвращает результат выражения. Т.е., если в консоль ввести просто 2, то консоль выведет эту двойку как результат выражения 2. Если ввести 2+2, то консоль выведет результат этого выражения - 5. Прочитав, что объявление функции - это выражение, мне захотелось это проверить. Я ввел в браузерную консоль выражение () => {}. Вау! Действительно! Консоль возвращает эту же функцию в качестве значения выражения. Затем я пробую объявить функцию через ключевое слово function и неожиданно получаю в ответ undefined. Т.е., выходит, значением выражения function doSomething () {} будет undefined? Ок, я присваиваю ссылку на мою только что созданную функцию переменной и, о чудо, она присваивается без проблем. Подскажите, пожалуйста, почему консоль в качестве значения выражения function doSomething () {} возвращает undefined? Спасибо! ","creator":{"public_name":"Владислав Родько","id":76372,"is_tutor":false},"comments":[{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":69950,"body":"Приветствую, Владислав.\n\nВсе дело в том что `function doSomething () {}` в отличии от `() => {}` - не выражение, а инструкция. Инструкции всегда возвращают undefined. Подробнее посмотрите в документации - [undefined](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/undefined#Description).","topic_id":32205},{"creator":{"public_name":"Владислав Родько","id":76372,"is_tutor":false},"id":70008,"body":"Станислав, спасибо за ответ!\n\nЯ не знал, что одно и то же объявление функции может быть как выражением, так и инструкцией, в зависимости от того, присваивается ли это объявление переменной или нет.\n\n_function doSmth () {}_ - это **инструкция**\n\nconst sayHello = _function doSmth () {}_ - это **выражение**\n","topic_id":32205},{"creator":{"public_name":"Владислав Родько","id":76372,"is_tutor":false},"id":69958,"body":"**Станислав Дзисяк**, \n\nБольшое спасибо за ответ! Я был такого же мнения после своего эксперимента. Раз **function doSomething () {}** возвращает **undefined**, значит, возможно, это не выражение, а инструкция. Но, вспоминая предыдущие статьи, где было сказано о том, что нельзя в JavaScript присвоить инструкцию переменной (например, if), я решил попробовать присвоить function doSomething () {} переменной. Т.е. написал следующее:\n\n const sayHello = function doSomething () {\n console.log('Hello!');\n }\n\nИ, по идее, если бы объявление функции таким способом **function doSomething () {}** было бы инструкцией, то код выше не отработал бы. Мы ведь не можем сделать как-то так: **const isOld = if (x > 18) { console.log('I am old'); }**\n\nНо никакой ошибки не появилось. Более того, я потом легко вызвал функцию **sayHello()** и она благополучно отработала. Поэтому я не понимаю такого поведения. Это либо выражение, но тогда значение выражение должна быть функция, а не undefined, либо инструкция, но тогда мы ее не должны мочь присваивать переменным, а мы можем :(","topic_id":32205},{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":69985,"body":"Владислав, все именно так, и это происходит потому, что есть несколько способов объявления функции. А конкретно четыре:\n- Объявление функции (инструкция function)\n- Функция-выражение (оператор function)\n- Стрелочная функция-выражение (=>)\n- Конструктор Function\n\nСоответственно в первом случае возвращается undefined, а в остальных случаях возвращается собственно функция.\n\nРекомендую вам для изучения - [Определение функций](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions#Defining_functions)\n\n\n","topic_id":32205}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Объекты первого класса","entity_url":null,"active":true}}],"lesson":{"exercise":{"id":643,"slug":"js_functions_hard_way_first_class_citizen_exercise","name":null,"state":"active","kind":"exercise","language":"javascript","locale":"ru","has_web_view":false,"has_test_view":false,"reviewable":true,"readme":"## apply.js\n\nРеализуйте и экспортируйте по умолчанию функцию, которая принимает на вход три параметра:\n\n* Количество раз, которое нужно применить функцию к аргументу (ряд последовательных вызовов, где каждому следующему вызову передается аргумент, являющийся результатом предыдущего вызова функции; см. примеры ниже)\n* Функцию для применения\n* Аргумент для применения\n\n### Примеры\n\n```javascript\napply(0, Math.sqrt, 4); // 4\napply(1, Math.sqrt, 4); // 2\n\n// Math.sqrt(Math.sqrt(16));\napply(2, Math.sqrt, 16); // 2\n// Math.sqrt(Math.sqrt(Math.sqrt(256)));\napply(3, Math.sqrt, 256); // 2\n\napply(1, v => v ** 2, 3); // 9\napply(5, v => v + 10, 3); // 53\n```\n","prepared_readme":"## apply.js\n\nРеализуйте и экспортируйте по умолчанию функцию, которая принимает на вход три параметра:\n\n* Количество раз, которое нужно применить функцию к аргументу (ряд последовательных вызовов, где каждому следующему вызову передается аргумент, являющийся результатом предыдущего вызова функции; см. примеры ниже)\n* Функцию для применения\n* Аргумент для применения\n\n### Примеры\n\n```javascript\napply(0, Math.sqrt, 4); // 4\napply(1, Math.sqrt, 4); // 2\n\n// Math.sqrt(Math.sqrt(16));\napply(2, Math.sqrt, 16); // 2\n// Math.sqrt(Math.sqrt(Math.sqrt(256)));\napply(3, Math.sqrt, 256); // 2\n\napply(1, v => v ** 2, 3); // 9\napply(5, v => v + 10, 3); // 53\n```\n","has_solution":true,"entity_name":"Объекты первого класса"},"units":[{"id":2024,"name":"theory","url":"/courses/js-functions-hard-way/lessons/first-class-citizen/theory_unit"},{"id":2042,"name":"quiz","url":"/courses/js-functions-hard-way/lessons/first-class-citizen/quiz_unit"},{"id":2031,"name":"exercise","url":"/courses/js-functions-hard-way/lessons/first-class-citizen/exercise_unit"}],"links":[],"ordered_units":[{"id":2024,"name":"theory","url":"/courses/js-functions-hard-way/lessons/first-class-citizen/theory_unit"},{"id":2042,"name":"quiz","url":"/courses/js-functions-hard-way/lessons/first-class-citizen/quiz_unit"},{"id":2031,"name":"exercise","url":"/courses/js-functions-hard-way/lessons/first-class-citizen/exercise_unit"}],"id":974,"slug":"first-class-citizen","state":"approved","name":"Объекты первого класса","course_order":400,"goal":"Выясняем, что функции – это данные","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"Продолжая тему предыдущего урока, познакомимся с понятием \"first-class citizen\" или \"объекты первого класса\".\n\nОбъектами первого класса в контексте конкретного языка программирования называются элементы, которые могут быть переданы как параметр, возвращены из функции или присвоены переменной. Другими словами, речь идет обо всем, что может быть данными. Самые простые типы данных — это числа и строки. Как вы потом увидите, все остальные типы данных также являются объектами первого класса.\n\nА теперь посмотрите внимательно на этот код: `const x = () => console.log('hey')`. Ничего необычного, вы видели и писали подобное множество раз. Если вы считаете, что в этом коде создается функция `x`, на самом деле это не так. Здесь происходят следующие две операции:\n\n1. Создание функции: `() => console.log('hey')`\n1. Создание константы со значением в виде функции: `const x =`\n\nЭтот момент нужно хорошо прочувствовать. Минимальное определение функции, которое только возможно, выглядит так: `() => {}`. Это пустая функция с пустым телом, которая не делает ничего. Присваивать ее константе или нет — вопрос отдельный. Вполне допустимо написать и выполнить подобную программу: `(a, b) => a + b;`. Попробуйте поэкспериментировать в REPL.\n\nИз примеров выше можно сделать вывод, что функция — тоже данные, ведь ее можно присвоить константе. Рассмотрим это утверждение на практике:\n\n```javascript\nconst identity = v => v // функция: (v) => v, константа: identity\nconsole.log(identity(10)) // => 10\n\nconst z = identity\nconsole.log(z === identity) // => true\n\nconst x = 5\nconsole.log(z(x) === identity(x)) // => true\n```\n\nВыше определена функция, которую обычно называют `identity`. Она возвращает то значение, которое было ей передано. На практике такая функция нужна редко, но она очень хорошо подходит для демонстрации. Далее мы создали новую константу, которую связали с той же функцией.\n\nГлавный вывод, который можно сделать из кода выше, заключается в том, что **определение** функции — это выражение, а значит оно возвращает значение, а именно — функцию. А раз определение функции — выражение, возвращающее функцию, то мы можем попробовать вызвать ее без создания промежуточной константы:\n\n```javascript\n// Определяем функцию (v) => v и тут же вызываем ее\n(v => v)('run') // run\n\n// Тот же код с использованием промежуточной константы.\n// Попробуйте мысленно заменить `identity` на `(v) => v`, тогда\n// получится ((v) => v)('run'). С выражениями так можно поступать всегда.\n// const identity = (v) => v;\n// identity('run'); // run\n```\n\nСкобки вокруг определения функции — не какой-то особый синтаксис. Здесь они используются с той же целью, что и в арифметических операциях — для группировки. Без них выражение `(v) => v('run')` приобретает совсем другой смысл. В этом случае в нем создается функция, принимающая на вход другую функцию `v` и вызывающая ее внутри с аргументом `'run'`.\n\nПопробуем усложнить:\n\n```javascript\nidentity(v => v)('run') // run\n// ((v) => v)((v) => v)('run') // run\n```\n\nПервым идет пример вызова функции по идентификатору, а во втором примере мы заменили идентификатор на определение функции, сделав подстановку. Результат получился тот же самый. Еще раз посмотрите на этот шаблон `(<тут определение функции>)()`. Попробуйте самостоятельно разобрать пример ниже:\n\n```javascript\n((a, b) => a + b)(3, 2) // 5\n// const sum = (a, b) => a + b;\n// sum(3, 2); // 5\n```\n\nТеперь попробуем использовать функции как данные:\n\n```javascript\nconst sqrt = identity(Math.sqrt)\nconsole.log(sqrt === Math.sqrt) // => true\nsqrt(4) // 2\n```\n\nВ первой строчке вызывается функция `identity`, в которую передается `Math.sqrt`. Результатом этого вызова будет все та же функция `Math.sqrt`.\n\nЗдесь мы видим сразу два новых аспекта: передача функции как аргумента и возврат функции как значения. Функции, которые принимают на вход другие функции или возвращают другие функции, называются **функциями высшего порядка**. В функциональных языках большинство задач, связанных с обработкой данных, работают именно через них. JavaScript в этом смысле ведет себя точно так же.\n\nВ следующем примере внутрь функции передается другая функция, определяемая в аргументах. В комментариях показан альтернативный способ через создание константы с функцией.\n\n```javascript\nconst sum = identity((a, b) => a + b)\nsum(3, 5) // 8\n\n// const f = (a, b) => a + b;\n// const sum = identity(f);\n// sum(3, 5); // 8\n```\n\nПодобная передача функций в функции с определением прямо в аргументах встречается повсеместно в реальном коде. Как правило, те функции, которые передаются в аргументах, нужны только здесь и сейчас.\n\nВозникает вопрос: есть ли имя у функций, определенных подобным образом? Имени нет даже у такой функции `const f = () => {}`. Мы просто связали константу с функцией, но сама функция ничего про константу не знает. Звучит слегка безумно, но это так. Ведь мы можем\nвзять и связать эту функцию уже с другой константой. По этой причине такие функции часто называют анонимными. Другое распространенное название — _лямбда-функция_. Своим названием лямбда-функция обязана лямбда-исчислению (математическая формальная система, легшая в основу языков семейства lisp). Только в отличие от языков программирования, \"лямбды\" в лямбда-исчислении — всегда функции от одного аргумента, поэтому общее с функциями из js у них, в первую очередь, анонимность, и то, что они являются объектами первого класса.\n\nПопробуем сделать что-нибудь полезное. Иногда встречается задача, в рамках которой нужно применить одну и ту же функцию несколько раз, например, так: `Math.sqrt(Math.sqrt(16))`. Создав функцию высшего порядка, можно упростить эту задачу. Рассмотрим пример с двойным применением одноаргументной функции:\n\n```javascript\nconst callTwice = (f, arg) => f(f(arg))\n\ncallTwice(Math.sqrt, 16) // 2\ncallTwice(x => x ** 2, 3) // 81\n// const f = (x) => x ** 2;\n// f(f(3));\n```\n\n`callTwice` применяет переданную функцию к своему аргументу два раза. Если расписать подробнее, то происходит следующее:\n\n```javascript\nconst res1 = f(arg)\nconst res2 = f(res1)\nreturn res2\n```\n"},"lessonMember":null,"courseMember":null,"course":{"start_lesson":{"exercise":null,"units":[{"id":2026,"name":"theory","url":"/courses/js-functions-hard-way/lessons/intro/theory_unit"}],"links":[],"ordered_units":[{"id":2026,"name":"theory","url":"/courses/js-functions-hard-way/lessons/intro/theory_unit"}],"id":976,"slug":"intro","state":"approved","name":"Введение","course_order":100,"goal":"Знакомимся с целями и задачами курса, готовим окружение","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"Функции — тот элемент языка, с которым вы чаще всего будете иметь дело в будущем. В JavaScript они повсюду. И хотя вы уже научились создавать и использовать их, настоящая мощь функций раскроется в курсе [JS: коллекции](https://ru.hexlet.io/courses/js_collections), когда вы пройдете весь необходимый для этого материал. В дальнейшем при работе с асинхронным кодом вам понадобится мастерское владение функциями, так как на этом этапе от их количества начнет рябить в глазах.\n\nНиже рассмотрим пример, в котором нет ни одного нового синтаксического элемента, но если ваш опыт программирования ограничивается парой начальных курсов Хекслета, вы вряд ли сможете его понять:\n\n```javascript\nconst f = (x = 5) => y => x + y(3)\nf()(x => 7 + x) // 15\n```\n\nБуквально несколько строк, но очень высокая плотность кода. К концу курса вы сможете не только понять этот код, но и научитесь так писать. Для этого нужно соблюсти несколько условий:\n\n* Практически каждый курс на Хекслете содержит дополнительные задания (челленджи), которые помогают закрепить пройденный материал. Их нужно проходить, чтобы набить руку. К [курсу JS: Массивы](https://ru.hexlet.io/courses/js-arrays) таких задач довольно много, поэтому рекомендуем остановиться и пойти выполнить хотя бы штук 5, если вы до сих пор этого не сделали.\n* Привыкайте к новому синтаксису функций, даже если сейчас сложно. Уверяю вас, это всего лишь дело привычки. Хекслет не просто дает новые знания, но и старается формировать хорошие привычки.\n* Рекурсия станет центральной темой в ближайших нескольких курсах. Если у вас возникли сложности с ней, то самое время их победить. Попробуйте пройти челленджи [курса введение в программирование](https://ru.hexlet.io/courses/introduction_to_programming), используя только рекурсию, или попросите помощи в нашем комьюнити.\n* Ни в коем случае не двигайтесь вперед, пока не поняли тот урок, который проходите. Вероятность того, что вы поймете его потом, крайне мала. Скорее всего все станет еще сложнее, так как каждый следующий урок использует знания предыдущего. Если вам что-то непонятно, пишите в «Вопросы и ответы», и мы поможем вам продвинуться.\n\nТемы, которые мы рассмотрим в рамках этого курса:\n\n* Значение по умолчанию\n* Функции как объекты первого рода\n* Функции высшего порядка\n* Сложность функции\n* Частичное применение\n* Каррирование\n\nПараллельно с курсом рекомендуем посматривать в Википедию и знакомиться с соответствующими понятиями.\n\nПрактика в этом курсе с одной стороны достаточно простая и короткая, но порой мозговыносящая, так как придется жонглировать функциями в совершенно необычной форме. Она по-прежнему в основном ориентирована на арифметические операции, так как ваш текущий багаж знаний не позволяет рассматривать более сложные и интересные примеры, но это продлится недолго — уже со следующего курса мы переключимся на них.\n"},"id":151,"slug":"js-functions-hard-way","challenges_count":3,"name":"JS: Функциональное программирование","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"paid","description":"На этом курсе вы изучите основы функционального программирования в JavaScript. Вы узнаете, что такое функции первого порядка. Вы научитесь уменьшать сложность функций и поймете, как функции ведут себя в составных выражениях. Вы освоите работу с механизмом замыканий, возвратом функций из функций, каррированием и частичным применением. Знания из этого курса помогут проектировать лаконичные и эффективные программы, отделяя побочные эффекты от чистого кода.","kind":"additional","updated_at":"2026-01-20T11:39:08.643Z","language":"javascript","duration_cache":39300,"skills":["Оценивать сложность функций и упрощать их код","Продвинутому использованию замыканий","Использовать композицию функций для решения реальных задач"],"keywords":["guard expression","основы функционального программирования","выражения и инструкции"],"lessons_count":9,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NjEwMCwicHVyIjoiYmxvYl9pZCJ9fQ==--8a19418dd689b3f227e6674ecd168dfacaea7c89/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJqcGciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--39ba06fa99226096df9fc6bb31f84e1d29ea98e9/image.png"},"recommendedLandings":[{"stack":{"id":20,"slug":"js-sicp","title":"СИКП на JS","audience":"for_programmers","start_type":"anytime","pricing_model":"subscription","priority":"medium","kind":"track","state":"published","stack_state":"finished","order":4050,"duration_in_months":1},"id":28,"slug":"js-sicp","title":"СИКП на JS","subtitle":"Навык понимать программы на фундаментальном уровне, уверенно проходить собеседования и решать сложные задачи","subtitle_for_lists":"Навык фундаментального программирования","locale":"ru","current":true,"duration_in_months_text":"1 месяц","stack_slug":"js-sicp","price_text":"от 3 900 ₽","duration_text":"1 месяц","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc2MCwicHVyIjoiYmxvYl9pZCJ9fQ==--9348098e4053d798b6f34bee4ef66947540261e4/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Low%20code%20development-rafiki.png"}],"lessonMemberUnit":null,"accessToLearnUnitExists":false,"accessToCourseExists":false},"url":"/courses/js-functions-hard-way/lessons/first-class-citizen/theory_unit","version":"8f286f6358a90a7bef2263b3a6edf5a90a94fa42","encryptHistory":false,"clearHistory":false}"><style data-mantine-styles="true">:root, :host{--mantine-font-family: Arial, sans-serif;--mantine-font-family-headings: Arial, sans-serif;--mantine-heading-font-weight: normal;--mantine-radius-default: 0rem;--mantine-primary-color-filled: var(--mantine-color-indigo-filled);--mantine-primary-color-filled-hover: var(--mantine-color-indigo-filled-hover);--mantine-primary-color-light: var(--mantine-color-indigo-light);--mantine-primary-color-light-hover: var(--mantine-color-indigo-light-hover);--mantine-primary-color-light-color: var(--mantine-color-indigo-light-color);--mantine-spacing-xxl: calc(4rem * var(--mantine-scale));--mantine-font-size-xs: 12px;--mantine-font-size-sm: 14px;--mantine-font-size-md: 16px;--mantine-font-size-lg: clamp(16.0000px, calc(15.2727px + 0.2273vw), 18.0000px);--mantine-font-size-xl: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-display-3: clamp(32.0000px, calc(26.1818px + 1.8182vw), 48.0000px);--mantine-font-size-display-2: clamp(36.0000px, calc(25.8182px + 3.1818vw), 64.0000px);--mantine-font-size-display-1: clamp(40.0000px, calc(25.4545px + 4.5455vw), 80.0000px);--mantine-font-size-h1: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-font-size-h2: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-font-size-h3: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-font-size-h4: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-font-size-h5: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-h6: 1rem;--mantine-primary-color-0: var(--mantine-color-indigo-0);--mantine-primary-color-1: var(--mantine-color-indigo-1);--mantine-primary-color-2: var(--mantine-color-indigo-2);--mantine-primary-color-3: var(--mantine-color-indigo-3);--mantine-primary-color-4: var(--mantine-color-indigo-4);--mantine-primary-color-5: var(--mantine-color-indigo-5);--mantine-primary-color-6: var(--mantine-color-indigo-6);--mantine-primary-color-7: var(--mantine-color-indigo-7);--mantine-primary-color-8: var(--mantine-color-indigo-8);--mantine-primary-color-9: var(--mantine-color-indigo-9);--mantine-color-red-0: #ffeaea;--mantine-color-red-1: #fed4d4;--mantine-color-red-2: #f4a7a8;--mantine-color-red-3: #ec7878;--mantine-color-red-4: #e55050;--mantine-color-red-5: #e03131;--mantine-color-red-6: #e02829;--mantine-color-red-7: #c71a1c;--mantine-color-red-8: #b21218;--mantine-color-red-9: #9c0411;--mantine-color-violet-0: #fce9ff;--mantine-color-violet-1: #f1cfff;--mantine-color-violet-2: #e09bff;--mantine-color-violet-3: #d16fff;--mantine-color-violet-4: #be37fe;--mantine-color-violet-5: #b51afe;--mantine-color-violet-6: #b009ff;--mantine-color-violet-7: #9b00e4;--mantine-color-violet-8: #8a00cc;--mantine-color-violet-9: #7800b3;--mantine-color-indigo-0: #edecff;--mantine-color-indigo-1: #d6d5fe;--mantine-color-indigo-2: #aaa9f4;--mantine-color-indigo-3: #7b79eb;--mantine-color-indigo-4: #5451e4;--mantine-color-indigo-5: #3b37e0;--mantine-color-indigo-6: #2d2adf;--mantine-color-indigo-7: #1f1ec7;--mantine-color-indigo-8: #1819b2;--mantine-color-indigo-9: #0c149e;--mantine-color-cyan-0: #dffdff;--mantine-color-cyan-1: #caf5ff;--mantine-color-cyan-2: #99e8ff;--mantine-color-cyan-3: #64daff;--mantine-color-cyan-4: #3ccffe;--mantine-color-cyan-5: #24c8fe;--mantine-color-cyan-6: #00c2ff;--mantine-color-cyan-7: #00ade4;--mantine-color-cyan-8: #009acd;--mantine-color-cyan-9: #0085b5;--mantine-color-green-0: #e9fdec;--mantine-color-green-1: #d7f6dc;--mantine-color-green-2: #b0eab9;--mantine-color-green-3: #86df94;--mantine-color-green-4: #62d574;--mantine-color-green-5: #4ccf5f;--mantine-color-green-6: #3fcc54;--mantine-color-green-7: #2fb344;--mantine-color-green-8: #25a03b;--mantine-color-green-9: #138a2e;--mantine-color-yellow-0: #fff7e2;--mantine-color-yellow-1: #ffeecd;--mantine-color-yellow-2: #ffdc9c;--mantine-color-yellow-3: #ffc966;--mantine-color-yellow-4: #feb93a;--mantine-color-yellow-5: #feae1e;--mantine-color-yellow-6: #ffa90f;--mantine-color-yellow-8: #ca8200;--mantine-color-yellow-9: #af7000;--mantine-h1-font-size: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-h1-font-weight: normal;--mantine-h2-font-size: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-h2-font-weight: normal;--mantine-h3-font-size: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-h3-font-weight: normal;--mantine-h4-font-size: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-h4-font-weight: normal;--mantine-h5-font-size: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-h5-font-weight: normal;--mantine-h6-font-size: 1rem;--mantine-h6-font-weight: normal;}
:root[data-mantine-color-scheme="dark"], :host([data-mantine-color-scheme="dark"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-dark-filled: var(--mantine-color-dark-5);--mantine-color-dark-filled-hover: var(--mantine-color-dark-6);--mantine-color-dark-light: rgba(105, 105, 105, 0.15);--mantine-color-dark-light-hover: rgba(105, 105, 105, 0.2);--mantine-color-dark-light-color: var(--mantine-color-dark-0);--mantine-color-dark-outline: var(--mantine-color-dark-1);--mantine-color-dark-outline-hover: rgba(184, 184, 184, 0.05);--mantine-color-gray-filled: var(--mantine-color-gray-5);--mantine-color-gray-filled-hover: var(--mantine-color-gray-6);--mantine-color-gray-light: rgba(222, 226, 230, 0.15);--mantine-color-gray-light-hover: rgba(222, 226, 230, 0.2);--mantine-color-gray-light-color: var(--mantine-color-gray-0);--mantine-color-gray-outline: var(--mantine-color-gray-1);--mantine-color-gray-outline-hover: rgba(241, 243, 245, 0.05);--mantine-color-red-filled: var(--mantine-color-red-5);--mantine-color-red-filled-hover: var(--mantine-color-red-6);--mantine-color-red-light: rgba(236, 120, 120, 0.15);--mantine-color-red-light-hover: rgba(236, 120, 120, 0.2);--mantine-color-red-light-color: var(--mantine-color-red-0);--mantine-color-red-outline: var(--mantine-color-red-1);--mantine-color-red-outline-hover: rgba(254, 212, 212, 0.05);--mantine-color-pink-filled: var(--mantine-color-pink-5);--mantine-color-pink-filled-hover: var(--mantine-color-pink-6);--mantine-color-pink-light: rgba(250, 162, 193, 0.15);--mantine-color-pink-light-hover: rgba(250, 162, 193, 0.2);--mantine-color-pink-light-color: var(--mantine-color-pink-0);--mantine-color-pink-outline: var(--mantine-color-pink-1);--mantine-color-pink-outline-hover: rgba(255, 222, 235, 0.05);--mantine-color-grape-filled: var(--mantine-color-grape-5);--mantine-color-grape-filled-hover: var(--mantine-color-grape-6);--mantine-color-grape-light: rgba(229, 153, 247, 0.15);--mantine-color-grape-light-hover: rgba(229, 153, 247, 0.2);--mantine-color-grape-light-color: var(--mantine-color-grape-0);--mantine-color-grape-outline: var(--mantine-color-grape-1);--mantine-color-grape-outline-hover: rgba(243, 217, 250, 0.05);--mantine-color-violet-filled: var(--mantine-color-violet-5);--mantine-color-violet-filled-hover: var(--mantine-color-violet-6);--mantine-color-violet-light: rgba(209, 111, 255, 0.15);--mantine-color-violet-light-hover: rgba(209, 111, 255, 0.2);--mantine-color-violet-light-color: var(--mantine-color-violet-0);--mantine-color-violet-outline: var(--mantine-color-violet-1);--mantine-color-violet-outline-hover: rgba(241, 207, 255, 0.05);--mantine-color-indigo-filled: var(--mantine-color-indigo-5);--mantine-color-indigo-filled-hover: var(--mantine-color-indigo-6);--mantine-color-indigo-light: rgba(123, 121, 235, 0.15);--mantine-color-indigo-light-hover: rgba(123, 121, 235, 0.2);--mantine-color-indigo-light-color: var(--mantine-color-indigo-0);--mantine-color-indigo-outline: var(--mantine-color-indigo-1);--mantine-color-indigo-outline-hover: rgba(214, 213, 254, 0.05);--mantine-color-blue-filled: var(--mantine-color-blue-5);--mantine-color-blue-filled-hover: var(--mantine-color-blue-6);--mantine-color-blue-light: rgba(116, 192, 252, 0.15);--mantine-color-blue-light-hover: rgba(116, 192, 252, 0.2);--mantine-color-blue-light-color: var(--mantine-color-blue-0);--mantine-color-blue-outline: var(--mantine-color-blue-1);--mantine-color-blue-outline-hover: rgba(208, 235, 255, 0.05);--mantine-color-cyan-filled: var(--mantine-color-cyan-5);--mantine-color-cyan-filled-hover: var(--mantine-color-cyan-6);--mantine-color-cyan-light: rgba(100, 218, 255, 0.15);--mantine-color-cyan-light-hover: rgba(100, 218, 255, 0.2);--mantine-color-cyan-light-color: var(--mantine-color-cyan-0);--mantine-color-cyan-outline: var(--mantine-color-cyan-1);--mantine-color-cyan-outline-hover: rgba(202, 245, 255, 0.05);--mantine-color-teal-filled: var(--mantine-color-teal-5);--mantine-color-teal-filled-hover: var(--mantine-color-teal-6);--mantine-color-teal-light: rgba(99, 230, 190, 0.15);--mantine-color-teal-light-hover: rgba(99, 230, 190, 0.2);--mantine-color-teal-light-color: var(--mantine-color-teal-0);--mantine-color-teal-outline: var(--mantine-color-teal-1);--mantine-color-teal-outline-hover: rgba(195, 250, 232, 0.05);--mantine-color-green-filled: var(--mantine-color-green-5);--mantine-color-green-filled-hover: var(--mantine-color-green-6);--mantine-color-green-light: rgba(134, 223, 148, 0.15);--mantine-color-green-light-hover: rgba(134, 223, 148, 0.2);--mantine-color-green-light-color: var(--mantine-color-green-0);--mantine-color-green-outline: var(--mantine-color-green-1);--mantine-color-green-outline-hover: rgba(215, 246, 220, 0.05);--mantine-color-lime-filled: var(--mantine-color-lime-5);--mantine-color-lime-filled-hover: var(--mantine-color-lime-6);--mantine-color-lime-light: rgba(192, 235, 117, 0.15);--mantine-color-lime-light-hover: rgba(192, 235, 117, 0.2);--mantine-color-lime-light-color: var(--mantine-color-lime-0);--mantine-color-lime-outline: var(--mantine-color-lime-1);--mantine-color-lime-outline-hover: rgba(233, 250, 200, 0.05);--mantine-color-yellow-filled: var(--mantine-color-yellow-5);--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-6);--mantine-color-yellow-light: rgba(255, 201, 102, 0.15);--mantine-color-yellow-light-hover: rgba(255, 201, 102, 0.2);--mantine-color-yellow-light-color: var(--mantine-color-yellow-0);--mantine-color-yellow-outline: var(--mantine-color-yellow-1);--mantine-color-yellow-outline-hover: rgba(255, 238, 205, 0.05);--mantine-color-orange-filled: var(--mantine-color-orange-5);--mantine-color-orange-filled-hover: var(--mantine-color-orange-6);--mantine-color-orange-light: rgba(255, 192, 120, 0.15);--mantine-color-orange-light-hover: rgba(255, 192, 120, 0.2);--mantine-color-orange-light-color: var(--mantine-color-orange-0);--mantine-color-orange-outline: var(--mantine-color-orange-1);--mantine-color-orange-outline-hover: rgba(255, 232, 204, 0.05);--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-9) 0%, var(--mantine-color-cyan-7) 100%);--app-color-surface: #2e2e2e;}
:root[data-mantine-color-scheme="light"], :host([data-mantine-color-scheme="light"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-red-light: rgba(224, 40, 41, 0.1);--mantine-color-red-light-hover: rgba(224, 40, 41, 0.12);--mantine-color-red-outline-hover: rgba(224, 40, 41, 0.05);--mantine-color-violet-light: rgba(176, 9, 255, 0.1);--mantine-color-violet-light-hover: rgba(176, 9, 255, 0.12);--mantine-color-violet-outline-hover: rgba(176, 9, 255, 0.05);--mantine-color-indigo-light: rgba(45, 42, 223, 0.1);--mantine-color-indigo-light-hover: rgba(45, 42, 223, 0.12);--mantine-color-indigo-outline-hover: rgba(45, 42, 223, 0.05);--mantine-color-cyan-light: rgba(0, 194, 255, 0.1);--mantine-color-cyan-light-hover: rgba(0, 194, 255, 0.12);--mantine-color-cyan-outline-hover: rgba(0, 194, 255, 0.05);--mantine-color-green-light: rgba(63, 204, 84, 0.1);--mantine-color-green-light-hover: rgba(63, 204, 84, 0.12);--mantine-color-green-outline-hover: rgba(63, 204, 84, 0.05);--mantine-color-yellow-light: rgba(255, 169, 15, 0.1);--mantine-color-yellow-light-hover: rgba(255, 169, 15, 0.12);--mantine-color-yellow-outline-hover: rgba(255, 169, 15, 0.05);--app-color-surface: #f1f3f5;--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-5) 100%);}</style><style data-mantine-styles="classes">@media (max-width: 35.99375em) {.mantine-visible-from-xs {display: none !important;}}@media (min-width: 36em) {.mantine-hidden-from-xs {display: none !important;}}@media (max-width: 47.99375em) {.mantine-visible-from-sm {display: none !important;}}@media (min-width: 48em) {.mantine-hidden-from-sm {display: none !important;}}@media (max-width: 61.99375em) {.mantine-visible-from-md {display: none !important;}}@media (min-width: 62em) {.mantine-hidden-from-md {display: none !important;}}@media (max-width: 74.99375em) {.mantine-visible-from-lg {display: none !important;}}@media (min-width: 75em) {.mantine-hidden-from-lg {display: none !important;}}@media (max-width: 87.99375em) {.mantine-visible-from-xl {display: none !important;}}@media (min-width: 88em) {.mantine-hidden-from-xl {display: none !important;}}</style><div style="position:absolute;top:0rem" class=""></div><div style="max-width:var(--container-size-xl);height:100%;min-height:0rem" class=""><style data-mantine-styles="inline">.__m__-_R_5ub_{--grid-gutter:0rem;}</style><div style="height:100%;min-height:0rem" class="m_410352e9 mantine-Grid-root __m__-_R_5ub_"><div class="m_dee7bd2f mantine-Grid-inner" style="height:100%"><style data-mantine-styles="inline">.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:91.66666666666667%;--col-max-width:91.66666666666667%;}@media(min-width: 48em){.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:83.33333333333334%;--col-max-width:83.33333333333334%;}}</style><div style="min-width:0rem;height:100%;min-height:0rem;display:flex" class="m_96bdd299 mantine-Grid-col __m__-_R_rdub_"><style data-mantine-styles="inline">.__m__-_R_6qrdub_{margin-top:0rem;padding-inline:var(--mantine-spacing-xs);width:100%;}@media(min-width: 48em){.__m__-_R_6qrdub_{margin-top:var(--mantine-spacing-xl);width:80%;}}@media(min-width: 62em){.__m__-_R_6qrdub_{padding-inline:var(--mantine-spacing-xl);}}</style><div style="margin-inline:auto;max-width:var(--mantine-breakpoint-xl)" class="__m__-_R_6qrdub_"><div style="color:var(--mantine-color-dimmed)" class="m_4451eb3a mantine-Center-root" data-inline="true"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:calc(0.125rem * var(--mantine-scale));color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-lock "><path d="M5 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-6"></path><path d="M11 16a1 1 0 1 0 2 0a1 1 0 0 0 -2 0"></path><path d="M8 11v-4a4 4 0 1 1 8 0v4"></path></svg></div><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">JS: Функциональное программирование</p></div><h1 style="--title-fw:var(--mantine-h1-font-weight);--title-lh:var(--mantine-h1-line-height);--title-fz:var(--mantine-h1-font-size);margin-bottom:var(--mantine-spacing-xl)" class="m_8a5d1357 mantine-Title-root" data-order="1">Теория: Объекты первого класса</h1><script type="application/ld+json">{"@context":"https://schema.org","@type":"LearningResource","name":"Объекты первого класса","inLanguage":"ru","isPartOf":{"@type":"LearningResource","name":"JS: Функциональное программирование"},"isAccessibleForFree":"False","hasPart":{"@type":"WebPageElement","isAccessibleForFree":"False","cssSelector":".paywalled"}}</script><div class=""><div style="--alert-color:var(--mantine-color-indigo-light-color);margin-bottom:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-lg)" class="m_66836ed3 mantine-Alert-root" id="mantine-_R_remqrdub_" role="alert" aria-describedby="mantine-_R_remqrdub_-body" aria-labelledby="mantine-_R_remqrdub_-title"><div class="m_a5d60502 mantine-Alert-wrapper"><div class="m_667f2a6a mantine-Alert-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-rocket "><path d="M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3 -5a9 9 0 0 0 6 -8a3 3 0 0 0 -3 -3a9 9 0 0 0 -8 6a6 6 0 0 0 -5 3"></path><path d="M7 14a6 6 0 0 0 -3 6a6 6 0 0 0 6 -3"></path><path d="M14 9a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path></svg></div><div class="m_667c2793 mantine-Alert-body"><div class="m_6a03f287 mantine-Alert-title"><span id="mantine-_R_remqrdub_-title" class="m_698f4f23 mantine-Alert-label">Полный доступ к материалам</span></div><div id="mantine-_R_remqrdub_-body" class="m_7fa78076 mantine-Alert-message"><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root"><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Зарегистрируйтесь и получите доступ к этому и десяткам других курсов</p><a style="--button-height:var(--button-height-xs);--button-padding-x:var(--button-padding-x-xs);--button-fz:var(--mantine-font-size-xs);--button-bg:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-hover:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-color:var(--mantine-color-white);--button-bd:none" class="mantine-focus-auto mantine-active m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root" data-variant="gradient" data-size="xs" href="/u/new"><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">Зарегистрироваться</span></span></a></div></div></div></div></div><div class="paywalled m_d08caa0 mantine-Typography-root"><p>Продолжая тему предыдущего урока, познакомимся с понятием "first-class citizen" или "объекты первого класса".</p>
<p>Объектами первого класса в контексте конкретного языка программирования называются элементы, которые могут быть переданы как параметр, возвращены из функции или присвоены переменной. Другими словами, речь идет обо всем, что может быть данными. Самые простые типы данных — это числа и строки. Как вы потом увидите, все остальные типы данных также являются объектами первого класса.</p>
<p>А теперь посмотрите внимательно на этот код: <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">const x = () => console.log('hey')</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>
<ol>
<li>Создание функции: <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">() => console.log('hey')</code></li>
<li>Создание константы со значением в виде функции: <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">const x =</code></li>
</ol>
<p>Этот момент нужно хорошо прочувствовать. Минимальное определение функции, которое только возможно, выглядит так: <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">() => {}</code>. Это пустая функция с пустым телом, которая не делает ничего. Присваивать ее константе или нет — вопрос отдельный. Вполне допустимо написать и выполнить подобную программу: <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">(a, b) => a + b;</code>. Попробуйте поэкспериментировать в REPL.</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 identity = v => v // функция: (v) => v, константа: identity
console.log(identity(10)) // => 10
const z = identity
console.log(z === identity) // => true
const x = 5
console.log(z(x) === identity(x)) // => 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">identity</code>. Она возвращает то значение, которое было ей передано. На практике такая функция нужна редко, но она очень хорошо подходит для демонстрации. Далее мы создали новую константу, которую связали с той же функцией.</p>
<p>Главный вывод, который можно сделать из кода выше, заключается в том, что <strong>определение</strong> функции — это выражение, а значит оно возвращает значение, а именно — функцию. А раз определение функции — выражение, возвращающее функцию, то мы можем попробовать вызвать ее без создания промежуточной константы:</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">// Определяем функцию (v) => v и тут же вызываем ее
(v => v)('run') // run
// Тот же код с использованием промежуточной константы.
// Попробуйте мысленно заменить `identity` на `(v) => v`, тогда
// получится ((v) => v)('run'). С выражениями так можно поступать всегда.
// const identity = (v) => v;
// identity('run'); // run</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">(v) => v('run')</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">v</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">'run'</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">identity(v => v)('run') // run
// ((v) => v)((v) => v)('run') // run</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Первым идет пример вызова функции по идентификатору, а во втором примере мы заменили идентификатор на определение функции, сделав подстановку. Результат получился тот же самый. Еще раз посмотрите на этот шаблон <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">(<тут определение функции>)()</code>. Попробуйте самостоятельно разобрать пример ниже:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">((a, b) => a + b)(3, 2) // 5
// const sum = (a, b) => a + b;
// sum(3, 2); // 5</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">const sqrt = identity(Math.sqrt)
console.log(sqrt === Math.sqrt) // => true
sqrt(4) // 2</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">identity</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">Math.sqrt</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">Math.sqrt</code>.</p>
<p>Здесь мы видим сразу два новых аспекта: передача функции как аргумента и возврат функции как значения. Функции, которые принимают на вход другие функции или возвращают другие функции, называются <strong>функциями высшего порядка</strong>. В функциональных языках большинство задач, связанных с обработкой данных, работают именно через них. JavaScript в этом смысле ведет себя точно так же.</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 sum = identity((a, b) => a + b)
sum(3, 5) // 8
// const f = (a, b) => a + b;
// const sum = identity(f);
// sum(3, 5); // 8</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Подобная передача функций в функции с определением прямо в аргументах встречается повсеместно в реальном коде. Как правило, те функции, которые передаются в аргументах, нужны только здесь и сейчас.</p>
<p>Возникает вопрос: есть ли имя у функций, определенных подобным образом? Имени нет даже у такой функции <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">const f = () => {}</code>. Мы просто связали константу с функцией, но сама функция ничего про константу не знает. Звучит слегка безумно, но это так. Ведь мы можем
взять и связать эту функцию уже с другой константой. По этой причине такие функции часто называют анонимными. Другое распространенное название — <em>лямбда-функция</em>. Своим названием лямбда-функция обязана лямбда-исчислению (математическая формальная система, легшая в основу языков семейства lisp). Только в отличие от языков программирования, "лямбды" в лямбда-исчислении — всегда функции от одного аргумента, поэтому общее с функциями из js у них, в первую очередь, анонимность, и то, что они являются объектами первого класса.</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">Math.sqrt(Math.sqrt(16))</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 callTwice = (f, arg) => f(f(arg))
callTwice(Math.sqrt, 16) // 2
callTwice(x => x ** 2, 3) // 81
// const f = (x) => x ** 2;
// f(f(3));</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p><code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">callTwice</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 res1 = f(arg)
const res2 = f(res1)
return res2</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div></div><div style="margin-block:var(--mantine-spacing-xl)" class=""><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size);margin-bottom:var(--mantine-spacing-md)" class="m_8a5d1357 mantine-Title-root" data-order="2">Рекомендуемые программы</h2><style data-mantine-styles="inline">.__m__-_R_2mremqrdub_{--carousel-slide-gap:var(--mantine-spacing-xs);--carousel-slide-size:70%;}@media(min-width: 36em){.__m__-_R_2mremqrdub_{--carousel-slide-gap:var(--mantine-spacing-xl);--carousel-slide-size:50%;}}</style><div style="--carousel-control-size:calc(2.5rem * var(--mantine-scale));--carousel-controls-offset:var(--mantine-spacing-sm);margin-bottom:var(--mantine-spacing-lg);padding-block:var(--mantine-spacing-sm);background:var(--app-color-surface)" class="m_17884d0f mantine-Carousel-root responsiveClassName" data-orientation="horizontal" data-include-gap-in-size="true"><div class="m_39bc3463 mantine-Carousel-controls" data-orientation="horizontal"><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="previous" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="next" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(-90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button></div><div class="m_a2dae653 mantine-Carousel-viewport" data-type="media"><div class="m_fcd81474 mantine-Carousel-container __m__-_R_2mremqrdub_" data-orientation="horizontal"><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/js-sicp?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">1 месяц</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Для продвинутых</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">СИКП на JS</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Навык фундаментального программирования</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc2MCwicHVyIjoiYmxvYl9pZCJ9fQ==--9348098e4053d798b6f34bee4ef66947540261e4/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Low%20code%20development-rafiki.png" alt="СИКП на JS" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 3 900 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size);margin-bottom:var(--mantine-spacing-md);font-size:var(--mantine-font-size-h3)" class="m_8a5d1357 mantine-Title-root" data-order="2" data-responsive="true">Каталог</h2><p style="margin-bottom:auto" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Полный список доступных курсов по разным направлениям</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="/vite/assets/development-BVihs_d5.png" alt="Orientation"/></div></div></div></a></div></div></div></div></div></div></div></div></div><style data-mantine-styles="inline">.__m__-_R_1bdub_{--col-flex-grow:auto;--col-flex-basis:8.333333333333334%;--col-max-width:8.333333333333334%;}@media(min-width: 48em){.__m__-_R_1bdub_{--col-flex-grow:auto;--col-flex-basis:16.666666666666668%;--col-max-width:16.666666666666668%;}}</style><div style="min-width:0rem;height:100%;min-height:0rem" class="m_96bdd299 mantine-Grid-col __m__-_R_1bdub_"><div style="margin-inline:var(--mantine-spacing-xs)" class="mantine-visible-from-sm"><a style="--button-color:var(--mantine-color-white);margin-bottom:var(--mantine-spacing-lg);text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/js-functions-hard-way/lessons/first-class-citizen/finish_unit?unit=theory" data-disabled="true" data-block="true" disabled=""><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label"><span style="margin-inline-end:var(--mantine-spacing-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Дальше</span>→</span></span></a><a style="padding-inline:0rem" class="mantine-focus-auto m_f0824112 mantine-NavLink-root m_87cf2631 mantine-UnstyledButton-root"><span class="m_690090b5 mantine-NavLink-section" data-position="left"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-list-numbers "><path d="M11 6h9"></path><path d="M11 12h9"></path><path d="M12 18h8"></path><path d="M4 16a2 2 0 1 1 4 0c0 .591 -.5 1 -1 1.5l-3 2.5h4"></path><path d="M6 10v-6l-2 2"></path></svg></div></span><div class="m_f07af9d2 mantine-NavLink-body"><span class="m_1f6ac4c4 mantine-NavLink-label">Навигация по теме</span><span class="m_57492dcc mantine-NavLink-description">Теория</span></div><span class="m_690090b5 mantine-NavLink-section" data-position="right"></span></a><div style="margin-block:var(--mantine-spacing-lg)" class="m_3eebeb36 mantine-Divider-root" data-orientation="horizontal" role="separator"></div><div style="margin-block:var(--mantine-spacing-lg)" class=""><div style="justify-content:space-between;margin-bottom:calc(0.1875rem * var(--mantine-scale));color:var(--mantine-color-dimmed);font-size:var(--mantine-font-size-xs)" class="m_8bffd616 mantine-Flex-root __m__-_R_qimrbdub_"><p style="font-size:var(--mantine-font-size-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Завершено</p><p style="font-size:var(--mantine-font-size-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">0 / 9</p></div><div style="--progress-size:var(--progress-size-sm)" class="m_db6d6462 mantine-Progress-root" data-size="sm"><div style="--progress-section-size:0%;--progress-section-color:var(--mantine-color-gray-filled)" class="m_2242eb65 mantine-Progress-section" role="progressbar" aria-valuemax="100" aria-valuemin="0" aria-valuenow="0" aria-valuetext="0%"></div></div></div><button style="padding-inline:0rem" class="mantine-focus-auto m_f0824112 mantine-NavLink-root m_87cf2631 mantine-UnstyledButton-root" type="button"><span class="m_690090b5 mantine-NavLink-section" data-position="left"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-message "><path d="M8 9h8"></path><path d="M8 13h6"></path><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"></path></svg></div></span><div class="m_f07af9d2 mantine-NavLink-body"><span class="m_1f6ac4c4 mantine-NavLink-label">Обсуждения (архив)</span><span class="m_57492dcc mantine-NavLink-description"></span></div></button><div style="--toc-bg:var(--mantine-color-blue-light);--toc-color:var(--mantine-color-blue-light-color);--toc-size:var(--mantine-font-size-sm);--toc-radius:var(--mantine-radius-sm);margin-top:var(--mantine-spacing-xl)" class="m_bcaa9990 mantine-TableOfContents-root" data-variant="light" data-size="sm"></div></div><div class="mantine-hidden-from-sm"><div style="--stack-gap:0rem;--stack-align:stretch;--stack-justify:flex-start" class="m_6d731127 mantine-Stack-root"><a style="--button-color:var(--mantine-color-white);margin-bottom:var(--mantine-spacing-xs);padding:0rem;text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/js-functions-hard-way/lessons/first-class-citizen/finish_unit?unit=theory" data-disabled="true" data-block="true" disabled=""><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">→</span></span></a><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" data-disabled="true" type="button" disabled=""><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-list-numbers "><path d="M11 6h9"></path><path d="M11 12h9"></path><path d="M12 18h8"></path><path d="M4 16a2 2 0 1 1 4 0c0 .591 -.5 1 -1 1.5l-3 2.5h4"></path><path d="M6 10v-6l-2 2"></path></svg></span></button><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto mantine-active m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" type="button"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-message "><path d="M8 9h8"></path><path d="M8 13h6"></path><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"></path></svg></span></button></div></div></div></div></div></div></div>
</main>
<footer class="bg-dark fw-light text-light px-3 py-5">
<div class="row small">
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 mb-3">Хекслет</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/about">О нас</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/testimonials">Отзывы</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://b2b.hexlet.io" role="button">Корпоративное обучение</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/blog">Блог</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/qna">Вопросы и ответы</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/glossary">Глоссарий</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://help.hexlet.io" data-target="_blank" role="button">Справка</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" target="_blank" rel="noopener noreferrer" href="/map">Карта сайта</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 fw-normal mb-3">Направления</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_devops">DevOps
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_data_analytics">Аналитика
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_backend_development">Бэкенд
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_programming">Программирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_testing">Тестирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_front_end_dev">Фронтенд
</a></li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Профессии</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/go">Go-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/java">Java-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python">Python-разработчик </a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/data-analytics">Аналитик данных</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/qa-engineer">Инженер по ручному тестированию</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php">РНР-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/frontend">Фронтенд-разработчик</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Навыки</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python-django-developer">Django</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/docker">Docker</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php-laravel-developer">Laravel</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/postman">Postman</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-react-developer">React</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-rest-api">REST API в Node.js</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/spring-boot">Spring Boot</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/typescript">Typescript</a>
</li>
</ul>
</div>
</div>
<hr>
<div class="row">
<div class="col-12 col-sm-4 col-md-2">
<div class="fs-4">
<ul class="list-unstyled d-flex">
<li class="me-3">
<a aria-label="Telegram" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://t.me/hexlet_ru"><span class="bi bi-telegram"></span>
</a></li>
<li>
<a aria-label="Youtube" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://www.youtube.com/user/HexletUniversity"><span class="bi bi-youtube"></span>
</a></li>
</ul>
</div>
<div class="mb-2 d-flex flex-column">
<a class="link-light text-decoration-none" rel="nofollow" href="mailto:support@hexlet.io">support@hexlet.io</a>
<a class="link-light text-decoration-none py-2" target="_blank" href="https://t.me/hexlet_help_bot">t.me/hexlet_help_bot</a>
</div>
<ul class="list-unstyled d-flex">
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://hexlet.io/locale/switch?new_locale=en" data-target="_self" role="button"><span class="my-auto">EN</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 opacity-100 external-link" rel="nofollow" data-href="https://ru.hexlet.io/locale/switch?new_locale=ru" data-target="_self" role="button"><span class="my-auto">RU</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://kz.hexlet.io/locale/switch?new_locale=kz" data-target="_self" role="button"><span class="my-auto">KZ</span>
</span></li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<ul class="list-unstyled fs-4">
<li class="mb-3">
<a class="link-light text-decoration-none" href="tel:8%20800%20100%2022%2047">8 800 100 22 47</a>
<span class="d-block opacity-50 small">бесплатно по РФ</span>
</li>
<li>
<a class="link-light text-decoration-none" href="tel:%2B7%20495%20085%2021%2062">+7 495 085 21 62</a>
<span class="d-block opacity-50 small">бесплатно по Москве</span>
</li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<div class="small mb-3">Образовательные услуги оказываются на основании Л035-01298-77/01989008 от 14.03.2025</div>
<ul class="list-unstyled small">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/legal">Правовая информация</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/offer">Оферта</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/license">Лицензия</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/contacts">Контакты</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-12 col-md-4 small">
<div class="mb-2">
<div>ООО «<a href="/" class="text-decoration-none link-light">Хекслет Рус</a>»</div>
<div>108813 г. Москва, вн.тер.г. поселение Московский,</div>
<div>г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3</div>
<div>ОГРН 1217300010476</div>
<div>ИНН 7325174845</div>
</div>
<hr>
<div>АНО ДПО «<a href="/" class="text-decoration-none link-light">Учебный центр «Хекслет</a>»</div>
<div>119331 г. Москва, вн. тер. г. муниципальный округ</div>
<div>Ломоносовский, пр-кт Вернадского, д. 29</div>
<div>ОГРН 1247700712390</div>
<div>ИНН 7736364948</div>
</div>
</div>
</footer>
<div id="root-assistant-offcanvas"></div>
<script src="/vite/assets/assistant-Bukl1lYy.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-BrRXra1y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/MarkdownBlock-DbyKWoR_.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/shiki-V011pkdv.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-XR8Qr8kR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dist-GCHh59xr.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useIsomorphicEffect-HJ6VK0D3.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-KSp6QbZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/classnames-l6ipYlLR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/debounce-jMQ_Cf4f.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v67327c56f0bb4ef8b305cae61679db8f1769101564043" integrity="sha512-rdcWY47ByXd76cbCFzznIcEaCN71jqkWBBqlwhF1SY7KubdLKZiEGeP7AyieKZlGP9hbY/MhGrwXzJC/HulNyg==" data-cf-beacon='{"version":"2024.11.0","token":"d11015b65d11429ea6b4a2ef37dd7e0b","server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
</body>
</html>