[{"data":1,"prerenderedAt":4786},["ShallowReactive",2],{"practice-content-catalog":3},{"source":4,"programSets":7,"programs":60,"schemaVersion":259,"articles":260,"codeExercises":268,"interviewQuestions":1731,"liveCodingTasks":4354,"quizzes":4701,"tasks":4766},{"kind":5,"path":6},"github","https:\u002F\u002Fgithub.com\u002Fcoldrain96\u002Fduckfrontend-content\u002Ftree\u002Fd2bbcb271ca524326809c71d49c885beda42d27c\u002Fcontent\u002Fv1",[8,22,32,42,51],{"slug":9,"title":10,"description":11,"order":12,"status":13,"seoTitle":14,"seoDescription":15,"programSlugs":16},"javascript-fundamentals","Основы JavaScript","Области видимости, объекты, типы, коллекции и механика выполнения JavaScript.",1,"published","Практика основ JavaScript","Вопросы и задачи по основам JavaScript для подготовки к frontend-собеседованию.",[17,18,19,20,21],"collections-iteration-arrays","objects-prototypes-classes","scope-closures-deep-dive","scope-hoisting-closures-this","types-coercion-symbol-json",{"slug":23,"title":24,"description":25,"order":26,"status":13,"seoTitle":27,"seoDescription":28,"programSlugs":29},"async-runtime","Асинхронный JavaScript","Event loop, микрозадачи, таймеры, Promise и async\u002Fawait.",2,"Практика асинхронного JavaScript","Вопросы и задачи по event loop, Promise, таймерам и async\u002Fawait для frontend-собеседования.",[30,31],"event-loop-promises-async-await","event-loop-promises-deep-dive",{"slug":33,"title":34,"description":35,"order":36,"status":13,"seoTitle":37,"seoDescription":38,"programSlugs":39},"browser-platform","Браузер","Рендеринг, DOM, события, формы, сеть, кеширование и диагностика в DevTools.",3,"Практика браузерных API","Вопросы и задачи по рендерингу, DOM, событиям, сети и DevTools для frontend-собеседования.",[40,41],"browser-network","rendering-dom-events-forms",{"slug":43,"title":44,"description":45,"order":46,"status":13,"seoTitle":47,"seoDescription":48,"programSlugs":49},"algorithms","Алгоритмы","Рекурсия, обход вложенных структур и разбор алгоритмических задач на собеседовании.",4,"Практика алгоритмов для frontend-собеседования","Задачи на рекурсию, обход структур и алгоритмическое мышление в JavaScript.",[50],"recursion",{"slug":52,"title":53,"description":54,"order":55,"status":13,"seoTitle":56,"seoDescription":57,"programSlugs":58},"interview-prep","Пробное собеседование","Смешанная тренировка: вопросы, порядок выполнения кода и live coding.",5,"Пробное frontend-собеседование","Тренировка вопросов по JavaScript, разбора кода и live coding перед frontend-собеседованием.",[59],"mock-interview-javascript-core",[61,95,111,127,144,161,177,193,209,225,241],{"slug":20,"setSlug":9,"title":62,"description":63,"audience":64,"language":65,"runtime":66,"order":67,"status":13,"seoTitle":68,"seoDescription":69,"accessLabel":70,"authorNote":71,"badgeLabel":72,"communityLabel":73,"lessons":74,"author":88,"repository":92},"Области видимости, hoisting, замыкания и this","Области видимости, объявления, hoisting, замыкания, this и strict mode.","Для учеников, которые готовятся к JavaScript-собеседованию и должны уверенно объяснять выполнение кода.","javascript","browser",0,"JavaScript scope, hoisting, closures and this practice","Практика по областям видимости, hoisting, замыканиям, this и strict mode.","Open","Практическая Duck Frontend программа для подготовки к frontend-собеседованию.","Mentoring","Duck Frontend",[75],{"slug":20,"moduleSlug":20,"title":76,"topic":77,"goal":78,"placementReason":79,"order":12,"status":13,"state":80,"activities":81,"steps":86,"overviewBody":87},"Области видимости, hoisting, замыкания, this и strict mode","Области видимости, объявления, замыкания, this и ошибки выполнения","Научиться объяснять выполнение JavaScript-кода через области видимости, объявления, замыкания, this и ошибки.","Этот урок задает базовую ментальную модель выполнения JavaScript перед объектами, типами и асинхронностью.","available",[82,83,84,85],"Карта тем урока","Q&A для собеседования","Predict-output упражнения","Live coding задачи",[],"# Области видимости, hoisting, замыкания и this\n\n## Области видимости\n\n- глобальная область видимости — [Вы не знаете JS: Область видимости и замыкания — глава 1 Что такое область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch1.md)\n- функциональная область видимости — [Вы не знаете JS: Область видимости и замыкания — глава 3 Область видимости функции против блоков](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch3.md)\n- блочная область видимости — [Вы не знаете JS: Область видимости и замыкания — глава 3 Область видимости функции против блоков](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch3.md)\n- лексическая область видимости — [Вы не знаете JS: Область видимости и замыкания — глава 2 Лексическая область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch2.md)\n- отличие лексической области видимости от динамической — [Вы не знаете JS: Область видимости и замыкания — приложение A Динамическая область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002FapA.md)\n- shadowing — [Вы не знаете JS: Область видимости и замыкания — глава 2 Лексическая область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch2.md)\n- область видимости `catch` — [MDN: try catch statement](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fstatements\u002Ftry...catch\u002Findex.md)\n- доступ к глобальному объекту при shadowing — [ru.javascript.info: Глобальный объект](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F05-global-object\u002Farticle.md)\n\n## Объявления и hoisting\n\n- hoisting — [Вы не знаете JS: Область видимости и замыкания — глава 4 Поднятие переменных Hoisting](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch4.md)\n- Temporal Dead Zone — [ru.javascript.info: Область видимости переменных замыкание](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md)\n- `var` — [ru.javascript.info: Устаревшее ключевое слово var](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F04-var\u002Farticle.md)\n- `let` — [ru.javascript.info: Переменные](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F04-variables\u002Farticle.md)\n- `const` — [ru.javascript.info: Переменные](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F04-variables\u002Farticle.md)\n- function declaration — [ru.javascript.info: Функции](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F15-function-basics\u002Farticle.md)\n- function expression — [ru.javascript.info: Function Expression](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F16-function-expressions\u002Farticle.md)\n- named function expression — [ru.javascript.info: Function Expression](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F16-function-expressions\u002Farticle.md)\n- function declaration внутри блока — [MDN: function declaration](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fstatements\u002Ffunction\u002Findex.md)\n- Automatic Semicolon Insertion рядом с `return` — [MDN: Lexical grammar](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Flexical_grammar\u002Findex.md)\n\n## Замыкания и функции\n\n- замыкания — [ru.javascript.info: Область видимости переменных замыкание](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md)\n- замыкания в циклах — [Вы не знаете JS: Область видимости и замыкания — глава 5 Замыкание области видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md)\n- IIFE — [Вы не знаете JS: Область видимости и замыкания — глава 3 Область видимости функции против блоков](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch3.md)\n- модульный паттерн через замыкание — [Вы не знаете JS: Область видимости и замыкания — глава 5 Замыкание области видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md)\n- `new Function` — [ru.javascript.info: Синтаксис new Function](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F07-new-function\u002Farticle.md)\n- глобальное окружение у функций из `new Function` — [ru.javascript.info: Синтаксис new Function](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F07-new-function\u002Farticle.md)\n\n## `this` и контекст вызова\n\n- `this` — [ru.javascript.info: Методы объекта this](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F04-object-methods\u002Farticle.md)\n- потеря `this` — [ru.javascript.info: Привязка контекста к функции](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F10-bind\u002Farticle.md)\n- `call` — [ru.javascript.info: Декораторы и переадресация вызова call apply](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F09-call-apply-decorators\u002Farticle.md)\n- `apply` — [ru.javascript.info: Декораторы и переадресация вызова call apply](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F09-call-apply-decorators\u002Farticle.md)\n- `bind` — [ru.javascript.info: Привязка контекста к функции](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F10-bind\u002Farticle.md)\n- стрелочные функции и лексический `this` — [ru.javascript.info: Повторяем стрелочные функции](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F12-arrow-functions\u002Farticle.md)\n- Reference Type при вызове метода — [MDN: this](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fthis\u002Findex.md)\n- потеря `this` при вычислении метода как значения — [MDN: this](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fthis\u002Findex.md)\n- comma operator и потеря исходного reference — [MDN: Comma operator](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fcomma_operator\u002Findex.md)\n\n## Strict mode и ошибки\n\n- `use strict` — [ru.javascript.info: Строгий режим use strict](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F03-strict-mode\u002Farticle.md)\n- LHS и RHS поиск — [Вы не знаете JS: Область видимости и замыкания — глава 1 Что такое область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch1.md)\n- `ReferenceError` — [Вы не знаете JS: Область видимости и замыкания — глава 1 Что такое область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch1.md)\n- `TypeError` — [Вы не знаете JS: Область видимости и замыкания — глава 1 Что такое область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch1.md)\n- случайные глобальные переменные — [ru.javascript.info: Переменные](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F04-variables\u002Farticle.md)\n- глобальный `var` и глобальный `let` — [MDN: var statement](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fstatements\u002Fvar\u002Findex.md)\n",{"githubUrl":89,"name":90,"username":91},"https:\u002F\u002Fgithub.com\u002Fcoldrain96","Kamil Bikmetov","coldrain96",{"label":93,"url":94},"content","https:\u002F\u002Fgithub.com\u002Fcoldrain96\u002Fduckfrontend-content\u002Fblob\u002Fmain\u002Fcontent\u002Fv1\u002Fprograms\u002Fjavascript-fundamentals\u002Fscope-hoisting-closures-this\u002Fprogram.json",{"slug":19,"setSlug":9,"title":96,"description":97,"audience":98,"language":65,"runtime":66,"order":12,"status":13,"seoTitle":99,"seoDescription":100,"accessLabel":70,"authorNote":71,"badgeLabel":72,"communityLabel":73,"lessons":101,"author":88,"repository":109},"Углубление: области видимости и замыкания","Дополнительные упражнения по LHS\u002FRHS-поиску, вложенным областям, eval, with, IIFE, hoisting и замыканиям.","Для учеников, которым нужно закрепить scope и closures на более неудобных вопросах и predict-output примерах.","JavaScript scope and closures deep dive practice","Дополнительная практика по областям видимости, LHS\u002FRHS, eval, with, IIFE, hoisting и замыканиям.",[102],{"slug":19,"moduleSlug":19,"title":96,"topic":103,"goal":104,"placementReason":105,"order":12,"status":13,"state":80,"activities":106,"steps":107,"overviewBody":108},"LHS\u002FRHS, вложенные области, eval, with, IIFE, hoisting и замыкания","Закрепить сложные вопросы по поиску имен, замыканиям и объявлениям в JavaScript.","Идет после базового урока по областям видимости как углубление той же механики выполнения кода.",[82,83,84],[],"# Углубление: области видимости и замыкания\n\n## Области видимости и замыкания\n\n- LHS и RHS поиск — [Вы не знаете JS: Область видимости и замыкания — глава 1 Что такое область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch1.md)\n- вложенные области видимости — [Вы не знаете JS: Область видимости и замыкания — глава 2 Лексическая область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch2.md)\n- `eval` и изменение локальной области — [Вы не знаете JS: Область видимости и замыкания — глава 2 Лексическая область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch2.md)\n- `with` и объект как область видимости — [Вы не знаете JS: Область видимости и замыкания — глава 2 Лексическая область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch2.md)\n- IIFE — [Вы не знаете JS: Область видимости и замыкания — глава 3 Область видимости функции против блоков](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch3.md)\n- hoisting — [Вы не знаете JS: Область видимости и замыкания — глава 4 Поднятие переменных Hoisting](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch4.md)\n- замыкание после выхода из функции — [Вы не знаете JS: Область видимости и замыкания — глава 5 Замыкание области видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md)\n- `setTimeout` и потеря `this` — [Вы не знаете JS: Область видимости и замыкания — приложение C Лексический this](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002FapC.md)\n- замыкания в циклах — [Вы не знаете JS: Область видимости и замыкания — глава 5 Замыкание области видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md)\n- модульный паттерн через замыкание — [Вы не знаете JS: Область видимости и замыкания — глава 5 Замыкание области видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md)\n- отличие лексической области видимости от динамической — [Вы не знаете JS: Область видимости и замыкания — приложение A Динамическая область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002FapA.md)\n",{"label":93,"url":110},"https:\u002F\u002Fgithub.com\u002Fcoldrain96\u002Fduckfrontend-content\u002Fblob\u002Fmain\u002Fcontent\u002Fv1\u002Fprograms\u002Fjavascript-fundamentals\u002Fscope-closures-deep-dive\u002Fprogram.json",{"slug":18,"setSlug":9,"title":112,"description":113,"audience":114,"language":65,"runtime":66,"order":26,"status":13,"seoTitle":115,"seoDescription":116,"accessLabel":70,"authorNote":71,"badgeLabel":72,"communityLabel":73,"lessons":117,"author":88,"repository":125},"Свойства объектов, прототипы и классы","Свойства и дескрипторы объектов, прототипы, конструкторы, instanceof и классы.","Для учеников, которые уже читают scope\u002Fclosure-задачи и переходят к объектной модели JavaScript.","JavaScript objects, prototypes and classes practice","Практика по свойствам объектов, дескрипторам, прототипам, конструкторам и классам.",[118],{"slug":18,"moduleSlug":18,"title":112,"topic":119,"goal":120,"placementReason":121,"order":12,"status":13,"state":80,"activities":122,"steps":123,"overviewBody":124},"Свойства, дескрипторы, прототипы, конструкторы, instanceof и class","Научиться объяснять чтение и изменение свойств, прототипную цепочку, конструкторы и class-механику.","После scope-модели ученик готов разбирать объектную модель JavaScript и наследование.",[82,83,84,85],[],"# Свойства объектов, прототипы и классы\n\n## Свойства объектов\n\n- поиск свойств объекта — [ru.javascript.info: Прототипное наследование](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F01-prototype-inheritance\u002Farticle.md)\n- собственные и унаследованные свойства — [ru.javascript.info: Прототипное наследование](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F01-prototype-inheritance\u002Farticle.md)\n- свойства данных и свойства аксессоры — [ru.javascript.info: Свойства геттеры и сеттеры](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F02-property-accessors\u002Farticle.md)\n- дескрипторы свойств — [ru.javascript.info: Флаги и дескрипторы свойств](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md)\n- флаги свойств `writable`, `enumerable`, `configurable` — [ru.javascript.info: Флаги и дескрипторы свойств](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md)\n- `Object.getOwnPropertyDescriptor` — [ru.javascript.info: Флаги и дескрипторы свойств](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md)\n- `Object.getOwnPropertyDescriptors` — [ru.javascript.info: Флаги и дескрипторы свойств](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md)\n- `Object.defineProperty` — [ru.javascript.info: Флаги и дескрипторы свойств](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md)\n- `Object.defineProperties` — [ru.javascript.info: Флаги и дескрипторы свойств](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md)\n- геттеры и сеттеры — [ru.javascript.info: Свойства геттеры и сеттеры](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F02-property-accessors\u002Farticle.md)\n- проверка свойства через `in` — [MDN: in operator](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fin\u002Findex.md)\n- удаление свойства через `delete` — [MDN: delete operator](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fdelete\u002Findex.md)\n\n## Ограничение изменений объекта\n\n- `Object.preventExtensions` — [ru.javascript.info: Флаги и дескрипторы свойств](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md)\n- `Object.seal` — [ru.javascript.info: Флаги и дескрипторы свойств](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md)\n- `Object.freeze` — [ru.javascript.info: Флаги и дескрипторы свойств](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md)\n\n## Прототипы\n\n- прототип объекта и `[[Prototype]]` — [ru.javascript.info: Прототипное наследование](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F01-prototype-inheritance\u002Farticle.md)\n- прототипная цепочка — [ru.javascript.info: Прототипное наследование](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F01-prototype-inheritance\u002Farticle.md)\n- `__proto__` — [ru.javascript.info: Методы прототипов объекты без свойства `__proto__`](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F04-prototype-methods\u002Farticle.md)\n- `Object.create` — [ru.javascript.info: Методы прототипов объекты без свойства `__proto__`](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F04-prototype-methods\u002Farticle.md)\n- `Object.getPrototypeOf` — [ru.javascript.info: Методы прототипов объекты без свойства `__proto__`](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F04-prototype-methods\u002Farticle.md)\n- `Object.setPrototypeOf` — [ru.javascript.info: Методы прототипов объекты без свойства `__proto__`](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F04-prototype-methods\u002Farticle.md)\n\n## Конструкторы и экземпляры\n\n- свойство функции `prototype` — [ru.javascript.info: F.prototype](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F02-function-prototype\u002Farticle.md)\n- `Function.prototype` — [ru.javascript.info: Встроенные прототипы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F03-native-prototypes\u002Farticle.md)\n- связь `new` и `prototype` — [ru.javascript.info: F.prototype](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F02-function-prototype\u002Farticle.md)\n- `instanceof` и `Symbol.hasInstance` — [MDN: instanceof operator](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Finstanceof\u002Findex.md)\n\n## Классы\n\n- базовый синтаксис `class` — [ru.javascript.info: Класс базовый синтаксис](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F01-class\u002Farticle.md)\n- `constructor` и создание экземпляра через `new` — [MDN: constructor](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fconstructor\u002Findex.md)\n- методы класса на `prototype` — [ru.javascript.info: Класс базовый синтаксис](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F01-class\u002Farticle.md)\n- неперечислимость методов класса — [ru.javascript.info: Класс базовый синтаксис](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F01-class\u002Farticle.md)\n- strict mode внутри class body — [MDN: Classes](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Findex.md)\n- потеря `this` у class methods — [MDN: Classes](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Findex.md)\n- public class fields — [MDN: Public class fields](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fpublic_class_fields\u002Findex.md)\n- private class fields и private methods — [MDN: Private elements](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fprivate_elements\u002Findex.md)\n- `extends` и прототипная связь классов — [ru.javascript.info: Наследование классов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F02-class-inheritance\u002Farticle.md)\n- `super()` и `super.method()` — [ru.javascript.info: Наследование классов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F02-class-inheritance\u002Farticle.md)\n- порядок инициализации public и private fields — [MDN: Public class fields](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fpublic_class_fields\u002Findex.md)\n- static fields и static methods — [ru.javascript.info: Статические свойства и методы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F03-static-properties-methods\u002Farticle.md)\n",{"label":93,"url":126},"https:\u002F\u002Fgithub.com\u002Fcoldrain96\u002Fduckfrontend-content\u002Fblob\u002Fmain\u002Fcontent\u002Fv1\u002Fprograms\u002Fjavascript-fundamentals\u002Fobjects-prototypes-classes\u002Fprogram.json",{"slug":21,"setSlug":9,"title":128,"description":129,"audience":130,"language":65,"runtime":66,"order":36,"status":13,"seoTitle":131,"seoDescription":132,"accessLabel":70,"authorNote":71,"badgeLabel":72,"communityLabel":73,"lessons":133,"author":88,"repository":142},"Типы, приведение, Symbol и JSON","Типы значений, приведение, Symbol, JSON, логические операторы, равенство и числа.","Для учеников, которым нужно перестать угадывать JavaScript edge cases и объяснять правила преобразований.","JavaScript types, coercion, equality and numbers practice","Практика по типам, coercion, equality, Symbol, JSON, операторам, сравнениям и numeric edge cases.",[134],{"slug":21,"moduleSlug":21,"title":135,"topic":136,"goal":137,"placementReason":138,"order":12,"status":13,"state":80,"activities":139,"steps":140,"overviewBody":141},"Типы, приведение, равенство и числа","Типы, примитивы, приведение, Symbol, JSON, логика, равенство, сравнения и числа","Научиться объяснять типы значений и преобразования JavaScript без заучивания случайных выводов.","Типы идут после execution basics, потому что для преобразований уже нужна уверенная трассировка выражений.",[82,83,84,85],[],"# Типы, приведение, Symbol и JSON\n\n## Типы и проверки\n\n- все типы значений JavaScript и результат оператора `typeof` — [ru.javascript.info: Типы данных](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F05-types\u002Farticle.md)\n- отличие типа значения от переменной которая это значение хранит — [Вы не знаете JS: Типы и грамматика — глава 1 Типы](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch1.md)\n- более точная проверка встроенного тега через `Object.prototype.toString` — [Вы не знаете JS: Типы и грамматика — глава 3 Стандартные встроенные объекты](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch3.md)\n- основные built in object tags для `Object`, `Array`, `Function`, `Error`, `Map` и `Set` — [Вы не знаете JS: Типы и грамматика — глава 3 Стандартные встроенные объекты](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch3.md)\n\n## Примитивы и оболочки\n\n- примитивы, временная упаковка примитивов и объектные оболочки — [ru.javascript.info: Методы примитивов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F01-primitives-methods\u002Farticle.md)\n- распаковка объектных оболочек через `valueOf` — [Вы не знаете JS: Типы и грамматика — глава 3 Стандартные встроенные объекты](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch3.md)\n\n## Приведение типов\n\n- истинные и ложные значения через `ToBoolean` — [ru.javascript.info: Преобразование типов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F07-type-conversions\u002Farticle.md)\n- явное численное приведение через `Number` — [ru.javascript.info: Преобразование типов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F07-type-conversions\u002Farticle.md)\n- явное строковое приведение через `String` — [ru.javascript.info: Преобразование типов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F07-type-conversions\u002Farticle.md)\n- приведение объекта к примитиву через `valueOf` и `toString` — [ru.javascript.info: Преобразование объектов в примитивы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F09-object-toprimitive\u002Farticle.md)\n- управление приведением через `Symbol.toPrimitive` — [ru.javascript.info: Преобразование объектов в примитивы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F09-object-toprimitive\u002Farticle.md)\n- поведение операторов `+`, `-`, `*` при неявном приведении — [ru.javascript.info: Базовые операторы математика](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F08-operators\u002Farticle.md)\n\n## Ключи объектов, Symbol и JSON\n\n- приведение ключей объекта к строкам — [ru.javascript.info: Объекты](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F01-object\u002Farticle.md)\n- `Symbol` как ключ свойства без строкового приведения — [ru.javascript.info: Тип данных Symbol](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F08-symbol\u002Farticle.md)\n- явное и неявное строковое приведение `Symbol` — [ru.javascript.info: Тип данных Symbol](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F08-symbol\u002Farticle.md)\n- сериализация `Symbol` ключей и значений через `JSON.stringify` — [MDN: JSON.stringify](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fjson\u002Fstringify\u002Findex.md)\n- сериализация специальных значений через `JSON.stringify` — [MDN: JSON.stringify](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fjson\u002Fstringify\u002Findex.md)\n\n## Логика и равенство\n\n- поведение оператора `!` и его влияние на дальнейшее сравнение — [ru.javascript.info: Логические операторы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F11-logical-operators\u002Farticle.md)\n- нестрогое равенство `==` — [MDN: Equality operator](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fequality\u002Findex.md)\n- специальные правила `==` для `null` и `undefined` — [ru.javascript.info: Операторы сравнения](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F09-comparison\u002Farticle.md)\n- приведение `boolean` в `==` — [MDN: Equality operator](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fequality\u002Findex.md)\n- массивы в `==` на примере `[] == ![]` — [Вы не знаете JS: Типы и грамматика — глава 4 Приведение](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md)\n- строгое равенство `===` — [ru.javascript.info: Операторы сравнения](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F09-comparison\u002Farticle.md)\n- сравнение через `Object.is` — [MDN: Object.is](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fis\u002Findex.md)\n- сравнение через SameValueZero — [MDN: Equality comparisons and sameness](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Fequality_comparisons_and_sameness\u002Findex.md)\n- отличие `includes` от `indexOf` в алгоритме сравнения — [MDN: Equality comparisons and sameness](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Fequality_comparisons_and_sameness\u002Findex.md)\n\n## Операторы значений\n\n- `??` и отличие nullish от falsy — [ru.javascript.info: Операторы нулевого слияния и присваивания](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F12-nullish-operators\u002Farticle.md)\n- `?.` и граница optional chaining — [ru.javascript.info: Опциональная цепочка](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F07-optional-chaining\u002Farticle.md)\n- `&&=`, `||=`, `??=` и short-circuit assignment — [MDN: Logical AND assignment](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Flogical_and_assignment\u002Findex.md)\n\n## Сравнения отношений\n\n- сравнения отношений `\u003C`, `>`, `\u003C=`, `>=` — [ru.javascript.info: Операторы сравнения](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F09-comparison\u002Farticle.md)\n- строковое и численное сравнение — [ru.javascript.info: Операторы сравнения](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F09-comparison\u002Farticle.md)\n- цепочки сравнений вроде `3 > 2 > 1` — [ru.javascript.info: Операторы сравнения](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F09-comparison\u002Farticle.md)\n\n## Числа и парсинг\n\n- особенности `NaN` — [ru.javascript.info: Числа](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F02-number\u002Farticle.md)\n- особенности `0` и `-0` — [Вы не знаете JS: Типы и грамматика — глава 2 Значения](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch2.md)\n- безопасные целые числа и `Number.MAX_SAFE_INTEGER` — [ru.javascript.info: Числа](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F02-number\u002Farticle.md)\n- смешивание `BigInt` и `number` — [ru.javascript.info: BigInt](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F99-js-misc\u002F06-bigint\u002Farticle.md)\n- глобальные `isNaN` и `isFinite` с численным приведением — [MDN: isNaN](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fisnan\u002Findex.md)\n- строгие проверки `Number.isNaN` и `Number.isFinite` без приведения — [MDN: Number.isNaN](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fnumber\u002Fisnan\u002Findex.md)\n- частичный численный парсинг через `parseInt` и `parseFloat` — [ru.javascript.info: Числа](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F02-number\u002Farticle.md)\n- основание системы счисления в `parseInt` — [ru.javascript.info: Числа](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F02-number\u002Farticle.md)\n- поиск `NaN` через `Array.prototype.includes` — [MDN: Array.prototype.includes](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fincludes\u002Findex.md)\n- `**` и скобки вокруг unary expression — [MDN: Exponentiation operator](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fexponentiation\u002Findex.md)\n- `%` как remainder, а не математический modulo — [MDN: Remainder operator](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fremainder\u002Findex.md)\n- битовые операторы и 32-bit преобразование — [ru.javascript.info: Побитовые операторы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F99-js-misc\u002F05-bitwise-operators\u002Farticle.md)\n",{"label":93,"url":143},"https:\u002F\u002Fgithub.com\u002Fcoldrain96\u002Fduckfrontend-content\u002Fblob\u002Fmain\u002Fcontent\u002Fv1\u002Fprograms\u002Fjavascript-fundamentals\u002Ftypes-coercion-symbol-json\u002Fprogram.json",{"slug":17,"setSlug":9,"title":145,"description":146,"audience":147,"language":65,"runtime":66,"order":46,"status":13,"seoTitle":148,"seoDescription":149,"accessLabel":70,"authorNote":71,"badgeLabel":72,"communityLabel":73,"lessons":150,"author":88,"repository":159},"Коллекции, итерация, массивы и строки","Map, Set, итераторы, массивы, строки и Web Workers.","Для учеников, которые готовятся к вопросам про структуры данных JavaScript и поведение стандартных коллекций.","JavaScript collections, iteration, arrays and strings practice","Практика по Map, Set, WeakMap, WeakSet, iterator protocol, arrays, strings и Web Workers.",[151],{"slug":17,"moduleSlug":17,"title":145,"topic":152,"goal":153,"placementReason":154,"order":12,"status":13,"state":80,"activities":155,"steps":157,"overviewBody":158},"Map, Set, WeakMap, WeakSet, итераторы, массивы, строки и Web Workers","Научиться выбирать и объяснять коллекции JavaScript, итерацию и особенности массивов\u002Fстрок.","После типов и объектов ученик готов разбирать коллекции и протоколы обхода данных.",[82,156,83,84,85],"Лекционный материал",[],"# Коллекции, итерация, массивы и строки\n\n## Коллекции\n\n- `Map` как коллекция ключ-значение — [ru.javascript.info: Map и Set](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F07-map-set\u002Farticle.md), [MDN: Map](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fmap\u002Findex.md)\n- отличие `Map` от обычного объекта — [ru.javascript.info: Map и Set](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F07-map-set\u002Farticle.md), [MDN: Map](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fmap\u002Findex.md)\n- порядок вставки в `Map` — [MDN: Map](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fmap\u002Findex.md)\n- `Set` как коллекция уникальных значений — [ru.javascript.info: Map и Set](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F07-map-set\u002Farticle.md), [MDN: Set](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fset\u002Findex.md)\n- сравнение ключей и значений через SameValueZero — [MDN: Map](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fmap\u002Findex.md), [MDN: Set](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fset\u002Findex.md)\n- `WeakMap` и слабые ключи — [ru.javascript.info: WeakMap и WeakSet](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F08-weakmap-weakset\u002Farticle.md), [MDN: WeakMap](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fweakmap\u002Findex.md)\n- `WeakSet` и слабые значения — [ru.javascript.info: WeakMap и WeakSet](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F08-weakmap-weakset\u002Farticle.md), [MDN: WeakSet](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fweakset\u002Findex.md)\n- `Object.groupBy` и объект с `null` prototype — [MDN: Object.groupBy](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fgroupby\u002Findex.md)\n- `Map.groupBy` — [MDN: Map.groupBy](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fmap\u002Fgroupby\u002Findex.md)\n- новые методы `Set` — [MDN: Set.prototype.union](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fset\u002Funion\u002Findex.md)\n\n## Синхронная итерация\n\n- протокол iterable — [ru.javascript.info: Перебираемые объекты](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F06-iterable\u002Farticle.md), [MDN: Iteration protocols](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fiteration_protocols\u002Findex.md)\n- `Symbol.iterator` — [MDN: Symbol.iterator](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fsymbol\u002Fiterator\u002Findex.md)\n- `for...of` и синхронный iterator — [MDN: Iteration protocols](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fiteration_protocols\u002Findex.md)\n- iterable и array-like — [ru.javascript.info: Перебираемые объекты](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F06-iterable\u002Farticle.md)\n- `Array.from` для iterable и array-like — [MDN: Array.from](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Ffrom\u002Findex.md)\n- синхронные генераторы — [ru.javascript.info: Генераторы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F12-generators-iterators\u002F1-generators\u002Farticle.md), [MDN: Iterators and generators](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Fiterators_and_generators\u002Findex.md)\n\n## Массивы\n\n- базовые методы массивов — [ru.javascript.info: Методы массивов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F05-array-methods\u002Farticle.md), [MDN: Array](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Findex.md)\n- `map`, `filter`, `reduce` — [MDN: Array.map](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fmap\u002Findex.md), [MDN: Array.filter](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Ffilter\u002Findex.md), [MDN: Array.reduce](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Freduce\u002Findex.md)\n- ловушка `map(parseInt)` — [Вы не знаете JS: Типы и грамматика — глава 4 Приведение](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md)\n- `find`, `some`, `every` — [MDN: Array.find](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Ffind\u002Findex.md), [MDN: Array.some](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fsome\u002Findex.md), [MDN: Array.every](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fevery\u002Findex.md)\n- `slice` и `splice` — [MDN: Array.slice](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fslice\u002Findex.md), [MDN: Array.splice](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fsplice\u002Findex.md)\n- `sort` без comparator, строковое сравнение и функция сравнения — [MDN: Array.sort](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fsort\u002Findex.md)\n- `flat` и `flatMap` — [MDN: Array.flat](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fflat\u002Findex.md), [MDN: Array.flatMap](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fflatmap\u002Findex.md)\n- sparse arrays, пустые слоты и `delete` в массивах — [MDN: Array](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Findex.md)\n- `toSorted` — [MDN: Array.prototype.toSorted](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Ftosorted\u002Findex.md)\n\n## Строки\n\n- строки как UTF-16 последовательности — [ru.javascript.info: Строки](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F03-string\u002Farticle.md), [MDN: String](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fstring\u002Findex.md)\n- строковый iterator и Unicode — [ru.javascript.info: Unicode](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F99-js-misc\u002F07-unicode\u002Farticle.md), [MDN: String.prototype@@iterator](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fstring\u002Fsymbol.iterator\u002Findex.md)\n- `codePointAt` и `fromCodePoint` — [MDN: String.codePointAt](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fstring\u002Fcodepointat\u002Findex.md), [MDN: String.fromCodePoint](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fstring\u002Ffromcodepoint\u002Findex.md)\n- `Intl.Collator` для сравнения строк — [ru.javascript.info: Intl.Collator](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F99-js-misc\u002F08-intl\u002F1-collate-array-sort\u002Ftask.md), [MDN: Intl.Collator](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fintl\u002Fcollator\u002Findex.md)\n\n## Web Workers\n\n- главный поток, event loop и отзывчивость интерфейса — [MDN: Web Workers API](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fweb_workers_api\u002Findex.md), [MDN: Using Web Workers](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fweb_workers_api\u002Fusing_web_workers\u002Findex.md)\n- Dedicated Worker и обмен сообщениями через `postMessage()` — [MDN: Using Web Workers](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fweb_workers_api\u002Fusing_web_workers\u002Findex.md)\n- structured clone algorithm — [MDN: The structured clone algorithm](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fweb_workers_api\u002Fstructured_clone_algorithm\u002Findex.md)\n- transferable objects и передача `ArrayBuffer` без копирования — [MDN: Transferable objects](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fweb_workers_api\u002Ftransferable_objects\u002Findex.md)\n- SharedWorker, Service Worker и Worklets — [MDN: Web Workers API](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fweb_workers_api\u002Findex.md), [MDN: Service Worker API](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fservice_worker_api\u002Findex.md), [MDN: Worklet](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fworklet\u002Findex.md)\n- `SharedArrayBuffer`, `Atomics` и общая память — [MDN: SharedArrayBuffer](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fsharedarraybuffer\u002Findex.md), [MDN: Atomics](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fatomics\u002Findex.md)\n- `OffscreenCanvas` в worker-контекстах — [MDN: OffscreenCanvas](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Foffscreencanvas\u002Findex.md)\n",{"label":93,"url":160},"https:\u002F\u002Fgithub.com\u002Fcoldrain96\u002Fduckfrontend-content\u002Fblob\u002Fmain\u002Fcontent\u002Fv1\u002Fprograms\u002Fjavascript-fundamentals\u002Fcollections-iteration-arrays\u002Fprogram.json",{"slug":30,"setSlug":23,"title":162,"description":163,"audience":164,"language":65,"runtime":66,"order":67,"status":13,"seoTitle":165,"seoDescription":166,"accessLabel":70,"authorNote":71,"badgeLabel":72,"communityLabel":73,"lessons":167,"author":88,"repository":175},"Event loop, Promise и async\u002Fawait","Event loop, очереди задач, Promise, async\u002Fawait, асинхронная итерация и fetch.","Для учеников, которые должны уверенно предсказывать порядок выполнения асинхронного JavaScript.","JavaScript event loop, Promise and async await practice","Практика по event loop, microtasks, Promise, async\u002Fawait, Promise API, async iteration, fetch и modules.",[168],{"slug":30,"moduleSlug":30,"title":162,"topic":169,"goal":170,"placementReason":171,"order":12,"status":13,"state":80,"activities":172,"steps":173,"overviewBody":174},"Event loop, микрозадачи, Promise, ошибки, async\u002Fawait, Promise API и асинхронные коллекции","Научиться читать порядок выполнения асинхронного кода и объяснять Promise-цепочки.","Это основной async-блок курса после фундаментальных JavaScript-механик.",[82,83,84,85],[],"# Event loop, Promise и async\u002Fawait\n\n## Event loop и очереди\n\n- асинхронная модель выполнения в браузере — [ru.javascript.info: Событийный цикл микрозадачи и макрозадачи](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F99-ui-misc\u002F03-event-loop\u002Farticle.md)\n- стек вызовов и правило run to completion — [Вы не знаете JS: Асинхронность и выполнение — глава 1 Асинхронность сейчас и потом](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fasync%20%26%20performance\u002Fch1.md)\n- задачи event loop и таймеры `setTimeout` — [ru.javascript.info: Событийный цикл микрозадачи и макрозадачи](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F99-ui-misc\u002F03-event-loop\u002Farticle.md)\n- микрозадачи `Promise`, `.then`, `.catch`, `.finally` и `queueMicrotask` — [ru.javascript.info: Микрозадачи](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md)\n- порядок выполнения синхронного кода, микрозадач и задач таймера — [ru.javascript.info: Событийный цикл микрозадачи и макрозадачи](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F99-ui-misc\u002F03-event-loop\u002Farticle.md)\n\n## Основы Promise\n\n- создание `Promise` и синхронный запуск executor — [ru.javascript.info: Промисы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F02-promise-basics\u002Farticle.md)\n- `Promise` как конструктор и ошибка при вызове без `new` — [MDN: Promise constructor](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fpromise\u002Findex.md)\n- состояния `Promise`: pending, fulfilled, rejected — [ru.javascript.info: Промисы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F02-promise-basics\u002Farticle.md)\n- однократное завершение `Promise` через `resolve` или `reject` — [ru.javascript.info: Промисы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F02-promise-basics\u002Farticle.md)\n- цепочки `.then` и передача результата дальше — [ru.javascript.info: Цепочка промисов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F03-promise-chaining\u002Farticle.md)\n- чередование нескольких независимых цепочек `.then` — [ru.javascript.info: Цепочка промисов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F03-promise-chaining\u002Farticle.md)\n- возврат обычного значения, промиса и thenable из обработчика — [ru.javascript.info: Цепочка промисов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F03-promise-chaining\u002Farticle.md)\n- thenable и асинхронное чтение результата через `then` — [Вы не знаете JS: Асинхронность и производительность — глава 3 Промисы](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fasync%20%26%20performance\u002Fch3.md)\n\n## Ошибки в Promise\n\n- обработка ошибок через `.catch` — [ru.javascript.info: Промисы обработка ошибок](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F04-promise-error-handling\u002Farticle.md)\n- граница обработчика ошибки во втором аргументе `.then` — [ru.javascript.info: Промисы обработка ошибок](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F04-promise-error-handling\u002Farticle.md)\n- восстановление цепочки после `.catch` — [ru.javascript.info: Промисы обработка ошибок](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F04-promise-error-handling\u002Farticle.md)\n- поведение `.finally` — [ru.javascript.info: Промисы обработка ошибок](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F04-promise-error-handling\u002Farticle.md)\n- замена причины ошибки через `throw` внутри `.finally` — [ru.javascript.info: Промисы обработка ошибок](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F04-promise-error-handling\u002Farticle.md)\n- `unhandledrejection` и момент появления необработанной ошибки промиса — [ru.javascript.info: Промисы обработка ошибок](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F04-promise-error-handling\u002Farticle.md)\n\n## Async await\n\n- `async function` и автоматический возврат `Promise` — [ru.javascript.info: Async await](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md)\n- отличие промиса async-функции от исходного промиса по ссылке — [MDN: async function](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fstatements\u002Fasync_function\u002Findex.md)\n- `async` executor внутри `new Promise` и потерянный результат — [MDN: Promise constructor](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fpromise\u002Findex.md)\n- `await` как пауза текущей async-функции без блокировки потока — [ru.javascript.info: Async await](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md)\n- `await` обычного значения и `await setTimeout` — [ru.javascript.info: Async await](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md)\n- `try\u002Fcatch` вместе с `await` — [ru.javascript.info: Async await](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md)\n- параллельный и последовательный запуск асинхронных операций — [Вы не знаете JS: Асинхронность и производительность — глава 3 Промисы](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fasync%20%26%20performance\u002Fch3.md)\n\n## Promise API\n\n- `Promise.all` — [MDN: Promise.all](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fall\u002Findex.md)\n- передача функций в `Promise.all` вместо результатов их вызова — [ru.javascript.info: Promise API](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F05-promise-api\u002Farticle.md)\n- `Promise.allSettled` — [MDN: Promise.allSettled](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fallsettled\u002Findex.md)\n- `Promise.race` — [MDN: Promise.race](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Frace\u002Findex.md)\n- пустой `Promise.race` и pending результат — [MDN: Promise.race](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Frace\u002Findex.md)\n- `Promise.any` — [MDN: Promise.any](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fany\u002Findex.md)\n- `AggregateError` — [MDN: AggregateError](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Faggregateerror\u002Findex.md)\n- `Promise.withResolvers` — [MDN: Promise.withResolvers](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fwithresolvers\u002Findex.md)\n- `Promise.try` — [MDN: Promise.try](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Ftry\u002Findex.md)\n\n## Асинхронные коллекции и итерация\n\n- `Array.fromAsync` — [MDN: Array.fromAsync](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Ffromasync\u002Findex.md)\n- async callback в методах массивов и ограничение `forEach` — [ru.javascript.info: Методы массивов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F05-array-methods\u002Farticle.md)\n- последовательный перебор через `for...of` и `await` — [ru.javascript.info: Async await](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md)\n- асинхронные итераторы — [ru.javascript.info: Асинхронные итераторы и генераторы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F12-generators-iterators\u002F2-async-iterators-generators\u002Farticle.md)\n- асинхронные генераторы — [ru.javascript.info: Асинхронные итераторы и генераторы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F12-generators-iterators\u002F2-async-iterators-generators\u002Farticle.md)\n- `for await...of` — [ru.javascript.info: Асинхронные итераторы и генераторы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F12-generators-iterators\u002F2-async-iterators-generators\u002Farticle.md)\n\n## Браузерные API и модули\n\n- `fetch`, чтение тела ответа и ошибки HTTP-статусов — [ru.javascript.info: Fetch](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F5-network\u002F01-fetch\u002Farticle.md)\n- отмена асинхронных операций через `AbortController` — [ru.javascript.info: Fetch прерывание запроса](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F5-network\u002F04-fetch-abort\u002Farticle.md)\n- top level `await` в ES-модулях — [MDN: await](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fawait\u002Findex.md)\n- динамический `import()` — [MDN: import operator](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fimport\u002Findex.md)\n",{"label":93,"url":176},"https:\u002F\u002Fgithub.com\u002Fcoldrain96\u002Fduckfrontend-content\u002Fblob\u002Fmain\u002Fcontent\u002Fv1\u002Fprograms\u002Fasync-runtime\u002Fevent-loop-promises-async-await\u002Fprogram.json",{"slug":31,"setSlug":23,"title":178,"description":179,"audience":180,"language":65,"runtime":66,"order":12,"status":13,"seoTitle":181,"seoDescription":182,"accessLabel":70,"authorNote":71,"badgeLabel":72,"communityLabel":73,"lessons":183,"author":88,"repository":191},"Углубление: event loop и Promise","Дополнительные упражнения по event loop, Promise-цепочкам, thenable, ошибкам, Promise API, async\u002Fawait, AbortController и async generators.","Для учеников, которым нужно добить асинхронные edge cases после основного async-блока.","Event loop and Promise deep dive practice","Дополнительная практика по event loop, Promise, async\u002Fawait, AbortController и async generators.",[184],{"slug":31,"moduleSlug":31,"title":178,"topic":185,"goal":186,"placementReason":187,"order":12,"status":13,"state":80,"activities":188,"steps":189,"overviewBody":190},"Вложенные микрозадачи, Promise-цепочки, thenable, ошибки, Promise API и async\u002Fawait","Закрепить асинхронную механику на дополнительных predict-output и interview-вопросах.","Идет после основного async-блока как углубление runtime перед браузерными и прикладными темами.",[82,83,84,85],[],"# Углубление: event loop и Promise\n\n## Закрепление event loop и Promise\n\n- чтение порядка выполнения через стек, микрозадачи и задачи таймера — [ru.javascript.info: Событийный цикл микрозадачи и макрозадачи](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F99-ui-misc\u002F03-event-loop\u002Farticle.md)\n- вложенные микрозадачи и микрозадачи внутри таймеров — [ru.javascript.info: Микрозадачи](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md)\n- независимые подписки `.then` и настоящая цепочка промисов — [ru.javascript.info: Цепочка промисов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F03-promise-chaining\u002Farticle.md)\n- thenable-объекты и усвоение результата — [ru.javascript.info: Async await](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md)\n- проброс, восстановление и замена ошибок в Promise-цепочке — [ru.javascript.info: Промисы обработка ошибок](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F04-promise-error-handling\u002Farticle.md)\n- выбор между `Promise.all`, `Promise.allSettled`, `Promise.race` и `Promise.any` — [ru.javascript.info: Promise API](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F05-promise-api\u002Farticle.md)\n- параллельный и последовательный запуск через `async\u002Fawait` — [ru.javascript.info: Async await](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md)\n- отмена асинхронных операций через `AbortController` — [ru.javascript.info: Fetch прерывание запроса](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F5-network\u002F04-fetch-abort\u002Farticle.md)\n- асинхронные генераторы и `for await...of` — [ru.javascript.info: Асинхронные итераторы и генераторы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F12-generators-iterators\u002F2-async-iterators-generators\u002Farticle.md)\n",{"label":93,"url":192},"https:\u002F\u002Fgithub.com\u002Fcoldrain96\u002Fduckfrontend-content\u002Fblob\u002Fmain\u002Fcontent\u002Fv1\u002Fprograms\u002Fasync-runtime\u002Fevent-loop-promises-deep-dive\u002Fprogram.json",{"slug":41,"setSlug":33,"title":194,"description":195,"audience":196,"language":65,"runtime":66,"order":67,"status":13,"seoTitle":197,"seoDescription":198,"accessLabel":70,"authorNote":71,"badgeLabel":72,"communityLabel":73,"lessons":199,"author":88,"repository":207},"Рендеринг, DOM, события и формы","Рендеринг страницы, layout, paint, compositing, DOM-события, формы и Virtual DOM.","Для frontend-учеников, которым нужно объяснять браузерную механику UI, события и производительность.","Browser rendering, DOM events and forms practice","Практика по critical rendering path, layout, paint, compositing, DOM events, forms and Virtual DOM.",[200],{"slug":41,"moduleSlug":41,"title":194,"topic":201,"goal":202,"placementReason":203,"order":12,"status":13,"state":80,"activities":204,"steps":205,"overviewBody":206},"Рендеринг браузера, layout, paint, observers, события, формы и Virtual DOM","Научиться объяснять, как браузер строит UI, обрабатывает события, формы и дорогие layout-операции.","После JS runtime ученик переходит к frontend-платформе и реальному браузерному поведению.",[82,83,84,85],[],"# Рендеринг, DOM, события и формы\n\n## Пайплайн рендеринга\n\n- критический путь рендеринга — [MDN: Critical rendering path](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fperformance\u002Fguides\u002Fcritical_rendering_path\u002Findex.md)\n- DOM и построение дерева документа — [MDN: Document Object Model](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fdocument_object_model\u002Findex.md)\n- CSSOM и вычисленные стили — [MDN: CSS Object Model](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fcss_object_model\u002Findex.md)\n- render tree и видимые элементы — [MDN: Critical rendering path](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fperformance\u002Fguides\u002Fcritical_rendering_path\u002Findex.md)\n- layout и reflow — [MDN: CSS performance optimization](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Flearn_web_development\u002Fextensions\u002Fperformance\u002Fcss\u002Findex.md)\n- paint и repaint — [MDN: CSS performance optimization](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Flearn_web_development\u002Fextensions\u002Fperformance\u002Fcss\u002Findex.md)\n- compositing и свойства для дешевых анимаций — [MDN: CSS and JavaScript animation performance](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fperformance\u002Fguides\u002Fcss_javascript_animation_performance\u002Findex.md)\n\n## Визуальные CSS-изменения\n\n- `transform` и влияние на визуальный размер без изменения layout — [MDN: transform](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fcss\u002Freference\u002Fproperties\u002Ftransform\u002Findex.md)\n- `opacity` и визуальная прозрачность без изменения layout — [MDN: opacity](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fcss\u002Freference\u002Fproperties\u002Fopacity\u002Findex.md)\n\n## Layout-метрики и принудительный layout\n\n- чтение layout-метрик через `offsetWidth` — [MDN: HTMLElement.offsetWidth](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlelement\u002Foffsetwidth\u002Findex.md)\n- различие `clientWidth`, `offsetWidth`, `scrollWidth` и `getBoundingClientRect` — [MDN: Determining the dimensions of elements](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fcss_object_model\u002Fdetermining_the_dimensions_of_elements\u002Findex.md)\n- чтение визуального прямоугольника через `getBoundingClientRect` — [MDN: Element.getBoundingClientRect](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Felement\u002Fgetboundingclientrect\u002Findex.md)\n- дробные размеры в layout и округление layout-метрик — [MDN: Determining the dimensions of elements](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fcss_object_model\u002Fdetermining_the_dimensions_of_elements\u002Findex.md)\n- чтение вычисленных стилей через `getComputedStyle` — [MDN: Window.getComputedStyle](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fwindow\u002Fgetcomputedstyle\u002Findex.md)\n- live-объект `getComputedStyle` — [MDN: Window.getComputedStyle](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fwindow\u002Fgetcomputedstyle\u002Findex.md)\n- `DocumentFragment` и вставка группы узлов — [MDN: Node.appendChild](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fnode\u002Fappendchild\u002Findex.md)\n- `display: contents` и отсутствие собственного box у элемента — [MDN: Relationship of flexbox to other layout methods](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fcss\u002Fguides\u002Fflexible_box_layout\u002Frelationship_with_other_layout_methods\u002Findex.md)\n- CSS containment и `contain: size` — [MDN: contain](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fcss\u002Freference\u002Fproperties\u002Fcontain\u002Findex.md)\n- forced synchronous layout — [MDN: CSS performance optimization](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Flearn_web_development\u002Fextensions\u002Fperformance\u002Fcss\u002Findex.md)\n- layout thrashing — [MDN: CSS performance optimization](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Flearn_web_development\u002Fextensions\u002Fperformance\u002Fcss\u002Findex.md)\n- batching DOM reads и DOM writes — [MDN: CSS performance optimization](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Flearn_web_development\u002Fextensions\u002Fperformance\u002Fcss\u002Findex.md)\n\n## Кадры и наблюдатели\n\n- `requestAnimationFrame` перед следующим repaint — [MDN: Window.requestAnimationFrame](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fwindow\u002Frequestanimationframe\u002Findex.md)\n- связь event loop и отрисовки кадра — [ru.javascript.info: Событийный цикл микрозадачи и макрозадачи](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F99-ui-misc\u002F03-event-loop\u002Farticle.md)\n- `ResizeObserver` и наблюдение за размерами элемента — [MDN: ResizeObserver](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fresizeobserver\u002Findex.md)\n- `IntersectionObserver` и наблюдение за попаданием элемента в viewport — [MDN: IntersectionObserver](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fintersectionobserver\u002Findex.md)\n- `PerformanceObserver` и наблюдение за метриками производительности — [MDN: PerformanceObserver](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fperformanceobserver\u002Findex.md)\n\n## DOM-события\n\n- браузерные события и `addEventListener` — [ru.javascript.info: Введение в браузерные события](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F01-introduction-browser-events\u002Farticle.md)\n- `EventTarget.addEventListener` и опции обработчика — [MDN: EventTarget addEventListener](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Feventtarget\u002Faddeventlistener\u002Findex.md)\n- всплытие и погружение событий — [ru.javascript.info: Всплытие и погружение](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F02-bubbling-and-capturing\u002Farticle.md)\n- `event.target` и `event.currentTarget` — [MDN: Event target](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fevent\u002Ftarget\u002Findex.md), [MDN: Event currentTarget](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fevent\u002Fcurrenttarget\u002Findex.md)\n- делегирование событий — [ru.javascript.info: Делегирование событий](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F03-event-delegation\u002Farticle.md)\n- отмена действия браузера через `preventDefault` — [MDN: Event preventDefault](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fevent\u002Fpreventdefault\u002Findex.md)\n- остановка распространения через `stopPropagation` — [MDN: Event stopPropagation](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fevent\u002Fstoppropagation\u002Findex.md)\n- passive listeners и влияние на прокрутку — [ru.javascript.info: Действия браузера по умолчанию](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F04-default-browser-action\u002Farticle.md)\n\n## Формы\n\n- элементы формы и навигация через `form.elements` — [ru.javascript.info: Свойства и методы формы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F4-forms-controls\u002F1-form-elements\u002Farticle.md)\n- `input` и `change` у элементов формы — [ru.javascript.info: События change input cut copy paste](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F4-forms-controls\u002F3-events-change-input\u002Farticle.md)\n- `submit`, `requestSubmit` и отправка формы — [ru.javascript.info: Отправка формы событие и метод submit](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F4-forms-controls\u002F4-forms-submit\u002Farticle.md), [MDN: HTMLFormElement requestSubmit](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlformelement\u002Frequestsubmit\u002Findex.md)\n- `focus`, `blur`, `focusin` и `focusout` — [ru.javascript.info: Фокусировка focus blur](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F4-forms-controls\u002F2-focus-blur\u002Farticle.md)\n- `HTMLFormElement.elements` — [MDN: HTMLFormElement elements](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlformelement\u002Felements\u002Findex.md)\n\n## Virtual DOM\n\n- Virtual DOM как описание UI в памяти\n- diff и patch между описанием UI и настоящим DOM\n- отличие Virtual DOM от browser render tree — [MDN: Critical rendering path](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fperformance\u002Fguides\u002Fcritical_rendering_path\u002Findex.md)\n",{"label":93,"url":208},"https:\u002F\u002Fgithub.com\u002Fcoldrain96\u002Fduckfrontend-content\u002Fblob\u002Fmain\u002Fcontent\u002Fv1\u002Fprograms\u002Fbrowser-platform\u002Frendering-dom-events-forms\u002Fprogram.json",{"slug":40,"setSlug":33,"title":210,"description":211,"audience":212,"language":65,"runtime":66,"order":12,"status":13,"seoTitle":213,"seoDescription":214,"accessLabel":70,"authorNote":71,"badgeLabel":72,"communityLabel":73,"lessons":215,"author":88,"repository":223},"Сеть в браузере","HTTP, Fetch API, CORS, кеширование, Service Worker и диагностика сети в DevTools.","Для frontend-учеников, которым нужно уверенно объяснять браузерные сетевые запросы и диагностику в DevTools.","Browser networking, fetch, CORS and cache practice","Практика по HTTP, Fetch API, headers, AbortController, CORS, cache, Service Worker и Chrome DevTools Network.",[216],{"slug":40,"moduleSlug":40,"title":210,"topic":217,"goal":218,"placementReason":219,"order":12,"status":13,"state":80,"activities":220,"steps":221,"overviewBody":222},"HTTP, Fetch API, Request\u002FResponse, CORS, кеширование, Service Worker и DevTools Network","Научиться объяснять сетевые запросы браузера, ошибки, кеширование и диагностику через DevTools.","Сетевой блок дополняет browser-platform после DOM\u002Frendering и нужен для реальных frontend-сценариев.",[82,83,84,85],[],"# Сеть в браузере\n\n## Сеть в браузере\n\n- HTTP-запрос и HTTP-ответ в браузере — [MDN: An overview of HTTP](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Fguides\u002Foverview\u002Findex.md)\n- методы HTTP и семантика запроса — [MDN: HTTP request methods](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Freference\u002Fmethods\u002Findex.md)\n- статусы HTTP-ответов — [MDN: HTTP response status codes](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Freference\u002Fstatus\u002Findex.md)\n- Fetch API — [MDN: Window fetch](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fwindow\u002Ffetch\u002Findex.md)\n- Request и Response — [MDN: Request](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Frequest\u002Findex.md), [MDN: Response](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fresponse\u002Findex.md)\n- Headers и нормализация HTTP-заголовков — [MDN: Headers](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fheaders\u002Findex.md)\n- AbortController для отмены запроса — [MDN: AbortController](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fabortcontroller\u002Findex.md)\n- URLSearchParams и query string — [MDN: URLSearchParams](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Furlsearchparams\u002Findex.md)\n- FormData и отправка данных формы — [MDN: FormData](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fformdata\u002Findex.md)\n- CORS и preflight-запросы — [MDN: Cross-Origin Resource Sharing CORS](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Fguides\u002Fcors\u002Findex.md)\n- HTTP-кеширование в браузере — [MDN: HTTP caching](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Fguides\u002Fcaching\u002Findex.md)\n- Cache-Control — [MDN: Cache-Control header](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Freference\u002Fheaders\u002Fcache-control\u002Findex.md)\n- Service Worker и перехват fetch — [MDN: Service Worker API](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fservice_worker_api\u002Findex.md)\n- Cache Storage — [MDN: CacheStorage](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fcachestorage\u002Findex.md)\n- вкладка Network в Chrome DevTools — [Chrome DevTools: Network panel](https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fdevtools\u002Fnetwork\u002F)\n- Headers, Payload, Preview, Response, Initiator и Timing в Network — [Chrome DevTools: Network features reference](https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fdevtools\u002Fnetwork\u002Freference\u002F)\n- throttling, Disable cache и request blocking в Chrome DevTools — [Chrome DevTools: Network panel overview](https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fdevtools\u002Fnetwork\u002Foverview)\n- вкладка Application для Service Workers, Cache Storage и cookies — [Chrome DevTools: Application panel](https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fdevtools\u002Fapplication)\n",{"label":93,"url":224},"https:\u002F\u002Fgithub.com\u002Fcoldrain96\u002Fduckfrontend-content\u002Fblob\u002Fmain\u002Fcontent\u002Fv1\u002Fprograms\u002Fbrowser-platform\u002Fbrowser-network\u002Fprogram.json",{"slug":50,"setSlug":43,"title":226,"description":227,"audience":228,"language":65,"runtime":66,"order":67,"status":13,"seoTitle":229,"seoDescription":230,"accessLabel":70,"authorNote":71,"badgeLabel":72,"communityLabel":73,"lessons":231,"author":88,"repository":239},"Рекурсия","Рекурсия, стек вызовов, обход вложенных структур и backtracking.","Для учеников, которые готовятся к алгоритмическим задачам и должны уверенно объяснять рекурсивное решение.","JavaScript recursion and backtracking practice","Практика по recursion, call stack, nested structures, named function expressions, tail recursion and backtracking.",[232],{"slug":50,"moduleSlug":50,"title":226,"topic":233,"goal":234,"placementReason":235,"order":12,"status":13,"state":80,"activities":236,"steps":237,"overviewBody":238},"Рекурсия, базовый случай, стек вызовов, обход структур и backtracking","Научиться строить и объяснять рекурсивные решения без потери базового случая и состояния.","Алгоритмический блок вынесен отдельно, потому что он тренирует способ решения задач, а не одну JS-механику.",[82,83,84,85],[],"# Рекурсия\n\n## Рекурсия\n\n- рекурсия как вызов функции самой себя — [MDN: Recursion](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md)\n- базовый случай и рекурсивный случай — [MDN: Recursion](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md)\n- стек вызовов и ограничение глубины рекурсии — [MDN: InternalError too much recursion](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Ferrors\u002Ftoo_much_recursion\u002Findex.md)\n- рекурсивный обход вложенных структур — [MDN: Recursion](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md)\n- имя function expression для самовызова — [ECMAScript: Function Definitions](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-function-definitions)\n- хвостовой вызов и хвостовая рекурсия — [Вы не знаете JS: ES6 и дальше — глава 7 Meta Programming](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fes6%20%26%20beyond\u002Fch7.md)\n- рекурсия в задачах на деревья — [MDN: Recursion](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md)\n- backtracking как рекурсивный перебор вариантов — [MDN: Recursion](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md)\n",{"label":93,"url":240},"https:\u002F\u002Fgithub.com\u002Fcoldrain96\u002Fduckfrontend-content\u002Fblob\u002Fmain\u002Fcontent\u002Fv1\u002Fprograms\u002Falgorithms\u002Frecursion\u002Fprogram.json",{"slug":59,"setSlug":52,"title":242,"description":243,"audience":244,"language":65,"runtime":66,"order":67,"status":13,"seoTitle":245,"seoDescription":246,"accessLabel":70,"authorNote":247,"badgeLabel":72,"communityLabel":73,"lessons":248,"author":88,"repository":257},"Пробное собеседование: JavaScript core","Вопросы по JavaScript core, задачи на порядок выполнения кода и live coding.","Для учеников, которые хотят собрать материал уроков в формат приближенного технического собеседования.","JavaScript mock interview practice","Mock interview materials for JavaScript core: questions, live coding tasks and predict-output examples.","Тренировка Duck Frontend в формате мок-собеседования по JavaScript core.",[249],{"slug":59,"moduleSlug":59,"title":250,"topic":251,"goal":252,"placementReason":253,"order":12,"status":13,"state":80,"activities":254,"steps":255,"overviewBody":256},"Mock interview: JavaScript core","Итоговое мок-собеседование по JavaScript core","Проверить, как ученик объясняет core JavaScript темы в режиме интервью.","Итоговая практика собирает вопросы и примеры из ранних JavaScript-уроков в собеседовательный формат.",[82,83,84,85],[],"# Mock interview: JavaScript core\n\nИтоговая подборка из локальной папки `mentoring\u002Fmock-interview`. Внутри собраны вопросы для интервью, predict-output примеры и live coding-задачи.\n",{"label":93,"url":258},"https:\u002F\u002Fgithub.com\u002Fcoldrain96\u002Fduckfrontend-content\u002Fblob\u002Fmain\u002Fcontent\u002Fv1\u002Fprograms\u002Finterview-prep\u002Fmock-interview-javascript-core\u002Fprogram.json","practice-content.v1",[261],{"slug":262,"title":263,"excerpt":264,"body":265,"seoTitle":266,"seoDescription":267,"status":13,"programSlug":30,"lessonSlug":30},"frontend-interview-map","Как разбирать порядок выполнения JavaScript","Короткий алгоритм для вопросов про синхронный код, Promise и таймеры.","Сначала выполните весь синхронный код текущего вызова. Записывайте console.log по мере чтения и не переходите к очередям, пока стек не опустеет.\n\nPromise.then, Promise.catch, Promise.finally и продолжение async-функции после await ставят реакции в очередь микрозадач. Микрозадачи выполняются после синхронного кода и до следующей задачи.\n\nsetTimeout не выполняет callback сразу после истечения задержки. Таймер только делает задачу доступной для очереди; она начнётся после текущего кода и всех накопившихся микрозадач.\n\nДля проверки выпишите три списка: синхронный вывод, микрозадачи и задачи таймеров. Затем последовательно опустошайте их, учитывая, что каждая выполненная задача может добавить новые микрозадачи.\n\nНа собеседовании проговаривайте не только итоговый порядок, но и причину каждого перехода: что осталось в стеке, какая реакция попала в микрозадачи и почему таймер ждёт следующей задачи.","Порядок выполнения JavaScript на собеседовании","Как определить порядок синхронного кода, микрозадач Promise и таймеров в JavaScript.",[269,276,283,290,297,304,311,318,325,332,339,346,353,360,367,374,381,388,395,402,409,414,421,428,435,442,449,456,463,470,477,484,491,498,505,512,519,526,531,538,545,551,558,565,570,577,584,591,598,603,610,616,622,629,636,643,651,658,665,672,677,684,690,697,704,711,718,726,733,740,747,754,761,768,775,782,789,797,804,811,818,825,832,839,846,853,861,868,875,882,889,895,902,909,916,923,931,938,945,952,959,966,973,980,987,994,1002,1009,1016,1023,1029,1036,1042,1049,1056,1063,1071,1078,1085,1092,1099,1105,1112,1119,1126,1133,1141,1148,1155,1162,1168,1175,1182,1189,1197,1204,1211,1218,1225,1232,1239,1246,1254,1261,1268,1275,1282,1289,1296,1304,1311,1318,1325,1332,1339,1346,1354,1361,1368,1375,1382,1389,1396,1404,1411,1418,1425,1432,1439,1445,1453,1460,1467,1474,1481,1488,1496,1503,1510,1515,1522,1530,1537,1544,1551,1559,1566,1573,1581,1588,1595,1602,1610,1617,1624,1632,1639,1646,1653,1660,1666,1673,1680,1687,1695,1702,1710,1716,1724],{"slug":270,"title":271,"source":272,"exerciseCode":273,"tutorialCode":274,"expectedOutput":275,"executionExplanation":274,"language":65,"runtime":66,"programSlug":40,"lessonSlug":40,"order":12,"status":13},"browser-network-ex1","Упражнение 1: сеть в браузере","mentoring\u002Fbrowser-network\u002Fex\u002Fex1","const a = new URL('https:\u002F\u002Fa.test\u002Fpath?x=1&x=2&y=3');\n\nconsole.log(a.searchParams.get('x'));\nconsole.log(a.searchParams.getAll('x').join('|'));\n\na.searchParams.set('x', '4');\na.searchParams.append('z', '5');\n\nconsole.log(a.search);\nconsole.log(a.href);\n","\u002F\u002F Упражнение 1: сеть в браузере\n\u002F\u002F Темы URLSearchParams дубли query-параметров set append и итоговый URL\n\u002F\u002F Читать дальше\n\u002F\u002F MDN URLSearchParams https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Furlsearchparams\u002Findex.md\nconst a = new URL('https:\u002F\u002Fa.test\u002Fpath?x=1&x=2&y=3');\n\n\u002F\u002F У query string может быть несколько параметров с одним именем.\n\u002F\u002F get возвращает первое значение, а getAll возвращает все значения по порядку.\nconsole.log(a.searchParams.get('x'));\nconsole.log(a.searchParams.getAll('x').join('|'));\n\n\u002F\u002F set заменяет все старые значения x одним новым значением.\n\u002F\u002F append добавляет новую пару в конец query string.\na.searchParams.set('x', '4');\na.searchParams.append('z', '5');\n\n\u002F\u002F searchParams связан с объектом URL.\n\u002F\u002F Поэтому изменение параметров сразу меняет search и href.\nconsole.log(a.search);\nconsole.log(a.href);","1\n1|2\n?x=4&y=3&z=5\nhttps:\u002F\u002Fa.test\u002Fpath?x=4&y=3&z=5",{"slug":277,"title":278,"source":279,"exerciseCode":280,"tutorialCode":281,"expectedOutput":282,"executionExplanation":281,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":12,"status":13},"collections-iteration-arrays-ex1","Упражнение 1: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex1","const a = {};\nconst b = {};\nconst c = {};\n\na[b] = '1';\na[c] = '2';\n\nconst d = new Map();\n\nd.set(b, '1');\nd.set(c, '2');\n\nconsole.log('1:', a[b]);\nconsole.log('2:', d.get(b));\nconsole.log('3:', d.size);\n","\u002F\u002F Упражнение 1: коллекции, итерация, массивы и строки\n\u002F\u002F Темы Map и объектные ключи\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Map и Set https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F07-map-set\u002Farticle.md\n\u002F\u002F MDN Map https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fmap\u002Findex.md\nconst a = {};\nconst b = {};\nconst c = {};\n\n\u002F\u002F Обычный объект приводит ключ свойства к строке или symbol.\n\u002F\u002F Оба объекта превращаются в один и тот же строковый ключ.\na[b] = '1';\na[c] = '2';\n\nconst d = new Map();\n\n\u002F\u002F Map хранит сам объект как ключ.\n\u002F\u002F Поэтому b и c остаются разными ключами.\nd.set(b, '1');\nd.set(c, '2');\n\n\u002F\u002F В объекте вторая запись перезаписала первую.\nconsole.log('1:', a[b]);\n\n\u002F\u002F В Map значение по ключу b осталось отдельным.\nconsole.log('2:', d.get(b));\n\n\u002F\u002F В Map две разные пары ключ значение.\nconsole.log('3:', d.size);","1: 2\n2: 1\n3: 2",{"slug":284,"title":285,"source":286,"exerciseCode":287,"tutorialCode":288,"expectedOutput":289,"executionExplanation":288,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":12,"status":13},"event-loop-promises-async-await-ex1","Упражнение 1: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex1","console.log('1');\n\nsetTimeout(() => console.log('2'), 0);\n\nPromise.resolve().then(() => console.log('3'));\n\nconsole.log('4');\n","\u002F\u002F Упражнение 1: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы event loop, задача таймера и микрозадача Promise\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS event loop https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F99-ui-misc\u002F03-event-loop\u002Farticle.md\n\u002F\u002F Learn JS микрозадачи https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md\n\u002F\u002F MDN microtask guide https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtml_dom_api\u002Fmicrotask_guide\u002Findex.md\n\u002F\u002F Сначала выполняется обычный синхронный script.\nconsole.log('1');\n\n\u002F\u002F Таймер не запускает callback сразу.\n\u002F\u002F Он ставит новую задачу для будущего прохода event loop.\nsetTimeout(() => console.log('2'), 0);\n\n\u002F\u002F Обработчик then тоже не запускается сразу.\n\u002F\u002F Он попадает в очередь микрозадач.\nPromise.resolve().then(() => console.log('3'));\n\n\u002F\u002F Текущий script должен выполниться до конца.\nconsole.log('4');\n\n\u002F\u002F После script браузер сначала очищает микрозадачи.\n\u002F\u002F Поэтому 3 будет раньше таймера 2.","1\n4\n3\n2",{"slug":291,"title":292,"source":293,"exerciseCode":294,"tutorialCode":295,"expectedOutput":296,"executionExplanation":295,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":12,"status":13},"event-loop-promises-deep-dive-ex1","Дополнительное упражнение 1: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex1","console.log('1');\n\nsetTimeout(() => {\n  console.log('2');\n  Promise.resolve().then(() => console.log('3'));\n}, 0);\n\nPromise.resolve().then(() => {\n  console.log('4');\n  setTimeout(() => console.log('5'), 0);\n});\n\nqueueMicrotask(() => console.log('6'));\n\nconsole.log('7');\n","\u002F\u002F Дополнительное упражнение 1: углубленная практика по event loop и Promise\n\u002F\u002F Темы вложенные микрозадачи и задачи таймера\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS event loop https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F99-ui-misc\u002F03-event-loop\u002Farticle.md\n\u002F\u002F Learn JS microtasks https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md\nconsole.log('1');\n\nsetTimeout(() => {\n  \u002F\u002F Первый таймер уже был поставлен во время синхронного script.\n  console.log('2');\n\n  \u002F\u002F Эта микрозадача выполнится сразу после callback текущего таймера.\n  Promise.resolve().then(() => console.log('3'));\n}, 0);\n\nPromise.resolve().then(() => {\n  \u002F\u002F then попадает в очередь микрозадач раньше queueMicrotask ниже.\n  console.log('4');\n\n  \u002F\u002F Таймер создается внутри микрозадачи, поэтому он встает после первого таймера.\n  setTimeout(() => console.log('5'), 0);\n});\n\n\u002F\u002F queueMicrotask использует ту же очередь микрозадач.\nqueueMicrotask(() => console.log('6'));\n\nconsole.log('7');","1\n7\n4\n6\n2\n3\n5",{"slug":298,"title":299,"source":300,"exerciseCode":301,"tutorialCode":302,"expectedOutput":303,"executionExplanation":302,"language":65,"runtime":66,"programSlug":59,"lessonSlug":59,"order":12,"status":13},"mock-interview-javascript-core-ex1","Пример мок-собеседования 1","mentoring\u002Fmock-interview-javascript-core\u002Fex\u002Fex1","function f() {\n  console.log('1:', a);\n\n  var a = 'a';\n\n  console.log('2:', a);\n}\n\nfunction g() {\n  try {\n    console.log('3:', b);\n  } catch (error) {\n    console.log('3:', error.name);\n  }\n\n  let b = 'b';\n\n  console.log('4:', b);\n}\n\nf();\ng();\n","\u002F\u002F Пример мок-собеседования 1\n\u002F\u002F Темы: hoisting с var и Temporal Dead Zone с let.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS устаревшее ключевое слово var https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F04-var\u002Farticle.md\n\u002F\u002F Learn JS лексическое окружение https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch4.md#L2 раздел Поднятие переменных\n\u002F\u002F MDN var https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Fvar\n\u002F\u002F MDN let https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Flet\n\nfunction f() {\n  \u002F\u002F Движок уже знает про var a ниже.\n  \u002F\u002F Но присваивание значения еще не произошло.\n  \u002F\u002F Поэтому переменная существует, но равна undefined.\n  console.log('1:', a);\n\n  \u002F\u002F Эта строка состоит из объявления и присваивания.\n  \u002F\u002F Объявление всплыло заранее, а присваивание выполняется здесь.\n  var a = 'a';\n\n  \u002F\u002F Теперь в a уже лежит строка a.\n  console.log('2:', a);\n}\n\nfunction g() {\n  try {\n    \u002F\u002F Движок уже знает про let b ниже.\n    \u002F\u002F Но до строки объявления b находится в TDZ.\n    \u002F\u002F Поэтому чтение b падает с ReferenceError.\n    console.log('3:', b);\n  } catch (error) {\n    console.log('3:', error.name);\n  }\n\n  \u002F\u002F После этой строки b инициализирована.\n  let b = 'b';\n\n  \u002F\u002F Теперь читать b можно.\n  console.log('4:', b);\n}\n\nf();\ng();","1: undefined\n2: a\n3: ReferenceError\n4: b",{"slug":305,"title":306,"source":307,"exerciseCode":308,"tutorialCode":309,"expectedOutput":310,"executionExplanation":309,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":12,"status":13},"objects-prototypes-classes-ex1","Упражнение 1: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex1","const a = {\n  x: 1,\n};\n\nObject.defineProperty(a, 'y', {\n  value: 2,\n});\n\nconst b = Object.getOwnPropertyDescriptor(a, 'x');\nconst c = Object.getOwnPropertyDescriptor(a, 'y');\n\nconsole.log('1:', b.writable, b.enumerable, b.configurable);\nconsole.log('2:', c.writable, c.enumerable, c.configurable);\nconsole.log('3:', a.x, a.y);\n","\u002F\u002F Упражнение 1: свойства объектов, прототипы и классы\n\u002F\u002F Темы дескрипторы свойств и флаги по умолчанию\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS дескрипторы свойств https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md\n\u002F\u002F MDN Object.defineProperty https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fdefineproperty\u002Findex.md\nconst a = {\n  \u002F\u002F Свойство из литерала создается как обычное свойство данных.\n  \u002F\u002F Его можно менять, перечислять и конфигурировать.\n  x: 1,\n};\n\nObject.defineProperty(a, 'y', {\n  \u002F\u002F При создании через defineProperty неуказанные флаги станут false.\n  value: 2,\n});\n\n\u002F\u002F Получаем полное описание собственного свойства x.\nconst b = Object.getOwnPropertyDescriptor(a, 'x');\n\n\u002F\u002F Получаем полное описание собственного свойства y.\nconst c = Object.getOwnPropertyDescriptor(a, 'y');\n\nconsole.log('1:', b.writable, b.enumerable, b.configurable);\nconsole.log('2:', c.writable, c.enumerable, c.configurable);\nconsole.log('3:', a.x, a.y);","1 true true true\n2 false false false\n3 1 2",{"slug":312,"title":313,"source":314,"exerciseCode":315,"tutorialCode":316,"expectedOutput":317,"executionExplanation":316,"language":65,"runtime":66,"programSlug":50,"lessonSlug":50,"order":12,"status":13},"recursion-ex1","Упражнение 1: рекурсия","mentoring\u002Frecursion\u002Fex\u002Fex1","function f(a) {\n  console.log(a);\n\n  if (a === 0) {\n    return;\n  }\n\n  f(a - 1);\n}\n\nf(3);\n","\u002F\u002F Упражнение 1: рекурсия\n\u002F\u002F Темы базовый случай и рекурсивный спуск\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Recursion https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md\nfunction f(a) {\n  \u002F\u002F Каждый вызов получает свое значение a.\n  console.log(a);\n\n  \u002F\u002F Базовый случай останавливает цепочку вызовов.\n  if (a === 0) {\n    return;\n  }\n\n  \u002F\u002F Мы вызываем ту же функцию с меньшим значением.\n  \u002F\u002F Так каждый шаг приближает нас к базовому случаю.\n  f(a - 1);\n}\n\nf(3);","3\n2\n1\n0",{"slug":319,"title":320,"source":321,"exerciseCode":322,"tutorialCode":323,"expectedOutput":324,"executionExplanation":323,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":12,"status":13},"rendering-dom-events-forms-ex1","Упражнение 1: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex1","const a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '10px';\ndocument.body.append(a);\n\nconsole.log(a.offsetWidth);\n\na.style.width = '200px';\n\nconsole.log(a.offsetWidth);\n","\u002F\u002F Упражнение 1: рендеринг, DOM, события и формы\n\u002F\u002F Темы layout read после DOM write и синхронный расчет layout\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Critical rendering path https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fperformance\u002Fguides\u002Fcritical_rendering_path\u002Findex.md\n\u002F\u002F MDN offsetWidth https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlelement\u002Foffsetwidth\u002Findex.md\nconst a = document.createElement('div');\n\n\u002F\u002F Мы создали элемент и задали ему размер через inline style.\n\u002F\u002F Пока элемент не добавлен в документ, браузеру не нужно считать его место на странице.\na.style.width = '100px';\na.style.height = '10px';\ndocument.body.append(a);\n\n\u002F\u002F offsetWidth это layout-метрика.\n\u002F\u002F Чтобы вернуть число, браузер должен знать актуальную ширину элемента в layout.\nconsole.log(a.offsetWidth);\n\n\u002F\u002F Мы меняем ширину. Это помечает layout как требующий обновления.\na.style.width = '200px';\n\n\u002F\u002F Новое чтение offsetWidth заставляет браузер выдать уже актуальную ширину.\n\u002F\u002F В реальном интерфейсе такая связка write -> read может дорого стоить.\nconsole.log(a.offsetWidth);","100\n200",{"slug":326,"title":327,"source":328,"exerciseCode":329,"tutorialCode":330,"expectedOutput":331,"executionExplanation":330,"language":65,"runtime":66,"programSlug":19,"lessonSlug":19,"order":12,"status":13},"scope-closures-deep-dive-ex1","Дополнительное упражнение 1: углубленная практика по областям видимости и замыканиям","mentoring\u002Fscope-closures-deep-dive\u002Fex\u002Fex1","function f(a) {\n  var b = a;\n\n  return b + c;\n}\n\nvar c = 2;\n\nconsole.log('1:', f(1));\n","\u002F\u002F Дополнительное упражнение 1: углубленная практика по областям видимости и замыканиям\n\u002F\u002F Темы: LHS и RHS поиск, глобальная и функциональная область.\n\u002F\u002F Читать дальше\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch1.md раздел Компилятор говорит\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch1.md раздел LHS и RHS\n\nfunction f(a) {\n  \u002F\u002F Параметр a создается в области функции f.\n  \u002F\u002F var b тоже создается в области функции f.\n  \u002F\u002F При присваивании b движок ищет место для записи.\n  var b = a;\n\n  \u002F\u002F Здесь b и c читаются.\n  \u002F\u002F b находится внутри f, а c ищется выше в глобальной области.\n  return b + c;\n}\n\n\u002F\u002F var c создается в глобальной области script.\nvar c = 2;\n\n\u002F\u002F Вызов f передает 1 в параметр a.\nconsole.log('1:', f(1));","1: 3",{"slug":333,"title":334,"source":335,"exerciseCode":336,"tutorialCode":337,"expectedOutput":338,"executionExplanation":337,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":12,"status":13},"scope-hoisting-closures-this-ex1","Упражнение 1: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex1","const a = 'a';\n\nconst f = function (a) {\n  var b = 'b';\n\n  console.log('1:', a);\n\n  if (true) {\n    let a = 'c';\n\n    console.log('2:', a, b);\n  }\n\n  console.log('3:', a, b);\n};\n\nf('d');\n\nconsole.log('4:', a);\n","\u002F\u002F Упражнение 1: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: глобальная, функциональная и блочная область видимости, shadowing.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS область видимости и замыкание https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch2.md#L2 раздел Лексическая область видимости\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch3.md#L8 раздел Область видимости из функций\n\u002F\u002F MDN var https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Fvar\n\u002F\u002F MDN let https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Flet\n\n\u002F\u002F Эта переменная создается в глобальной области.\n\u002F\u002F Она будет доступна снаружи функции и блока.\nconst a = 'a';\n\n\u002F\u002F Function Expression создает функцию и кладет ее в переменную f.\n\u002F\u002F У этой функции есть параметр a.\n\u002F\u002F При вызове он создаст локальную переменную и закроет глобальную a.\nconst f = function (a) {\n  \u002F\u002F var b живет во всей функции f, а не только в ближайшем блоке.\n  var b = 'b';\n\n  \u002F\u002F Здесь ближайшая a это параметр функции.\n  console.log('1:', a);\n\n  \u002F\u002F Этот блок нужен, чтобы показать отдельную блочную область.\n  if (true) {\n    \u002F\u002F Здесь создается новая блочная a.\n    \u002F\u002F Она временно закрывает параметр функции.\n    let a = 'c';\n\n    \u002F\u002F Внутри блока ближайшая a равна c.\n    \u002F\u002F Переменная b доступна, потому что var имеет область всей функции.\n    console.log('2:', a, b);\n  }\n\n  \u002F\u002F Блок закончился, его let a больше недоступна.\n  \u002F\u002F Теперь ближайшая a снова параметр функции.\n  console.log('3:', a, b);\n};\n\n\u002F\u002F Передаем значение в параметр a.\nf('d');\n\n\u002F\u002F Функция закончилась.\n\u002F\u002F Снаружи снова видна глобальная a.\nconsole.log('4:', a);","1: d\n2: c b\n3: d b\n4: a",{"slug":340,"title":341,"source":342,"exerciseCode":343,"tutorialCode":344,"expectedOutput":345,"executionExplanation":344,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":12,"status":13},"types-coercion-symbol-json-ex1","Упражнение 1: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex1","let a = 1;\n\nconsole.log('1:', typeof null);\nconsole.log('2:', typeof undefined);\nconsole.log('3:', typeof false);\nconsole.log('4:', typeof 1n);\nconsole.log('5:', typeof Symbol('a'));\nconsole.log('6:', typeof []);\nconsole.log('7:', typeof {});\nconsole.log('8:', typeof function f() {});\nconsole.log('9:', typeof a);\n\na = '1';\n\nconsole.log('10:', typeof a);\nconsole.log('11:', typeof typeof a);\n","\u002F\u002F Упражнение 1: типы, приведение, Symbol и JSON\n\u002F\u002F Темы typeof, базовые типы и тип значения\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS типы данных https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F05-types\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch1.md\n\u002F\u002F MDN typeof\n\u002F\u002F В JavaScript тип есть у значения, а не у переменной.\n\u002F\u002F Переменная a сейчас хранит number.\nlet a = 1;\n\n\u002F\u002F typeof возвращает строку с названием типа значения.\n\u002F\u002F Для null есть старый баг языка.\n\u002F\u002F Поэтому результат не null, а object.\nconsole.log('1:', typeof null);\n\n\u002F\u002F undefined получает ожидаемый результат undefined.\nconsole.log('2:', typeof undefined);\n\n\u002F\u002F boolean, bigint и symbol имеют отдельные результаты typeof.\nconsole.log('3:', typeof false);\nconsole.log('4:', typeof 1n);\nconsole.log('5:', typeof Symbol('a'));\n\n\u002F\u002F Массив это объект со специальным поведением.\n\u002F\u002F typeof не отличает массив от обычного объекта.\nconsole.log('6:', typeof []);\n\n\u002F\u002F Обычный объект тоже дает object.\nconsole.log('7:', typeof {});\n\n\u002F\u002F Функция технически является вызываемым объектом.\n\u002F\u002F Но typeof для нее возвращает отдельную строку function.\nconsole.log('8:', typeof function f() {});\n\n\u002F\u002F typeof не спрашивает тип переменной как контейнера.\n\u002F\u002F Он спрашивает тип текущего значения внутри переменной.\nconsole.log('9:', typeof a);\n\n\u002F\u002F Теперь в той же переменной лежит строка.\na = '1';\n\nconsole.log('10:', typeof a);\n\n\u002F\u002F typeof всегда возвращает строку.\n\u002F\u002F Поэтому typeof от результата typeof тоже дает string.\nconsole.log('11:', typeof typeof a);","1 object\n2 undefined\n3 boolean\n4 bigint\n5 symbol\n6 object\n7 object\n8 function\n9 number\n10 string\n11 string",{"slug":347,"title":348,"source":349,"exerciseCode":350,"tutorialCode":351,"expectedOutput":352,"executionExplanation":351,"language":65,"runtime":66,"programSlug":40,"lessonSlug":40,"order":26,"status":13},"browser-network-ex2","Упражнение 2: сеть в браузере","mentoring\u002Fbrowser-network\u002Fex\u002Fex2","const a = new Headers({\n  'Content-Type': 'text\u002Fplain',\n});\n\na.append('X-A', '1');\na.append('x-a', '2');\na.set('X-B', '3');\n\nconsole.log(a.get('content-type'));\nconsole.log(a.get('x-a'));\nconsole.log(a.has('X-B'));\n\na.delete('x-b');\n\nconsole.log(a.has('X-B'));\n","\u002F\u002F Упражнение 2: сеть в браузере\n\u002F\u002F Темы Headers нормализация имен append set has delete\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Headers https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fheaders\u002Findex.md\nconst a = new Headers({\n  'Content-Type': 'text\u002Fplain',\n});\n\n\u002F\u002F Имена заголовков в Headers не зависят от регистра.\n\u002F\u002F Content-Type и content-type указывают на один и тот же заголовок.\na.append('X-A', '1');\na.append('x-a', '2');\na.set('X-B', '3');\n\nconsole.log(a.get('content-type'));\n\n\u002F\u002F append добавляет значение к существующему заголовку.\n\u002F\u002F В браузере два значения соединяются через запятую и пробел.\nconsole.log(a.get('x-a'));\nconsole.log(a.has('X-B'));\n\n\u002F\u002F delete тоже ищет имя без учета регистра.\na.delete('x-b');\n\nconsole.log(a.has('X-B'));","text\u002Fplain\n1, 2\ntrue\nfalse",{"slug":354,"title":355,"source":356,"exerciseCode":357,"tutorialCode":358,"expectedOutput":359,"executionExplanation":358,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":26,"status":13},"collections-iteration-arrays-ex2","Упражнение 2: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex2","const a = new Map();\n\na.set('a', 1);\na.set('b', 2);\na.set('a', 3);\n\nconsole.log([...a.keys()].join(','));\nconsole.log([...a.values()].join(','));\n\na.delete('a');\na.set('a', 4);\n\nconsole.log([...a.keys()].join(','));\n","\u002F\u002F Упражнение 2: коллекции, итерация, массивы и строки\n\u002F\u002F Темы порядок вставки в Map\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Map и Set https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F07-map-set\u002Farticle.md\n\u002F\u002F MDN Map https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fmap\u002Findex.md\nconst a = new Map();\n\n\u002F\u002F Первое добавление ключа фиксирует его место в порядке обхода.\na.set('a', 1);\na.set('b', 2);\n\n\u002F\u002F Повторная запись меняет значение.\n\u002F\u002F Но место ключа a не переносится в конец.\na.set('a', 3);\n\nconsole.log([...a.keys()].join(','));\nconsole.log([...a.values()].join(','));\n\n\u002F\u002F После удаления и новой записи ключ добавляется заново.\n\u002F\u002F Теперь a становится последним ключом.\na.delete('a');\na.set('a', 4);\n\nconsole.log([...a.keys()].join(','));","a,b\n3,2\nb,a",{"slug":361,"title":362,"source":363,"exerciseCode":364,"tutorialCode":365,"expectedOutput":366,"executionExplanation":365,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":26,"status":13},"event-loop-promises-async-await-ex2","Упражнение 2: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex2","const a = new Promise((resolve) => {\n  console.log('1');\n  resolve('2');\n  console.log('3');\n});\n\na.then((b) => console.log('4:', b));\n\nconsole.log('5');\n","\u002F\u002F Упражнение 2: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы Promise executor и асинхронность then\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Promise basics https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F02-promise-basics\u002Farticle.md\n\u002F\u002F Learn JS микрозадачи https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md\n\u002F\u002F MDN Promise https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Findex.md\n\u002F\u002F Executor запускается сразу во время создания Promise.\nconst a = new Promise((resolve) => {\n  console.log('1');\n\n  \u002F\u002F resolve меняет состояние промиса на fulfilled.\n  \u002F\u002F Но обработчики then не выполняются внутри executor.\n  resolve('2');\n\n  \u002F\u002F Executor продолжает идти синхронно до конца.\n  console.log('3');\n});\n\n\u002F\u002F then подписывает обработчик на результат.\n\u002F\u002F Его вызов попадет в очередь микрозадач.\na.then((b) => console.log('4:', b));\n\n\u002F\u002F Текущий script еще не завершен.\nconsole.log('5');","1\n3\n5\n4: 2",{"slug":368,"title":369,"source":370,"exerciseCode":371,"tutorialCode":372,"expectedOutput":373,"executionExplanation":372,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":26,"status":13},"event-loop-promises-deep-dive-ex2","Дополнительное упражнение 2: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex2","Promise.reject('a')\n  .then((a) => console.log('1:', a))\n  .then(null, (a) => {\n    console.log('2:', a);\n    return 'b';\n  })\n  .then((a) => {\n    console.log('3:', a);\n    throw 'c';\n  })\n  .then(\n    (a) => console.log('4:', a),\n    (a) => console.log('5:', a),\n  );\n\nconsole.log('6');\n","\u002F\u002F Дополнительное упражнение 2: углубленная практика по event loop и Promise\n\u002F\u002F Темы проброс ошибки и восстановление Promise цепочки\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS promise error handling https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F04-promise-error-handling\u002Farticle.md\n\u002F\u002F MDN Promise.prototype.then https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fthen\u002Findex.md\nPromise.reject('a')\n  .then((a) => console.log('1:', a))\n  .then(null, (a) => {\n    \u002F\u002F Первый then не обработал rejection, поэтому ошибка дошла сюда.\n    console.log('2:', a);\n\n    \u002F\u002F Возврат обычного значения восстанавливает цепочку.\n    return 'b';\n  })\n  .then((a) => {\n    console.log('3:', a);\n\n    \u002F\u002F throw снова переводит следующий Promise в rejected.\n    throw 'c';\n  })\n  .then(\n    (a) => console.log('4:', a),\n    \u002F\u002F Второй аргумент then обрабатывает ошибку из предыдущего шага.\n    (a) => console.log('5:', a),\n  );\n\nconsole.log('6');","6\n2: a\n3: b\n5: c",{"slug":375,"title":376,"source":377,"exerciseCode":378,"tutorialCode":379,"expectedOutput":380,"executionExplanation":379,"language":65,"runtime":66,"programSlug":59,"lessonSlug":59,"order":26,"status":13},"mock-interview-javascript-core-ex2","Пример мок-собеседования 2","mentoring\u002Fmock-interview-javascript-core\u002Fex\u002Fex2","const d = (function () {\n  var a = 0;\n\n  return {\n    b() {\n      a++;\n\n      return a;\n    },\n\n    c() {\n      return a;\n    },\n  };\n})();\n\nconsole.log('1:', d.b());\nconsole.log('2:', d.b());\nconsole.log('3:', d.a);\nconsole.log('4:', d.c());\n\ntry {\n  console.log('5:', a);\n} catch (error) {\n  console.log('5:', error.name);\n}\n","\u002F\u002F Пример мок-собеседования 2\n\u002F\u002F Темы: IIFE и модульный паттерн через замыкание.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS IIFE https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F04-var\u002Farticle.md\n\u002F\u002F Learn JS замыкание https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch3.md#L234 раздел Вызов функциональных выражений по месту\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md#L314 раздел Модули\n\u002F\u002F MDN Closures https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FGuide\u002FClosures\n\n\u002F\u002F Функциональное выражение сразу вызывается.\n\u002F\u002F Такая конструкция называется IIFE.\n\u002F\u002F Здесь IIFE создает приватную область для маленького модуля.\nconst d = (function () {\n  \u002F\u002F Эта переменная приватная для IIFE.\n  \u002F\u002F Снаружи напрямую ее прочитать нельзя.\n  var a = 0;\n\n  \u002F\u002F Возвращаем объект с методами.\n  \u002F\u002F Методы замыкаются на приватную переменную a.\n  return {\n    b() {\n      a++;\n\n      return a;\n    },\n\n    c() {\n      return a;\n    },\n  };\n})();\n\n\u002F\u002F Метод b меняет приватную a.\nconsole.log('1:', d.b());\nconsole.log('2:', d.b());\n\n\u002F\u002F Свойства a в публичном объекте нет.\nconsole.log('3:', d.a);\n\n\u002F\u002F Но метод c все еще имеет доступ к приватной a через замыкание.\nconsole.log('4:', d.c());\n\ntry {\n  \u002F\u002F После выполнения IIFE ее локальная a недоступна снаружи.\n  console.log('5:', a);\n} catch (error) {\n  console.log('5:', error.name);\n}","1: 1\n2: 2\n3: undefined\n4: 2\n5: ReferenceError",{"slug":382,"title":383,"source":384,"exerciseCode":385,"tutorialCode":386,"expectedOutput":387,"executionExplanation":386,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":26,"status":13},"objects-prototypes-classes-ex2","Упражнение 2: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex2","const a = {\n  x: 1,\n};\n\nObject.defineProperty(a, 'x', {\n  writable: false,\n});\n\na.x = 2;\n\nconsole.log('1:', a.x);\n\nObject.defineProperty(a, 'x', {\n  writable: true,\n});\n\na.x = 3;\n\nconsole.log('2:', a.x);\n","\u002F\u002F Упражнение 2: свойства объектов, прототипы и классы\n\u002F\u002F Темы writable и запись в свойство данных\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS дескрипторы свойств https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md\n\u002F\u002F MDN Object.defineProperty https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fdefineproperty\u002Findex.md\nconst a = {\n  x: 1,\n};\n\nObject.defineProperty(a, 'x', {\n  \u002F\u002F Запрещаем менять значение свойства через присваивание.\n  writable: false,\n});\n\n\u002F\u002F Код упражнения выполняется как обычный browser script без strict mode.\n\u002F\u002F Поэтому запись молча не сработает.\na.x = 2;\n\nconsole.log('1:', a.x);\n\nObject.defineProperty(a, 'x', {\n  \u002F\u002F Свойство из литерала было configurable true.\n  \u002F\u002F Поэтому мы можем снова разрешить запись.\n  writable: true,\n});\n\na.x = 3;\n\nconsole.log('2:', a.x);","1 1\n2 3",{"slug":389,"title":390,"source":391,"exerciseCode":392,"tutorialCode":393,"expectedOutput":394,"executionExplanation":393,"language":65,"runtime":66,"programSlug":50,"lessonSlug":50,"order":26,"status":13},"recursion-ex2","Упражнение 2: рекурсия","mentoring\u002Frecursion\u002Fex\u002Fex2","function f(a) {\n  if (a === 1) {\n    return 1;\n  }\n\n  return a * f(a - 1);\n}\n\nconsole.log(f(4));\n","\u002F\u002F Упражнение 2: рекурсия\n\u002F\u002F Темы факториал и возврат результата из рекурсии\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Recursion https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md\nfunction f(a) {\n  \u002F\u002F Для 1 ответ уже известен.\n  \u002F\u002F Это базовый случай и дальше спускаться не нужно.\n  if (a === 1) {\n    return 1;\n  }\n\n  \u002F\u002F Внешний вызов не может сразу умножить.\n  \u002F\u002F Сначала он ждет результат f(a - 1).\n  return a * f(a - 1);\n}\n\n\u002F\u002F f(4) раскладывается в 4 * 3 * 2 * 1.\nconsole.log(f(4));","24",{"slug":396,"title":397,"source":398,"exerciseCode":399,"tutorialCode":400,"expectedOutput":401,"executionExplanation":400,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":26,"status":13},"rendering-dom-events-forms-ex2","Упражнение 2: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex2","const a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '10px';\n\nconsole.log(a.offsetWidth);\n\ndocument.body.append(a);\n\nconsole.log(a.offsetWidth);\n","\u002F\u002F Упражнение 2: рендеринг, DOM, события и формы\n\u002F\u002F Темы disconnected element и участие элемента в layout\n\u002F\u002F Читать дальше\n\u002F\u002F MDN DOM https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fdocument_object_model\u002Findex.md\n\u002F\u002F MDN offsetWidth https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlelement\u002Foffsetwidth\u002Findex.md\nconst a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '10px';\n\n\u002F\u002F Элемент существует как DOM-объект, но еще не находится в документе.\n\u002F\u002F У него нет места в layout-дереве страницы, поэтому offsetWidth дает 0.\nconsole.log(a.offsetWidth);\n\ndocument.body.append(a);\n\n\u002F\u002F После append элемент стал частью документа.\n\u002F\u002F Теперь браузер может посчитать его размер в layout.\nconsole.log(a.offsetWidth);","0\n100",{"slug":403,"title":404,"source":405,"exerciseCode":406,"tutorialCode":407,"expectedOutput":408,"executionExplanation":407,"language":65,"runtime":66,"programSlug":19,"lessonSlug":19,"order":26,"status":13},"scope-closures-deep-dive-ex2","Дополнительное упражнение 2: углубленная практика по областям видимости и замыканиям","mentoring\u002Fscope-closures-deep-dive\u002Fex\u002Fex2","function f(a) {\n  var b = a * 2;\n\n  function g(c) {\n    console.log('1:', a, b, c);\n  }\n\n  g(b * 3);\n}\n\nf(2);\n","\u002F\u002F Дополнительное упражнение 2: углубленная практика по областям видимости и замыканиям\n\u002F\u002F Темы: вложенные области видимости и поиск имени наружу.\n\u002F\u002F Читать дальше\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch2.md раздел Время компиляции\n\nfunction f(a) {\n  \u002F\u002F a живет в области функции f.\n  \u002F\u002F b тоже живет в области функции f.\n  var b = a * 2;\n\n  function g(c) {\n    \u002F\u002F c находится в области функции g.\n    \u002F\u002F a и b в g нет, поэтому движок идет наружу в область f.\n    console.log('1:', a, b, c);\n  }\n\n  \u002F\u002F b читается в области f.\n  \u002F\u002F Результат передается в параметр c функции g.\n  g(b * 3);\n}\n\nf(2);","1: 2 4 12",{"slug":410,"title":411,"source":412,"exerciseCode":301,"tutorialCode":413,"expectedOutput":303,"executionExplanation":413,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":26,"status":13},"scope-hoisting-closures-this-ex2","Упражнение 2: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex2","\u002F\u002F Упражнение 2: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: hoisting с var и Temporal Dead Zone с let.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS устаревшее ключевое слово var https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F04-var\u002Farticle.md\n\u002F\u002F Learn JS лексическое окружение https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch4.md#L2 раздел Поднятие переменных\n\u002F\u002F MDN var https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Fvar\n\u002F\u002F MDN let https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Flet\n\nfunction f() {\n  \u002F\u002F Движок уже знает про var a ниже.\n  \u002F\u002F Но присваивание значения еще не произошло.\n  \u002F\u002F Поэтому переменная существует, но равна undefined.\n  console.log('1:', a);\n\n  \u002F\u002F Эта строка состоит из объявления и присваивания.\n  \u002F\u002F Объявление всплыло заранее, а присваивание выполняется здесь.\n  var a = 'a';\n\n  \u002F\u002F Теперь в a уже лежит строка a.\n  console.log('2:', a);\n}\n\nfunction g() {\n  try {\n    \u002F\u002F Движок уже знает про let b ниже.\n    \u002F\u002F Но до строки объявления b находится в TDZ.\n    \u002F\u002F Поэтому чтение b падает с ReferenceError.\n    console.log('3:', b);\n  } catch (error) {\n    console.log('3:', error.name);\n  }\n\n  \u002F\u002F После этой строки b инициализирована.\n  let b = 'b';\n\n  \u002F\u002F Теперь читать b можно.\n  console.log('4:', b);\n}\n\nf();\ng();",{"slug":415,"title":416,"source":417,"exerciseCode":418,"tutorialCode":419,"expectedOutput":420,"executionExplanation":419,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":26,"status":13},"types-coercion-symbol-json-ex2","Упражнение 2: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex2","const a = Object.prototype.toString;\n\nconsole.log('1:', a.call([]));\nconsole.log(\n  '2:',\n  a.call(function f() {}),\n);\nconsole.log('3:', a.call(new Error('a')));\nconsole.log('4:', a.call(new Map()));\nconsole.log('5:', a.call(new Set()));\nconsole.log('6:', a.call(null));\nconsole.log('7:', a.call(undefined));\nconsole.log('8:', a.call('a'));\nconsole.log('9:', a.call(1));\nconsole.log('10:', a.call(true));\nconsole.log('11:', a.call(Symbol('a')));\nconsole.log('12:', a.call(1n));\nconsole.log('13:', a.call({}));\n","\u002F\u002F Упражнение 2: типы, приведение, Symbol и JSON\n\u002F\u002F Темы внутренний тег значения и Object.prototype.toString\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Object.prototype.toString https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F06-instanceof\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch3.md\n\u002F\u002F MDN Object.prototype.toString\n\u002F\u002F typeof часто сжимает разные значения до object.\n\u002F\u002F Object.prototype.toString показывает внутренний тег точнее.\nconst a = Object.prototype.toString;\n\n\u002F\u002F Массив получает тег Array.\nconsole.log('1:', a.call([]));\n\n\u002F\u002F Функция получает тег Function.\nconsole.log(\n  '2:',\n  a.call(function f() {}),\n);\n\n\u002F\u002F У многих встроенных объектов есть отдельный тег.\n\u002F\u002F Это не проверка класса в ООП смысле, а строковая метка значения.\nconsole.log('3:', a.call(new Error('a')));\nconsole.log('4:', a.call(new Map()));\nconsole.log('5:', a.call(new Set()));\n\n\u002F\u002F null и undefined не имеют конструкторов.\n\u002F\u002F Но внутренний тег для них все равно отдельный.\nconsole.log('6:', a.call(null));\nconsole.log('7:', a.call(undefined));\n\n\u002F\u002F Примитивы временно упаковываются для этой проверки.\n\u002F\u002F Поэтому видны теги String, Number, Boolean, Symbol и BigInt.\nconsole.log('8:', a.call('a'));\nconsole.log('9:', a.call(1));\nconsole.log('10:', a.call(true));\nconsole.log('11:', a.call(Symbol('a')));\nconsole.log('12:', a.call(1n));\n\n\u002F\u002F Обычный объект получает тег Object.\nconsole.log('13:', a.call({}));","1 [object Array]\n2 [object Function]\n3 [object Error]\n4 [object Map]\n5 [object Set]\n6 [object Null]\n7 [object Undefined]\n8 [object String]\n9 [object Number]\n10 [object Boolean]\n11 [object Symbol]\n12 [object BigInt]\n13 [object Object]",{"slug":422,"title":423,"source":424,"exerciseCode":425,"tutorialCode":426,"expectedOutput":427,"executionExplanation":426,"language":65,"runtime":66,"programSlug":40,"lessonSlug":40,"order":36,"status":13},"browser-network-ex3","Упражнение 3: сеть в браузере","mentoring\u002Fbrowser-network\u002Fex\u002Fex3","(async () => {\n  const a = new Request('https:\u002F\u002Fa.test\u002Fa?x=1', {\n    body: '2',\n    headers: {\n      'Content-Type': 'text\u002Fplain',\n    },\n    method: 'POST',\n  });\n\n  console.log(a.method);\n  console.log(a.headers.get('content-type'));\n  console.log(a.bodyUsed);\n\n  const b = a.clone();\n\n  console.log(await a.text());\n  console.log(a.bodyUsed);\n  console.log(await b.text());\n})();\n","\u002F\u002F Упражнение 3: сеть в браузере\n\u002F\u002F Темы Request метод заголовки тело bodyUsed и clone\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Request https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Frequest\u002Findex.md\n(async () => {\n  const a = new Request('https:\u002F\u002Fa.test\u002Fa?x=1', {\n    body: '2',\n    headers: {\n      'Content-Type': 'text\u002Fplain',\n    },\n    method: 'POST',\n  });\n\n  \u002F\u002F Request хранит данные будущего запроса.\n  \u002F\u002F Метод приводится к стандартному виду, а заголовки доступны через Headers.\n  console.log(a.method);\n  console.log(a.headers.get('content-type'));\n  console.log(a.bodyUsed);\n\n  \u002F\u002F Тело запроса это поток.\n  \u002F\u002F Чтобы прочитать один и тот же body два раза, заранее создаем clone.\n  const b = a.clone();\n\n  console.log(await a.text());\n  console.log(a.bodyUsed);\n  console.log(await b.text());\n})();","POST\ntext\u002Fplain\nfalse\n2\ntrue\n2",{"slug":429,"title":430,"source":431,"exerciseCode":432,"tutorialCode":433,"expectedOutput":434,"executionExplanation":433,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":36,"status":13},"collections-iteration-arrays-ex3","Упражнение 3: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex3","const a = new Set([NaN, NaN, 0, -0]);\nconst b = {};\nconst c = {};\n\na.add(b);\na.add(b);\na.add(c);\n\nconsole.log('1:', a.size);\nconsole.log('2:', a.has(NaN));\nconsole.log('3:', a.has(-0));\nconsole.log('4:', b === c);\n","\u002F\u002F Упражнение 3: коллекции, итерация, массивы и строки\n\u002F\u002F Темы Set и SameValueZero\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Map и Set https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F07-map-set\u002Farticle.md\n\u002F\u002F MDN Set https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fset\u002Findex.md\n\u002F\u002F ECMA SameValueZero https:\u002F\u002Ftc39.es\u002Fecma262\u002F#sec-samevaluezero\nconst a = new Set([NaN, NaN, 0, -0]);\nconst b = {};\nconst c = {};\n\n\u002F\u002F Set хранит только одно NaN.\n\u002F\u002F Для Set NaN считается тем же самым значением.\n\u002F\u002F Плюс ноль и минус ноль тоже считаются одним значением.\na.add(b);\n\n\u002F\u002F Повторное добавление той же ссылки ничего не меняет.\na.add(b);\n\n\u002F\u002F Другой объект это другая ссылка.\n\u002F\u002F Даже если он выглядит пустым так же как b.\na.add(c);\n\nconsole.log('1:', a.size);\nconsole.log('2:', a.has(NaN));\nconsole.log('3:', a.has(-0));\nconsole.log('4:', b === c);","1: 4\n2: true\n3: true\n4: false",{"slug":436,"title":437,"source":438,"exerciseCode":439,"tutorialCode":440,"expectedOutput":441,"executionExplanation":440,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":36,"status":13},"event-loop-promises-async-await-ex3","Упражнение 3: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex3","const a = new Promise((resolve, reject) => {\n  resolve('a');\n  reject('b');\n  resolve('c');\n});\n\na.then(\n  (b) => console.log('1:', b),\n  (b) => console.log('2:', b),\n).finally(() => console.log('3'));\n\nconsole.log('4');\n","\u002F\u002F Упражнение 3: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы однократное завершение Promise и finally\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Promise basics https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F02-promise-basics\u002Farticle.md\n\u002F\u002F Learn JS Promise error handling https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F04-promise-error-handling\u002Farticle.md\n\u002F\u002F MDN Promise https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Findex.md\nconst a = new Promise((resolve, reject) => {\n  \u002F\u002F Первый вызов завершает промис успешно со значением a.\n  resolve('a');\n\n  \u002F\u002F После завершения состояние уже нельзя заменить.\n  reject('b');\n  resolve('c');\n});\n\na.then(\n  \u002F\u002F Выполнится только обработчик успеха.\n  (b) => console.log('1:', b),\n  (b) => console.log('2:', b),\n).finally(() => console.log('3'));\n\n\u002F\u002F Синхронный код идет раньше обработчиков промиса.\nconsole.log('4');","4\n1: a\n3",{"slug":443,"title":444,"source":445,"exerciseCode":446,"tutorialCode":447,"expectedOutput":448,"executionExplanation":447,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":36,"status":13},"event-loop-promises-deep-dive-ex3","Дополнительное упражнение 3: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex3","const a = Promise.resolve('a');\n\na.then((b) => {\n  console.log('1:', b);\n  return 'b';\n}).then((b) => console.log('2:', b));\n\na.then((b) => console.log('3:', b));\n\nPromise.resolve().then(() => console.log('4'));\n\nconsole.log('5');\n","\u002F\u002F Дополнительное упражнение 3: углубленная практика по event loop и Promise\n\u002F\u002F Темы независимые подписки then и цепочка then\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS promise chaining https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F03-promise-chaining\u002Farticle.md\n\u002F\u002F MDN Promise.prototype.then https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fthen\u002Findex.md\nconst a = Promise.resolve('a');\n\na.then((b) => {\n  \u002F\u002F Это первая независимая подписка на исходный Promise a.\n  console.log('1:', b);\n\n  \u002F\u002F Возвращенное значение уйдет только в продолжение этой цепочки.\n  return 'b';\n}).then((b) => console.log('2:', b));\n\n\u002F\u002F Это вторая независимая подписка на тот же исходный Promise a.\na.then((b) => console.log('3:', b));\n\n\u002F\u002F Эта микрозадача уже стоит в очереди раньше continuation со значением b.\nPromise.resolve().then(() => console.log('4'));\n\nconsole.log('5');","5\n1: a\n3: a\n4\n2: b",{"slug":450,"title":451,"source":452,"exerciseCode":453,"tutorialCode":454,"expectedOutput":455,"executionExplanation":454,"language":65,"runtime":66,"programSlug":59,"lessonSlug":59,"order":36,"status":13},"mock-interview-javascript-core-ex3","Пример мок-собеседования 3","mentoring\u002Fmock-interview-javascript-core\u002Fex\u002Fex3","const a = false;\nconst b = new Boolean(false);\n\nconsole.log('1:', Boolean(a));\nconsole.log('2:', Boolean(b));\nconsole.log('3:', b.valueOf());\nconsole.log('4:', a == b);\nconsole.log('5:', a === b);\n","\u002F\u002F Пример мок-собеседования 3\n\u002F\u002F Темы объектные оболочки и boolean\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS методы примитивов https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F01-primitives-methods\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch3.md\n\u002F\u002F MDN Boolean\n\u002F\u002F a хранит обычный boolean примитив false.\nconst a = false;\n\n\u002F\u002F b хранит объектную оболочку Boolean.\n\u002F\u002F Внутри нее лежит false, но само значение b является объектом.\nconst b = new Boolean(false);\n\n\u002F\u002F Примитив false остается ложным значением.\nconsole.log('1:', Boolean(a));\n\n\u002F\u002F Любой обычный объект является truthy значением.\n\u002F\u002F Даже если внутри оболочки лежит false.\nconsole.log('2:', Boolean(b));\n\n\u002F\u002F valueOf достает примитив из оболочки.\nconsole.log('3:', b.valueOf());\n\n\u002F\u002F Нестрогое сравнение распаковывает объект.\n\u002F\u002F Поэтому false становится равен false.\nconsole.log('4:', a == b);\n\n\u002F\u002F Строгое сравнение не распаковывает типы.\n\u002F\u002F boolean и object не равны.\nconsole.log('5:', a === b);","1 false\n2 true\n3 false\n4 true\n5 false",{"slug":457,"title":458,"source":459,"exerciseCode":460,"tutorialCode":461,"expectedOutput":462,"executionExplanation":461,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":36,"status":13},"objects-prototypes-classes-ex3","Упражнение 3: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex3","const a = {\n  x: 1,\n  y: 2,\n};\n\nObject.defineProperty(a, 'y', {\n  enumerable: false,\n});\n\nconst b = [];\n\nfor (const c in a) {\n  b.push(c);\n}\n\nconsole.log('1:', Object.keys(a).join(','));\nconsole.log('2:', b.join(','));\nconsole.log('3:', 'y' in a, a.y);\n","\u002F\u002F Упражнение 3: свойства объектов, прототипы и классы\n\u002F\u002F Темы enumerable, Object.keys и for in\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS дескрипторы свойств https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md\n\u002F\u002F MDN Enumerability and ownership https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Fenumerability_and_ownership_of_properties\u002Findex.md\nconst a = {\n  x: 1,\n  y: 2,\n};\n\nObject.defineProperty(a, 'y', {\n  \u002F\u002F Свойство останется в объекте, но пропадет из перечисления.\n  enumerable: false,\n});\n\nconst b = [];\n\n\u002F\u002F for in проходит по перечислимым свойствам.\nfor (const c in a) {\n  b.push(c);\n}\n\n\u002F\u002F Object.keys тоже возвращает только перечислимые собственные свойства.\nconsole.log('1:', Object.keys(a).join(','));\nconsole.log('2:', b.join(','));\n\n\u002F\u002F Неперечислимое свойство все еще существует и читается напрямую.\nconsole.log('3:', 'y' in a, a.y);","1 x\n2 x\n3 true 2",{"slug":464,"title":465,"source":466,"exerciseCode":467,"tutorialCode":468,"expectedOutput":469,"executionExplanation":468,"language":65,"runtime":66,"programSlug":50,"lessonSlug":50,"order":36,"status":13},"recursion-ex3","Упражнение 3: рекурсия","mentoring\u002Frecursion\u002Fex\u002Fex3","function f(a) {\n  if (a === 0) {\n    return 0;\n  }\n\n  return a + f(a - 1);\n}\n\nconsole.log(f(4));\n","\u002F\u002F Упражнение 3: рекурсия\n\u002F\u002F Темы сумма через рекурсивное накопление назад\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Recursion https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md\nfunction f(a) {\n  \u002F\u002F Сумма до 0 равна 0.\n  \u002F\u002F Отсюда цепочка начинает возвращаться назад.\n  if (a === 0) {\n    return 0;\n  }\n\n  \u002F\u002F Мы берем текущее число и добавляем сумму меньшей задачи.\n  return a + f(a - 1);\n}\n\n\u002F\u002F 4 + 3 + 2 + 1 + 0.\nconsole.log(f(4));","10",{"slug":471,"title":472,"source":473,"exerciseCode":474,"tutorialCode":475,"expectedOutput":476,"executionExplanation":475,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":36,"status":13},"rendering-dom-events-forms-ex3","Упражнение 3: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex3","const a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '10px';\ndocument.body.append(a);\n\nconsole.log(a.offsetWidth);\n\na.style.visibility = 'hidden';\n\nconsole.log(a.offsetWidth);\n\na.style.display = 'none';\n\nconsole.log(a.offsetWidth);\n","\u002F\u002F Упражнение 3: рендеринг, DOM, события и формы\n\u002F\u002F Темы display none, visibility hidden и render tree\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Critical rendering path https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fperformance\u002Fguides\u002Fcritical_rendering_path\u002Findex.md\n\u002F\u002F MDN CSS performance https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Flearn_web_development\u002Fextensions\u002Fperformance\u002Fcss\u002Findex.md\nconst a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '10px';\ndocument.body.append(a);\n\nconsole.log(a.offsetWidth);\n\n\u002F\u002F visibility hidden делает элемент невидимым, но место в layout сохраняется.\na.style.visibility = 'hidden';\n\nconsole.log(a.offsetWidth);\n\n\u002F\u002F display none убирает элемент из render tree.\n\u002F\u002F Поэтому для layout он больше не занимает ширину.\na.style.display = 'none';\n\nconsole.log(a.offsetWidth);","100\n100\n0",{"slug":478,"title":479,"source":480,"exerciseCode":481,"tutorialCode":482,"expectedOutput":483,"executionExplanation":482,"language":65,"runtime":66,"programSlug":19,"lessonSlug":19,"order":36,"status":13},"scope-closures-deep-dive-ex3","Дополнительное упражнение 3: углубленная практика по областям видимости и замыканиям","mentoring\u002Fscope-closures-deep-dive\u002Fex\u002Fex3","function f(a) {\n  eval('var b = 3;');\n\n  console.log('1:', a, b);\n}\n\nvar b = 2;\n\nf(1);\n\nconsole.log('2:', b);\n","\u002F\u002F Дополнительное упражнение 3: углубленная практика по областям видимости и замыканиям\n\u002F\u002F Темы: eval и изменение локальной области.\n\u002F\u002F Читать дальше\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch2.md раздел eval\n\u002F\u002F MDN eval https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002Feval\n\nfunction f(a) {\n  \u002F\u002F В обычном script без strict mode прямой eval выполняется в текущей области.\n  \u002F\u002F Строка объявляет локальную var b внутри f.\n  eval('var b = 3;');\n\n  \u002F\u002F a это параметр функции.\n  \u002F\u002F b находится в локальной области f и закрывает глобальную b.\n  console.log('1:', a, b);\n}\n\n\u002F\u002F Эта b живет в глобальной области.\nvar b = 2;\n\nf(1);\n\n\u002F\u002F Глобальная b не изменилась.\nconsole.log('2:', b);","1: 1 3\n2: 2",{"slug":485,"title":486,"source":487,"exerciseCode":488,"tutorialCode":489,"expectedOutput":490,"executionExplanation":489,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":36,"status":13},"scope-hoisting-closures-this-ex3","Упражнение 3: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex3","const f = function (a) {\n  let b = 0;\n\n  return function () {\n    b++;\n\n    console.log(a, b, c);\n  };\n};\n\nlet c = 'c';\n\nconst g = f('b:');\nconst h = f('d:');\n\nc = 'e';\n\ng();\ng();\nh();\ng();\nh();\n","\u002F\u002F Упражнение 3: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: независимые замыкания и измененная внешняя переменная.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS замыкание https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md#L2 раздел Замыкание области видимости\n\u002F\u002F MDN Closures https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FGuide\u002FClosures\n\nconst f = function (a) {\n  \u002F\u002F Для каждого вызова f создается своя переменная b.\n  let b = 0;\n\n  return function () {\n    \u002F\u002F Внутренняя функция помнит a и b именно своего вызова f.\n    \u002F\u002F А переменную c она ищет во внешней области при каждом вызове.\n    b++;\n\n    console.log(a, b, c);\n  };\n};\n\n\u002F\u002F Эта переменная находится во внешней области.\n\u002F\u002F Замыкания будут читать ее в момент вызова, а не сохранять копию.\nlet c = 'c';\n\n\u002F\u002F Первый вызов f создает первое окружение.\nconst g = f('b:');\n\n\u002F\u002F Второй вызов f создает другое окружение.\nconst h = f('d:');\n\n\u002F\u002F Меняем внешнюю переменную после создания функций.\n\u002F\u002F Обе функции увидят новое значение.\nc = 'e';\n\n\u002F\u002F g и h не делят одну b.\ng();\ng();\nh();\ng();\nh();","b: 1 e\nb: 2 e\nd: 1 e\nb: 3 e\nd: 2 e",{"slug":492,"title":493,"source":494,"exerciseCode":495,"tutorialCode":496,"expectedOutput":497,"executionExplanation":496,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":36,"status":13},"types-coercion-symbol-json-ex3","Упражнение 3: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex3","const a = 'abc';\n\nconsole.log('1:', a.length);\nconsole.log('2:', a.toUpperCase());\n\na.x = 1;\n\nconsole.log('3:', a.x);\n","\u002F\u002F Упражнение 3: типы, приведение, Symbol и JSON\n\u002F\u002F Темы boxing примитивов и доступ к свойствам\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS методы примитивов https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F01-primitives-methods\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch3.md\n\u002F\u002F MDN String primitives and String objects\n\u002F\u002F Строка ниже это примитив, а не объект String.\n\u002F\u002F Но движок умеет временно оборачивать ее для чтения свойств.\nconst a = 'abc';\n\n\u002F\u002F length читается через временную объектную оболочку.\nconsole.log('1:', a.length);\n\n\u002F\u002F Метод тоже берется с временной оболочки.\nconsole.log('2:', a.toUpperCase());\n\n\u002F\u002F В нестрогом режиме запись свойства в примитив не сохраняется.\n\u002F\u002F Временная оболочка сразу исчезает.\na.x = 1;\n\n\u002F\u002F При новом чтении создается другая временная оболочка.\n\u002F\u002F Поэтому записанное выше свойство x нигде не сохранилось.\nconsole.log('3:', a.x);","1 3\n2 ABC\n3 undefined",{"slug":499,"title":500,"source":501,"exerciseCode":502,"tutorialCode":503,"expectedOutput":504,"executionExplanation":503,"language":65,"runtime":66,"programSlug":40,"lessonSlug":40,"order":46,"status":13},"browser-network-ex4","Упражнение 4: сеть в браузере","mentoring\u002Fbrowser-network\u002Fex\u002Fex4","(async () => {\n  const a = new Response('{\"x\":1}', {\n    headers: {\n      'Content-Type': 'application\u002Fjson',\n    },\n    status: 404,\n    statusText: 'Not Found',\n  });\n\n  const b = a.clone();\n\n  console.log(a.ok);\n  console.log(a.status);\n  console.log(a.statusText);\n  console.log(await a.text());\n  console.log((await b.json()).x);\n})();\n","\u002F\u002F Упражнение 4: сеть в браузере\n\u002F\u002F Темы Response ok status statusText тело ответа и clone\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Response https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fresponse\u002Findex.md\n(async () => {\n  const a = new Response('{\"x\":1}', {\n    headers: {\n      'Content-Type': 'application\u002Fjson',\n    },\n    status: 404,\n    statusText: 'Not Found',\n  });\n\n  const b = a.clone();\n\n  \u002F\u002F ok это не факт успешного парсинга тела.\n  \u002F\u002F ok true только для статусов от 200 до 299.\n  console.log(a.ok);\n  console.log(a.status);\n  console.log(a.statusText);\n\n  \u002F\u002F Тело ответа тоже поток.\n  \u002F\u002F Один Response читаем как текст, его clone читаем как JSON.\n  console.log(await a.text());\n  console.log((await b.json()).x);\n})();","false\n404\nNot Found\n{\"x\":1}\n1",{"slug":506,"title":507,"source":508,"exerciseCode":509,"tutorialCode":510,"expectedOutput":511,"executionExplanation":510,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":46,"status":13},"collections-iteration-arrays-ex4","Упражнение 4: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex4","const a = new WeakMap();\nconst b = {};\n\na.set(b, 1);\n\nconsole.log('1:', a.get(b));\n\ntry {\n  a.set(1, 2);\n} catch (error) {\n  console.log('2:', error.name);\n}\n\nconsole.log('3:', typeof a.size);\nconsole.log('4:', typeof a[Symbol.iterator]);\n\nconst c = new WeakSet();\n\nc.add(b);\n\nconsole.log('5:', c.has(b));\n","\u002F\u002F Упражнение 4: коллекции, итерация, массивы и строки\n\u002F\u002F Темы WeakMap WeakSet и ограничения\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS WeakMap и WeakSet https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F08-weakmap-weakset\u002Farticle.md\n\u002F\u002F MDN WeakMap https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fweakmap\u002Findex.md\n\u002F\u002F MDN WeakSet https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fweakset\u002Findex.md\nconst a = new WeakMap();\nconst b = {};\n\n\u002F\u002F Ключ WeakMap должен быть объектом.\n\u002F\u002F Слабая связь нужна чтобы ключ не удерживался от сборки мусора.\na.set(b, 1);\n\nconsole.log('1:', a.get(b));\n\ntry {\n  \u002F\u002F Примитив нельзя использовать как ключ WeakMap.\n  a.set(1, 2);\n} catch (error) {\n  console.log('2:', error.name);\n}\n\n\u002F\u002F У WeakMap нет size.\n\u002F\u002F Также WeakMap нельзя обойти через for of.\nconsole.log('3:', typeof a.size);\nconsole.log('4:', typeof a[Symbol.iterator]);\n\nconst c = new WeakSet();\n\n\u002F\u002F WeakSet хранит только объекты.\nc.add(b);\n\nconsole.log('5:', c.has(b));","1: 1\n2: TypeError\n3: undefined\n4: undefined\n5: true",{"slug":513,"title":514,"source":515,"exerciseCode":516,"tutorialCode":517,"expectedOutput":518,"executionExplanation":517,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":46,"status":13},"event-loop-promises-async-await-ex4","Упражнение 4: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex4","Promise.resolve(1)\n  .then((a) => {\n    console.log('1:', a);\n    return a + 1;\n  })\n  .then((a) => Promise.resolve(a + 1))\n  .then((a) => console.log('2:', a));\n\nconsole.log('3');\n","\u002F\u002F Упражнение 4: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы цепочка Promise и передача результата\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Promise chaining https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F03-promise-chaining\u002Farticle.md\n\u002F\u002F Learn JS микрозадачи https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md\n\u002F\u002F MDN Promise.prototype.then https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fthen\u002Findex.md\nPromise.resolve(1)\n  .then((a) => {\n    console.log('1:', a);\n\n    \u002F\u002F Обычное значение станет результатом следующего промиса в цепочке.\n    return a + 1;\n  })\n  .then((a) => Promise.resolve(a + 1))\n  .then((a) => console.log('2:', a));\n\n\u002F\u002F Пока цепочка ждет микрозадач, script завершается.\nconsole.log('3');","3\n1: 1\n2: 3",{"slug":520,"title":521,"source":522,"exerciseCode":523,"tutorialCode":524,"expectedOutput":525,"executionExplanation":524,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":46,"status":13},"event-loop-promises-deep-dive-ex4","Дополнительное упражнение 4: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex4","const a = {\n  then(resolve) {\n    console.log('1');\n    resolve('a');\n    console.log('2');\n  },\n};\n\nPromise.resolve(a).then((b) => console.log('3:', b));\n\nPromise.resolve().then(() => console.log('4'));\n\nconsole.log('5');\n","\u002F\u002F Дополнительное упражнение 4: углубленная практика по event loop и Promise\n\u002F\u002F Темы thenable и асинхронное усвоение результата\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS async await thenable https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md\n\u002F\u002F MDN Promise.resolve https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fresolve\u002Findex.md\nconst a = {\n  then(resolve) {\n    \u002F\u002F thenable распознается по методу then.\n    console.log('1');\n\n    \u002F\u002F resolve завершает Promise, созданный Promise.resolve(a).\n    resolve('a');\n\n    \u002F\u002F Текущая микрозадача продолжает выполняться до конца.\n    console.log('2');\n  },\n};\n\n\u002F\u002F Вызов then у thenable произойдет асинхронно через promise job.\nPromise.resolve(a).then((b) => console.log('3:', b));\n\n\u002F\u002F Эта микрозадача уже стоит в очереди, когда thenable только начнет усваиваться.\nPromise.resolve().then(() => console.log('4'));\n\nconsole.log('5');","5\n1\n2\n4\n3: a",{"slug":527,"title":528,"source":529,"exerciseCode":280,"tutorialCode":530,"expectedOutput":282,"executionExplanation":530,"language":65,"runtime":66,"programSlug":59,"lessonSlug":59,"order":46,"status":13},"mock-interview-javascript-core-ex4","Пример мок-собеседования 4","mentoring\u002Fmock-interview-javascript-core\u002Fex\u002Fex4","\u002F\u002F Пример мок-собеседования 4\n\u002F\u002F Темы Map и объектные ключи\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Map и Set https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F07-map-set\u002Farticle.md\n\u002F\u002F MDN Map https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fmap\u002Findex.md\nconst a = {};\nconst b = {};\nconst c = {};\n\n\u002F\u002F Обычный объект приводит ключ свойства к строке или symbol.\n\u002F\u002F Оба объекта превращаются в один и тот же строковый ключ.\na[b] = '1';\na[c] = '2';\n\nconst d = new Map();\n\n\u002F\u002F Map хранит сам объект как ключ.\n\u002F\u002F Поэтому b и c остаются разными ключами.\nd.set(b, '1');\nd.set(c, '2');\n\n\u002F\u002F В объекте вторая запись перезаписала первую.\nconsole.log('1:', a[b]);\n\n\u002F\u002F В Map значение по ключу b осталось отдельным.\nconsole.log('2:', d.get(b));\n\n\u002F\u002F В Map две разные пары ключ значение.\nconsole.log('3:', d.size);",{"slug":532,"title":533,"source":534,"exerciseCode":535,"tutorialCode":536,"expectedOutput":537,"executionExplanation":536,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":46,"status":13},"objects-prototypes-classes-ex4","Упражнение 4: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex4","const a = {\n  x: 1,\n};\n\nObject.defineProperty(a, 'x', {\n  configurable: false,\n});\n\nconsole.log('1:', delete a.x);\n\na.x = 2;\n\nconsole.log('2:', a.x);\n\ntry {\n  Object.defineProperty(a, 'x', {\n    configurable: true,\n  });\n} catch (error) {\n  console.log('3:', error.name);\n}\n\nObject.defineProperty(a, 'x', {\n  writable: false,\n});\n\na.x = 3;\n\nconsole.log('4:', a.x);\n","\u002F\u002F Упражнение 4: свойства объектов, прототипы и классы\n\u002F\u002F Темы configurable и ограничения неконфигурируемого свойства\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS дескрипторы свойств https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md\n\u002F\u002F MDN Object.defineProperty https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fdefineproperty\u002Findex.md\nconst a = {\n  x: 1,\n};\n\nObject.defineProperty(a, 'x', {\n  \u002F\u002F Теперь свойство нельзя удалить и нельзя свободно перенастроить.\n  configurable: false,\n});\n\n\u002F\u002F В нестрогом режиме delete вернет false.\nconsole.log('1:', delete a.x);\n\n\u002F\u002F configurable false не запрещает менять value само по себе.\n\u002F\u002F Свойство все еще writable true, потому что создано через литерал.\na.x = 2;\n\nconsole.log('2:', a.x);\n\ntry {\n  Object.defineProperty(a, 'x', {\n    \u002F\u002F Обратно сделать configurable true уже нельзя.\n    configurable: true,\n  });\n} catch (error) {\n  console.log('3:', error.name);\n}\n\nObject.defineProperty(a, 'x', {\n  \u002F\u002F Это разрешенное движение для неконфигурируемого свойства.\n  writable: false,\n});\n\n\u002F\u002F Теперь запись молча не сработает.\na.x = 3;\n\nconsole.log('4:', a.x);","1 false\n2 2\n3 TypeError\n4 2",{"slug":539,"title":540,"source":541,"exerciseCode":542,"tutorialCode":543,"expectedOutput":544,"executionExplanation":543,"language":65,"runtime":66,"programSlug":50,"lessonSlug":50,"order":46,"status":13},"recursion-ex4","Упражнение 4: рекурсия","mentoring\u002Frecursion\u002Fex\u002Fex4","function f(a) {\n  if (a \u003C= 1) {\n    return a;\n  }\n\n  return f(a - 1) + f(a - 2);\n}\n\nconsole.log(f(6));\n","\u002F\u002F Упражнение 4: рекурсия\n\u002F\u002F Темы ветвящаяся рекурсия и повторные подзадачи\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Recursion https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md\nfunction f(a) {\n  \u002F\u002F Для 0 и 1 ответ известен сразу.\n  if (a \u003C= 1) {\n    return a;\n  }\n\n  \u002F\u002F Здесь один вызов порождает два меньших вызова.\n  \u002F\u002F Это уже не линейная цепочка а дерево вызовов.\n  return f(a - 1) + f(a - 2);\n}\n\nconsole.log(f(6));","8",{"slug":546,"title":547,"source":548,"exerciseCode":549,"tutorialCode":550,"expectedOutput":324,"executionExplanation":550,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":46,"status":13},"rendering-dom-events-forms-ex4","Упражнение 4: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex4","const a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '10px';\na.style.transform = 'scaleX(2)';\ndocument.body.append(a);\n\nconsole.log(a.offsetWidth);\nconsole.log(Math.round(a.getBoundingClientRect().width));\n","\u002F\u002F Упражнение 4: рендеринг, DOM, события и формы\n\u002F\u002F Темы transform, layout width и визуальный прямоугольник\n\u002F\u002F Читать дальше\n\u002F\u002F MDN transform https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fcss\u002Freference\u002Fproperties\u002Ftransform\u002Findex.md\n\u002F\u002F MDN getBoundingClientRect https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Felement\u002Fgetboundingclientrect\u002Findex.md\nconst a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '10px';\na.style.transform = 'scaleX(2)';\ndocument.body.append(a);\n\n\u002F\u002F offsetWidth показывает layout-ширину.\n\u002F\u002F transform не меняет место элемента в потоке документа.\nconsole.log(a.offsetWidth);\n\n\u002F\u002F getBoundingClientRect возвращает визуальный прямоугольник.\n\u002F\u002F Поэтому scaleX(2) уже влияет на измеренную ширину.\nconsole.log(Math.round(a.getBoundingClientRect().width));",{"slug":552,"title":553,"source":554,"exerciseCode":555,"tutorialCode":556,"expectedOutput":557,"executionExplanation":556,"language":65,"runtime":66,"programSlug":19,"lessonSlug":19,"order":46,"status":13},"scope-closures-deep-dive-ex4","Дополнительное упражнение 4: углубленная практика по областям видимости и замыканиям","mentoring\u002Fscope-closures-deep-dive\u002Fex\u002Fex4","var a = 2;\n\n(function f() {\n  var a = 3;\n\n  console.log('1:', a);\n  console.log('2:', typeof f);\n})();\n\nconsole.log('3:', a);\nconsole.log('4:', typeof f);\n","\u002F\u002F Дополнительное упражнение 4: углубленная практика по областям видимости и замыканиям\n\u002F\u002F Темы: IIFE, function expression и скрытое имя функции.\n\u002F\u002F Читать дальше\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch3.md раздел Функции как области видимости\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch3.md раздел Анонимный против названного\n\nvar a = 2;\n\n\u002F\u002F Скобки превращают function f в Function Expression.\n\u002F\u002F Такая функция сразу вызывается и создает отдельную область.\n(function f() {\n  \u002F\u002F Эта a локальная для IIFE.\n  var a = 3;\n\n  console.log('1:', a);\n\n  \u002F\u002F Имя f доступно внутри самой функции.\n  console.log('2:', typeof f);\n})();\n\n\u002F\u002F Снаружи видна глобальная a.\nconsole.log('3:', a);\n\n\u002F\u002F Имя f не попало во внешнюю область.\nconsole.log('4:', typeof f);","1: 3\n2: function\n3: 2\n4: undefined",{"slug":559,"title":560,"source":561,"exerciseCode":562,"tutorialCode":563,"expectedOutput":564,"executionExplanation":563,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":46,"status":13},"scope-hoisting-closures-this-ex4","Упражнение 4: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex4","const a = [];\n\nfor (var b = 0; b \u003C 3; b++) {\n  a.push(function () {\n    console.log('1:', b);\n  });\n}\n\nconst c = [];\n\nfor (let d = 0; d \u003C 3; d++) {\n  c.push(function () {\n    console.log('2:', d);\n  });\n}\n\na[0]();\na[1]();\na[2]();\n\nc[0]();\nc[1]();\nc[2]();\n","\u002F\u002F Упражнение 4: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: замыкание в цикле с var и let.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS замыкание https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md\n\u002F\u002F Learn JS var и IIFE https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F04-var\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md#L202 раздел Циклы + замыкание\n\u002F\u002F MDN Closures https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FGuide\u002FClosures\n\u002F\u002F MDN let https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Flet\n\nconst a = [];\n\n\u002F\u002F var b создает одну общую переменную на весь цикл.\nfor (var b = 0; b \u003C 3; b++) {\n  \u002F\u002F Каждая функция запоминает не значение b, а доступ к одной общей b.\n  a.push(function () {\n    console.log('1:', b);\n  });\n}\n\nconst c = [];\n\n\u002F\u002F let d в цикле создает отдельную привязку для каждой итерации.\nfor (let d = 0; d \u003C 3; d++) {\n  \u002F\u002F Каждая функция запоминает свою d.\n  c.push(function () {\n    console.log('2:', d);\n  });\n}\n\n\u002F\u002F После первого цикла b уже равно 3.\n\u002F\u002F Все функции из массива a смотрят на одну и ту же b.\na[0]();\na[1]();\na[2]();\n\n\u002F\u002F Функции из массива c смотрят на разные d.\nc[0]();\nc[1]();\nc[2]();","1: 3\n1: 3\n1: 3\n2: 0\n2: 1\n2: 2",{"slug":566,"title":567,"source":568,"exerciseCode":453,"tutorialCode":569,"expectedOutput":455,"executionExplanation":569,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":46,"status":13},"types-coercion-symbol-json-ex4","Упражнение 4: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex4","\u002F\u002F Упражнение 4: типы, приведение, Symbol и JSON\n\u002F\u002F Темы объектные оболочки и boolean\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS методы примитивов https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F01-primitives-methods\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch3.md\n\u002F\u002F MDN Boolean\n\u002F\u002F a хранит обычный boolean примитив false.\nconst a = false;\n\n\u002F\u002F b хранит объектную оболочку Boolean.\n\u002F\u002F Внутри нее лежит false, но само значение b является объектом.\nconst b = new Boolean(false);\n\n\u002F\u002F Примитив false остается ложным значением.\nconsole.log('1:', Boolean(a));\n\n\u002F\u002F Любой обычный объект является truthy значением.\n\u002F\u002F Даже если внутри оболочки лежит false.\nconsole.log('2:', Boolean(b));\n\n\u002F\u002F valueOf достает примитив из оболочки.\nconsole.log('3:', b.valueOf());\n\n\u002F\u002F Нестрогое сравнение распаковывает объект.\n\u002F\u002F Поэтому false становится равен false.\nconsole.log('4:', a == b);\n\n\u002F\u002F Строгое сравнение не распаковывает типы.\n\u002F\u002F boolean и object не равны.\nconsole.log('5:', a === b);",{"slug":571,"title":572,"source":573,"exerciseCode":574,"tutorialCode":575,"expectedOutput":576,"executionExplanation":575,"language":65,"runtime":66,"programSlug":40,"lessonSlug":40,"order":55,"status":13},"browser-network-ex5","Упражнение 5: сеть в браузере","mentoring\u002Fbrowser-network\u002Fex\u002Fex5","(async () => {\n  const a = await fetch('data:application\u002Fjson,%7B%22x%22%3A1%7D');\n\n  console.log(a.ok);\n  console.log(a.status);\n  console.log(a.headers.get('content-type'));\n\n  const b = await a.json();\n\n  console.log(b.x);\n})();\n","\u002F\u002F Упражнение 5: сеть в браузере\n\u002F\u002F Темы fetch промис Response status headers json\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Window fetch https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fwindow\u002Ffetch\u002Findex.md\n(async () => {\n  \u002F\u002F fetch возвращает Promise.\n  \u002F\u002F После await мы получаем не готовые данные, а объект Response.\n  const a = await fetch('data:application\u002Fjson,%7B%22x%22%3A1%7D');\n\n  console.log(a.ok);\n  console.log(a.status);\n  console.log(a.headers.get('content-type'));\n\n  \u002F\u002F JSON читается отдельным асинхронным шагом.\n  \u002F\u002F Это важно на собеседовании: await fetch и await response.json это разные ожидания.\n  const b = await a.json();\n\n  console.log(b.x);\n})();","true\n200\napplication\u002Fjson\n1",{"slug":578,"title":579,"source":580,"exerciseCode":581,"tutorialCode":582,"expectedOutput":583,"executionExplanation":582,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":55,"status":13},"collections-iteration-arrays-ex5","Упражнение 5: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex5","const a = new Map([\n  ['a', 1],\n  ['b', 2],\n]);\n\nfor (const [b, c] of a) {\n  console.log(b, c);\n}\n\nconst d = new Set(['x', 'y']);\n\nfor (const b of d) {\n  console.log(b);\n}\n","\u002F\u002F Упражнение 5: коллекции, итерация, массивы и строки\n\u002F\u002F Темы for of с Map и Set\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Map и Set https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F07-map-set\u002Farticle.md\n\u002F\u002F MDN Map iterator https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fmap\u002Fsymbol.iterator\u002Findex.md\n\u002F\u002F MDN Set iterator https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fset\u002Fsymbol.iterator\u002Findex.md\nconst a = new Map([\n  ['a', 1],\n  ['b', 2],\n]);\n\n\u002F\u002F При обходе Map по умолчанию мы получаем пары.\n\u002F\u002F Каждая пара имеет вид массив из ключа и значения.\nfor (const [b, c] of a) {\n  console.log(b, c);\n}\n\nconst d = new Set(['x', 'y']);\n\n\u002F\u002F При обходе Set по умолчанию мы получаем значения.\nfor (const b of d) {\n  console.log(b);\n}","a 1\nb 2\nx\ny",{"slug":585,"title":586,"source":587,"exerciseCode":588,"tutorialCode":589,"expectedOutput":590,"executionExplanation":589,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":55,"status":13},"event-loop-promises-async-await-ex5","Упражнение 5: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex5","Promise.resolve('a')\n  .then((a) => {\n    console.log('1:', a);\n    throw 'b';\n  })\n  .catch((a) => {\n    console.log('2:', a);\n    return 'c';\n  })\n  .then((a) => console.log('3:', a));\n\nconsole.log('4');\n","\u002F\u002F Упражнение 5: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы ошибка в then, catch и восстановление цепочки\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Promise error handling https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F04-promise-error-handling\u002Farticle.md\n\u002F\u002F Learn JS Promise chaining https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F03-promise-chaining\u002Farticle.md\n\u002F\u002F MDN Promise.prototype.catch https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fcatch\u002Findex.md\nPromise.resolve('a')\n  .then((a) => {\n    console.log('1:', a);\n\n    \u002F\u002F throw внутри then превращает следующий промис в rejected.\n    throw 'b';\n  })\n  .catch((a) => {\n    console.log('2:', a);\n\n    \u002F\u002F Если catch возвращает значение, цепочка снова становится fulfilled.\n    return 'c';\n  })\n  .then((a) => console.log('3:', a));\n\nconsole.log('4');","4\n1: a\n2: b\n3: c",{"slug":592,"title":593,"source":594,"exerciseCode":595,"tutorialCode":596,"expectedOutput":597,"executionExplanation":596,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":55,"status":13},"event-loop-promises-deep-dive-ex5","Дополнительное упражнение 5: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex5","async function f() {\n  console.log('1');\n\n  await 0;\n  console.log('2');\n\n  await 0;\n  console.log('3');\n}\n\nf();\n\nPromise.resolve().then(() => console.log('4'));\n\nqueueMicrotask(() => console.log('5'));\n\nconsole.log('6');\n","\u002F\u002F Дополнительное упражнение 5: углубленная практика по event loop и Promise\n\u002F\u002F Темы await обычного значения и очередь микрозадач\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS async await https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md\n\u002F\u002F MDN await https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fawait\u002Findex.md\nasync function f() {\n  console.log('1');\n\n  \u002F\u002F await обычного значения все равно приостанавливает async функцию.\n  await 0;\n  console.log('2');\n\n  \u002F\u002F Второй await ставит новое продолжение в конец очереди микрозадач.\n  await 0;\n  console.log('3');\n}\n\nf();\n\n\u002F\u002F Эта микрозадача попадает в очередь после первого продолжения f.\nPromise.resolve().then(() => console.log('4'));\n\n\u002F\u002F queueMicrotask тоже попадает после первого продолжения f.\nqueueMicrotask(() => console.log('5'));\n\nconsole.log('6');","1\n6\n2\n4\n5\n3",{"slug":599,"title":600,"source":601,"exerciseCode":287,"tutorialCode":602,"expectedOutput":289,"executionExplanation":602,"language":65,"runtime":66,"programSlug":59,"lessonSlug":59,"order":55,"status":13},"mock-interview-javascript-core-ex5","Пример мок-собеседования 5","mentoring\u002Fmock-interview-javascript-core\u002Fex\u002Fex5","\u002F\u002F Пример мок-собеседования 5\n\u002F\u002F Темы event loop, задача таймера и микрозадача Promise\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS event loop https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F99-ui-misc\u002F03-event-loop\u002Farticle.md\n\u002F\u002F Learn JS микрозадачи https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md\n\u002F\u002F MDN microtask guide https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtml_dom_api\u002Fmicrotask_guide\u002Findex.md\n\u002F\u002F Сначала выполняется обычный синхронный script.\nconsole.log('1');\n\n\u002F\u002F Таймер не запускает callback сразу.\n\u002F\u002F Он ставит новую задачу для будущего прохода event loop.\nsetTimeout(() => console.log('2'), 0);\n\n\u002F\u002F Обработчик then тоже не запускается сразу.\n\u002F\u002F Он попадает в очередь микрозадач.\nPromise.resolve().then(() => console.log('3'));\n\n\u002F\u002F Текущий script должен выполниться до конца.\nconsole.log('4');\n\n\u002F\u002F После script браузер сначала очищает микрозадачи.\n\u002F\u002F Поэтому 3 будет раньше таймера 2.",{"slug":604,"title":605,"source":606,"exerciseCode":607,"tutorialCode":608,"expectedOutput":609,"executionExplanation":608,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":55,"status":13},"objects-prototypes-classes-ex5","Упражнение 5: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex5","const a = {\n  x: 1,\n  y: 2,\n\n  get z() {\n    return this.x + this.y;\n  },\n\n  set z(b) {\n    this.x = b;\n    this.y = b + 1;\n  },\n};\n\nconsole.log('1:', a.z);\n\na.z = 4;\n\nconsole.log('2:', a.x, a.y, a.z);\n\nconst c = Object.getOwnPropertyDescriptor(a, 'z');\n\nconsole.log('3:', 'value' in c, typeof c.get, typeof c.set);\n","\u002F\u002F Упражнение 5: свойства объектов, прототипы и классы\n\u002F\u002F Темы getter setter и виртуальное свойство\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS геттеры и сеттеры https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F02-property-accessors\u002Farticle.md\n\u002F\u002F MDN getter https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Ffunctions\u002Fget\u002Findex.md\n\u002F\u002F MDN setter https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Ffunctions\u002Fset\u002Findex.md\nconst a = {\n  x: 1,\n  y: 2,\n\n  get z() {\n    \u002F\u002F При чтении a.z выполнится getter.\n    return this.x + this.y;\n  },\n\n  set z(b) {\n    \u002F\u002F При записи a.z = 4 выполнится setter.\n    this.x = b;\n    this.y = b + 1;\n  },\n};\n\nconsole.log('1:', a.z);\n\na.z = 4;\n\nconsole.log('2:', a.x, a.y, a.z);\n\nconst c = Object.getOwnPropertyDescriptor(a, 'z');\n\n\u002F\u002F У accessor property нет value.\n\u002F\u002F Зато есть get и set.\nconsole.log('3:', 'value' in c, typeof c.get, typeof c.set);","1 3\n2 4 5 9\n3 false function function",{"slug":611,"title":612,"source":613,"exerciseCode":614,"tutorialCode":615,"expectedOutput":469,"executionExplanation":615,"language":65,"runtime":66,"programSlug":50,"lessonSlug":50,"order":55,"status":13},"recursion-ex5","Упражнение 5: рекурсия","mentoring\u002Frecursion\u002Fex\u002Fex5","function f(a) {\n  if (a.length === 0) {\n    return 0;\n  }\n\n  const [b, ...c] = a;\n\n  return b + f(c);\n}\n\nconsole.log(f([1, 2, 3, 4]));\n","\u002F\u002F Упражнение 5: рекурсия\n\u002F\u002F Темы рекурсия по массиву и уменьшение данных\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Recursion https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md\nfunction f(a) {\n  \u002F\u002F Пустой массив больше нечем обрабатывать.\n  if (a.length === 0) {\n    return 0;\n  }\n\n  \u002F\u002F Мы отделяем первый элемент от остатка.\n  const [b, ...c] = a;\n\n  \u002F\u002F Текущий элемент складывается с суммой оставшейся части.\n  return b + f(c);\n}\n\nconsole.log(f([1, 2, 3, 4]));",{"slug":617,"title":618,"source":619,"exerciseCode":620,"tutorialCode":621,"expectedOutput":476,"executionExplanation":621,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":55,"status":13},"rendering-dom-events-forms-ex5","Упражнение 5: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex5","const a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '10px';\ndocument.body.append(a);\n\nconsole.log(a.offsetWidth);\n\na.style.opacity = '0';\n\nconsole.log(a.offsetWidth);\nconsole.log(getComputedStyle(a).opacity);\n","\u002F\u002F Упражнение 5: рендеринг, DOM, события и формы\n\u002F\u002F Темы opacity и отсутствие изменения layout\n\u002F\u002F Читать дальше\n\u002F\u002F MDN opacity https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fcss\u002Freference\u002Fproperties\u002Fopacity\u002Findex.md\n\u002F\u002F MDN CSS performance https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Flearn_web_development\u002Fextensions\u002Fperformance\u002Fcss\u002Findex.md\nconst a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '10px';\ndocument.body.append(a);\n\nconsole.log(a.offsetWidth);\n\n\u002F\u002F opacity влияет на то, как элемент смешивается с фоном.\n\u002F\u002F Но размер и место элемента от прозрачности не меняются.\na.style.opacity = '0';\n\nconsole.log(a.offsetWidth);\nconsole.log(getComputedStyle(a).opacity);",{"slug":623,"title":624,"source":625,"exerciseCode":626,"tutorialCode":627,"expectedOutput":628,"executionExplanation":627,"language":65,"runtime":66,"programSlug":19,"lessonSlug":19,"order":55,"status":13},"scope-closures-deep-dive-ex5","Дополнительное упражнение 5: углубленная практика по областям видимости и замыканиям","mentoring\u002Fscope-closures-deep-dive\u002Fex\u002Fex5","a = 2;\n\nvar a;\n\nconsole.log('1:', a);\nconsole.log('2:', b);\n\nvar b = 3;\n","\u002F\u002F Дополнительное упражнение 5: углубленная практика по областям видимости и замыканиям\n\u002F\u002F Темы: hoisting var и разделение объявления с присваиванием.\n\u002F\u002F Читать дальше\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch4.md раздел Цыпленок или яйцо\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch4.md раздел Сначала компилятор\n\n\u002F\u002F На этапе подготовки var a уже создана.\n\u002F\u002F Поэтому присваивание работает, хотя строка var a ниже.\na = 2;\n\nvar a;\n\n\u002F\u002F a уже получила значение 2.\nconsole.log('1:', a);\n\n\u002F\u002F var b тоже поднята, но присваивание b = 3 еще не выполнилось.\nconsole.log('2:', b);\n\nvar b = 3;","1: 2\n2: undefined",{"slug":630,"title":631,"source":632,"exerciseCode":633,"tutorialCode":634,"expectedOutput":635,"executionExplanation":634,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":55,"status":13},"scope-hoisting-closures-this-ex5","Упражнение 5: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex5","const a = {\n  x: 'a',\n\n  f() {\n    console.log('1:', this === a);\n    console.log('2:', this && this.x);\n  },\n};\n\na.f();\n\nconst b = a.f;\n\nb();\n\nfunction g() {\n  'use strict';\n\n  console.log('3:', this);\n}\n\ng();\n","\u002F\u002F Упражнение 5: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: this при вызове метода объекта, потеря this и strict mode.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS методы объекта и this https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F04-object-methods\u002Farticle.md\n\u002F\u002F Learn JS строгий режим https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F03-strict-mode\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002FapC.md#L2 раздел Лексический this\n\u002F\u002F MDN this https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FOperators\u002Fthis\n\u002F\u002F MDN Strict mode https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStrict_mode\n\nconst a = {\n  x: 'a',\n\n  f() {\n    \u002F\u002F this определяется в момент вызова функции.\n    \u002F\u002F Если вызвать как a.f(), то this будет объектом a.\n    console.log('1:', this === a);\n    console.log('2:', this && this.x);\n  },\n};\n\n\u002F\u002F Слева от точки стоит объект a.\n\u002F\u002F Значит внутри f значение this равно a.\na.f();\n\n\u002F\u002F Здесь мы забираем саму функцию из объекта.\n\u002F\u002F Объект a вместе с ней не привязывается.\nconst b = a.f;\n\n\u002F\u002F Это обычный вызов функции без объекта слева от точки.\n\u002F\u002F Поэтому this уже не равен a.\nb();\n\nfunction g() {\n  'use strict';\n\n  \u002F\u002F В strict mode обычный вызов функции не подставляет window.\n  \u002F\u002F this остается undefined.\n  console.log('3:', this);\n}\n\ng();","1: true\n2: a\n1: false\n2: undefined\n3: undefined",{"slug":637,"title":638,"source":639,"exerciseCode":640,"tutorialCode":641,"expectedOutput":642,"executionExplanation":641,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":55,"status":13},"types-coercion-symbol-json-ex5","Упражнение 5: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex5","console.log('1:', Boolean(''));\nconsole.log('2:', Boolean('0'));\nconsole.log('3:', Boolean(0));\nconsole.log('4:', Boolean([]));\nconsole.log('5:', Boolean({}));\nconsole.log('6:', Boolean(new Boolean(false)));\n","\u002F\u002F Упражнение 5: типы, приведение, Symbol и JSON\n\u002F\u002F Темы ToBoolean и истинность значений\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS преобразование типов https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F07-type-conversions\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md\n\u002F\u002F MDN Boolean\n\u002F\u002F Пустая строка входит в короткий список falsy значений.\nconsole.log('1:', Boolean(''));\n\n\u002F\u002F Непустая строка истинна.\n\u002F\u002F Даже если внутри символ 0.\nconsole.log('2:', Boolean('0'));\n\n\u002F\u002F Число 0 ложно.\nconsole.log('3:', Boolean(0));\n\n\u002F\u002F Массив это объект.\n\u002F\u002F Все обычные объекты truthy, даже если они пустые.\nconsole.log('4:', Boolean([]));\n\n\u002F\u002F Обычный пустой объект тоже истинен.\nconsole.log('5:', Boolean({}));\n\n\u002F\u002F Оболочка Boolean это объект.\n\u002F\u002F Поэтому она истинна даже с false внутри.\nconsole.log('6:', Boolean(new Boolean(false)));","1 false\n2 true\n3 false\n4 true\n5 true\n6 true",{"slug":644,"title":645,"source":646,"exerciseCode":647,"tutorialCode":648,"expectedOutput":649,"executionExplanation":648,"language":65,"runtime":66,"programSlug":40,"lessonSlug":40,"order":650,"status":13},"browser-network-ex6","Упражнение 6: сеть в браузере","mentoring\u002Fbrowser-network\u002Fex\u002Fex6","(async () => {\n  const a = new AbortController();\n\n  a.abort();\n\n  try {\n    await fetch('data:text\u002Fplain,1', {\n      signal: a.signal,\n    });\n  } catch (b) {\n    console.log(b.name);\n    console.log(a.signal.aborted);\n  }\n})();\n","\u002F\u002F Упражнение 6: сеть в браузере\n\u002F\u002F Темы AbortController signal отмена fetch и AbortError\n\u002F\u002F Читать дальше\n\u002F\u002F MDN AbortController https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fabortcontroller\u002Findex.md\n(async () => {\n  const a = new AbortController();\n\n  \u002F\u002F abort переводит signal в состояние aborted.\n  \u002F\u002F fetch с таким signal должен завершиться отклоненным Promise.\n  a.abort();\n\n  try {\n    await fetch('data:text\u002Fplain,1', {\n      signal: a.signal,\n    });\n  } catch (b) {\n    \u002F\u002F Отмена запроса это не HTTP-статус.\n    \u002F\u002F Мы не получаем Response, а попадаем в catch с AbortError.\n    console.log(b.name);\n    console.log(a.signal.aborted);\n  }\n})();","AbortError\ntrue",6,{"slug":652,"title":653,"source":654,"exerciseCode":655,"tutorialCode":656,"expectedOutput":657,"executionExplanation":656,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":650,"status":13},"collections-iteration-arrays-ex6","Упражнение 6: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex6","const a = {\n  x: 1,\n  y: 3,\n  [Symbol.iterator]() {\n    let b = this.x;\n    const c = this.y;\n\n    return {\n      next() {\n        if (b \u003C= c) {\n          return {\n            value: b++,\n            done: false,\n          };\n        }\n\n        return {\n          done: true,\n        };\n      },\n    };\n  },\n};\n\nconsole.log([...a].join(','));\n\nconst b = a[Symbol.iterator]();\n\nconsole.log(b.next().value);\nconsole.log(b.next().value);\n","\u002F\u002F Упражнение 6: коллекции, итерация, массивы и строки\n\u002F\u002F Темы Symbol.iterator и ручной iterator\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS перебираемые объекты https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F06-iterable\u002Farticle.md\n\u002F\u002F MDN Iteration protocols https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fiteration_protocols\u002Findex.md\n\u002F\u002F MDN Symbol.iterator https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fsymbol\u002Fiterator\u002Findex.md\nconst a = {\n  x: 1,\n  y: 3,\n  [Symbol.iterator]() {\n    \u002F\u002F При старте обхода создается отдельное состояние iterator.\n    let b = this.x;\n    const c = this.y;\n\n    return {\n      next() {\n        if (b \u003C= c) {\n          return {\n            value: b++,\n            done: false,\n          };\n        }\n\n        return {\n          done: true,\n        };\n      },\n    };\n  },\n};\n\n\u002F\u002F Spread берет iterator через Symbol.iterator и читает значения до done true.\nconsole.log([...a].join(','));\n\n\u002F\u002F Iterator можно получить и дергать вручную.\nconst b = a[Symbol.iterator]();\n\nconsole.log(b.next().value);\nconsole.log(b.next().value);","1,2,3\n1\n2",{"slug":659,"title":660,"source":661,"exerciseCode":662,"tutorialCode":663,"expectedOutput":664,"executionExplanation":663,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":650,"status":13},"event-loop-promises-async-await-ex6","Упражнение 6: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex6","Promise.resolve('a')\n  .finally(() => {\n    console.log('1');\n    return 'b';\n  })\n  .then((a) => console.log('2:', a));\n\nconsole.log('3');\n","\u002F\u002F Упражнение 6: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы finally и сохранение исходного результата\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Promise basics https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F02-promise-basics\u002Farticle.md\n\u002F\u002F Learn JS Promise error handling https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F04-promise-error-handling\u002Farticle.md\n\u002F\u002F MDN Promise.prototype.finally https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Ffinally\u002Findex.md\nPromise.resolve('a')\n  .finally(() => {\n    \u002F\u002F finally обычно используют для очистки.\n    \u002F\u002F Он не получает исходное значение как аргумент.\n    console.log('1');\n\n    \u002F\u002F Возврат обычного значения из finally не заменяет результат цепочки.\n    return 'b';\n  })\n  .then((a) => console.log('2:', a));\n\nconsole.log('3');","3\n1\n2: a",{"slug":666,"title":667,"source":668,"exerciseCode":669,"tutorialCode":670,"expectedOutput":671,"executionExplanation":670,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":650,"status":13},"event-loop-promises-deep-dive-ex6","Дополнительное упражнение 6: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex6","Promise.resolve('a')\n  .finally(() => {\n    console.log('1');\n    return Promise.reject('b');\n  })\n  .then((a) => console.log('2:', a))\n  .catch((a) => console.log('3:', a));\n\nPromise.reject('c')\n  .finally(() => {\n    console.log('4');\n    return Promise.resolve('d');\n  })\n  .catch((a) => console.log('5:', a));\n\nconsole.log('6');\n","\u002F\u002F Дополнительное упражнение 6: углубленная практика по event loop и Promise\n\u002F\u002F Темы finally и Promise результат внутри finally\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS promise error handling https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F04-promise-error-handling\u002Farticle.md\n\u002F\u002F MDN Promise.prototype.finally https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Ffinally\u002Findex.md\nPromise.resolve('a')\n  .finally(() => {\n    console.log('1');\n\n    \u002F\u002F Rejected Promise из finally заменит прежний успешный результат.\n    return Promise.reject('b');\n  })\n  .then((a) => console.log('2:', a))\n  .catch((a) => console.log('3:', a));\n\nPromise.reject('c')\n  .finally(() => {\n    console.log('4');\n\n    \u002F\u002F Fulfilled Promise из finally не заменяет прежнюю ошибку c.\n    return Promise.resolve('d');\n  })\n  .catch((a) => console.log('5:', a));\n\nconsole.log('6');","6\n1\n4\n5: c\n3: b",{"slug":673,"title":674,"source":675,"exerciseCode":364,"tutorialCode":676,"expectedOutput":366,"executionExplanation":676,"language":65,"runtime":66,"programSlug":59,"lessonSlug":59,"order":650,"status":13},"mock-interview-javascript-core-ex6","Пример мок-собеседования 6","mentoring\u002Fmock-interview-javascript-core\u002Fex\u002Fex6","\u002F\u002F Пример мок-собеседования 6\n\u002F\u002F Темы Promise executor и асинхронность then\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Promise basics https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F02-promise-basics\u002Farticle.md\n\u002F\u002F Learn JS микрозадачи https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md\n\u002F\u002F MDN Promise https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Findex.md\n\u002F\u002F Executor запускается сразу во время создания Promise.\nconst a = new Promise((resolve) => {\n  console.log('1');\n\n  \u002F\u002F resolve меняет состояние промиса на fulfilled.\n  \u002F\u002F Но обработчики then не выполняются внутри executor.\n  resolve('2');\n\n  \u002F\u002F Executor продолжает идти синхронно до конца.\n  console.log('3');\n});\n\n\u002F\u002F then подписывает обработчик на результат.\n\u002F\u002F Его вызов попадет в очередь микрозадач.\na.then((b) => console.log('4:', b));\n\n\u002F\u002F Текущий script еще не завершен.\nconsole.log('5');",{"slug":678,"title":679,"source":680,"exerciseCode":681,"tutorialCode":682,"expectedOutput":683,"executionExplanation":682,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":650,"status":13},"objects-prototypes-classes-ex6","Упражнение 6: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex6","const a = {\n  x: 1,\n};\n\nObject.defineProperty(a, 'y', {\n  get() {\n    return this.x + 1;\n  },\n  enumerable: true,\n});\n\nconsole.log('1:', a.y);\n\na.y = 5;\n\nconsole.log('2:', a.y);\nconsole.log('3:', Object.keys(a).join(','));\n\nconst b = Object.getOwnPropertyDescriptor(a, 'y');\n\nconsole.log('4:', b.enumerable, b.configurable);\n","\u002F\u002F Упражнение 6: свойства объектов, прототипы и классы\n\u002F\u002F Темы accessor descriptor через Object.defineProperty\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS геттеры и сеттеры https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F02-property-accessors\u002Farticle.md\n\u002F\u002F MDN Object.defineProperty https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fdefineproperty\u002Findex.md\nconst a = {\n  x: 1,\n};\n\nObject.defineProperty(a, 'y', {\n  get() {\n    return this.x + 1;\n  },\n  \u002F\u002F Без этого флага y не попала бы в Object.keys.\n  enumerable: true,\n});\n\nconsole.log('1:', a.y);\n\n\u002F\u002F У свойства есть getter, но нет setter.\n\u002F\u002F В нестрогом режиме запись молча не изменит результат чтения.\na.y = 5;\n\nconsole.log('2:', a.y);\nconsole.log('3:', Object.keys(a).join(','));\n\nconst b = Object.getOwnPropertyDescriptor(a, 'y');\n\n\u002F\u002F configurable не указан в defineProperty.\n\u002F\u002F Значит по умолчанию он false.\nconsole.log('4:', b.enumerable, b.configurable);","1 2\n2 2\n3 x,y\n4 true false",{"slug":685,"title":686,"source":687,"exerciseCode":688,"tutorialCode":689,"expectedOutput":469,"executionExplanation":689,"language":65,"runtime":66,"programSlug":50,"lessonSlug":50,"order":650,"status":13},"recursion-ex6","Упражнение 6: рекурсия","mentoring\u002Frecursion\u002Fex\u002Fex6","function f(a) {\n  let b = 0;\n\n  for (const c of a) {\n    if (Array.isArray(c)) {\n      b += f(c);\n    } else {\n      b += c;\n    }\n  }\n\n  return b;\n}\n\nconsole.log(f([1, [2, [3]], 4]));\n","\u002F\u002F Упражнение 6: рекурсия\n\u002F\u002F Темы рекурсивный обход вложенного массива\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Recursion https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md\n\u002F\u002F MDN Array.isArray https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fisarray\u002Findex.md\nfunction f(a) {\n  let b = 0;\n\n  for (const c of a) {\n    if (Array.isArray(c)) {\n      \u002F\u002F Вложенный массив имеет такую же форму как внешний.\n      \u002F\u002F Поэтому мы можем обработать его той же функцией.\n      b += f(c);\n    } else {\n      b += c;\n    }\n  }\n\n  return b;\n}\n\nconsole.log(f([1, [2, [3]], 4]));",{"slug":691,"title":692,"source":693,"exerciseCode":694,"tutorialCode":695,"expectedOutput":696,"executionExplanation":695,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":650,"status":13},"rendering-dom-events-forms-ex6","Упражнение 6: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex6","const a = document.createElement('style');\nconst b = document.createElement('div');\n\na.textContent = '.x { width: 80px; height: 10px; } .y { width: 140px; height: 10px; }';\ndocument.head.append(a);\n\nb.className = 'x';\ndocument.body.append(b);\n\nconsole.log(getComputedStyle(b).width);\n\nb.className = 'y';\n\nconsole.log(b.offsetWidth);\n","\u002F\u002F Упражнение 6: рендеринг, DOM, события и формы\n\u002F\u002F Темы CSSOM, style recalculation и чтение computed style\n\u002F\u002F Читать дальше\n\u002F\u002F MDN CSSOM https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fcss_object_model\u002Findex.md\n\u002F\u002F MDN getComputedStyle https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fwindow\u002Fgetcomputedstyle\u002Findex.md\nconst a = document.createElement('style');\nconst b = document.createElement('div');\n\n\u002F\u002F style-тег добавляет CSS-правила в CSSOM страницы.\na.textContent = '.x { width: 80px; height: 10px; } .y { width: 140px; height: 10px; }';\ndocument.head.append(a);\n\nb.className = 'x';\ndocument.body.append(b);\n\n\u002F\u002F getComputedStyle читает уже вычисленное значение CSS-свойства.\nconsole.log(getComputedStyle(b).width);\n\n\u002F\u002F Смена класса меняет набор правил, которые применяются к элементу.\n\u002F\u002F Перед layout-метрикой браузер должен учитывать новый computed style.\nb.className = 'y';\n\nconsole.log(b.offsetWidth);","80px\n140",{"slug":698,"title":699,"source":700,"exerciseCode":701,"tutorialCode":702,"expectedOutput":703,"executionExplanation":702,"language":65,"runtime":66,"programSlug":19,"lessonSlug":19,"order":650,"status":13},"scope-closures-deep-dive-ex6","Дополнительное упражнение 6: углубленная практика по областям видимости и замыканиям","mentoring\u002Fscope-closures-deep-dive\u002Fex\u002Fex6","f();\n\nvar f = function () {\n  console.log('2:', 'b');\n};\n\nfunction f() {\n  console.log('1:', 'a');\n}\n\nf();\n","\u002F\u002F Дополнительное упражнение 6: углубленная практика по областям видимости и замыканиям\n\u002F\u002F Темы: hoisting function declaration и var.\n\u002F\u002F Читать дальше\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch4.md раздел Функции первыми\n\n\u002F\u002F Function Declaration поднимается вместе с телом функции.\n\u002F\u002F Поэтому первый вызов уже видит функцию f ниже по коду.\nf();\n\n\u002F\u002F var f как объявление уже было учтено.\n\u002F\u002F А вот присваивание Function Expression выполняется только на этой строке.\nvar f = function () {\n  console.log('2:', 'b');\n};\n\nfunction f() {\n  console.log('1:', 'a');\n}\n\n\u002F\u002F Теперь f уже перезаписана функцией из Function Expression.\nf();","1: a\n2: b",{"slug":705,"title":706,"source":707,"exerciseCode":708,"tutorialCode":709,"expectedOutput":710,"executionExplanation":709,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":650,"status":13},"scope-hoisting-closures-this-ex6","Упражнение 6: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex6","const f = function (a, b) {\n  console.log(a, this.x + b);\n};\n\nconst c = {\n  x: 'a',\n};\n\nconst d = {\n  x: 'z',\n};\n\nf.apply(c, ['b', 'c']);\nf.call(c, 'd', 'e');\n\nconst g = f.bind(c, 'f');\n\ng('g');\ng.call(d, 'h');\n","\u002F\u002F Упражнение 6: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: this, call, apply и bind.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS call и apply https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F09-call-apply-decorators\u002Farticle.md\n\u002F\u002F Learn JS bind https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F10-bind\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002FapC.md#L2 раздел Лексический this\n\u002F\u002F MDN call https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FFunction\u002Fcall\n\u002F\u002F MDN apply https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FFunction\u002Fapply\n\u002F\u002F MDN bind https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FFunction\u002Fbind\n\nconst f = function (a, b) {\n  \u002F\u002F a и b это обычные аргументы функции.\n  \u002F\u002F this.x берется из объекта, который передали через apply или call.\n  console.log(a, this.x + b);\n};\n\nconst c = {\n  x: 'a',\n};\n\nconst d = {\n  x: 'z',\n};\n\n\u002F\u002F apply задает this первым аргументом.\n\u002F\u002F Аргументы функции передаются массивом.\nf.apply(c, ['b', 'c']);\n\n\u002F\u002F call тоже задает this первым аргументом.\n\u002F\u002F Но аргументы функции передаются через запятую.\nf.call(c, 'd', 'e');\n\n\u002F\u002F bind создает новую функцию с заранее закрепленным this.\n\u002F\u002F Первый обычный аргумент тоже можно закрепить заранее.\nconst g = f.bind(c, 'f');\n\n\u002F\u002F Здесь this будет c, а первый аргумент уже равен f.\ng('g');\n\n\u002F\u002F call пытается заменить this на d.\n\u002F\u002F Но у g this уже закреплен через bind, поэтому останется c.\n\u002F\u002F Аргумент h все равно попадет на место b.\ng.call(d, 'h');","b ac\nd ae\nf ag\nf ah",{"slug":712,"title":713,"source":714,"exerciseCode":715,"tutorialCode":716,"expectedOutput":717,"executionExplanation":716,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":650,"status":13},"types-coercion-symbol-json-ex6","Упражнение 6: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex6","console.log('1:', Number(''));\nconsole.log('2:', Number(' '));\nconsole.log('3:', Number(null));\nconsole.log('4:', Number(undefined));\nconsole.log('5:', Number([]));\nconsole.log('6:', Number([1]));\nconsole.log('7:', Number([1, 2]));\n","\u002F\u002F Упражнение 6: типы, приведение, Symbol и JSON\n\u002F\u002F Темы ToNumber и явное численное приведение\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS преобразование типов https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F07-type-conversions\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md\n\u002F\u002F MDN Number\n\u002F\u002F Number явно запускает численное приведение.\n\u002F\u002F Пустая строка при таком приведении становится 0.\nconsole.log('1:', Number(''));\n\n\u002F\u002F Строка только из пробелов тоже становится 0.\nconsole.log('2:', Number(' '));\n\n\u002F\u002F null становится 0.\nconsole.log('3:', Number(null));\n\n\u002F\u002F undefined становится NaN.\nconsole.log('4:', Number(undefined));\n\n\u002F\u002F Пустой массив сначала становится пустой строкой.\n\u002F\u002F Потом пустая строка становится 0.\nconsole.log('5:', Number([]));\n\n\u002F\u002F Массив с одним элементом становится строкой 1.\n\u002F\u002F Потом строка 1 становится числом 1.\nconsole.log('6:', Number([1]));\n\n\u002F\u002F Массив с двумя элементами сначала становится строкой 1,2.\n\u002F\u002F Эта строка не похожа на числовой литерал и дает NaN.\nconsole.log('7:', Number([1, 2]));","1 0\n2 0\n3 0\n4 NaN\n5 0\n6 1\n7 NaN",{"slug":719,"title":720,"source":721,"exerciseCode":722,"tutorialCode":723,"expectedOutput":724,"executionExplanation":723,"language":65,"runtime":66,"programSlug":40,"lessonSlug":40,"order":725,"status":13},"browser-network-ex7","Упражнение 7: сеть в браузере","mentoring\u002Fbrowser-network\u002Fex\u002Fex7","(async () => {\n  const a = new Response('1', {\n    status: 500,\n  });\n\n  console.log(a.ok);\n  console.log(await a.text());\n\n  try {\n    throw new TypeError('2');\n  } catch (b) {\n    console.log(b instanceof TypeError);\n  }\n})();\n","\u002F\u002F Упражнение 7: сеть в браузере\n\u002F\u002F Темы HTTP ошибка не равна network error\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Response ok https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fresponse\u002Fok\u002Findex.md\n(async () => {\n  const a = new Response('1', {\n    status: 500,\n  });\n\n  \u002F\u002F Для fetch HTTP-статус 500 все равно был бы ответом сервера.\n  \u002F\u002F Такой Response можно прочитать, но ok будет false.\n  console.log(a.ok);\n  console.log(await a.text());\n\n  try {\n    \u002F\u002F Network error устроен иначе: Promise отклоняется и Response нет.\n    \u002F\u002F Здесь мы моделируем сам факт ошибки, а не реальный сетевой запрос.\n    throw new TypeError('2');\n  } catch (b) {\n    console.log(b instanceof TypeError);\n  }\n})();","false\n1\ntrue",7,{"slug":727,"title":728,"source":729,"exerciseCode":730,"tutorialCode":731,"expectedOutput":732,"executionExplanation":731,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":725,"status":13},"collections-iteration-arrays-ex7","Упражнение 7: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex7","const a = {\n  0: 'a',\n  1: 'b',\n  length: 2,\n};\n\nconsole.log(Array.from(a).join(''));\n\ntry {\n  for (const b of a) {\n    console.log(b);\n  }\n} catch (error) {\n  console.log(error.name);\n}\n\na[Symbol.iterator] = function* () {\n  yield this[0];\n  yield this[1];\n};\n\nconsole.log([...a].join(''));\n","\u002F\u002F Упражнение 7: коллекции, итерация, массивы и строки\n\u002F\u002F Темы array like и iterable\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS iterable и array like https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F06-iterable\u002Farticle.md\n\u002F\u002F MDN Array.from https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Ffrom\u002Findex.md\nconst a = {\n  0: 'a',\n  1: 'b',\n  length: 2,\n};\n\n\u002F\u002F У объекта есть индексы и length.\n\u002F\u002F Поэтому Array.from может собрать из него массив.\nconsole.log(Array.from(a).join(''));\n\ntry {\n  \u002F\u002F Но for of требует Symbol.iterator.\n  \u002F\u002F Одного length для for of недостаточно.\n  for (const b of a) {\n    console.log(b);\n  }\n} catch (error) {\n  console.log(error.name);\n}\n\n\u002F\u002F Теперь объект сам умеет выдавать iterator.\na[Symbol.iterator] = function* () {\n  yield this[0];\n  yield this[1];\n};\n\nconsole.log([...a].join(''));","ab\nTypeError\nab",{"slug":734,"title":735,"source":736,"exerciseCode":737,"tutorialCode":738,"expectedOutput":739,"executionExplanation":738,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":725,"status":13},"event-loop-promises-async-await-ex7","Упражнение 7: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex7","async function f() {\n  console.log('1');\n\n  const a = await 2;\n\n  console.log('2:', a);\n\n  return 3;\n}\n\nconst a = f();\n\nconsole.log('3:', a instanceof Promise);\n\na.then((b) => console.log('4:', b));\n\nconsole.log('5');\n","\u002F\u002F Упражнение 7: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы async function, await и возвращаемый Promise\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS async await https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md\n\u002F\u002F Learn JS микрозадачи https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md\n\u002F\u002F MDN async function https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fstatements\u002Fasync_function\u002Findex.md\nasync function f() {\n  \u002F\u002F До первого await async-функция выполняется синхронно.\n  console.log('1');\n\n  \u002F\u002F await оборачивает значение в промис и ставит продолжение в микрозадачи.\n  const a = await 2;\n\n  console.log('2:', a);\n\n  \u002F\u002F return станет fulfillment value для промиса функции f.\n  return 3;\n}\n\nconst a = f();\n\n\u002F\u002F async-функция всегда возвращает Promise.\nconsole.log('3:', a instanceof Promise);\n\na.then((b) => console.log('4:', b));\n\nconsole.log('5');","1\n3: true\n5\n2: 2\n4: 3",{"slug":741,"title":742,"source":743,"exerciseCode":744,"tutorialCode":745,"expectedOutput":746,"executionExplanation":745,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":725,"status":13},"event-loop-promises-deep-dive-ex7","Дополнительное упражнение 7: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex7","Promise.all([]).then((a) => console.log('1:', a.length));\n\nPromise.all([1, Promise.resolve(2)]).then((a) => console.log('2:', a[0], a[1]));\n\nPromise.resolve().then(() => console.log('3'));\n\nconsole.log('4');\n","\u002F\u002F Дополнительное упражнение 7: углубленная практика по event loop и Promise\n\u002F\u002F Темы Promise.all пустой iterable и обычные значения\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Promise API https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F05-promise-api\u002Farticle.md\n\u002F\u002F MDN Promise.all https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fall\u002Findex.md\n\u002F\u002F Для пустого iterable Promise.all уже может завершиться успешно.\nPromise.all([]).then((a) => console.log('1:', a.length));\n\n\u002F\u002F Обычные значения считаются уже готовыми успешными результатами.\nPromise.all([1, Promise.resolve(2)]).then((a) => console.log('2:', a[0], a[1]));\n\n\u002F\u002F Эта микрозадача попадает в очередь после внутренних jobs Promise.all.\nPromise.resolve().then(() => console.log('3'));\n\nconsole.log('4');","4\n1: 0\n3\n2: 1 2",{"slug":748,"title":749,"source":750,"exerciseCode":751,"tutorialCode":752,"expectedOutput":753,"executionExplanation":752,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":725,"status":13},"objects-prototypes-classes-ex7","Упражнение 7: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex7","try {\n  Object.defineProperty({}, 'x', {\n    get() {\n      return 1;\n    },\n    value: 2,\n  });\n} catch (error) {\n  console.log('1:', error.name);\n}\n\nconst a = {};\n\nObject.defineProperty(a, 'x', {\n  value: 1,\n  configurable: false,\n});\n\ntry {\n  Object.defineProperty(a, 'x', {\n    get() {\n      return 2;\n    },\n  });\n} catch (error) {\n  console.log('2:', error.name);\n}\n\nconsole.log('3:', a.x);\n","\u002F\u002F Упражнение 7: свойства объектов, прототипы и классы\n\u002F\u002F Темы некорректные дескрипторы и смена типа свойства\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS геттеры и сеттеры https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F02-property-accessors\u002Farticle.md\n\u002F\u002F MDN Object.defineProperty https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fdefineproperty\u002Findex.md\ntry {\n  Object.defineProperty({}, 'x', {\n    get() {\n      return 1;\n    },\n    \u002F\u002F Нельзя смешивать accessor descriptor и data descriptor.\n    value: 2,\n  });\n} catch (error) {\n  console.log('1:', error.name);\n}\n\nconst a = {};\n\nObject.defineProperty(a, 'x', {\n  value: 1,\n  configurable: false,\n});\n\ntry {\n  Object.defineProperty(a, 'x', {\n    \u002F\u002F Неконфигурируемое data property нельзя превратить в accessor.\n    get() {\n      return 2;\n    },\n  });\n} catch (error) {\n  console.log('2:', error.name);\n}\n\nconsole.log('3:', a.x);","1 TypeError\n2 TypeError\n3 1",{"slug":755,"title":756,"source":757,"exerciseCode":758,"tutorialCode":759,"expectedOutput":760,"executionExplanation":759,"language":65,"runtime":66,"programSlug":50,"lessonSlug":50,"order":725,"status":13},"recursion-ex7","Упражнение 7: рекурсия","mentoring\u002Frecursion\u002Fex\u002Fex7","function f(a) {\n  const b = [];\n\n  for (const c of a) {\n    if (Array.isArray(c)) {\n      b.push(...f(c));\n    } else {\n      b.push(c);\n    }\n  }\n\n  return b;\n}\n\nconsole.log(f([1, [2, [3, 4]], 5]).join(','));\n","\u002F\u002F Упражнение 7: рекурсия\n\u002F\u002F Темы flatten через рекурсию и сбор результата\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Recursion https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md\n\u002F\u002F MDN Array.isArray https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fisarray\u002Findex.md\nfunction f(a) {\n  const b = [];\n\n  for (const c of a) {\n    if (Array.isArray(c)) {\n      \u002F\u002F Рекурсивный вызов возвращает уже плоский массив.\n      \u002F\u002F Мы добавляем его элементы в текущий результат.\n      b.push(...f(c));\n    } else {\n      b.push(c);\n    }\n  }\n\n  return b;\n}\n\nconsole.log(f([1, [2, [3, 4]], 5]).join(','));","1,2,3,4,5",{"slug":762,"title":763,"source":764,"exerciseCode":765,"tutorialCode":766,"expectedOutput":767,"executionExplanation":766,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":725,"status":13},"rendering-dom-events-forms-ex7","Упражнение 7: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex7","const a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '10px';\ndocument.body.append(a);\n\na.style.width = '200px';\na.style.width = '300px';\n\nconsole.log(a.offsetWidth);\n","\u002F\u002F Упражнение 7: рендеринг, DOM, события и формы\n\u002F\u002F Темы batching DOM writes и один layout read\n\u002F\u002F Читать дальше\n\u002F\u002F MDN CSS performance https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Flearn_web_development\u002Fextensions\u002Fperformance\u002Fcss\u002Findex.md\n\u002F\u002F MDN offsetWidth https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlelement\u002Foffsetwidth\u002Findex.md\nconst a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '10px';\ndocument.body.append(a);\n\n\u002F\u002F Мы несколько раз пишем новое значение ширины.\n\u002F\u002F Пока мы только пишем, браузер может отложить дорогой расчет layout.\na.style.width = '200px';\na.style.width = '300px';\n\n\u002F\u002F Первое чтение layout-метрики видит уже последнее значение.\n\u002F\u002F Промежуточная ширина 200px не успела стать отдельным видимым кадром.\nconsole.log(a.offsetWidth);","300",{"slug":769,"title":770,"source":771,"exerciseCode":772,"tutorialCode":773,"expectedOutput":774,"executionExplanation":773,"language":65,"runtime":66,"programSlug":19,"lessonSlug":19,"order":725,"status":13},"scope-closures-deep-dive-ex7","Дополнительное упражнение 7: углубленная практика по областям видимости и замыканиям","mentoring\u002Fscope-closures-deep-dive\u002Fex\u002Fex7","function f() {\n  var a = 1;\n\n  return function () {\n    a += 1;\n\n    console.log('1:', a);\n  };\n}\n\nvar g = f();\n\ng();\ng();\n","\u002F\u002F Дополнительное упражнение 7: углубленная практика по областям видимости и замыканиям\n\u002F\u002F Темы: замыкание после выхода из внешней функции.\n\u002F\u002F Читать дальше\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md раздел Просвещение\n\nfunction f() {\n  \u002F\u002F Для вызова f создается локальная переменная a.\n  var a = 1;\n\n  \u002F\u002F Возвращаем внутреннюю функцию наружу.\n  return function () {\n    \u002F\u002F Функция продолжает иметь доступ к той же a.\n    a += 1;\n\n    console.log('1:', a);\n  };\n}\n\n\u002F\u002F f завершилась, но ее окружение осталось нужно функции g.\nvar g = f();\n\ng();\ng();","1: 2\n1: 3",{"slug":776,"title":777,"source":778,"exerciseCode":779,"tutorialCode":780,"expectedOutput":781,"executionExplanation":780,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":725,"status":13},"scope-hoisting-closures-this-ex7","Упражнение 7: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex7","const a = {\n  x: 'a',\n\n  f: () => {\n    console.log('1:', this && this.x);\n  },\n\n  g() {\n    const h = () => {\n      console.log('2:', this.x);\n    };\n\n    h();\n  },\n\n  k() {\n    function h() {\n      console.log('3:', this && this.x);\n    }\n\n    h();\n  },\n};\n\na.f();\na.g();\na.k();\n","\u002F\u002F Упражнение 7: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: стрелочная функция как метод объекта, стрелка внутри метода и обычная вложенная функция.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS this и стрелочные функции https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F04-object-methods\u002Farticle.md\n\u002F\u002F Learn JS повторяем стрелочные функции https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F12-arrow-functions\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002FapC.md#L2 раздел Лексический this\n\u002F\u002F MDN Arrow functions https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FFunctions\u002FArrow_functions\n\u002F\u002F MDN this https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FOperators\u002Fthis\n\nconst a = {\n  x: 'a',\n\n  \u002F\u002F Стрелочная функция не создает свой this.\n  \u002F\u002F Поэтому объект a не станет this для этой функции.\n  f: () => {\n    console.log('1:', this && this.x);\n  },\n\n  \u002F\u002F Это обычный метод.\n  \u002F\u002F При вызове a.g() его this будет объектом a.\n  g() {\n    \u002F\u002F Стрелка внутри метода берет this из внешней функции g.\n    const h = () => {\n      console.log('2:', this.x);\n    };\n\n    h();\n  },\n\n  \u002F\u002F Это обычный метод.\n  k() {\n    \u002F\u002F Но h это обычная вложенная функция.\n    \u002F\u002F Она не наследует this метода k.\n    function h() {\n      console.log('3:', this && this.x);\n    }\n\n    \u002F\u002F Это обычный вызов h без объекта слева от точки.\n    h();\n  },\n};\n\n\u002F\u002F Несмотря на запись a.f(), стрелка не получит this от a.\na.f();\n\n\u002F\u002F А здесь стрелка создана внутри обычного метода.\n\u002F\u002F Она возьмет this этого метода, то есть объект a.\na.g();\n\n\u002F\u002F А обычная вложенная функция this метода не наследует.\na.k();","1: undefined\n2: a\n3: undefined",{"slug":783,"title":784,"source":785,"exerciseCode":786,"tutorialCode":787,"expectedOutput":788,"executionExplanation":787,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":725,"status":13},"types-coercion-symbol-json-ex7","Упражнение 7: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex7","console.log('1:', String(null));\nconsole.log('2:', String(undefined));\nconsole.log('3:', String([1, 2]));\nconsole.log('4:', String([null]));\nconsole.log('5:', String([undefined]));\nconsole.log('6:', String({}));\n","\u002F\u002F Упражнение 7: типы, приведение, Symbol и JSON\n\u002F\u002F Темы ToString для примитивов, массивов и объектов\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS преобразование типов https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F07-type-conversions\u002Farticle.md\n\u002F\u002F Learn JS массивы и toString https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F04-array\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md\n\u002F\u002F MDN String\n\u002F\u002F null превращается в строку null.\nconsole.log('1:', String(null));\n\n\u002F\u002F undefined превращается в строку undefined.\nconsole.log('2:', String(undefined));\n\n\u002F\u002F Массив при строковом приведении вызывает поведение вроде join.\n\u002F\u002F Элементы соединяются через запятую.\nconsole.log('3:', String([1, 2]));\n\n\u002F\u002F null внутри массива дает пустую часть строки.\nconsole.log('4:', String([null]));\n\n\u002F\u002F undefined внутри массива тоже дает пустую часть строки.\nconsole.log('5:', String([undefined]));\n\n\u002F\u002F Обычный объект берет стандартное строковое представление.\nconsole.log('6:', String({}));","1 null\n2 undefined\n3 1,2\n4\n5\n6 [object Object]",{"slug":790,"title":791,"source":792,"exerciseCode":793,"tutorialCode":794,"expectedOutput":795,"executionExplanation":794,"language":65,"runtime":66,"programSlug":40,"lessonSlug":40,"order":796,"status":13},"browser-network-ex8","Упражнение 8: сеть в браузере","mentoring\u002Fbrowser-network\u002Fex\u002Fex8","const a = document.createElement('form');\n\na.innerHTML = `\n  \u003Cinput name=\"x\" value=\"1\">\n  \u003Cinput name=\"x\" value=\"2\">\n  \u003Cinput name=\"y\" value=\"3\">\n`;\n\nconst b = new FormData(a);\nconst c = new URLSearchParams(b);\n\nconsole.log(b.get('x'));\nconsole.log(b.getAll('x').join('|'));\nconsole.log(c.toString());\n","\u002F\u002F Упражнение 8: сеть в браузере\n\u002F\u002F Темы FormData форма повторяющиеся имена и URLSearchParams\n\u002F\u002F Читать дальше\n\u002F\u002F MDN FormData https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fformdata\u002Findex.md\nconst a = document.createElement('form');\n\na.innerHTML = `\n  \u003Cinput name=\"x\" value=\"1\">\n  \u003Cinput name=\"x\" value=\"2\">\n  \u003Cinput name=\"y\" value=\"3\">\n`;\n\n\u002F\u002F FormData берет успешные поля формы и сохраняет пары name value.\n\u002F\u002F Одинаковые name не схлопываются в одно значение.\nconst b = new FormData(a);\nconst c = new URLSearchParams(b);\n\nconsole.log(b.get('x'));\nconsole.log(b.getAll('x').join('|'));\n\n\u002F\u002F URLSearchParams превращает данные в формат application\u002Fx-www-form-urlencoded.\nconsole.log(c.toString());","1\n1|2\nx=1&x=2&y=3",8,{"slug":798,"title":799,"source":800,"exerciseCode":801,"tutorialCode":802,"expectedOutput":803,"executionExplanation":802,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":796,"status":13},"collections-iteration-arrays-ex8","Упражнение 8: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex8","function* f() {\n  console.log('1');\n  yield 'a';\n  console.log('2');\n  yield 'b';\n}\n\nconst a = f();\n\nconsole.log('3');\nconsole.log('4:', a.next().value);\nconsole.log('5:', a.next().value);\nconsole.log('6:', a.next().done);\n","\u002F\u002F Упражнение 8: коллекции, итерация, массивы и строки\n\u002F\u002F Темы generator и ленивое выполнение\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS генераторы https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F12-generators-iterators\u002F1-generators\u002Farticle.md\n\u002F\u002F MDN Generator https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fgenerator\u002Findex.md\nfunction* f() {\n  console.log('1');\n  yield 'a';\n  console.log('2');\n  yield 'b';\n}\n\n\u002F\u002F Вызов generator function не запускает тело функции.\n\u002F\u002F Он создает объект generator.\nconst a = f();\n\nconsole.log('3');\n\n\u002F\u002F Первый next запускает тело до первого yield.\nconsole.log('4:', a.next().value);\n\n\u002F\u002F Второй next продолжает выполнение после первого yield.\nconsole.log('5:', a.next().value);\n\n\u002F\u002F Третий next доходит до конца функции.\nconsole.log('6:', a.next().done);","3\n1\n4: a\n2\n5: b\n6: true",{"slug":805,"title":806,"source":807,"exerciseCode":808,"tutorialCode":809,"expectedOutput":810,"executionExplanation":809,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":796,"status":13},"event-loop-promises-async-await-ex8","Упражнение 8: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex8","async function f() {\n  console.log('1');\n\n  await 2;\n\n  console.log('2');\n}\n\nf();\n\nPromise.resolve().then(() => console.log('3'));\n\nconsole.log('4');\n","\u002F\u002F Упражнение 8: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы await обычного значения и порядок микрозадач\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS async await https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md\n\u002F\u002F Learn JS микрозадачи https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md\n\u002F\u002F MDN await https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fawait\u002Findex.md\nasync function f() {\n  console.log('1');\n\n  \u002F\u002F Даже обычное значение после await продолжит функцию не сразу.\n  await 2;\n\n  console.log('2');\n}\n\n\u002F\u002F Продолжение f после await ставится в микрозадачи раньше then ниже.\nf();\n\nPromise.resolve().then(() => console.log('3'));\n\nconsole.log('4');","1\n4\n2\n3",{"slug":812,"title":813,"source":814,"exerciseCode":815,"tutorialCode":816,"expectedOutput":817,"executionExplanation":816,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":796,"status":13},"event-loop-promises-deep-dive-ex8","Дополнительное упражнение 8: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex8","Promise.any([\n  Promise.reject('a'),\n  new Promise((resolve) => setTimeout(() => resolve('b'), 0)),\n]).then((a) => console.log('1:', a));\n\nPromise.any([Promise.reject('c'), 'd']).then((a) => console.log('2:', a));\n\nPromise.any([Promise.reject('e'), Promise.reject('f')]).catch((a) => {\n  console.log('3:', a instanceof AggregateError, a.errors.join(','));\n});\n\nconsole.log('4');\n","\u002F\u002F Дополнительное упражнение 8: углубленная практика по event loop и Promise\n\u002F\u002F Темы Promise.any и AggregateError\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Promise API https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F05-promise-api\u002Farticle.md\n\u002F\u002F MDN Promise.any https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fany\u002Findex.md\n\u002F\u002F MDN AggregateError https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Faggregateerror\u002Findex.md\nPromise.any([\n  Promise.reject('a'),\n  new Promise((resolve) => setTimeout(() => resolve('b'), 0)),\n]).then((a) => console.log('1:', a));\n\n\u002F\u002F Обычное значение d считается успешным результатом.\nPromise.any([Promise.reject('c'), 'd']).then((a) => console.log('2:', a));\n\nPromise.any([Promise.reject('e'), Promise.reject('f')]).catch((a) => {\n  \u002F\u002F Если все входы отклонены, итоговая ошибка будет AggregateError.\n  console.log('3:', a instanceof AggregateError, a.errors.join(','));\n});\n\nconsole.log('4');","4\n2: d\n3: true e,f\n1: b",{"slug":819,"title":820,"source":821,"exerciseCode":822,"tutorialCode":823,"expectedOutput":824,"executionExplanation":823,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":796,"status":13},"objects-prototypes-classes-ex8","Упражнение 8: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex8","const a = {\n  x: 1,\n};\n\nObject.defineProperty(a, 'y', {\n  value: 2,\n  writable: false,\n  enumerable: false,\n  configurable: false,\n});\n\nconst b = { ...a };\nconst c = Object.defineProperties({}, Object.getOwnPropertyDescriptors(a));\n\nconsole.log('1:', Object.keys(b).join(','));\nconsole.log('2:', b.y);\nconsole.log('3:', Object.keys(c).join(','));\nconsole.log('4:', c.y);\n\nc.y = 3;\n\nconsole.log('5:', c.y);\n","\u002F\u002F Упражнение 8: свойства объектов, прототипы и классы\n\u002F\u002F Темы копирование значений и копирование дескрипторов\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS дескрипторы свойств https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md\n\u002F\u002F MDN Object.getOwnPropertyDescriptors https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fgetownpropertydescriptors\u002Findex.md\n\u002F\u002F MDN Object.defineProperties https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fdefineproperties\u002Findex.md\nconst a = {\n  x: 1,\n};\n\nObject.defineProperty(a, 'y', {\n  value: 2,\n  writable: false,\n  enumerable: false,\n  configurable: false,\n});\n\n\u002F\u002F Spread копирует перечислимые собственные значения.\n\u002F\u002F Неперечислимое y не попадет в b.\nconst b = { ...a };\n\n\u002F\u002F Здесь мы копируем не только значения, а дескрипторы свойств.\nconst c = Object.defineProperties({}, Object.getOwnPropertyDescriptors(a));\n\nconsole.log('1:', Object.keys(b).join(','));\nconsole.log('2:', b.y);\nconsole.log('3:', Object.keys(c).join(','));\nconsole.log('4:', c.y);\n\n\u002F\u002F В c свойство y осталось writable false.\nc.y = 3;\n\nconsole.log('5:', c.y);","1 x\n2 undefined\n3 x\n4 2\n5 2",{"slug":826,"title":827,"source":828,"exerciseCode":829,"tutorialCode":830,"expectedOutput":831,"executionExplanation":830,"language":65,"runtime":66,"programSlug":50,"lessonSlug":50,"order":796,"status":13},"recursion-ex8","Упражнение 8: рекурсия","mentoring\u002Frecursion\u002Fex\u002Fex8","function f(a) {\n  let b = 0;\n\n  for (const c of Object.values(a)) {\n    if (typeof c === 'object' && c !== null) {\n      b += f(c);\n    } else {\n      b += 1;\n    }\n  }\n\n  return b;\n}\n\nconsole.log(f({ a: 1, b: { c: 2, d: { e: 3 } } }));\n","\u002F\u002F Упражнение 8: рекурсия\n\u002F\u002F Темы рекурсивный обход объекта и подсчет листьев\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Recursion https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md\n\u002F\u002F MDN Object.values https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fvalues\u002Findex.md\nfunction f(a) {\n  let b = 0;\n\n  for (const c of Object.values(a)) {\n    if (typeof c === 'object' && c !== null) {\n      \u002F\u002F Вложенный объект обрабатывается тем же правилом.\n      b += f(c);\n    } else {\n      \u002F\u002F Примитивное значение считаем листом.\n      b += 1;\n    }\n  }\n\n  return b;\n}\n\nconsole.log(f({ a: 1, b: { c: 2, d: { e: 3 } } }));","3",{"slug":833,"title":834,"source":835,"exerciseCode":836,"tutorialCode":837,"expectedOutput":838,"executionExplanation":837,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":796,"status":13},"rendering-dom-events-forms-ex8","Упражнение 8: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex8","const a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '10px';\ndocument.body.append(a);\n\nfor (let b = 0; b \u003C 3; b += 1) {\n  a.style.width = `${100 + b}px`;\n  console.log(a.offsetWidth);\n}\n","\u002F\u002F Упражнение 8: рендеринг, DOM, события и формы\n\u002F\u002F Темы layout thrashing и чередование write -> read\n\u002F\u002F Читать дальше\n\u002F\u002F MDN CSS performance https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Flearn_web_development\u002Fextensions\u002Fperformance\u002Fcss\u002Findex.md\n\u002F\u002F MDN offsetWidth https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlelement\u002Foffsetwidth\u002Findex.md\nconst a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '10px';\ndocument.body.append(a);\n\nfor (let b = 0; b \u003C 3; b += 1) {\n  \u002F\u002F На каждой итерации мы сначала меняем layout-свойство.\n  a.style.width = `${100 + b}px`;\n\n  \u002F\u002F Потом сразу читаем layout-метрику.\n  \u002F\u002F Такой паттерн заставляет браузер снова и снова синхронизировать layout.\n  console.log(a.offsetWidth);\n}","100\n101\n102",{"slug":840,"title":841,"source":842,"exerciseCode":843,"tutorialCode":844,"expectedOutput":845,"executionExplanation":844,"language":65,"runtime":66,"programSlug":19,"lessonSlug":19,"order":796,"status":13},"scope-closures-deep-dive-ex8","Дополнительное упражнение 8: углубленная практика по областям видимости и замыканиям","mentoring\u002Fscope-closures-deep-dive\u002Fex\u002Fex8","var a = [];\n\nfor (var b = 0; b \u003C 3; b++) {\n  (function () {\n    a.push(function () {\n      return b;\n    });\n  })();\n}\n\nvar c = [];\n\nfor (var d = 0; d \u003C 3; d++) {\n  (function (e) {\n    c.push(function () {\n      return e;\n    });\n  })(d);\n}\n\nconsole.log('1:', a[0](), a[1](), a[2]());\nconsole.log('2:', c[0](), c[1](), c[2]());\n","\u002F\u002F Дополнительное упражнение 8: углубленная практика по областям видимости и замыканиям\n\u002F\u002F Темы: замыкание в цикле, пустая IIFE и IIFE с параметром.\n\u002F\u002F Читать дальше\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md раздел Циклы + замыкание\n\nvar a = [];\n\nfor (var b = 0; b \u003C 3; b++) {\n  (function () {\n    \u002F\u002F Эта IIFE создает область, но внутри нее нет своей копии b.\n    \u002F\u002F Поэтому функция все равно замыкается на одну общую b из цикла.\n    a.push(function () {\n      return b;\n    });\n  })();\n}\n\nvar c = [];\n\nfor (var d = 0; d \u003C 3; d++) {\n  (function (e) {\n    \u002F\u002F Параметр e создает новую переменную для каждого вызова IIFE.\n    \u002F\u002F Каждая функция замыкается на свою e.\n    c.push(function () {\n      return e;\n    });\n  })(d);\n}\n\n\u002F\u002F После первого цикла b равно 3.\nconsole.log('1:', a[0](), a[1](), a[2]());\n\n\u002F\u002F Во втором цикле каждая функция помнит свое значение e.\nconsole.log('2:', c[0](), c[1](), c[2]());","1: 3 3 3\n2: 0 1 2",{"slug":847,"title":848,"source":849,"exerciseCode":850,"tutorialCode":851,"expectedOutput":852,"executionExplanation":851,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":796,"status":13},"types-coercion-symbol-json-ex8","Упражнение 8: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex8","console.log('1:', '5' - 1);\nconsole.log('2:', '5' + 1);\nconsole.log('3:', true + true + true);\nconsole.log('4:', '5' * '2');\nconsole.log('5:', '5' + true);\n","\u002F\u002F Упражнение 8: типы, приведение, Symbol и JSON\n\u002F\u002F Темы плюс, минус и неявное приведение\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS базовые операторы https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F08-operators\u002Farticle.md\n\u002F\u002F Learn JS преобразование типов https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F07-type-conversions\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md\n\u002F\u002F MDN Addition operator\n\u002F\u002F Минус не умеет складывать строки.\n\u002F\u002F Поэтому оба операнда приводятся к number.\n\u002F\u002F Строка 5 становится числом 5.\nconsole.log('1:', '5' - 1);\n\n\u002F\u002F Плюс умеет быть строковым сложением.\n\u002F\u002F Если один операнд строка, второй приводится к строке.\nconsole.log('2:', '5' + 1);\n\n\u002F\u002F true при численном сложении становится 1.\nconsole.log('3:', true + true + true);\n\n\u002F\u002F Умножение тоже работает только как численная операция.\nconsole.log('4:', '5' * '2');\n\n\u002F\u002F Здесь снова строковый плюс.\n\u002F\u002F true превращается в строку true.\nconsole.log('5:', '5' + true);","1 4\n2 51\n3 3\n4 10\n5 5true",{"slug":854,"title":855,"source":856,"exerciseCode":857,"tutorialCode":858,"expectedOutput":859,"executionExplanation":858,"language":65,"runtime":66,"programSlug":40,"lessonSlug":40,"order":860,"status":13},"browser-network-ex9","Упражнение 9: сеть в браузере","mentoring\u002Fbrowser-network\u002Fex\u002Fex9","const a = new URL('https:\u002F\u002Fa.test\u002F');\n\na.searchParams.set('x', 'a b');\na.searchParams.set('y', '1+2');\n\nconsole.log(a.search);\nconsole.log(a.searchParams.get('x'));\nconsole.log(a.searchParams.get('y'));\n","\u002F\u002F Упражнение 9: сеть в браузере\n\u002F\u002F Темы URLSearchParams кодирование пробела и плюса\n\u002F\u002F Читать дальше\n\u002F\u002F MDN URLSearchParams https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Furlsearchparams\u002Findex.md\nconst a = new URL('https:\u002F\u002Fa.test\u002F');\n\n\u002F\u002F В query string пробел при сериализации через URLSearchParams становится плюсом.\n\u002F\u002F Настоящий плюс в значении кодируется как %2B, чтобы не спутать его с пробелом.\na.searchParams.set('x', 'a b');\na.searchParams.set('y', '1+2');\n\nconsole.log(a.search);\n\n\u002F\u002F При чтении обратно браузер декодирует значения.\nconsole.log(a.searchParams.get('x'));\nconsole.log(a.searchParams.get('y'));","?x=a+b&y=1%2B2\na b\n1+2",9,{"slug":862,"title":863,"source":864,"exerciseCode":865,"tutorialCode":866,"expectedOutput":867,"executionExplanation":866,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":860,"status":13},"collections-iteration-arrays-ex9","Упражнение 9: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex9","function* f() {\n  yield 'a';\n  yield* ['b', 'c'];\n  return 'd';\n}\n\nconsole.log([...f()].join(','));\n\nconst a = f();\n\nconsole.log(a.next().value);\nconsole.log(a.next().value);\nconsole.log(a.next().value);\n\nconst b = a.next();\n\nconsole.log(b.value, b.done);\n","\u002F\u002F Упражнение 9: коллекции, итерация, массивы и строки\n\u002F\u002F Темы yield star и return generator\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS генераторы https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F12-generators-iterators\u002F1-generators\u002Farticle.md\n\u002F\u002F MDN yield star https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fyield_star_\u002Findex.md\nfunction* f() {\n  yield 'a';\n\n  \u002F\u002F yield star передает значения из другого iterable.\n  yield* ['b', 'c'];\n\n  \u002F\u002F return завершает generator.\n  \u002F\u002F for of и spread не включают это значение в результат обхода.\n  return 'd';\n}\n\nconsole.log([...f()].join(','));\n\nconst a = f();\n\nconsole.log(a.next().value);\nconsole.log(a.next().value);\nconsole.log(a.next().value);\n\n\u002F\u002F При ручном next значение return видно вместе с done true.\nconst b = a.next();\n\nconsole.log(b.value, b.done);","a,b,c\na\nb\nc\nd true",{"slug":869,"title":870,"source":871,"exerciseCode":872,"tutorialCode":873,"expectedOutput":874,"executionExplanation":873,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":860,"status":13},"event-loop-promises-async-await-ex9","Упражнение 9: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex9","async function f() {\n  try {\n    await Promise.reject('a');\n    console.log('1');\n  } catch (a) {\n    console.log('2:', a);\n  }\n\n  return 'b';\n}\n\nf().then((a) => console.log('3:', a));\n\nconsole.log('4');\n","\u002F\u002F Упражнение 9: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы rejected Promise, await и try catch\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS async await https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md\n\u002F\u002F Learn JS Promise error handling https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F04-promise-error-handling\u002Farticle.md\n\u002F\u002F MDN async function https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fstatements\u002Fasync_function\u002Findex.md\nasync function f() {\n  try {\n    \u002F\u002F Rejected Promise внутри await ведет себя как исключение в этой функции.\n    await Promise.reject('a');\n    console.log('1');\n  } catch (a) {\n    console.log('2:', a);\n  }\n\n  \u002F\u002F После catch функция завершается успешно.\n  return 'b';\n}\n\nf().then((a) => console.log('3:', a));\n\nconsole.log('4');","4\n2: a\n3: b",{"slug":876,"title":877,"source":878,"exerciseCode":879,"tutorialCode":880,"expectedOutput":881,"executionExplanation":880,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":860,"status":13},"event-loop-promises-deep-dive-ex9","Дополнительное упражнение 9: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex9","Promise.race([\n  new Promise((resolve) => setTimeout(() => resolve('a'), 0)),\n  Promise.resolve('b'),\n]).then((a) => console.log('1:', a));\n\nPromise.race([Promise.reject('c'), 'd']).catch((a) => console.log('2:', a));\n\nconsole.log('3');\n","\u002F\u002F Дополнительное упражнение 9: углубленная практика по event loop и Promise\n\u002F\u002F Темы Promise.race и первый завершившийся вход\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Promise API https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F05-promise-api\u002Farticle.md\n\u002F\u002F MDN Promise.race https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Frace\u002Findex.md\nPromise.race([\n  new Promise((resolve) => setTimeout(() => resolve('a'), 0)),\n  Promise.resolve('b'),\n]).then((a) => console.log('1:', a));\n\n\u002F\u002F Первый завершившийся вход может быть rejection.\nPromise.race([Promise.reject('c'), 'd']).catch((a) => console.log('2:', a));\n\nconsole.log('3');","3\n1: b\n2: c",{"slug":883,"title":884,"source":885,"exerciseCode":886,"tutorialCode":887,"expectedOutput":888,"executionExplanation":887,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":860,"status":13},"objects-prototypes-classes-ex9","Упражнение 9: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex9","const a = {};\n\nObject.defineProperty(a, 'x', {\n  value: 1,\n  writable: false,\n});\n\nconst b = Object.create(a);\n\nb.x = 2;\n\nconsole.log('1:', b.x);\nconsole.log('2:', Object.hasOwn(b, 'x'));\n\nconst c = {\n  get y() {\n    return this.z;\n  },\n\n  set y(d) {\n    this.z = d;\n  },\n};\n\nconst e = Object.create(c);\n\ne.y = 3;\n\nconsole.log('3:', e.y, e.z, Object.hasOwn(e, 'z'));\n","\u002F\u002F Упражнение 9: свойства объектов, прототипы и классы\n\u002F\u002F Темы дескрипторы в прототипной цепочке\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS прототипное наследование https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F01-prototype-inheritance\u002Farticle.md\n\u002F\u002F Learn JS дескрипторы свойств https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md\n\u002F\u002F Learn JS геттеры и сеттеры https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F02-property-accessors\u002Farticle.md\n\u002F\u002F MDN inheritance and prototype chain https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Finheritance_and_the_prototype_chain\u002Findex.md\nconst a = {};\n\nObject.defineProperty(a, 'x', {\n  value: 1,\n  \u002F\u002F Свойство в прототипе найдено как non writable.\n  writable: false,\n});\n\nconst b = Object.create(a);\n\n\u002F\u002F Запись не создаст свое x на объекте b.\nb.x = 2;\n\n\u002F\u002F Чтение идет в прототип и находит значение 1.\nconsole.log('1:', b.x);\nconsole.log('2:', Object.hasOwn(b, 'x'));\n\nconst c = {\n  get y() {\n    return this.z;\n  },\n\n  set y(d) {\n    \u002F\u002F Setter найден в прототипе, но this будет объект e.\n    this.z = d;\n  },\n};\n\nconst e = Object.create(c);\n\n\u002F\u002F Запись вызывает унаследованный setter.\ne.y = 3;\n\n\u002F\u002F Getter тоже унаследован и читает z с объекта e.\nconsole.log('3:', e.y, e.z, Object.hasOwn(e, 'z'));","1 1\n2 false\n3 3 3 true",{"slug":890,"title":891,"source":892,"exerciseCode":893,"tutorialCode":894,"expectedOutput":831,"executionExplanation":894,"language":65,"runtime":66,"programSlug":50,"lessonSlug":50,"order":860,"status":13},"recursion-ex9","Упражнение 9: рекурсия","mentoring\u002Frecursion\u002Fex\u002Fex9","const a = {\n  b: {\n    b: null,\n    c: null,\n  },\n  c: {\n    b: {\n      b: null,\n      c: null,\n    },\n    c: null,\n  },\n};\n\nfunction f(x) {\n  if (x === null) {\n    return 0;\n  }\n\n  return 1 + Math.max(f(x.b), f(x.c));\n}\n\nconsole.log(f(a));\n","\u002F\u002F Упражнение 9: рекурсия\n\u002F\u002F Темы глубина бинарного дерева\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Recursion https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md\nconst a = {\n  b: {\n    b: null,\n    c: null,\n  },\n  c: {\n    b: {\n      b: null,\n      c: null,\n    },\n    c: null,\n  },\n};\n\nfunction f(x) {\n  \u002F\u002F Пустого узла нет, поэтому его глубина 0.\n  if (x === null) {\n    return 0;\n  }\n\n  \u002F\u002F Глубина узла это 1 плюс большая глубина его частей.\n  return 1 + Math.max(f(x.b), f(x.c));\n}\n\nconsole.log(f(a));",{"slug":896,"title":897,"source":898,"exerciseCode":899,"tutorialCode":900,"expectedOutput":901,"executionExplanation":900,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":860,"status":13},"rendering-dom-events-forms-ex9","Упражнение 9: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex9","console.log('1');\n\nlet a = '2';\n\nrequestAnimationFrame(() => {\n  a = '3';\n});\n\nPromise.resolve().then(() => console.log(a));\n","\u002F\u002F Упражнение 9: рендеринг, DOM, события и формы\n\u002F\u002F Темы микрозадачи и requestAnimationFrame перед repaint\n\u002F\u002F Читать дальше\n\u002F\u002F MDN requestAnimationFrame https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fwindow\u002Frequestanimationframe\u002Findex.md\n\u002F\u002F Learn JS event loop https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F99-ui-misc\u002F03-event-loop\u002Farticle.md\nconsole.log('1');\n\nlet a = '2';\n\n\u002F\u002F requestAnimationFrame просит браузер вызвать callback перед следующим repaint.\n\u002F\u002F Это не синхронный вызов внутри текущего script.\nrequestAnimationFrame(() => {\n  a = '3';\n});\n\n\u002F\u002F Микрозадача Promise выполнится после текущего script, но до rAF callback.\n\u002F\u002F Поэтому a все еще хранит значение 2.\nPromise.resolve().then(() => console.log(a));","1\n2",{"slug":903,"title":904,"source":905,"exerciseCode":906,"tutorialCode":907,"expectedOutput":908,"executionExplanation":907,"language":65,"runtime":66,"programSlug":19,"lessonSlug":19,"order":860,"status":13},"scope-closures-deep-dive-ex9","Дополнительное упражнение 9: углубленная практика по областям видимости и замыканиям","mentoring\u002Fscope-closures-deep-dive\u002Fex\u002Fex9","var a = (function () {\n  var b = 0;\n\n  return {\n    f() {\n      b += 1;\n\n      return b;\n    },\n\n    g() {\n      return b * 2;\n    },\n  };\n})();\n\nconsole.log('1:', a.f());\nconsole.log('2:', a.f());\nconsole.log('3:', a.g());\n\ntry {\n  console.log('4:', b);\n} catch (error) {\n  console.log('4:', error.name);\n}\n","\u002F\u002F Дополнительное упражнение 9: углубленная практика по областям видимости и замыканиям\n\u002F\u002F Темы: модульный паттерн через замыкание.\n\u002F\u002F Читать дальше\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md раздел Модули\n\nvar a = (function () {\n  \u002F\u002F b приватная для IIFE.\n  var b = 0;\n\n  \u002F\u002F Возвращаем наружу объект с методами.\n  \u002F\u002F Оба метода замыкаются на одну и ту же b.\n  return {\n    f() {\n      b += 1;\n\n      return b;\n    },\n\n    g() {\n      return b * 2;\n    },\n  };\n})();\n\nconsole.log('1:', a.f());\nconsole.log('2:', a.f());\nconsole.log('3:', a.g());\n\ntry {\n  \u002F\u002F Снаружи имени b нет.\n  \u002F\u002F Доступ есть только у методов, которые были созданы внутри IIFE.\n  console.log('4:', b);\n} catch (error) {\n  console.log('4:', error.name);\n}","1: 1\n2: 2\n3: 4\n4: ReferenceError",{"slug":910,"title":911,"source":912,"exerciseCode":913,"tutorialCode":914,"expectedOutput":915,"executionExplanation":914,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":860,"status":13},"scope-hoisting-closures-this-ex9","Упражнение 9: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex9","let a = 'a';\n\n{\n  try {\n    console.log('1:', a);\n  } catch (error) {\n    console.log('1:', error.name);\n  }\n\n  let a = 'b';\n\n  console.log('2:', a);\n}\n\nconsole.log('3:', a);\n","\u002F\u002F Упражнение 9: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: shadowing и Temporal Dead Zone.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS блоки и лексическое окружение https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch2.md#L2 раздел Лексическая область видимости\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch3.md#L325 раздел Блоки как области видимости\n\u002F\u002F MDN let https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Flet\n\n\u002F\u002F Внешняя переменная.\nlet a = 'a';\n\n{\n  try {\n    \u002F\u002F Внутри этого же блока ниже объявлена let a.\n    \u002F\u002F Она затеняет внешнюю a с начала блока.\n    \u002F\u002F Но до объявления внутренняя a находится в TDZ.\n    console.log('1:', a);\n  } catch (error) {\n    console.log('1:', error.name);\n  }\n\n  \u002F\u002F После этой строки внутренняя a доступна.\n  let a = 'b';\n\n  console.log('2:', a);\n}\n\n\u002F\u002F Блок закончился, внутренняя a исчезла.\n\u002F\u002F Здесь снова видна внешняя a.\nconsole.log('3:', a);","1: ReferenceError\n2: b\n3: a",{"slug":917,"title":918,"source":919,"exerciseCode":920,"tutorialCode":921,"expectedOutput":922,"executionExplanation":921,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":860,"status":13},"types-coercion-symbol-json-ex9","Упражнение 9: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex9","const a = {\n  valueOf() {\n    return 2;\n  },\n\n  toString() {\n    return '3';\n  },\n};\n\nconst b = {\n  [Symbol.toPrimitive](c) {\n    if (c === 'string') {\n      return '4';\n    }\n\n    return 5;\n  },\n};\n\nconsole.log('1:', a + 1);\nconsole.log('2:', String(a));\nconsole.log('3:', Number(a));\nconsole.log('4:', String(b));\nconsole.log('5:', b + 1);\nconsole.log('6:', b == 5);\n","\u002F\u002F Упражнение 9: типы, приведение, Symbol и JSON\n\u002F\u002F Темы ToPrimitive, valueOf, toString и Symbol.toPrimitive\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS преобразование объектов в примитивы https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F09-object-toprimitive\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md\n\u002F\u002F MDN Symbol.toPrimitive\nconst a = {\n  valueOf() {\n    return 2;\n  },\n\n  toString() {\n    return '3';\n  },\n};\n\nconst b = {\n  \u002F\u002F Этот метод получает hint от операции приведения.\n  \u002F\u002F Так объект может сам выбрать нужный примитив.\n  [Symbol.toPrimitive](c) {\n    if (c === 'string') {\n      return '4';\n    }\n\n    return 5;\n  },\n};\n\n\u002F\u002F Операции не складывают объект напрямую.\n\u002F\u002F Сначала объект приводится к примитиву.\n\u002F\u002F Для обычного объекта первым пробуется valueOf.\n\u002F\u002F valueOf вернул 2, затем 2 + 1 дает 3.\nconsole.log('1:', a + 1);\n\n\u002F\u002F String просит строковое представление.\n\u002F\u002F В этом случае первым подходит toString.\nconsole.log('2:', String(a));\n\n\u002F\u002F Number снова просит численное представление.\n\u002F\u002F Для обычного объекта первым подходит valueOf.\nconsole.log('3:', Number(a));\n\n\u002F\u002F String передает подсказку string.\n\u002F\u002F Метод Symbol.toPrimitive возвращает строку 4.\nconsole.log('4:', String(b));\n\n\u002F\u002F Плюс передает подсказку default.\n\u002F\u002F Метод возвращает число 5, затем 5 + 1 дает 6.\nconsole.log('5:', b + 1);\n\n\u002F\u002F Нестрогое сравнение тоже приводит объект к примитиву.\n\u002F\u002F Метод возвращает 5, поэтому сравнение истинно.\nconsole.log('6:', b == 5);","1 3\n2 3\n3 2\n4 4\n5 6\n6 true",{"slug":924,"title":925,"source":926,"exerciseCode":927,"tutorialCode":928,"expectedOutput":929,"executionExplanation":928,"language":65,"runtime":66,"programSlug":40,"lessonSlug":40,"order":930,"status":13},"browser-network-ex10","Упражнение 10: сеть в браузере","mentoring\u002Fbrowser-network\u002Fex\u002Fex10","const a = [];\n\nwindow.addEventListener('offline', () => {\n  a.push('offline');\n});\n\nwindow.addEventListener('online', () => {\n  a.push('online');\n});\n\nwindow.dispatchEvent(new Event('offline'));\nwindow.dispatchEvent(new Event('online'));\n\nconsole.log(typeof navigator.onLine);\nconsole.log(a.join('|'));\n","\u002F\u002F Упражнение 10: сеть в браузере\n\u002F\u002F Темы navigator.onLine и события online offline\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Navigator onLine https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fnavigator\u002Fonline\u002Findex.md\nconst a = [];\n\n\u002F\u002F Браузер умеет сообщать странице о смене сетевого состояния.\n\u002F\u002F Это сигнал для интерфейса, а не гарантия доступности конкретного API.\nwindow.addEventListener('offline', () => {\n  a.push('offline');\n});\n\nwindow.addEventListener('online', () => {\n  a.push('online');\n});\n\n\u002F\u002F В упражнении мы сами отправляем события, чтобы увидеть порядок обработчиков.\nwindow.dispatchEvent(new Event('offline'));\nwindow.dispatchEvent(new Event('online'));\n\nconsole.log(typeof navigator.onLine);\nconsole.log(a.join('|'));","boolean\noffline|online",10,{"slug":932,"title":933,"source":934,"exerciseCode":935,"tutorialCode":936,"expectedOutput":937,"executionExplanation":936,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":930,"status":13},"collections-iteration-arrays-ex10","Упражнение 10: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex10","const a = ['1', '2', '3', '10'];\n\nconsole.log(a.map(parseInt).join(','));\nconsole.log(a.map((b) => parseInt(b, 10)).join(','));\n","\u002F\u002F Упражнение 10: коллекции, итерация, массивы и строки\n\u002F\u002F Темы map и parseInt\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Array map https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fmap\u002Findex.md\n\u002F\u002F MDN parseInt https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fparseint\u002Findex.md\nconst a = ['1', '2', '3', '10'];\n\n\u002F\u002F map передает callback три аргумента.\n\u002F\u002F Значение индекс и сам массив.\n\u002F\u002F parseInt вторым аргументом ждет систему счисления.\n\u002F\u002F Поэтому индекс становится radix.\nconsole.log(a.map(parseInt).join(','));\n\n\u002F\u002F Здесь мы явно передаем только строку и radix 10.\nconsole.log(a.map((b) => parseInt(b, 10)).join(','));","1,NaN,NaN,3\n1,2,3,10",{"slug":939,"title":940,"source":941,"exerciseCode":942,"tutorialCode":943,"expectedOutput":944,"executionExplanation":943,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":930,"status":13},"event-loop-promises-async-await-ex10","Упражнение 10: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex10","const a = new Promise((resolve) => {\n  setTimeout(() => {\n    console.log('1');\n    resolve('a');\n  }, 0);\n});\nconst b = Promise.reject('b');\n\nPromise.all([a, b]).catch((c) => console.log('2:', c));\nPromise.allSettled([a, b]).then((c) => console.log('3:', c[0].status, c[1].status));\n\nconsole.log('4');\n","\u002F\u002F Упражнение 10: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы Promise all и allSettled\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Promise API https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F05-promise-api\u002Farticle.md\n\u002F\u002F Learn JS микрозадачи https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md\n\u002F\u002F MDN Promise.all https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fall\u002Findex.md\n\u002F\u002F MDN Promise.allSettled https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fallsettled\u002Findex.md\nconst a = new Promise((resolve) => {\n  setTimeout(() => {\n    console.log('1');\n    resolve('a');\n  }, 0);\n});\nconst b = Promise.reject('b');\n\n\u002F\u002F Promise.all завершается с ошибкой при первом rejected входе.\nPromise.all([a, b]).catch((c) => console.log('2:', c));\n\n\u002F\u002F Promise.allSettled ждет, пока завершатся все входные промисы.\nPromise.allSettled([a, b]).then((c) => console.log('3:', c[0].status, c[1].status));\n\nconsole.log('4');","4\n2: b\n1\n3: fulfilled rejected",{"slug":946,"title":947,"source":948,"exerciseCode":949,"tutorialCode":950,"expectedOutput":951,"executionExplanation":950,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":930,"status":13},"event-loop-promises-deep-dive-ex10","Дополнительное упражнение 10: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex10","function f(a) {\n  return new Promise((resolve) => {\n    console.log('1:', a);\n\n    setTimeout(() => {\n      console.log('2:', a);\n      resolve(a);\n    }, 0);\n  });\n}\n\nasync function g() {\n  const a = f('a');\n  const b = f('b');\n\n  console.log('3');\n  console.log('4:', await a, await b);\n}\n\ng();\n\nconsole.log('5');\n","\u002F\u002F Дополнительное упражнение 10: углубленная практика по event loop и Promise\n\u002F\u002F Темы параллельный запуск и последовательное ожидание результатов\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS async await https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md\n\u002F\u002F YDKJS async performance https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fasync%20%26%20performance\u002Fch3.md\nfunction f(a) {\n  return new Promise((resolve) => {\n    \u002F\u002F Операция стартует сразу при вызове f.\n    console.log('1:', a);\n\n    setTimeout(() => {\n      console.log('2:', a);\n      resolve(a);\n    }, 0);\n  });\n}\n\nasync function g() {\n  \u002F\u002F Оба промиса создаются до первого await.\n  const a = f('a');\n  const b = f('b');\n\n  console.log('3');\n\n  \u002F\u002F Ожидание идет слева направо, но сами операции уже запущены.\n  console.log('4:', await a, await b);\n}\n\ng();\n\nconsole.log('5');","1: a\n1: b\n3\n5\n2: a\n2: b\n4: a b",{"slug":953,"title":954,"source":955,"exerciseCode":956,"tutorialCode":957,"expectedOutput":958,"executionExplanation":957,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":930,"status":13},"objects-prototypes-classes-ex10","Упражнение 10: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex10","class A {\n  constructor(x) {\n    this.x = x;\n  }\n\n  f() {\n    return this.x + 1;\n  }\n}\n\nconst a = new A(1);\n\nconsole.log('1:', typeof A, A === A.prototype.constructor);\nconsole.log('2:', Object.hasOwn(a, 'x'), Object.hasOwn(a, 'f'));\nconsole.log('3:', Object.hasOwn(A.prototype, 'f'), a.f());\nconsole.log('4:', Object.keys(A.prototype).join(','));\n","\u002F\u002F Упражнение 10: свойства объектов, прототипы и классы\n\u002F\u002F Темы class constructor prototype и неперечислимые методы\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS классы https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F01-class\u002Farticle.md\n\u002F\u002F MDN classes https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Findex.md\nclass A {\n  constructor(x) {\n    \u002F\u002F constructor запускается при new A.\n    \u002F\u002F Обычная запись создает собственное свойство экземпляра.\n    this.x = x;\n  }\n\n  f() {\n    \u002F\u002F Метод не копируется в каждый экземпляр.\n    \u002F\u002F Он лежит на A.prototype и получает this при вызове через точку.\n    return this.x + 1;\n  }\n}\n\nconst a = new A(1);\n\n\u002F\u002F Объявление class создает функцию конструктор.\n\u002F\u002F Ее prototype.constructor указывает обратно на сам класс.\nconsole.log('1:', typeof A, A === A.prototype.constructor);\n\n\u002F\u002F x лежит прямо на экземпляре.\n\u002F\u002F f на экземпляре не лежит.\nconsole.log('2:', Object.hasOwn(a, 'x'), Object.hasOwn(a, 'f'));\n\n\u002F\u002F f лежит на прототипе и доступен экземпляру через цепочку прототипов.\nconsole.log('3:', Object.hasOwn(A.prototype, 'f'), a.f());\n\n\u002F\u002F Методы класса создаются неперечислимыми.\nconsole.log('4:', Object.keys(A.prototype).join(','));","1 function true\n2 true false\n3 true 2\n4",{"slug":960,"title":961,"source":962,"exerciseCode":963,"tutorialCode":964,"expectedOutput":965,"executionExplanation":964,"language":65,"runtime":66,"programSlug":50,"lessonSlug":50,"order":930,"status":13},"recursion-ex10","Упражнение 10: рекурсия","mentoring\u002Frecursion\u002Fex\u002Fex10","const a = {\n  x: 1,\n  y: [\n    { x: 2, y: [] },\n    {\n      x: 3,\n      y: [{ x: 4, y: [] }],\n    },\n  ],\n};\n\nfunction f(b, c) {\n  if (b.x === c) {\n    return b;\n  }\n\n  for (const d of b.y) {\n    const e = f(d, c);\n\n    if (e !== null) {\n      return e;\n    }\n  }\n\n  return null;\n}\n\nconsole.log(f(a, 4).x);\n","\u002F\u002F Упражнение 10: рекурсия\n\u002F\u002F Темы рекурсивный поиск в дереве\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Recursion https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md\nconst a = {\n  x: 1,\n  y: [\n    { x: 2, y: [] },\n    {\n      x: 3,\n      y: [{ x: 4, y: [] }],\n    },\n  ],\n};\n\nfunction f(b, c) {\n  \u002F\u002F Сначала проверяем текущий узел.\n  if (b.x === c) {\n    return b;\n  }\n\n  for (const d of b.y) {\n    \u002F\u002F Потом ищем в каждом дочернем узле.\n    const e = f(d, c);\n\n    \u002F\u002F Если глубже нашли результат, возвращаем его наружу.\n    if (e !== null) {\n      return e;\n    }\n  }\n\n  return null;\n}\n\nconsole.log(f(a, 4).x);","4",{"slug":967,"title":968,"source":969,"exerciseCode":970,"tutorialCode":971,"expectedOutput":972,"executionExplanation":971,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":930,"status":13},"rendering-dom-events-forms-ex10","Упражнение 10: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex10","const a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '10px';\ndocument.body.append(a);\n\nlet b = '1';\n\nconst c = new ResizeObserver((d) => {\n  b = Math.round(d[0].contentRect.width).toString();\n});\n\nc.observe(a);\na.style.width = '150px';\n\nconsole.log(b);\n","\u002F\u002F Упражнение 10: рендеринг, DOM, события и формы\n\u002F\u002F Темы ResizeObserver и уведомление после изменения размера\n\u002F\u002F Читать дальше\n\u002F\u002F MDN ResizeObserver https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fresizeobserver\u002Findex.md\n\u002F\u002F MDN requestAnimationFrame https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fwindow\u002Frequestanimationframe\u002Findex.md\nconst a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '10px';\ndocument.body.append(a);\n\nlet b = '1';\n\nconst c = new ResizeObserver((d) => {\n  \u002F\u002F ResizeObserver сообщает размер после того, как браузер обработал изменение.\n  \u002F\u002F Этот callback не запускается синхронно в момент изменения width.\n  b = Math.round(d[0].contentRect.width).toString();\n});\n\nc.observe(a);\n\n\u002F\u002F Мы меняем размер наблюдаемого элемента.\na.style.width = '150px';\n\n\u002F\u002F Прямо сейчас observer еще не успел изменить b.\n\u002F\u002F Поэтому видим старое значение.\nconsole.log(b);","1",{"slug":974,"title":975,"source":976,"exerciseCode":977,"tutorialCode":978,"expectedOutput":979,"executionExplanation":978,"language":65,"runtime":66,"programSlug":19,"lessonSlug":19,"order":930,"status":13},"scope-closures-deep-dive-ex10","Дополнительное упражнение 10: углубленная практика по областям видимости и замыканиям","mentoring\u002Fscope-closures-deep-dive\u002Fex\u002Fex10","function f() {\n  console.log('1:', a);\n}\n\nfunction g() {\n  var a = 2;\n\n  f();\n}\n\nvar a = 1;\n\ng();\n","\u002F\u002F Дополнительное упражнение 10: углубленная практика по областям видимости и замыканиям\n\u002F\u002F Темы: лексическая область видимости против динамической.\n\u002F\u002F Читать дальше\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002FapA.md приложение A Динамическая область видимости\n\nfunction f() {\n  \u002F\u002F f была создана в глобальной области.\n  \u002F\u002F Поэтому a ищется не в месте вызова, а в месте создания функции.\n  console.log('1:', a);\n}\n\nfunction g() {\n  \u002F\u002F Эта a локальная для g.\n  var a = 2;\n\n  \u002F\u002F Вызов из g не делает область g внешней областью для f.\n  f();\n}\n\nvar a = 1;\n\ng();","1: 1",{"slug":981,"title":982,"source":983,"exerciseCode":984,"tutorialCode":985,"expectedOutput":986,"executionExplanation":985,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":930,"status":13},"scope-hoisting-closures-this-ex10","Упражнение 10: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex10","function f(a) {\n  console.log('1:', a);\n\n  var a;\n\n  console.log('2:', a);\n\n  a = 'b';\n\n  console.log('3:', a);\n}\n\nf('a');\n\ntry {\n  Function(`\n    function g(a) {\n      let a = 'c';\n\n      console.log(a);\n    }\n  `);\n} catch (error) {\n  console.log('4:', error.name);\n}\n","\u002F\u002F Упражнение 10: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: параметр функции, var с тем же именем и let с тем же именем.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS лексическое окружение функции https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md\n\u002F\u002F Learn JS var https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F04-var\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch3.md#L8 раздел Область видимости из функций\n\u002F\u002F MDN var https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Fvar\n\u002F\u002F MDN let https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Flet\n\nfunction f(a) {\n  \u002F\u002F Параметр a уже существует в функциональной области.\n  console.log('1:', a);\n\n  \u002F\u002F var a не создает новую отдельную переменную.\n  \u002F\u002F Он относится к той же функциональной области, что и параметр.\n  var a;\n\n  \u002F\u002F Поэтому значение параметра не потерялось.\n  console.log('2:', a);\n\n  \u002F\u002F Меняем эту же переменную.\n  a = 'b';\n\n  console.log('3:', a);\n}\n\nf('a');\n\ntry {\n  \u002F\u002F Function constructor нужен, чтобы показать синтаксическую ошибку\n  \u002F\u002F и не сломать весь файл.\n  \u002F\u002F Внутри функции уже есть параметр a.\n  \u002F\u002F let a в той же области объявлять нельзя.\n  Function(`\n    function g(a) {\n      let a = 'c';\n\n      console.log(a);\n    }\n  `);\n} catch (error) {\n  console.log('4:', error.name);\n}","1: a\n2: a\n3: b\n4: SyntaxError",{"slug":988,"title":989,"source":990,"exerciseCode":991,"tutorialCode":992,"expectedOutput":993,"executionExplanation":992,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":930,"status":13},"types-coercion-symbol-json-ex10","Упражнение 10: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex10","const a = {};\nconst b = {};\nconst c = Symbol('a');\n\na[true] = 1;\na[3] = 2;\na[b] = 3;\na[c] = 4;\na['Symbol(a)'] = 5;\n\nconsole.log('1:', a.true);\nconsole.log('2:', a['3']);\nconsole.log('3:', a['[object Object]']);\nconsole.log('4:', a[c]);\nconsole.log('5:', a['Symbol(a)']);\nconsole.log('6:', Object.keys(a).length);\nconsole.log('7:', Object.getOwnPropertySymbols(a).length);\n","\u002F\u002F Упражнение 10: типы, приведение, Symbol и JSON\n\u002F\u002F Темы ключи объекта, строковое приведение и Symbol\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS свойства объекта https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F01-object\u002Farticle.md\n\u002F\u002F Learn JS Symbol https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F08-symbol\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fthis%20%26%20object%20prototypes\u002Fch3.md\n\u002F\u002F MDN Property accessors\n\u002F\u002F MDN Symbol\n\u002F\u002F В обычном объекте ключи свойств это строки или Symbol.\n\u002F\u002F Все остальные значения перед записью ключа приводятся к строке.\nconst a = {};\nconst b = {};\nconst c = Symbol('a');\n\n\u002F\u002F true приводится к строке true.\na[true] = 1;\n\n\u002F\u002F Число 3 приводится к строке 3.\na[3] = 2;\n\n\u002F\u002F Обычный объект как ключ становится строкой [object Object].\na[b] = 3;\n\n\u002F\u002F Symbol может быть ключом без приведения к строке.\na[c] = 4;\n\n\u002F\u002F А это обычная строка.\n\u002F\u002F Она похожа на текстовое представление Symbol, но это другой ключ.\na['Symbol(a)'] = 5;\n\n\u002F\u002F Точечная запись a.true читает ключ true.\nconsole.log('1:', a.true);\n\n\u002F\u002F Ключ 3 тоже хранится как строка.\nconsole.log('2:', a['3']);\n\n\u002F\u002F Ключ от объекта b стал строкой [object Object].\nconsole.log('3:', a['[object Object]']);\n\n\u002F\u002F Symbol ключ читается только тем же Symbol.\nconsole.log('4:', a[c]);\n\n\u002F\u002F Строковый ключ Symbol(a) остается отдельным строковым ключом.\nconsole.log('5:', a['Symbol(a)']);\n\n\u002F\u002F Object.keys показывает только строковые ключи.\nconsole.log('6:', Object.keys(a).length);\n\n\u002F\u002F Symbol ключи нужно получать отдельно.\nconsole.log('7:', Object.getOwnPropertySymbols(a).length);","1 1\n2 2\n3 3\n4 4\n5 5\n6 4\n7 1",{"slug":995,"title":996,"source":997,"exerciseCode":998,"tutorialCode":999,"expectedOutput":1000,"executionExplanation":999,"language":65,"runtime":66,"programSlug":40,"lessonSlug":40,"order":1001,"status":13},"browser-network-ex11","Упражнение 11: сеть в браузере","mentoring\u002Fbrowser-network\u002Fex\u002Fex11","(async () => {\n  const a = await new Promise((resolve) => {\n    const b = new XMLHttpRequest();\n\n    b.open('GET', 'data:text\u002Fplain,1');\n    b.addEventListener('load', () => {\n      resolve({\n        status: b.status,\n        text: b.responseText,\n      });\n    });\n    b.send();\n  });\n\n  console.log(a.status);\n  console.log(a.text);\n})();\n","\u002F\u002F Упражнение 11: сеть в браузере\n\u002F\u002F Темы XMLHttpRequest open send load status responseText\n\u002F\u002F Читать дальше\n\u002F\u002F MDN XMLHttpRequest https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fxmlhttprequest\u002Findex.md\n(async () => {\n  const a = await new Promise((resolve) => {\n    const b = new XMLHttpRequest();\n\n    \u002F\u002F XMLHttpRequest старше fetch, но на интервью его все еще могут спросить.\n    \u002F\u002F open задает метод и URL, send начинает запрос.\n    b.open('GET', 'data:text\u002Fplain,1');\n    b.addEventListener('load', () => {\n      resolve({\n        status: b.status,\n        text: b.responseText,\n      });\n    });\n    b.send();\n  });\n\n  console.log(a.status);\n  console.log(a.text);\n})();","200\n1",11,{"slug":1003,"title":1004,"source":1005,"exerciseCode":1006,"tutorialCode":1007,"expectedOutput":1008,"executionExplanation":1007,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":1001,"status":13},"collections-iteration-arrays-ex11","Упражнение 11: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex11","const a = [10, 2, 1];\nconst b = a.sort();\n\nconsole.log(a.join(','));\nconsole.log(b === a);\n\nconst c = [10, 2, 1];\nconst d = [...c].sort((b, c) => b - c);\n\nconsole.log(c.join(','));\nconsole.log(d.join(','));\n","\u002F\u002F Упражнение 11: коллекции, итерация, массивы и строки\n\u002F\u002F Темы sort строковое сравнение и мутация\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS методы массивов sort https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F05-array-methods\u002Farticle.md\n\u002F\u002F MDN Array sort https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fsort\u002Findex.md\nconst a = [10, 2, 1];\n\n\u002F\u002F Без функции сравнения sort приводит элементы к строкам.\n\u002F\u002F Поэтому 10 идет перед 2.\n\u002F\u002F sort меняет исходный массив и возвращает его же.\nconst b = a.sort();\n\nconsole.log(a.join(','));\nconsole.log(b === a);\n\nconst c = [10, 2, 1];\n\n\u002F\u002F Если исходный массив менять нельзя сначала делаем копию.\n\u002F\u002F Числовая функция сравнения задает нужный порядок чисел.\nconst d = [...c].sort((b, c) => b - c);\n\nconsole.log(c.join(','));\nconsole.log(d.join(','));","1,10,2\ntrue\n10,2,1\n1,2,10",{"slug":1010,"title":1011,"source":1012,"exerciseCode":1013,"tutorialCode":1014,"expectedOutput":1015,"executionExplanation":1014,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":1001,"status":13},"event-loop-promises-async-await-ex11","Упражнение 11: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex11","const a = Promise.reject('a');\nconst b = new Promise((resolve) => {\n  setTimeout(() => resolve('b'), 0);\n});\n\nPromise.race([a, b]).catch((c) => console.log('1:', c));\nPromise.any([a, b]).then((c) => console.log('2:', c));\n\nconsole.log('3');\n","\u002F\u002F Упражнение 11: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы Promise race и Promise any\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Promise API https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F05-promise-api\u002Farticle.md\n\u002F\u002F MDN Promise.race https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Frace\u002Findex.md\n\u002F\u002F MDN Promise.any https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fany\u002Findex.md\nconst a = Promise.reject('a');\nconst b = new Promise((resolve) => {\n  setTimeout(() => resolve('b'), 0);\n});\n\n\u002F\u002F race берет первое завершение независимо от успеха или ошибки.\nPromise.race([a, b]).catch((c) => console.log('1:', c));\n\n\u002F\u002F any ждет первый успешный результат и пропускает rejected входы.\nPromise.any([a, b]).then((c) => console.log('2:', c));\n\nconsole.log('3');","3\n1: a\n2: b",{"slug":1017,"title":1018,"source":1019,"exerciseCode":1020,"tutorialCode":1021,"expectedOutput":1022,"executionExplanation":1021,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":1001,"status":13},"event-loop-promises-deep-dive-ex11","Дополнительное упражнение 11: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex11","function f(a) {\n  return new Promise((resolve) => {\n    console.log('1:', a);\n\n    setTimeout(() => {\n      console.log('2:', a);\n      resolve(a);\n    }, 0);\n  });\n}\n\nasync function g() {\n  const a = await f('a');\n  const b = await f('b');\n\n  console.log('3:', a, b);\n}\n\ng();\n\nconsole.log('4');\n","\u002F\u002F Дополнительное упражнение 11: углубленная практика по event loop и Promise\n\u002F\u002F Темы последовательный запуск через await\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS async await https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md\n\u002F\u002F YDKJS async performance https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fasync%20%26%20performance\u002Fch3.md\nfunction f(a) {\n  return new Promise((resolve) => {\n    console.log('1:', a);\n\n    setTimeout(() => {\n      console.log('2:', a);\n      resolve(a);\n    }, 0);\n  });\n}\n\nasync function g() {\n  \u002F\u002F Второй вызов f начнется только после результата первого await.\n  const a = await f('a');\n  const b = await f('b');\n\n  console.log('3:', a, b);\n}\n\ng();\n\nconsole.log('4');","1: a\n4\n2: a\n1: b\n2: b\n3: a b",{"slug":1024,"title":1025,"source":1026,"exerciseCode":1027,"tutorialCode":1028,"expectedOutput":753,"executionExplanation":1028,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":1001,"status":13},"objects-prototypes-classes-ex11","Упражнение 11: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex11","class A {\n  constructor() {\n    this.x = 1;\n  }\n\n  f() {\n    return this.x;\n  }\n}\n\nconst a = new A();\nconst b = a.f;\n\ntry {\n  A();\n} catch (error) {\n  console.log('1:', error.name);\n}\n\ntry {\n  b();\n} catch (error) {\n  console.log('2:', error.name);\n}\n\nconsole.log('3:', a.f());\n","\u002F\u002F Упражнение 11: свойства объектов, прототипы и классы\n\u002F\u002F Темы class constructor без new strict mode и потеря this\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS классы https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F01-class\u002Farticle.md\n\u002F\u002F MDN classes https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Findex.md\nclass A {\n  constructor() {\n    this.x = 1;\n  }\n\n  f() {\n    \u002F\u002F Код внутри class body всегда strict mode.\n    \u002F\u002F Если метод вызвать без объекта слева от точки то this будет undefined.\n    return this.x;\n  }\n}\n\nconst a = new A();\nconst b = a.f;\n\ntry {\n  \u002F\u002F Class constructor нельзя вызвать как обычную функцию.\n  A();\n} catch (error) {\n  console.log('1:', error.name);\n}\n\ntry {\n  \u002F\u002F Здесь метод потерял объект вызова.\n  \u002F\u002F Внутри f значение this будет undefined.\n  b();\n} catch (error) {\n  console.log('2:', error.name);\n}\n\n\u002F\u002F При вызове через точку this снова равен a.\nconsole.log('3:', a.f());",{"slug":1030,"title":1031,"source":1032,"exerciseCode":1033,"tutorialCode":1034,"expectedOutput":1035,"executionExplanation":1034,"language":65,"runtime":66,"programSlug":50,"lessonSlug":50,"order":1001,"status":13},"recursion-ex11","Упражнение 11: рекурсия","mentoring\u002Frecursion\u002Fex\u002Fex11","function f(a) {\n  if (a === 0) {\n    return true;\n  }\n\n  return g(a - 1);\n}\n\nfunction g(a) {\n  if (a === 0) {\n    return false;\n  }\n\n  return f(a - 1);\n}\n\nconsole.log(f(4));\nconsole.log(f(5));\n","\u002F\u002F Упражнение 11: рекурсия\n\u002F\u002F Темы взаимная рекурсия\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Recursion https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md\nfunction f(a) {\n  \u002F\u002F f отвечает true для нуля.\n  if (a === 0) {\n    return true;\n  }\n\n  \u002F\u002F И передает меньшую задачу в g.\n  return g(a - 1);\n}\n\nfunction g(a) {\n  \u002F\u002F g отвечает false для нуля.\n  if (a === 0) {\n    return false;\n  }\n\n  \u002F\u002F И передает меньшую задачу обратно в f.\n  return f(a - 1);\n}\n\nconsole.log(f(4));\nconsole.log(f(5));","true\nfalse",{"slug":1037,"title":1038,"source":1039,"exerciseCode":1040,"tutorialCode":1041,"expectedOutput":972,"executionExplanation":1041,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1001,"status":13},"rendering-dom-events-forms-ex11","Упражнение 11: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex11","const a = document.createElement('div');\n\na.style.width = '10px';\na.style.height = '10px';\ndocument.body.append(a);\n\nlet b = '1';\n\nconst c = new IntersectionObserver((d) => {\n  b = d[0].isIntersecting.toString();\n});\n\nc.observe(a);\n\nconsole.log(b);\n","\u002F\u002F Упражнение 11: рендеринг, DOM, события и формы\n\u002F\u002F Темы IntersectionObserver и асинхронное наблюдение за viewport\n\u002F\u002F Читать дальше\n\u002F\u002F MDN IntersectionObserver https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fintersectionobserver\u002Findex.md\n\u002F\u002F MDN Critical rendering path https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fperformance\u002Fguides\u002Fcritical_rendering_path\u002Findex.md\nconst a = document.createElement('div');\n\na.style.width = '10px';\na.style.height = '10px';\ndocument.body.append(a);\n\nlet b = '1';\n\nconst c = new IntersectionObserver((d) => {\n  \u002F\u002F Элемент добавлен в начало body и попадает в viewport.\n  \u002F\u002F Observer сообщает это не синхронно в момент observe.\n  b = d[0].isIntersecting.toString();\n});\n\nc.observe(a);\n\n\u002F\u002F Прямо сейчас callback observer еще не успел поменять b.\n\u002F\u002F Поэтому видим старое значение.\nconsole.log(b);",{"slug":1043,"title":1044,"source":1045,"exerciseCode":1046,"tutorialCode":1047,"expectedOutput":1048,"executionExplanation":1047,"language":65,"runtime":66,"programSlug":19,"lessonSlug":19,"order":1001,"status":13},"scope-closures-deep-dive-ex11","Дополнительное упражнение 11: углубленная практика по областям видимости и замыканиям","mentoring\u002Fscope-closures-deep-dive\u002Fex\u002Fex11","function f(x) {\n  with (x) {\n    a = 2;\n  }\n}\n\nvar x = {\n  a: 3,\n};\n\nvar y = {\n  b: 3,\n};\n\nf(x);\nconsole.log('1:', x.a);\n\nf(y);\nconsole.log('2:', y.a);\nconsole.log('3:', a);\n","\u002F\u002F Дополнительное упражнение 11: углубленная практика по областям видимости и замыканиям\n\u002F\u002F Темы: with, LHS поиск и неявная глобальная переменная в sloppy mode.\n\u002F\u002F Читать дальше\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch2.md раздел with\n\u002F\u002F MDN with https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Fwith\n\nfunction f(x) {\n  \u002F\u002F with временно рассматривает свойства x как имена в отдельной области.\n  with (x) {\n    \u002F\u002F Это присваивание сначала пытается найти имя a внутри объекта x.\n    a = 2;\n  }\n}\n\nvar x = {\n  a: 3,\n};\n\nvar y = {\n  b: 3,\n};\n\n\u002F\u002F В x есть свойство a.\n\u002F\u002F Поэтому присваивание внутри with меняет x.a.\nf(x);\nconsole.log('1:', x.a);\n\n\u002F\u002F В y свойства a нет.\n\u002F\u002F В sloppy mode присваивание в неизвестное имя создает глобальную переменную.\nf(y);\nconsole.log('2:', y.a);\nconsole.log('3:', a);","1: 2\n2: undefined\n3: 2",{"slug":1050,"title":1051,"source":1052,"exerciseCode":1053,"tutorialCode":1054,"expectedOutput":1055,"executionExplanation":1054,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":1001,"status":13},"scope-hoisting-closures-this-ex11","Упражнение 11: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex11","const a = {\n  x: 'a',\n};\n\na.x = 'b';\n\nconsole.log('1:', a.x);\n\ntry {\n  a = {\n    x: 'c',\n  };\n} catch (error) {\n  console.log('2:', error.name);\n}\n","\u002F\u002F Упражнение 11: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: const и изменение объекта.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS переменные и const https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F04-variables\u002Farticle.md\n\u002F\u002F Learn JS объекты и const https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F02-object-copy\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch3.md#L580 раздел const\n\u002F\u002F MDN const https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Fconst\n\n\u002F\u002F const запрещает переприсваивать переменную a.\n\u002F\u002F Но сама переменная хранит ссылку на объект.\nconst a = {\n  x: 'a',\n};\n\n\u002F\u002F Менять свойство объекта можно.\n\u002F\u002F Мы не переприсваиваем a, а меняем объект по ссылке.\na.x = 'b';\n\nconsole.log('1:', a.x);\n\ntry {\n  \u002F\u002F А здесь уже попытка записать в a новую ссылку.\n  \u002F\u002F Для const это запрещено.\n  a = {\n    x: 'c',\n  };\n} catch (error) {\n  console.log('2:', error.name);\n}","1: b\n2: TypeError",{"slug":1057,"title":1058,"source":1059,"exerciseCode":1060,"tutorialCode":1061,"expectedOutput":1062,"executionExplanation":1061,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":1001,"status":13},"types-coercion-symbol-json-ex11","Упражнение 11: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex11","const a = Symbol('a');\nconst b = {\n  x: a,\n  y: 2,\n  [a]: 1,\n};\n\nconsole.log('1:', String(a));\n\ntry {\n  console.log('2:', '' + a);\n} catch (error) {\n  console.log('2:', error.name);\n}\n\nconsole.log('3:', JSON.stringify(a));\nconsole.log('4:', JSON.stringify([a]));\nconsole.log('5:', JSON.stringify(b));\nconsole.log('6:', Object.getOwnPropertySymbols(b).length);\n","\u002F\u002F Упражнение 11: типы, приведение, Symbol и JSON\n\u002F\u002F Темы Symbol, строковое приведение и JSON.stringify\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Symbol https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F08-symbol\u002Farticle.md\n\u002F\u002F Learn JS JSON.stringify https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F12-json\u002Farticle.md\n\u002F\u002F MDN Symbol\n\u002F\u002F MDN JSON.stringify\n\u002F\u002F MDN TypeError can't convert symbol to string\nconst a = Symbol('a');\nconst b = {\n  x: a,\n  y: 2,\n  [a]: 1,\n};\n\n\u002F\u002F Явный вызов String умеет превращать Symbol в строку.\nconsole.log('1:', String(a));\n\ntry {\n  \u002F\u002F Неявное строковое приведение через плюс для Symbol запрещено.\n  console.log('2:', '' + a);\n} catch (error) {\n  console.log('2:', error.name);\n}\n\n\u002F\u002F JSON.stringify для самого Symbol возвращает undefined.\nconsole.log('3:', JSON.stringify(a));\n\n\u002F\u002F В массиве Symbol заменяется на null.\n\u002F\u002F Так JSON сохраняет позицию элемента.\nconsole.log('4:', JSON.stringify([a]));\n\n\u002F\u002F В объекте свойство со значением Symbol пропадает.\n\u002F\u002F Symbol ключ тоже пропадает из JSON.\nconsole.log('5:', JSON.stringify(b));\n\n\u002F\u002F При этом Symbol ключ все еще есть в самом объекте.\nconsole.log('6:', Object.getOwnPropertySymbols(b).length);","1 Symbol(a)\n2 TypeError\n3 undefined\n4 [null]\n5 {\"y\":2}\n6 1",{"slug":1064,"title":1065,"source":1066,"exerciseCode":1067,"tutorialCode":1068,"expectedOutput":1069,"executionExplanation":1068,"language":65,"runtime":66,"programSlug":40,"lessonSlug":40,"order":1070,"status":13},"browser-network-ex12","Упражнение 12: сеть в браузере","mentoring\u002Fbrowser-network\u002Fex\u002Fex12","(async () => {\n  const a = new Blob(['1'], {\n    type: 'text\u002Fplain',\n  });\n  const b = URL.createObjectURL(a);\n  const c = await fetch(b);\n\n  console.log(c.ok);\n  console.log(c.headers.get('content-type'));\n  console.log(await c.text());\n\n  URL.revokeObjectURL(b);\n})();\n","\u002F\u002F Упражнение 12: сеть в браузере\n\u002F\u002F Темы Blob object URL fetch и освобождение URL\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Blob https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fblob\u002Findex.md\n\u002F\u002F MDN URL createObjectURL https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Furl\u002Fcreateobjecturl_static\u002Findex.md\n(async () => {\n  const a = new Blob(['1'], {\n    type: 'text\u002Fplain',\n  });\n  const b = URL.createObjectURL(a);\n  const c = await fetch(b);\n\n  \u002F\u002F Object URL дает браузеру временный адрес для данных в памяти.\n  \u002F\u002F fetch может читать такой адрес как обычный ресурс.\n  console.log(c.ok);\n  console.log(c.headers.get('content-type'));\n  console.log(await c.text());\n\n  \u002F\u002F Когда адрес больше не нужен, освобождаем его.\n  URL.revokeObjectURL(b);\n})();","true\ntext\u002Fplain\n1",12,{"slug":1072,"title":1073,"source":1074,"exerciseCode":1075,"tutorialCode":1076,"expectedOutput":1077,"executionExplanation":1076,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":1070,"status":13},"collections-iteration-arrays-ex12","Упражнение 12: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex12","const a = [1, 2, 3, 4, 5];\nconst b = a.filter((c) => c % 2 === 1).map((c) => c * 10);\n\nconsole.log(b.join(','));\nconsole.log(a.find((c) => c > 3));\nconsole.log(a.some((c) => c > 4));\nconsole.log(a.every((c) => c > 0));\nconsole.log(a.join(','));\n","\u002F\u002F Упражнение 12: коллекции, итерация, массивы и строки\n\u002F\u002F Темы map filter find some every\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS методы массивов https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F05-array-methods\u002Farticle.md\n\u002F\u002F MDN Array map https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fmap\u002Findex.md\n\u002F\u002F MDN Array filter https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Ffilter\u002Findex.md\n\u002F\u002F MDN Array find https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Ffind\u002Findex.md\n\u002F\u002F MDN Array some https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fsome\u002Findex.md\n\u002F\u002F MDN Array every https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fevery\u002Findex.md\nconst a = [1, 2, 3, 4, 5];\n\n\u002F\u002F filter оставляет только подходящие элементы.\n\u002F\u002F map превращает каждый оставшийся элемент в новое значение.\n\u002F\u002F Эти методы возвращают новый массив.\nconst b = a.filter((c) => c % 2 === 1).map((c) => c * 10);\n\nconsole.log(b.join(','));\n\n\u002F\u002F find возвращает первый подходящий элемент.\nconsole.log(a.find((c) => c > 3));\n\n\u002F\u002F some проверяет есть ли хотя бы один подходящий элемент.\nconsole.log(a.some((c) => c > 4));\n\n\u002F\u002F every проверяет подходят ли все элементы.\nconsole.log(a.every((c) => c > 0));\n\n\u002F\u002F Исходный массив не изменился.\nconsole.log(a.join(','));","10,30,50\n4\ntrue\ntrue\n1,2,3,4,5",{"slug":1079,"title":1080,"source":1081,"exerciseCode":1082,"tutorialCode":1083,"expectedOutput":1084,"executionExplanation":1083,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":1070,"status":13},"event-loop-promises-async-await-ex12","Упражнение 12: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex12","queueMicrotask(() => {\n  console.log('1');\n  queueMicrotask(() => console.log('2'));\n});\n\nPromise.resolve().then(() => console.log('3'));\n\nconsole.log('4');\n","\u002F\u002F Упражнение 12: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы queueMicrotask и порядок микрозадач FIFO\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS микрозадачи https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md\n\u002F\u002F Learn JS event loop https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F99-ui-misc\u002F03-event-loop\u002Farticle.md\n\u002F\u002F MDN microtask guide https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtml_dom_api\u002Fmicrotask_guide\u002Findex.md\nqueueMicrotask(() => {\n  console.log('1');\n\n  \u002F\u002F Новая микрозадача добавляется в конец очереди.\n  queueMicrotask(() => console.log('2'));\n});\n\n\u002F\u002F then тоже добавляет микрозадачу.\nPromise.resolve().then(() => console.log('3'));\n\nconsole.log('4');","4\n1\n3\n2",{"slug":1086,"title":1087,"source":1088,"exerciseCode":1089,"tutorialCode":1090,"expectedOutput":1091,"executionExplanation":1090,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":1070,"status":13},"event-loop-promises-deep-dive-ex12","Дополнительное упражнение 12: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex12","const a = new AbortController();\n\na.signal.addEventListener('abort', () => {\n  console.log('1:', a.signal.aborted);\n});\n\na.abort('a');\n\na.signal.addEventListener('abort', () => console.log('2'));\n\nconsole.log('3:', a.signal.aborted, a.signal.reason);\n\na.abort('b');\n\nconsole.log('4:', a.signal.reason);\n","\u002F\u002F Дополнительное упражнение 12: углубленная практика по event loop и Promise\n\u002F\u002F Темы AbortController и однократная отмена\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Fetch abort https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F5-network\u002F04-fetch-abort\u002Farticle.md\n\u002F\u002F MDN AbortController https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fabortcontroller\u002Findex.md\nconst a = new AbortController();\n\na.signal.addEventListener('abort', () => {\n  \u002F\u002F abort событие вызывается во время первого abort.\n  console.log('1:', a.signal.aborted);\n});\n\n\u002F\u002F Первый abort переводит signal в состояние aborted и сохраняет reason.\na.abort('a');\n\n\u002F\u002F Поздняя подписка не запускается задним числом.\na.signal.addEventListener('abort', () => console.log('2'));\n\nconsole.log('3:', a.signal.aborted, a.signal.reason);\n\n\u002F\u002F Повторный abort уже не меняет reason.\na.abort('b');\n\nconsole.log('4:', a.signal.reason);","1: true\n3: true a\n4: a",{"slug":1093,"title":1094,"source":1095,"exerciseCode":1096,"tutorialCode":1097,"expectedOutput":1098,"executionExplanation":1097,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":1070,"status":13},"objects-prototypes-classes-ex12","Упражнение 12: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex12","class A {\n  x = 1;\n  y = this.x + 1;\n\n  constructor() {\n    console.log('1:', this.x, this.y);\n    this.x = 3;\n  }\n}\n\nconst a = new A();\n\nconsole.log('2:', a.x, a.y);\nconsole.log('3:', Object.hasOwn(a, 'x'), Object.hasOwn(A.prototype, 'x'));\n","\u002F\u002F Упражнение 12: свойства объектов, прототипы и классы\n\u002F\u002F Темы public fields и порядок инициализации базового класса\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS свойства классов https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F01-class\u002Farticle.md\n\u002F\u002F MDN public class fields https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fpublic_class_fields\u002Findex.md\nclass A {\n  \u002F\u002F В базовом классе public fields создаются до тела constructor.\n  x = 1;\n\n  \u002F\u002F Инициализаторы идут сверху вниз.\n  y = this.x + 1;\n\n  constructor() {\n    \u002F\u002F constructor уже видит x и y.\n    console.log('1:', this.x, this.y);\n\n    \u002F\u002F Меняем только x.\n    \u002F\u002F y не пересчитается автоматически.\n    this.x = 3;\n  }\n}\n\nconst a = new A();\n\nconsole.log('2:', a.x, a.y);\n\n\u002F\u002F Public fields создаются как собственные свойства экземпляра.\nconsole.log('3:', Object.hasOwn(a, 'x'), Object.hasOwn(A.prototype, 'x'));","1 1 2\n2 3 2\n3 true false",{"slug":1100,"title":1101,"source":1102,"exerciseCode":1103,"tutorialCode":1104,"expectedOutput":831,"executionExplanation":1104,"language":65,"runtime":66,"programSlug":50,"lessonSlug":50,"order":1070,"status":13},"recursion-ex12","Упражнение 12: рекурсия","mentoring\u002Frecursion\u002Fex\u002Fex12","let a = function b(c) {\n  if (c === 0) {\n    return 0;\n  }\n\n  return 1 + b(c - 1);\n};\n\nconst d = a;\na = null;\n\nconsole.log(d(3));\n","\u002F\u002F Упражнение 12: рекурсия\n\u002F\u002F Темы имя function expression и саморекурсия\n\u002F\u002F Читать дальше\n\u002F\u002F ECMAScript Function Definitions https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-function-definitions\n\u002F\u002F YDKJS self reference https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fes6%20%26%20beyond\u002Fch2.md\nlet a = function b(c) {\n  \u002F\u002F Имя b доступно внутри самой функции.\n  \u002F\u002F Оно указывает на эту функцию, а не на внешнюю переменную a.\n  if (c === 0) {\n    return 0;\n  }\n\n  return 1 + b(c - 1);\n};\n\nconst d = a;\na = null;\n\n\u002F\u002F Внешнюю переменную a мы изменили.\n\u002F\u002F Но внутри функции имя b все еще работает для рекурсии.\nconsole.log(d(3));",{"slug":1106,"title":1107,"source":1108,"exerciseCode":1109,"tutorialCode":1110,"expectedOutput":1111,"executionExplanation":1110,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1070,"status":13},"rendering-dom-events-forms-ex12","Упражнение 12: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex12","const a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '20px';\na.style.overflow = 'auto';\ndocument.body.append(a);\n\nconsole.log(a.scrollHeight);\n\nconst b = document.createElement('div');\n\nb.style.height = '50px';\na.append(b);\n\nconsole.log(a.scrollHeight);\n","\u002F\u002F Упражнение 12: рендеринг, DOM, события и формы\n\u002F\u002F Темы scrollHeight и layout после добавления контента\n\u002F\u002F Читать дальше\n\u002F\u002F MDN CSS performance https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Flearn_web_development\u002Fextensions\u002Fperformance\u002Fcss\u002Findex.md\n\u002F\u002F MDN CSSOM view https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fcss_object_model\u002Findex.md\nconst a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '20px';\na.style.overflow = 'auto';\ndocument.body.append(a);\n\n\u002F\u002F scrollHeight показывает высоту содержимого.\n\u002F\u002F Пока внутри нет более высокого контента, она равна высоте самого блока.\nconsole.log(a.scrollHeight);\n\nconst b = document.createElement('div');\n\nb.style.height = '50px';\na.append(b);\n\n\u002F\u002F После добавления вложенного блока содержимое стало выше видимой области.\n\u002F\u002F Чтение scrollHeight возвращает уже пересчитанное значение.\nconsole.log(a.scrollHeight);","20\n50",{"slug":1113,"title":1114,"source":1115,"exerciseCode":1116,"tutorialCode":1117,"expectedOutput":1118,"executionExplanation":1117,"language":65,"runtime":66,"programSlug":19,"lessonSlug":19,"order":1070,"status":13},"scope-closures-deep-dive-ex12","Дополнительное упражнение 12: углубленная практика по областям видимости и замыканиям","mentoring\u002Fscope-closures-deep-dive\u002Fex\u002Fex12","var a = 'b';\n\nvar x = {\n  a: 'a',\n\n  f() {\n    console.log('1:', this.a);\n  },\n\n  g() {\n    setTimeout(this.f, 0);\n  },\n\n  h() {\n    setTimeout(\n      function () {\n        console.log('2:', this.a);\n      }.bind(this),\n      0,\n    );\n  },\n};\n\nx.f();\nx.g();\nx.h();\n","\u002F\u002F Дополнительное упражнение 12: углубленная практика по областям видимости и замыканиям\n\u002F\u002F Темы: setTimeout, потеря this и bind.\n\u002F\u002F Читать дальше\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002FapC.md приложение C Лексический this\n\u002F\u002F MDN setTimeout https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FWindow\u002FsetTimeout\n\u002F\u002F MDN bind https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FFunction\u002Fbind\n\n\u002F\u002F В browser script var a становится свойством window.a.\nvar a = 'b';\n\nvar x = {\n  a: 'a',\n\n  f() {\n    \u002F\u002F this зависит от способа вызова функции.\n    console.log('1:', this.a);\n  },\n\n  g() {\n    \u002F\u002F Здесь мы передаем в setTimeout значение метода.\n    \u002F\u002F Связь с объектом x теряется.\n    setTimeout(this.f, 0);\n  },\n\n  h() {\n    \u002F\u002F Третий аргумент setTimeout передает аргумент в callback, а не this.\n    \u002F\u002F Чтобы сохранить this, передаем уже привязанную функцию.\n    setTimeout(\n      function () {\n        console.log('2:', this.a);\n      }.bind(this),\n      0,\n    );\n  },\n};\n\n\u002F\u002F Вызов через объект дает this === x.\nx.f();\n\n\u002F\u002F Таймер вызовет функцию без исходного объекта.\n\u002F\u002F В браузере обычная функция внутри setTimeout получает this === window.\nx.g();\n\n\u002F\u002F bind заранее фиксирует this из вызова x.h().\nx.h();","1: a\n1: b\n2: a",{"slug":1120,"title":1121,"source":1122,"exerciseCode":1123,"tutorialCode":1124,"expectedOutput":1125,"executionExplanation":1124,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":1070,"status":13},"scope-hoisting-closures-this-ex12","Упражнение 12: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex12","function f(a) {\n  try {\n    console.log('1:', b);\n  } catch (error) {\n    console.log('1:', error.name);\n  }\n\n  b = a;\n\n  console.log('2:', window.b);\n}\n\nf(2);\n\nfunction g(a) {\n  'use strict';\n\n  try {\n    c = a;\n  } catch (error) {\n    console.log('3:', error.name);\n  }\n}\n\ng(3);\n\nconsole.log('4:', window.c);\n\ndelete window.b;\n","\u002F\u002F Упражнение 12: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: LHS и RHS поиск, случайная глобальная переменная, strict mode.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS лексическое окружение и поиск переменных https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md\n\u002F\u002F Learn JS переменные без use strict https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F04-variables\u002Farticle.md\n\u002F\u002F Learn JS строгий режим https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F03-strict-mode\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch1.md#L82 раздел Компилятор расскажет\n\u002F\u002F MDN Strict mode https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStrict_mode\n\u002F\u002F MDN Window https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FWindow\n\nfunction f(a) {\n  try {\n    \u002F\u002F Здесь b находится справа от чтения значения.\n    \u002F\u002F Движку нужно прочитать b, это RHS поиск.\n    \u002F\u002F Переменной b нет ни в локальной, ни во внешней области.\n    \u002F\u002F Поэтому чтение падает с ReferenceError.\n    console.log('1:', b);\n  } catch (error) {\n    console.log('1:', error.name);\n  }\n\n  \u002F\u002F Здесь b находится слева от присваивания.\n  \u002F\u002F Это LHS поиск.\n  \u002F\u002F В нестрогом режиме, если переменная не найдена, создается свойство window.\n  b = a;\n\n  \u002F\u002F Поэтому после присваивания значение можно увидеть на глобальном объекте.\n  console.log('2:', window.b);\n}\n\nf(2);\n\nfunction g(a) {\n  'use strict';\n\n  try {\n    \u002F\u002F В strict mode нельзя создать глобальную переменную случайным LHS присваиванием.\n    \u002F\u002F Поэтому эта строка бросит ReferenceError.\n    c = a;\n  } catch (error) {\n    console.log('3:', error.name);\n  }\n}\n\ng(3);\n\n\u002F\u002F Свойство c на window не появилось.\nconsole.log('4:', window.c);\n\n\u002F\u002F Убираем свойство b, созданное в нестрогом режиме.\ndelete window.b;","1: ReferenceError\n2: 2\n3: ReferenceError\n4: undefined",{"slug":1127,"title":1128,"source":1129,"exerciseCode":1130,"tutorialCode":1131,"expectedOutput":1132,"executionExplanation":1131,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":1070,"status":13},"types-coercion-symbol-json-ex12","Упражнение 12: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex12","const a = [NaN, undefined, Infinity, function f() {}];\nconst b = {\n  x: undefined,\n  y: NaN,\n  z: Infinity,\n  f() {},\n};\n\nconsole.log('1:', JSON.stringify(a));\nconsole.log('2:', JSON.stringify(b));\n","\u002F\u002F Упражнение 12: типы, приведение, Symbol и JSON\n\u002F\u002F Темы JSON.stringify и специальные значения\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS JSON.stringify https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F12-json\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md\n\u002F\u002F MDN JSON.stringify\nconst a = [NaN, undefined, Infinity, function f() {}];\nconst b = {\n  x: undefined,\n  y: NaN,\n  z: Infinity,\n  f() {},\n};\n\n\u002F\u002F В массиве специальные значения заменяются на null.\n\u002F\u002F Это сохраняет позиции элементов.\nconsole.log('1:', JSON.stringify(a));\n\n\u002F\u002F В объекте undefined и функция пропадают как свойства.\n\u002F\u002F NaN и Infinity превращаются в null.\nconsole.log('2:', JSON.stringify(b));","1 [null,null,null,null]\n2 {\"y\":null,\"z\":null}",{"slug":1134,"title":1135,"source":1136,"exerciseCode":1137,"tutorialCode":1138,"expectedOutput":1139,"executionExplanation":1138,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":1140,"status":13},"collections-iteration-arrays-ex13","Упражнение 13: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex13","const a = [1, 2, 3];\n\nconsole.log(a.reduce((b, c) => b + c));\nconsole.log(a.reduce((b, c) => b + c, 10));\n\ntry {\n  console.log([].reduce((b, c) => b + c));\n} catch (error) {\n  console.log(error.name);\n}\n","\u002F\u002F Упражнение 13: коллекции, итерация, массивы и строки\n\u002F\u002F Темы reduce и начальное значение\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS reduce https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F05-array-methods\u002Farticle.md\n\u002F\u002F MDN Array reduce https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Freduce\u002Findex.md\nconst a = [1, 2, 3];\n\n\u002F\u002F Без начального значения reduce берет первый элемент как аккумулятор.\nconsole.log(a.reduce((b, c) => b + c));\n\n\u002F\u002F С начальным значением reduce начинает с 10.\nconsole.log(a.reduce((b, c) => b + c, 10));\n\ntry {\n  \u002F\u002F У пустого массива нет первого элемента.\n  \u002F\u002F Без initialValue reduce не может создать аккумулятор.\n  console.log([].reduce((b, c) => b + c));\n} catch (error) {\n  console.log(error.name);\n}","6\n16\nTypeError",13,{"slug":1142,"title":1143,"source":1144,"exerciseCode":1145,"tutorialCode":1146,"expectedOutput":1147,"executionExplanation":1146,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":1140,"status":13},"event-loop-promises-async-await-ex13","Упражнение 13: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex13","async function f() {\n  const a = [1, 2];\n\n  a.forEach(async (b) => {\n    await Promise.resolve();\n    console.log('1:', b);\n  });\n\n  for (const b of a) {\n    await Promise.resolve();\n    console.log('2:', b);\n  }\n\n  console.log('3');\n}\n\nf();\n\nconsole.log('4');\n","\u002F\u002F Упражнение 13: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы async callback, forEach и последовательный for of\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS async await https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md\n\u002F\u002F Learn JS Array methods https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F05-array-methods\u002Farticle.md\nasync function f() {\n  const a = [1, 2];\n\n  \u002F\u002F forEach не ждет промисы из async callback.\n  a.forEach(async (b) => {\n    await Promise.resolve();\n    console.log('1:', b);\n  });\n\n  \u002F\u002F for of внутри async-функции можно остановить через await на каждой итерации.\n  for (const b of a) {\n    await Promise.resolve();\n    console.log('2:', b);\n  }\n\n  console.log('3');\n}\n\nf();\n\nconsole.log('4');","4\n1: 1\n1: 2\n2: 1\n2: 2\n3",{"slug":1149,"title":1150,"source":1151,"exerciseCode":1152,"tutorialCode":1153,"expectedOutput":1154,"executionExplanation":1153,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":1140,"status":13},"event-loop-promises-deep-dive-ex13","Дополнительное упражнение 13: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex13","console.log('1');\n\nsetTimeout(() => {\n  console.log('2');\n\n  Promise.resolve().then(() => {\n    console.log('3');\n    queueMicrotask(() => console.log('4'));\n  });\n\n  queueMicrotask(() => console.log('5'));\n}, 0);\n\nPromise.resolve()\n  .then(() => {\n    console.log('6');\n    setTimeout(() => console.log('7'), 0);\n\n    return Promise.resolve('a').then((a) => {\n      console.log('8:', a);\n\n      return 'b';\n    });\n  })\n  .then((a) => console.log('9:', a));\n\nqueueMicrotask(() => {\n  console.log('10');\n  Promise.resolve().then(() => console.log('11'));\n});\n\nconsole.log('12');\n","\u002F\u002F Дополнительное упражнение 13: углубленная практика по event loop и Promise\n\u002F\u002F Темы вложенные микрозадачи, таймеры и возвращение Promise из then\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS event loop https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F99-ui-misc\u002F03-event-loop\u002Farticle.md\n\u002F\u002F Learn JS promise chaining https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F03-promise-chaining\u002Farticle.md\n\u002F\u002F MDN microtask guide https:\u002F\u002Fdeveloper.mozilla.org\u002Fdocs\u002FWeb\u002FAPI\u002FHTML_DOM_API\u002FMicrotask_guide\nconsole.log('1');\n\nsetTimeout(() => {\n  console.log('2');\n\n  Promise.resolve().then(() => {\n    \u002F\u002F Эта микрозадача появилась внутри первого таймера.\n    console.log('3');\n\n    \u002F\u002F Новая микрозадача встает в конец текущей очереди микрозадач.\n    queueMicrotask(() => console.log('4'));\n  });\n\n  queueMicrotask(() => console.log('5'));\n}, 0);\n\nPromise.resolve()\n  .then(() => {\n    console.log('6');\n\n    \u002F\u002F Таймер создан внутри микрозадачи, поэтому он встанет после таймера с 2.\n    setTimeout(() => console.log('7'), 0);\n\n    return Promise.resolve('a').then((a) => {\n      console.log('8:', a);\n\n      return 'b';\n    });\n  })\n  .then((a) => console.log('9:', a));\n\nqueueMicrotask(() => {\n  console.log('10');\n\n  \u002F\u002F Эта микрозадача успевает встать перед продолжением со значением b.\n  Promise.resolve().then(() => console.log('11'));\n});\n\nconsole.log('12');","1\n12\n6\n10\n8: a\n11\n9: b\n2\n3\n5\n4\n7",{"slug":1156,"title":1157,"source":1158,"exerciseCode":1159,"tutorialCode":1160,"expectedOutput":1161,"executionExplanation":1160,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":1140,"status":13},"objects-prototypes-classes-ex13","Упражнение 13: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex13","class A {\n  x = [];\n\n  f() {\n    return this.x;\n  }\n}\n\nconst a = new A();\nconst b = new A();\n\na.x.push(1);\n\nconsole.log('1:', a.x.length, b.x.length);\nconsole.log('2:', a.x === b.x, a.f === b.f);\nconsole.log('3:', a.f() === a.x);\n","\u002F\u002F Упражнение 13: свойства объектов, прототипы и классы\n\u002F\u002F Темы поля экземпляра и общие методы прототипа\n\u002F\u002F Читать дальше\n\u002F\u002F MDN public class fields https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fpublic_class_fields\u002Findex.md\n\u002F\u002F MDN classes methods https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Findex.md\nclass A {\n  \u002F\u002F Инициализатор поля выполняется для каждого нового экземпляра.\n  \u002F\u002F Поэтому два экземпляра получат разные массивы.\n  x = [];\n\n  f() {\n    \u002F\u002F Метод общий и находится на A.prototype.\n    return this.x;\n  }\n}\n\nconst a = new A();\nconst b = new A();\n\na.x.push(1);\n\nconsole.log('1:', a.x.length, b.x.length);\n\n\u002F\u002F Поля разные потому что они собственные для каждого экземпляра.\n\u002F\u002F Метод один и тот же потому что он живет на прототипе.\nconsole.log('2:', a.x === b.x, a.f === b.f);\nconsole.log('3:', a.f() === a.x);","1 1 0\n2 false true\n3 true",{"slug":1163,"title":1164,"source":1165,"exerciseCode":1166,"tutorialCode":1167,"expectedOutput":469,"executionExplanation":1167,"language":65,"runtime":66,"programSlug":50,"lessonSlug":50,"order":1140,"status":13},"recursion-ex13","Упражнение 13: рекурсия","mentoring\u002Frecursion\u002Fex\u002Fex13","function f(a, b = 0) {\n  if (a === 0) {\n    return b;\n  }\n\n  return f(a - 1, b + a);\n}\n\nconsole.log(f(4));\n","\u002F\u002F Упражнение 13: рекурсия\n\u002F\u002F Темы аккумулятор и хвостовая форма\n\u002F\u002F Читать дальше\n\u002F\u002F YDKJS tail calls https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fes6%20%26%20beyond\u002Fch7.md\nfunction f(a, b = 0) {\n  \u002F\u002F b хранит уже накопленную сумму.\n  if (a === 0) {\n    return b;\n  }\n\n  \u002F\u002F Рекурсивный вызов это последнее действие функции.\n  \u002F\u002F После него текущему вызову уже нечего досчитывать.\n  return f(a - 1, b + a);\n}\n\nconsole.log(f(4));",{"slug":1169,"title":1170,"source":1171,"exerciseCode":1172,"tutorialCode":1173,"expectedOutput":1174,"executionExplanation":1173,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1140,"status":13},"rendering-dom-events-forms-ex13","Упражнение 13: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex13","const a = {\n  type: 'button',\n  props: {\n    children: '1',\n  },\n};\n\nconsole.log(a instanceof Node);\n\nconst b = document.createElement(a.type);\n\nb.textContent = a.props.children;\n\nconsole.log(b instanceof Node);\nconsole.log(document.body.children.length);\n\ndocument.body.append(b);\n\nconsole.log(document.body.children.length);\n","\u002F\u002F Упражнение 13: рендеринг, DOM, события и формы\n\u002F\u002F Темы Virtual DOM как описание и реальный DOM-узел\n\u002F\u002F Читать дальше\n\u002F\u002F Vue Rendering Mechanism https:\u002F\u002Fvuejs.org\u002Fguide\u002Fextras\u002Frendering-mechanism\n\u002F\u002F React createElement https:\u002F\u002Freact.dev\u002Freference\u002Freact\u002FcreateElement\n\u002F\u002F React Render and Commit https:\u002F\u002Freact.dev\u002Flearn\u002Frender-and-commit\n\u002F\u002F Это обычный JavaScript-объект.\n\u002F\u002F Он похож на описание будущего элемента, но сам не является DOM-узлом.\nconst a = {\n  type: 'button',\n  props: {\n    children: '1',\n  },\n};\n\nconsole.log(a instanceof Node);\n\n\u002F\u002F Только здесь мы создаем настоящий DOM-узел через browser API.\nconst b = document.createElement(a.type);\n\nb.textContent = a.props.children;\n\nconsole.log(b instanceof Node);\n\n\u002F\u002F DOM-узел уже создан, но еще не вставлен в document.body.\n\u002F\u002F Поэтому на странице у body пока нет дочерних элементов.\nconsole.log(document.body.children.length);\n\ndocument.body.append(b);\n\n\u002F\u002F После append реальный DOM изменился.\n\u002F\u002F Теперь браузер сможет учитывать этот узел в следующих этапах rendering pipeline.\nconsole.log(document.body.children.length);","false\ntrue\n0\n1",{"slug":1176,"title":1177,"source":1178,"exerciseCode":1179,"tutorialCode":1180,"expectedOutput":1181,"executionExplanation":1180,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":1140,"status":13},"scope-hoisting-closures-this-ex13","Упражнение 13: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex13","try {\n  a();\n} catch (error) {\n  console.log('1:', error.name);\n}\n\ntry {\n  var b;\n\n  b();\n} catch (error) {\n  console.log('2:', error.name);\n}\n","\u002F\u002F Упражнение 13: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: ReferenceError и TypeError.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS обработка ошибок https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F10-error-handling\u002F1-try-catch\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch1.md#L243 раздел Ошибки\n\u002F\u002F MDN ReferenceError https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FReferenceError\n\u002F\u002F MDN TypeError https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FTypeError\n\ntry {\n  \u002F\u002F Идентификатор a нигде не объявлен.\n  \u002F\u002F Движок не может найти имя в цепочке областей видимости.\n  \u002F\u002F Это ошибка разрешения имени, поэтому ReferenceError.\n  a();\n} catch (error) {\n  console.log('1:', error.name);\n}\n\ntry {\n  \u002F\u002F Объявление var b всплывает.\n  \u002F\u002F Переменная b существует, но ее значение undefined.\n  var b;\n\n  \u002F\u002F Имя b найдено успешно.\n  \u002F\u002F Ошибка в другом: undefined нельзя вызвать как функцию.\n  \u002F\u002F Поэтому это TypeError, а не ReferenceError.\n  b();\n} catch (error) {\n  console.log('2:', error.name);\n}","1: ReferenceError\n2: TypeError",{"slug":1183,"title":1184,"source":1185,"exerciseCode":1186,"tutorialCode":1187,"expectedOutput":1188,"executionExplanation":1187,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":1140,"status":13},"types-coercion-symbol-json-ex13","Упражнение 13: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex13","console.log('1:', null == undefined);\nconsole.log('2:', null == 0);\nconsole.log('3:', undefined == 0);\nconsole.log('4:', null === undefined);\nconsole.log('5:', null >= 0);\nconsole.log('6:', null > 0);\nconsole.log('7:', undefined >= 0);\nconsole.log('8:', undefined > 0);\n","\u002F\u002F Упражнение 13: типы, приведение, Symbol и JSON\n\u002F\u002F Темы null, undefined, равенство и сравнения отношений\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS операторы сравнения https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F09-comparison\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md\n\u002F\u002F MDN Equality comparisons and sameness\n\u002F\u002F У == есть отдельное правило для null и undefined.\n\u002F\u002F Они равны друг другу и почти больше никому.\nconsole.log('1:', null == undefined);\n\n\u002F\u002F null не равен числу 0 через ==.\nconsole.log('2:', null == 0);\n\n\u002F\u002F undefined тоже не равен числу 0 через ==.\nconsole.log('3:', undefined == 0);\n\n\u002F\u002F Строгое равенство не приводит типы.\n\u002F\u002F null и undefined разные типы.\nconsole.log('4:', null === undefined);\n\n\u002F\u002F >= не использует правило null == undefined.\n\u002F\u002F Здесь null проходит численное приведение и становится 0.\n\u002F\u002F Поэтому 0 >= 0 дает true.\nconsole.log('5:', null >= 0);\n\n\u002F\u002F null снова становится 0.\n\u002F\u002F 0 > 0 дает false.\nconsole.log('6:', null > 0);\n\n\u002F\u002F undefined при численном приведении становится NaN.\n\u002F\u002F Сравнения с NaN дают false.\nconsole.log('7:', undefined >= 0);\nconsole.log('8:', undefined > 0);","1 true\n2 false\n3 false\n4 false\n5 true\n6 false\n7 false\n8 false",{"slug":1190,"title":1191,"source":1192,"exerciseCode":1193,"tutorialCode":1194,"expectedOutput":1195,"executionExplanation":1194,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":1196,"status":13},"collections-iteration-arrays-ex14","Упражнение 14: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex14","const a = ['a', 'b', 'c', 'd'];\nconst b = a.slice(1, 3);\nconst c = a.splice(1, 2, 'x', 'y');\n\nconsole.log(b.join(','));\nconsole.log(c.join(','));\nconsole.log(a.join(','));\n","\u002F\u002F Упражнение 14: коллекции, итерация, массивы и строки\n\u002F\u002F Темы slice и splice\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS методы массивов slice splice https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F05-array-methods\u002Farticle.md\n\u002F\u002F MDN Array slice https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fslice\u002Findex.md\n\u002F\u002F MDN Array splice https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fsplice\u002Findex.md\nconst a = ['a', 'b', 'c', 'd'];\n\n\u002F\u002F slice возвращает копию части массива.\n\u002F\u002F Исходный массив остается прежним.\nconst b = a.slice(1, 3);\n\n\u002F\u002F splice меняет исходный массив.\n\u002F\u002F Он возвращает удаленные элементы.\nconst c = a.splice(1, 2, 'x', 'y');\n\nconsole.log(b.join(','));\nconsole.log(c.join(','));\nconsole.log(a.join(','));","b,c\nb,c\na,x,y,d",14,{"slug":1198,"title":1199,"source":1200,"exerciseCode":1201,"tutorialCode":1202,"expectedOutput":1203,"executionExplanation":1202,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":1196,"status":13},"event-loop-promises-async-await-ex14","Упражнение 14: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex14","async function* f() {\n  yield 1;\n  yield Promise.resolve(2);\n  return 3;\n}\n\n(async function g() {\n  for await (const a of f()) {\n    console.log('1:', a);\n  }\n\n  console.log('2');\n})();\n\nconsole.log('3');\n","\u002F\u002F Упражнение 14: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы async generator и for await of\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS async iterators https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F12-generators-iterators\u002F2-async-iterators-generators\u002Farticle.md\n\u002F\u002F MDN AsyncGenerator https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fasyncgenerator\u002Findex.md\n\u002F\u002F MDN for await...of https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fstatements\u002Ffor-await...of\u002Findex.md\nasync function* f() {\n  yield 1;\n\n  \u002F\u002F for await распакует промис и отдаст наружу значение 2.\n  yield Promise.resolve(2);\n\n  \u002F\u002F return завершает генератор и не попадает в тело цикла.\n  return 3;\n}\n\n(async function g() {\n  for await (const a of f()) {\n    console.log('1:', a);\n  }\n\n  console.log('2');\n})();\n\nconsole.log('3');","3\n1: 1\n1: 2\n2",{"slug":1205,"title":1206,"source":1207,"exerciseCode":1208,"tutorialCode":1209,"expectedOutput":1210,"executionExplanation":1209,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":1196,"status":13},"event-loop-promises-deep-dive-ex14","Дополнительное упражнение 14: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex14","async function f() {\n  console.log('1');\n\n  try {\n    await Promise.resolve()\n      .then(() => {\n        console.log('2');\n        throw 'a';\n      })\n      .catch((a) => {\n        console.log('3:', a);\n\n        return Promise.resolve('b').finally(() => console.log('4'));\n      });\n\n    console.log('5');\n  } finally {\n    console.log('6');\n\n    await 0;\n\n    console.log('7');\n  }\n\n  return 'c';\n}\n\nf().then((a) => console.log('8:', a));\n\nPromise.resolve().then(() => console.log('9'));\n\nconsole.log('10');\n","\u002F\u002F Дополнительное упражнение 14: углубленная практика по event loop и Promise\n\u002F\u002F Темы async await, catch, finally и дополнительное ожидание внутри finally\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS async await https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md\n\u002F\u002F Learn JS promise error handling https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F04-promise-error-handling\u002Farticle.md\n\u002F\u002F MDN Promise.prototype.finally https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FPromise\u002Ffinally\nasync function f() {\n  console.log('1');\n\n  try {\n    await Promise.resolve()\n      .then(() => {\n        console.log('2');\n\n        \u002F\u002F Ошибка переводит следующий шаг цепочки в rejected.\n        throw 'a';\n      })\n      .catch((a) => {\n        console.log('3:', a);\n\n        \u002F\u002F catch восстанавливает цепочку, но finally добавляет еще один шаг.\n        return Promise.resolve('b').finally(() => console.log('4'));\n      });\n\n    console.log('5');\n  } finally {\n    \u002F\u002F finally у try выполнится после await выше.\n    console.log('6');\n\n    \u002F\u002F await внутри finally снова приостанавливает async функцию.\n    await 0;\n\n    console.log('7');\n  }\n\n  return 'c';\n}\n\nf().then((a) => console.log('8:', a));\n\nPromise.resolve().then(() => console.log('9'));\n\nconsole.log('10');","1\n10\n2\n9\n3: a\n4\n5\n6\n7\n8: c",{"slug":1212,"title":1213,"source":1214,"exerciseCode":1215,"tutorialCode":1216,"expectedOutput":1217,"executionExplanation":1216,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":1196,"status":13},"objects-prototypes-classes-ex14","Упражнение 14: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex14","class A {\n  static x = 1;\n\n  x = 2;\n\n  static f() {\n    return this.x + 1;\n  }\n\n  f() {\n    return this.x + 1;\n  }\n}\n\nconst a = new A();\n\nconsole.log('1:', A.x, a.x);\nconsole.log('2:', A.f(), a.f());\nconsole.log('3:', typeof a.f, typeof a.constructor.f);\nconsole.log('4:', Object.hasOwn(A, 'x'), Object.hasOwn(a, 'x'));\n","\u002F\u002F Упражнение 14: свойства объектов, прототипы и классы\n\u002F\u002F Темы static fields static methods и instance members\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS static https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F03-static-properties-methods\u002Farticle.md\n\u002F\u002F MDN static https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fstatic\u002Findex.md\nclass A {\n  \u002F\u002F static x создается на самом классе A.\n  static x = 1;\n\n  \u002F\u002F Обычное поле x создается на каждом экземпляре.\n  x = 2;\n\n  static f() {\n    \u002F\u002F При A.f() значение this равно классу A.\n    return this.x + 1;\n  }\n\n  f() {\n    \u002F\u002F При a.f() значение this равно экземпляру a.\n    return this.x + 1;\n  }\n}\n\nconst a = new A();\n\nconsole.log('1:', A.x, a.x);\nconsole.log('2:', A.f(), a.f());\n\n\u002F\u002F Static method доступен через constructor экземпляра.\n\u002F\u002F Это все равно метод класса а не метод самого экземпляра.\nconsole.log('3:', typeof a.f, typeof a.constructor.f);\nconsole.log('4:', Object.hasOwn(A, 'x'), Object.hasOwn(a, 'x'));","1 1 2\n2 2 3\n3 function function\n4 true true",{"slug":1219,"title":1220,"source":1221,"exerciseCode":1222,"tutorialCode":1223,"expectedOutput":1224,"executionExplanation":1223,"language":65,"runtime":66,"programSlug":50,"lessonSlug":50,"order":1196,"status":13},"recursion-ex14","Упражнение 14: рекурсия","mentoring\u002Frecursion\u002Fex\u002Fex14","function f(a) {\n  console.log('a', a);\n\n  if (a === 0) {\n    return;\n  }\n\n  f(a - 1);\n\n  console.log('b', a);\n}\n\nf(3);\n","\u002F\u002F Упражнение 14: рекурсия\n\u002F\u002F Темы спуск и возврат из рекурсии\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Recursion https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md\nfunction f(a) {\n  \u002F\u002F Этот вывод происходит при спуске вглубь.\n  console.log('a', a);\n\n  if (a === 0) {\n    return;\n  }\n\n  f(a - 1);\n\n  \u002F\u002F Этот вывод происходит после возврата внутреннего вызова.\n  \u002F\u002F Поэтому значения идут в обратном порядке.\n  console.log('b', a);\n}\n\nf(3);","a 3\na 2\na 1\na 0\nb 1\nb 2\nb 3",{"slug":1226,"title":1227,"source":1228,"exerciseCode":1229,"tutorialCode":1230,"expectedOutput":1231,"executionExplanation":1230,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1196,"status":13},"rendering-dom-events-forms-ex14","Упражнение 14: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex14","const a = document.createElement('div');\n\na.style.width = '100px';\na.style.height = '10px';\na.style.padding = '10px';\na.style.border = '5px solid';\ndocument.body.append(a);\n\nconsole.log(a.clientWidth);\nconsole.log(a.offsetWidth);\nconsole.log(Math.round(a.getBoundingClientRect().width));\n","\u002F\u002F Упражнение 14: рендеринг, DOM, события и формы\n\u002F\u002F Темы clientWidth, offsetWidth и getBoundingClientRect в box model\n\u002F\u002F Читать дальше\n\u002F\u002F MDN dimensions https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fcss_object_model\u002Fdetermining_the_dimensions_of_elements\u002Findex.md\n\u002F\u002F MDN getBoundingClientRect https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Felement\u002Fgetboundingclientrect\u002Findex.md\nconst a = document.createElement('div');\n\n\u002F\u002F Мы задаем content width 100px.\n\u002F\u002F Padding добавит по 10px слева и справа.\n\u002F\u002F Border добавит по 5px слева и справа.\na.style.width = '100px';\na.style.height = '10px';\na.style.padding = '10px';\na.style.border = '5px solid';\ndocument.body.append(a);\n\n\u002F\u002F clientWidth включает content и padding, но не включает border.\nconsole.log(a.clientWidth);\n\n\u002F\u002F offsetWidth включает content, padding и border.\nconsole.log(a.offsetWidth);\n\n\u002F\u002F getBoundingClientRect показывает визуальный border box.\n\u002F\u002F В этом примере transform нет, поэтому ширина совпадает с offsetWidth.\nconsole.log(Math.round(a.getBoundingClientRect().width));","120\n130\n130",{"slug":1233,"title":1234,"source":1235,"exerciseCode":1236,"tutorialCode":1237,"expectedOutput":1238,"executionExplanation":1237,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":1196,"status":13},"scope-hoisting-closures-this-ex14","Упражнение 14: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex14","const b = {\n  f() {\n    console.log('1:', a);\n  },\n};\n\nfunction g() {\n  var a = 'b';\n\n  b.f();\n}\n\nvar a = 'a';\n\ng();\n","\u002F\u002F Упражнение 14: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: лексическая область видимости против динамической.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS лексическое окружение https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch2.md#L2 раздел Лексическая область видимости\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002FapA.md#L2 раздел Динамическая область видимости\n\nconst b = {\n  f() {\n    \u002F\u002F Метод f был создан во внешней области.\n    \u002F\u002F Поэтому его поиск a идет по месту объявления, а не по месту вызова.\n    console.log('1:', a);\n  },\n};\n\nfunction g() {\n  \u002F\u002F Эта a локальная для g.\n  \u002F\u002F Она не становится видимой внутри b.f только потому, что метод вызвали из g.\n  var a = 'b';\n\n  b.f();\n}\n\n\u002F\u002F Эту a найдет метод b.f.\nvar a = 'a';\n\n\u002F\u002F В JS область видимости лексическая.\n\u002F\u002F Поэтому результат a, а не b.\ng();","1: a",{"slug":1240,"title":1241,"source":1242,"exerciseCode":1243,"tutorialCode":1244,"expectedOutput":1245,"executionExplanation":1244,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":1196,"status":13},"types-coercion-symbol-json-ex14","Упражнение 14: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex14","console.log('1:', '0' == false);\nconsole.log('2:', false == '');\nconsole.log('3:', true == 1);\nconsole.log('4:', [] == ![]);\nconsole.log('5:', Boolean([]));\nconsole.log('6:', Number([]));\nconsole.log('7:', Number(false));\n","\u002F\u002F Упражнение 14: типы, приведение, Symbol и JSON\n\u002F\u002F Темы boolean, отрицание и нестрогое сравнение\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS операторы сравнения https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F09-comparison\u002Farticle.md\n\u002F\u002F Learn JS сравнение массивов https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F04-array\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md\n\u002F\u002F MDN Equality operator\n\u002F\u002F Если в == участвует boolean, он сначала приводится к number.\n\u002F\u002F false становится 0.\n\u002F\u002F Строка 0 тоже становится числом 0.\nconsole.log('1:', '0' == false);\n\n\u002F\u002F false становится 0, а пустая строка тоже 0.\nconsole.log('2:', false == '');\n\n\u002F\u002F true становится 1.\nconsole.log('3:', true == 1);\n\n\u002F\u002F Сначала выполняется ![].\n\u002F\u002F Пустой массив это объект, поэтому он truthy.\n\u002F\u002F Отрицание истинного значения дает false.\n\u002F\u002F Дальше сравнение становится [] == false.\n\u002F\u002F false приводится к 0, массив приводится к пустой строке, потом к 0.\nconsole.log('4:', [] == ![]);\n\n\u002F\u002F Сам массив истинный.\nconsole.log('5:', Boolean([]));\n\n\u002F\u002F Но при численном приведении пустой массив становится 0.\nconsole.log('6:', Number([]));\n\n\u002F\u002F false тоже становится 0.\nconsole.log('7:', Number(false));","1 true\n2 true\n3 true\n4 true\n5 true\n6 0\n7 0",{"slug":1247,"title":1248,"source":1249,"exerciseCode":1250,"tutorialCode":1251,"expectedOutput":1252,"executionExplanation":1251,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":1253,"status":13},"collections-iteration-arrays-ex15","Упражнение 15: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex15","const a = [1, [2, [3]], 4];\n\nconsole.log(JSON.stringify(a.flat()));\nconsole.log(JSON.stringify(a.flat(2)));\n\nconst b = [1, 2, 3].flatMap((c) => [c, c * 2]);\n\nconsole.log(JSON.stringify(b));\n","\u002F\u002F Упражнение 15: коллекции, итерация, массивы и строки\n\u002F\u002F Темы flat и flatMap\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Array flat https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fflat\u002Findex.md\n\u002F\u002F MDN Array flatMap https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fflatmap\u002Findex.md\nconst a = [1, [2, [3]], 4];\n\n\u002F\u002F flat без аргумента раскрывает один уровень вложенности.\nconsole.log(JSON.stringify(a.flat()));\n\n\u002F\u002F flat с глубиной 2 раскрывает два уровня.\nconsole.log(JSON.stringify(a.flat(2)));\n\n\u002F\u002F flatMap сначала делает map.\n\u002F\u002F Потом раскрывает один уровень результата.\nconst b = [1, 2, 3].flatMap((c) => [c, c * 2]);\n\nconsole.log(JSON.stringify(b));","[1,2,[3],4]\n[1,2,3,4]\n[1,2,2,4,3,6]",15,{"slug":1255,"title":1256,"source":1257,"exerciseCode":1258,"tutorialCode":1259,"expectedOutput":1260,"executionExplanation":1259,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":1253,"status":13},"event-loop-promises-async-await-ex15","Упражнение 15: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex15","const a = new AbortController();\n\na.signal.addEventListener('abort', () => {\n  console.log('1:', a.signal.aborted);\n});\n\nsetTimeout(() => console.log('2:', a.signal.reason), 0);\n\na.abort('a');\n\nconsole.log('3');\n","\u002F\u002F Упражнение 15: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы AbortController и отмена асинхронной операции\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Fetch abort https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F5-network\u002F04-fetch-abort\u002Farticle.md\n\u002F\u002F MDN AbortController https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fabortcontroller\u002Findex.md\nconst a = new AbortController();\n\n\u002F\u002F Подписчик на abort вызывается во время abort.\na.signal.addEventListener('abort', () => {\n  console.log('1:', a.signal.aborted);\n});\n\n\u002F\u002F Таймер прочитает reason позже, когда текущий script закончится.\nsetTimeout(() => console.log('2:', a.signal.reason), 0);\n\n\u002F\u002F abort переводит signal в состояние aborted и сохраняет reason.\na.abort('a');\n\nconsole.log('3');","1: true\n3\n2: a",{"slug":1262,"title":1263,"source":1264,"exerciseCode":1265,"tutorialCode":1266,"expectedOutput":1267,"executionExplanation":1266,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":1253,"status":13},"event-loop-promises-deep-dive-ex15","Дополнительное упражнение 15: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex15","function f(a, b) {\n  return new Promise((resolve, reject) => {\n    console.log('1:', a);\n\n    setTimeout(() => {\n      console.log('2:', a);\n\n      if (b) {\n        reject(a);\n      } else {\n        resolve(a);\n      }\n    }, 0);\n  });\n}\n\nconst a = f('a', false);\nconst b = f('b', true);\n\nPromise.all([\n  a.catch((a) => a),\n  b.catch((a) => {\n    console.log('3:', a);\n\n    return 'c';\n  }),\n]).then((a) => console.log('4:', a.join(',')));\n\nPromise.race([\n  Promise.resolve('d').then((a) => {\n    console.log('5:', a);\n\n    return a;\n  }),\n  a.then((a) => {\n    console.log('6:', a);\n\n    return 'e';\n  }),\n]).then((a) => console.log('7:', a));\n\nconsole.log('8');\n","\u002F\u002F Дополнительное упражнение 15: углубленная практика по event loop и Promise\n\u002F\u002F Темы Promise.all, Promise.race, catch и таймеры\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Promise API https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F05-promise-api\u002Farticle.md\n\u002F\u002F MDN Promise.all https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fall\u002Findex.md\n\u002F\u002F MDN Promise.race https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Frace\u002Findex.md\nfunction f(a, b) {\n  return new Promise((resolve, reject) => {\n    \u002F\u002F Операция стартует сразу при вызове f.\n    console.log('1:', a);\n\n    setTimeout(() => {\n      console.log('2:', a);\n\n      if (b) {\n        reject(a);\n      } else {\n        resolve(a);\n      }\n    }, 0);\n  });\n}\n\nconst a = f('a', false);\nconst b = f('b', true);\n\nPromise.all([\n  \u002F\u002F catch превращает ошибку в обычное успешное значение.\n  a.catch((a) => a),\n  b.catch((a) => {\n    console.log('3:', a);\n\n    return 'c';\n  }),\n]).then((a) => console.log('4:', a.join(',')));\n\nPromise.race([\n  Promise.resolve('d').then((a) => {\n    console.log('5:', a);\n\n    return a;\n  }),\n  a.then((a) => {\n    console.log('6:', a);\n\n    return 'e';\n  }),\n]).then((a) => console.log('7:', a));\n\nconsole.log('8');","1: a\n1: b\n8\n5: d\n7: d\n2: a\n6: a\n2: b\n3: b\n4: a,c",{"slug":1269,"title":1270,"source":1271,"exerciseCode":1272,"tutorialCode":1273,"expectedOutput":1274,"executionExplanation":1273,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":1253,"status":13},"objects-prototypes-classes-ex15","Упражнение 15: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex15","class A {\n  static x = 1;\n\n  static h() {\n    return this.x;\n  }\n\n  f() {\n    return this.x + 1;\n  }\n}\n\nclass B extends A {\n  static x = 2;\n\n  constructor(x) {\n    super();\n    this.x = x;\n  }\n\n  f() {\n    return super.f() + 1;\n  }\n\n  g() {\n    return this.x + 3;\n  }\n}\n\nconst b = new B(1);\n\nconsole.log('1:', b.f(), b.g());\nconsole.log('2:', b instanceof B, b instanceof A);\nconsole.log('3:', Object.getPrototypeOf(B) === A);\nconsole.log('4:', Object.getPrototypeOf(B.prototype) === A.prototype);\nconsole.log('5:', B.h(), A.h());\n","\u002F\u002F Упражнение 15: свойства объектов, прототипы и классы\n\u002F\u002F Темы extends super prototype links и static inheritance\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS наследование классов https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F02-class-inheritance\u002Farticle.md\n\u002F\u002F Learn JS static https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F03-static-properties-methods\u002Farticle.md\n\u002F\u002F MDN extends https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fextends\u002Findex.md\nclass A {\n  static x = 1;\n\n  static h() {\n    return this.x;\n  }\n\n  f() {\n    return this.x + 1;\n  }\n}\n\nclass B extends A {\n  static x = 2;\n\n  constructor(x) {\n    \u002F\u002F В наследнике свой constructor обязан вызвать super до работы с this.\n    super();\n    this.x = x;\n  }\n\n  f() {\n    \u002F\u002F super.f ищет метод выше от B.prototype.\n    \u002F\u002F this при этом остается текущим экземпляром b.\n    return super.f() + 1;\n  }\n\n  g() {\n    return this.x + 3;\n  }\n}\n\nconst b = new B(1);\n\nconsole.log('1:', b.f(), b.g());\nconsole.log('2:', b instanceof B, b instanceof A);\n\n\u002F\u002F extends создает две прототипные связи.\nconsole.log('3:', Object.getPrototypeOf(B) === A);\nconsole.log('4:', Object.getPrototypeOf(B.prototype) === A.prototype);\n\n\u002F\u002F Static method наследуется через связь B -> A.\n\u002F\u002F Но this при B.h() равен B.\nconsole.log('5:', B.h(), A.h());","1 3 4\n2 true true\n3 true\n4 true\n5 2 1",{"slug":1276,"title":1277,"source":1278,"exerciseCode":1279,"tutorialCode":1280,"expectedOutput":1281,"executionExplanation":1280,"language":65,"runtime":66,"programSlug":50,"lessonSlug":50,"order":1253,"status":13},"recursion-ex15","Упражнение 15: рекурсия","mentoring\u002Frecursion\u002Fex\u002Fex15","function f(a) {\n  const b = document.createElement('div');\n  b.textContent = a.x;\n\n  if (a.y) {\n    b.append(f(a.y));\n  }\n\n  return b;\n}\n\nconst a = f({\n  x: '1',\n  y: {\n    x: '2',\n    y: {\n      x: '3',\n    },\n  },\n});\n\ndocument.body.append(a);\n\nconsole.log(document.body.textContent);\n","\u002F\u002F Упражнение 15: рекурсия\n\u002F\u002F Темы рекурсивное создание DOM из вложенных данных\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Recursion https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md\n\u002F\u002F MDN Document.createElement https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fdocument\u002Fcreateelement\u002Findex.md\nfunction f(a) {\n  \u002F\u002F На каждом уровне создаем узел для текущих данных.\n  const b = document.createElement('div');\n  b.textContent = a.x;\n\n  if (a.y) {\n    \u002F\u002F Для вложенных данных создаем вложенный DOM тем же способом.\n    b.append(f(a.y));\n  }\n\n  return b;\n}\n\nconst a = f({\n  x: '1',\n  y: {\n    x: '2',\n    y: {\n      x: '3',\n    },\n  },\n});\n\ndocument.body.append(a);\n\nconsole.log(document.body.textContent);","123",{"slug":1283,"title":1284,"source":1285,"exerciseCode":1286,"tutorialCode":1287,"expectedOutput":1288,"executionExplanation":1287,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1253,"status":13},"rendering-dom-events-forms-ex15","Упражнение 15: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex15","const a = document.createElement('div');\n\na.style.width = '10.5px';\na.style.height = '10px';\ndocument.body.append(a);\n\nconsole.log(a.offsetWidth);\nconsole.log(a.getBoundingClientRect().width);\n","\u002F\u002F Упражнение 15: рендеринг, DOM, события и формы\n\u002F\u002F Темы дробные CSS-размеры, offsetWidth и getBoundingClientRect\n\u002F\u002F Читать дальше\n\u002F\u002F MDN dimensions https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fcss_object_model\u002Fdetermining_the_dimensions_of_elements\u002Findex.md\n\u002F\u002F MDN offsetWidth https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlelement\u002Foffsetwidth\u002Findex.md\nconst a = document.createElement('div');\n\n\u002F\u002F CSS может хранить дробный размер.\n\u002F\u002F Layout внутри браузера не обязан быть только целым числом пикселей.\na.style.width = '10.5px';\na.style.height = '10px';\ndocument.body.append(a);\n\n\u002F\u002F offsetWidth возвращает целое число.\n\u002F\u002F Поэтому 10.5px в Chromium округляется до 11.\nconsole.log(a.offsetWidth);\n\n\u002F\u002F getBoundingClientRect дает более точный визуальный размер.\nconsole.log(a.getBoundingClientRect().width);","11\n10.5",{"slug":1290,"title":1291,"source":1292,"exerciseCode":1293,"tutorialCode":1294,"expectedOutput":1295,"executionExplanation":1294,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":1253,"status":13},"types-coercion-symbol-json-ex15","Упражнение 15: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex15","console.log('1:', NaN === NaN);\nconsole.log('2:', Object.is(NaN, NaN));\nconsole.log('3:', 0 === -0);\nconsole.log('4:', Object.is(0, -0));\nconsole.log('5:', 1 \u002F -0);\n","\u002F\u002F Упражнение 15: типы, приведение, Symbol и JSON\n\u002F\u002F Темы NaN, -0, === и Object.is\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS числа https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F02-number\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch2.md\n\u002F\u002F MDN Object.is\n\u002F\u002F MDN Equality comparisons and sameness\n\u002F\u002F NaN это number значение, которое не равно даже самому себе.\nconsole.log('1:', NaN === NaN);\n\n\u002F\u002F Object.is использует другую проверку одинаковости.\n\u002F\u002F Для NaN она возвращает true.\nconsole.log('2:', Object.is(NaN, NaN));\n\n\u002F\u002F Строгое равенство считает 0 и -0 равными.\nconsole.log('3:', 0 === -0);\n\n\u002F\u002F Object.is отличает 0 от -0.\nconsole.log('4:', Object.is(0, -0));\n\n\u002F\u002F Деление на -0 помогает увидеть знак нуля.\nconsole.log('5:', 1 \u002F -0);","1 false\n2 true\n3 true\n4 false\n5 -Infinity",{"slug":1297,"title":1298,"source":1299,"exerciseCode":1300,"tutorialCode":1301,"expectedOutput":1302,"executionExplanation":1301,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":1303,"status":13},"collections-iteration-arrays-ex16","Упражнение 16: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex16","const a = [1, , 3];\n\nconsole.log(a.length);\nconsole.log(1 in a);\nconsole.log(a.map((b) => b ?? 2).join(','));\nconsole.log(Array.from(a, (b) => b ?? 2).join(','));\n","\u002F\u002F Упражнение 16: коллекции, итерация, массивы и строки\n\u002F\u002F Темы sparse array и Array.from\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Array https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Findex.md\n\u002F\u002F MDN Array from https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Ffrom\u002Findex.md\nconst a = [1, , 3];\n\n\u002F\u002F Пропуск в массиве считается пустым слотом.\n\u002F\u002F Длина учитывает позицию но значения там нет.\nconsole.log(a.length);\nconsole.log(1 in a);\n\n\u002F\u002F map не вызывает callback для пустого слота.\n\u002F\u002F Поэтому пустое место остается пустым.\nconsole.log(a.map((b) => b ?? 2).join(','));\n\n\u002F\u002F Array.from читает позицию как undefined.\n\u002F\u002F Поэтому mapping функция может заменить ее на 2.\nconsole.log(Array.from(a, (b) => b ?? 2).join(','));","3\nfalse\n1,,3\n1,2,3",16,{"slug":1305,"title":1306,"source":1307,"exerciseCode":1308,"tutorialCode":1309,"expectedOutput":1310,"executionExplanation":1309,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":1303,"status":13},"event-loop-promises-async-await-ex16","Упражнение 16: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex16","try {\n  const a = Promise((resolve) => resolve('a'));\n\n  console.log('1:', a);\n} catch (error) {\n  console.log('1:', error.name);\n}\n\nconst b = new Promise((resolve) => resolve('b'));\n\nconsole.log('2:', b instanceof Promise);\n\nb.then((c) => console.log('3:', c));\n\nconsole.log('4');\n","\u002F\u002F Упражнение 16: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы Promise constructor, обязательный new и TypeError\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Promise basics https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F02-promise-basics\u002Farticle.md\n\u002F\u002F MDN Promise https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FPromise\n\u002F\u002F MDN Promise constructor https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fpromise\u002Findex.md\ntry {\n  \u002F\u002F Promise это конструктор.\n  \u002F\u002F В отличие от String или Number его нельзя вызвать как обычную функцию.\n  const a = Promise((resolve) => resolve('a'));\n\n  \u002F\u002F До этой строки выполнение не дойдет.\n  console.log('1:', a);\n} catch (error) {\n  \u002F\u002F Promise constructor ожидает вызов через new.\n  \u002F\u002F Если вызова через new не было, NewTarget равен undefined и бросается TypeError.\n  console.log('1:', error.name);\n}\n\n\u002F\u002F Здесь Promise вызван правильно через new.\n\u002F\u002F Executor запускается сразу и синхронно вызывает resolve.\nconst b = new Promise((resolve) => resolve('b'));\n\nconsole.log('2:', b instanceof Promise);\n\n\u002F\u002F Даже уже fulfilled промис вызывает then обработчик через микрозадачу.\nb.then((c) => console.log('3:', c));\n\nconsole.log('4');","1: TypeError\n2: true\n4\n3: b",{"slug":1312,"title":1313,"source":1314,"exerciseCode":1315,"tutorialCode":1316,"expectedOutput":1317,"executionExplanation":1316,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":1303,"status":13},"event-loop-promises-deep-dive-ex16","Дополнительное упражнение 16: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex16","async function* f() {\n  console.log('1');\n\n  yield Promise.resolve('a').then((a) => {\n    console.log('2:', a);\n\n    return 'b';\n  });\n\n  console.log('3');\n\n  await 0;\n\n  yield 'c';\n\n  console.log('4');\n}\n\n(async function g() {\n  for await (const a of f()) {\n    console.log('5:', a);\n    Promise.resolve().then(() => console.log('6:', a));\n  }\n\n  console.log('7');\n})();\n\nPromise.resolve().then(() => console.log('8'));\n\nconsole.log('9');\n","\u002F\u002F Дополнительное упражнение 16: углубленная практика по event loop и Promise\n\u002F\u002F Темы async generator, for await of и микрозадачи в теле цикла\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS async iterators https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F12-generators-iterators\u002F2-async-iterators-generators\u002Farticle.md\n\u002F\u002F MDN for await...of https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fstatements\u002Ffor-await...of\u002Findex.md\nasync function* f() {\n  console.log('1');\n\n  yield Promise.resolve('a').then((a) => {\n    console.log('2:', a);\n\n    return 'b';\n  });\n\n  console.log('3');\n\n  \u002F\u002F Генератор приостанавливается перед вторым yield.\n  await 0;\n\n  yield 'c';\n\n  \u002F\u002F Этот код выполнится, когда цикл попросит следующий элемент после c.\n  console.log('4');\n}\n\n(async function g() {\n  for await (const a of f()) {\n    console.log('5:', a);\n\n    \u002F\u002F Мы только ставим микрозадачу, но не ждем ее через await.\n    \u002F\u002F Поэтому цикл может запросить следующий элемент раньше.\n    Promise.resolve().then(() => console.log('6:', a));\n  }\n\n  console.log('7');\n})();\n\nPromise.resolve().then(() => console.log('8'));\n\nconsole.log('9');","1\n9\n2: a\n8\n5: b\n3\n6: b\n5: c\n4\n6: c\n7",{"slug":1319,"title":1320,"source":1321,"exerciseCode":1322,"tutorialCode":1323,"expectedOutput":1324,"executionExplanation":1323,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":1303,"status":13},"objects-prototypes-classes-ex16","Упражнение 16: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex16","class A {\n  constructor(x) {\n    this.x = x;\n  }\n}\n\nclass B extends A {\n  constructor() {\n    try {\n      this.y = 2;\n    } catch (error) {\n      console.log('1:', error.name);\n    }\n\n    super(1);\n    this.y = 2;\n  }\n}\n\nclass C extends A {}\n\nconst b = new B();\nconst c = new C(3);\n\nconsole.log('2:', b.x, b.y);\nconsole.log('3:', c.x);\n","\u002F\u002F Упражнение 16: свойства объектов, прототипы и классы\n\u002F\u002F Темы derived constructor super и default constructor\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS наследование классов https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F02-class-inheritance\u002Farticle.md\n\u002F\u002F MDN constructor https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fconstructor\u002Findex.md\nclass A {\n  constructor(x) {\n    this.x = x;\n  }\n}\n\nclass B extends A {\n  constructor() {\n    try {\n      \u002F\u002F В derived constructor this еще не создан до super.\n      this.y = 2;\n    } catch (error) {\n      console.log('1:', error.name);\n    }\n\n    \u002F\u002F super вызывает родительский constructor.\n    \u002F\u002F Только после этого можно работать с this.\n    super(1);\n    this.y = 2;\n  }\n}\n\n\u002F\u002F Если у наследника нет constructor то движок добавляет default constructor.\n\u002F\u002F По смыслу он передает аргументы в super.\nclass C extends A {}\n\nconst b = new B();\nconst c = new C(3);\n\nconsole.log('2:', b.x, b.y);\nconsole.log('3:', c.x);","1 ReferenceError\n2 1 2\n3 3",{"slug":1326,"title":1327,"source":1328,"exerciseCode":1329,"tutorialCode":1330,"expectedOutput":1331,"executionExplanation":1330,"language":65,"runtime":66,"programSlug":50,"lessonSlug":50,"order":1303,"status":13},"recursion-ex16","Упражнение 16: рекурсия","mentoring\u002Frecursion\u002Fex\u002Fex16","function f(a, b) {\n  if (b.length === 0) {\n    return a;\n  }\n\n  const [c, ...d] = b;\n\n  if (a[c] === undefined) {\n    return undefined;\n  }\n\n  return f(a[c], d);\n}\n\nconst a = {\n  b: {\n    c: {\n      d: 4,\n    },\n  },\n};\n\nconsole.log(f(a, ['b', 'c', 'd']));\nconsole.log(f(a, ['b', 'x']));\n","\u002F\u002F Упражнение 16: рекурсия\n\u002F\u002F Темы рекурсивный проход по пути в объекте\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Recursion https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md\nfunction f(a, b) {\n  \u002F\u002F Если путь закончился, текущий объект и есть ответ.\n  if (b.length === 0) {\n    return a;\n  }\n\n  const [c, ...d] = b;\n\n  \u002F\u002F Если следующего шага нет, дальше идти нельзя.\n  if (a[c] === undefined) {\n    return undefined;\n  }\n\n  \u002F\u002F Мы переходим на один уровень глубже и отдаем остаток пути.\n  return f(a[c], d);\n}\n\nconst a = {\n  b: {\n    c: {\n      d: 4,\n    },\n  },\n};\n\nconsole.log(f(a, ['b', 'c', 'd']));\nconsole.log(f(a, ['b', 'x']));","4\nundefined",{"slug":1333,"title":1334,"source":1335,"exerciseCode":1336,"tutorialCode":1337,"expectedOutput":1338,"executionExplanation":1337,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1303,"status":13},"rendering-dom-events-forms-ex16","Упражнение 16: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex16","const a = document.createElement('div');\n\na.style.width = '100px';\ndocument.body.append(a);\n\nconst b = getComputedStyle(a);\n\nconsole.log(b.width);\n\na.style.width = '200px';\n\nconsole.log(b.width);\n","\u002F\u002F Упражнение 16: рендеринг, DOM, события и формы\n\u002F\u002F Темы live-объект getComputedStyle и resolved values\n\u002F\u002F Читать дальше\n\u002F\u002F MDN getComputedStyle https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fwindow\u002Fgetcomputedstyle\u002Findex.md\n\u002F\u002F MDN CSSOM https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fcss_object_model\u002Findex.md\nconst a = document.createElement('div');\n\na.style.width = '100px';\ndocument.body.append(a);\n\n\u002F\u002F getComputedStyle возвращает read only объект с resolved values.\n\u002F\u002F Важная ловушка в том, что этот объект live.\nconst b = getComputedStyle(a);\n\nconsole.log(b.width);\n\n\u002F\u002F Мы меняем inline style после того, как уже получили b.\na.style.width = '200px';\n\n\u002F\u002F b не является снимком старого состояния.\n\u002F\u002F Он обновляется и показывает актуальное resolved value.\nconsole.log(b.width);","100px\n200px",{"slug":1340,"title":1341,"source":1342,"exerciseCode":1343,"tutorialCode":1344,"expectedOutput":1345,"executionExplanation":1344,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":1303,"status":13},"types-coercion-symbol-json-ex16","Упражнение 16: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex16","const a = [NaN, 0, -0];\n\nconsole.log('1:', a.indexOf(NaN));\nconsole.log('2:', a.includes(NaN));\nconsole.log('3:', a.indexOf(-0));\nconsole.log('4:', a.includes(-0));\nconsole.log('5:', Object.is(a[1], a[2]));\nconsole.log('6:', a.indexOf(0));\n","\u002F\u002F Упражнение 16: типы, приведение, Symbol и JSON\n\u002F\u002F Темы indexOf, includes, NaN и SameValueZero\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS indexOf и includes https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F05-array-methods\u002Farticle.md\n\u002F\u002F MDN Array.prototype.indexOf\n\u002F\u002F MDN Array.prototype.includes\n\u002F\u002F MDN Equality comparisons and sameness\nconst a = [NaN, 0, -0];\n\n\u002F\u002F indexOf ищет через строгое равенство.\n\u002F\u002F NaN не равен даже самому себе, поэтому индекс не найден.\nconsole.log('1:', a.indexOf(NaN));\n\n\u002F\u002F includes использует SameValueZero.\n\u002F\u002F Этот алгоритм считает NaN одинаковым с NaN.\nconsole.log('2:', a.includes(NaN));\n\n\u002F\u002F Для строгого равенства 0 и -0 одинаковые.\n\u002F\u002F Поэтому indexOf находит первый ноль на индексе 1.\nconsole.log('3:', a.indexOf(-0));\n\n\u002F\u002F SameValueZero тоже считает 0 и -0 одинаковыми.\nconsole.log('4:', a.includes(-0));\n\n\u002F\u002F Object.is использует SameValue.\n\u002F\u002F Он отличает 0 от -0.\nconsole.log('5:', Object.is(a[1], a[2]));\n\n\u002F\u002F Поиск 0 также возвращает индекс первого нуля.\nconsole.log('6:', a.indexOf(0));","1 -1\n2 true\n3 1\n4 true\n5 false\n6 1",{"slug":1347,"title":1348,"source":1349,"exerciseCode":1350,"tutorialCode":1351,"expectedOutput":1352,"executionExplanation":1351,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":1353,"status":13},"collections-iteration-arrays-ex17","Упражнение 17: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex17","const a = '😀a';\n\nconsole.log(a.length);\nconsole.log(a.split('').length);\nconsole.log(Array.from(a).length);\n\nfor (const b of a) {\n  console.log(b);\n}\n","\u002F\u002F Упражнение 17: коллекции, итерация, массивы и строки\n\u002F\u002F Темы строки UTF 16 и iterator\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS строки https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F03-string\u002Farticle.md\n\u002F\u002F Learn JS Unicode https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F99-js-misc\u002F07-unicode\u002Farticle.md\n\u002F\u002F MDN String iterator https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fstring\u002Fsymbol.iterator\u002Findex.md\nconst a = '😀a';\n\n\u002F\u002F length считает UTF 16 code units.\n\u002F\u002F Смайл занимает две такие единицы.\nconsole.log(a.length);\n\n\u002F\u002F split по пустой строке тоже режет по code units.\nconsole.log(a.split('').length);\n\n\u002F\u002F Строковый iterator идет по Unicode code points.\n\u002F\u002F Array.from использует именно iterator.\nconsole.log(Array.from(a).length);\n\nfor (const b of a) {\n  console.log(b);\n}","3\n3\n2\n😀\na",17,{"slug":1355,"title":1356,"source":1357,"exerciseCode":1358,"tutorialCode":1359,"expectedOutput":1360,"executionExplanation":1359,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":1353,"status":13},"event-loop-promises-async-await-ex17","Упражнение 17: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex17","Promise.resolve()\n  .then(() => console.log('1'))\n  .then(() => console.log('2'));\n\nPromise.resolve()\n  .then(() => console.log('3'))\n  .then(() => console.log('4'));\n\nconsole.log('5');\n","\u002F\u002F Упражнение 17: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы независимые Promise chains и порядок микрозадач\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS микрозадачи https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md\n\u002F\u002F MDN Using promises https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FGuide\u002FUsing_promises\n\u002F\u002F BFE Promise order https:\u002F\u002Fbigfrontend.dev\u002Fquiz\u002F1-promise-order\nPromise.resolve()\n  .then(() => console.log('1'))\n  \u002F\u002F Этот then не ставится в очередь сразу.\n  \u002F\u002F Он будет поставлен только после выполнения предыдущего then.\n  .then(() => console.log('2'));\n\nPromise.resolve()\n  .then(() => console.log('3'))\n  .then(() => console.log('4'));\n\n\u002F\u002F Сначала заканчивается текущий script.\nconsole.log('5');\n\n\u002F\u002F В очереди сначала два первых then из двух разных цепочек.\n\u002F\u002F Поэтому порядок не 1 2 3 4, а 1 3 2 4.","5\n1\n3\n2\n4",{"slug":1362,"title":1363,"source":1364,"exerciseCode":1365,"tutorialCode":1366,"expectedOutput":1367,"executionExplanation":1366,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":1353,"status":13},"event-loop-promises-deep-dive-ex17","Дополнительное упражнение 17: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex17","Promise.resolve('a')\n  .then(async (a) => {\n    console.log('1:', a);\n\n    await Promise.resolve().then(() => console.log('2'));\n\n    console.log('3');\n\n    return 'b';\n  })\n  .then((a) => console.log('4:', a));\n\nPromise.resolve()\n  .then(() => {\n    console.log('5');\n\n    return 'c';\n  })\n  .then((a) => console.log('6:', a));\n\nconsole.log('7');\n","\u002F\u002F Дополнительное упражнение 17: углубленная практика по event loop и Promise\n\u002F\u002F Темы async обработчик then и соседняя Promise цепочка\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS async await https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md\n\u002F\u002F Learn JS promise chaining https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F03-promise-chaining\u002Farticle.md\nPromise.resolve('a')\n  .then(async (a) => {\n    console.log('1:', a);\n\n    \u002F\u002F async обработчик возвращает Promise, поэтому внешняя цепочка ждет его.\n    await Promise.resolve().then(() => console.log('2'));\n\n    console.log('3');\n\n    return 'b';\n  })\n  .then((a) => console.log('4:', a));\n\nPromise.resolve()\n  .then(() => {\n    console.log('5');\n\n    return 'c';\n  })\n  .then((a) => console.log('6:', a));\n\nconsole.log('7');","7\n1: a\n5\n2\n6: c\n3\n4: b",{"slug":1369,"title":1370,"source":1371,"exerciseCode":1372,"tutorialCode":1373,"expectedOutput":1374,"executionExplanation":1373,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":1353,"status":13},"objects-prototypes-classes-ex17","Упражнение 17: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex17","class A {\n  x = 1;\n\n  constructor() {\n    console.log('1:', this.x, this.y);\n    this.x = 2;\n  }\n}\n\nclass B extends A {\n  y = this.x + 1;\n\n  constructor() {\n    super();\n    console.log('2:', this.x, this.y);\n    this.x = 4;\n  }\n}\n\nconst b = new B();\n\nconsole.log('3:', b.x, b.y);\n","\u002F\u002F Упражнение 17: свойства объектов, прототипы и классы\n\u002F\u002F Темы порядок инициализации fields в базовом и наследуемом классе\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS наследование классов https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F02-class-inheritance\u002Farticle.md\n\u002F\u002F MDN public class fields https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fpublic_class_fields\u002Findex.md\nclass A {\n  \u002F\u002F Поля базового класса создаются до тела constructor A.\n  x = 1;\n\n  constructor() {\n    \u002F\u002F Поле y из B еще не создано.\n    console.log('1:', this.x, this.y);\n    this.x = 2;\n  }\n}\n\nclass B extends A {\n  \u002F\u002F Поля наследника создаются сразу после super.\n  \u002F\u002F К этому моменту A уже поменял x на 2.\n  y = this.x + 1;\n\n  constructor() {\n    super();\n    console.log('2:', this.x, this.y);\n    this.x = 4;\n  }\n}\n\nconst b = new B();\n\nconsole.log('3:', b.x, b.y);","1 1 undefined\n2 2 3\n3 4 3",{"slug":1376,"title":1377,"source":1378,"exerciseCode":1379,"tutorialCode":1380,"expectedOutput":1381,"executionExplanation":1380,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1353,"status":13},"rendering-dom-events-forms-ex17","Упражнение 17: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex17","const a = document.createDocumentFragment();\nconst b = document.createElement('div');\nconst c = document.createElement('div');\n\na.append(b, c);\n\nconsole.log(a.children.length);\n\ndocument.body.append(a);\n\nconsole.log(a.children.length);\nconsole.log(document.body.children.length);\n","\u002F\u002F Упражнение 17: рендеринг, DOM, события и формы\n\u002F\u002F Темы DocumentFragment и групповая вставка DOM-узлов\n\u002F\u002F Читать дальше\n\u002F\u002F MDN appendChild https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fnode\u002Fappendchild\u002Findex.md\n\u002F\u002F MDN DOM https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fdocument_object_model\u002Findex.md\nconst a = document.createDocumentFragment();\nconst b = document.createElement('div');\nconst c = document.createElement('div');\n\n\u002F\u002F Fragment может временно держать несколько DOM-узлов вне document.\na.append(b, c);\n\nconsole.log(a.children.length);\n\n\u002F\u002F При append в body вставляется не сам fragment как wrapper.\n\u002F\u002F Его дети перемещаются в body, а fragment становится пустым.\ndocument.body.append(a);\n\nconsole.log(a.children.length);\nconsole.log(document.body.children.length);","2\n0\n2",{"slug":1383,"title":1384,"source":1385,"exerciseCode":1386,"tutorialCode":1387,"expectedOutput":1388,"executionExplanation":1387,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":1353,"status":13},"scope-hoisting-closures-this-ex17","Упражнение 17: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex17","try {\n  f();\n} catch (error) {\n  console.log('1:', error.name);\n}\n\nvar f = function g() {\n  console.log('2:', typeof g);\n};\n\nf();\n\ntry {\n  g();\n} catch (error) {\n  console.log('3:', error.name);\n}\n","\u002F\u002F Упражнение 17: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: hoisting функционального выражения и named function expression.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Function Expression https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F16-function-expressions\u002Farticle.md\n\u002F\u002F Learn JS Named Function Expression https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F06-function-object\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch4.md#L2 раздел Поднятие переменных\n\u002F\u002F MDN function expression https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FOperators\u002Ffunction\n\u002F\u002F MDN var https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Fvar\n\ntry {\n  \u002F\u002F Объявление var f всплывает.\n  \u002F\u002F Но присваивание функции еще не выполнилось.\n  \u002F\u002F В этот момент f равно undefined.\n  \u002F\u002F Имя найдено, но undefined нельзя вызвать.\n  f();\n} catch (error) {\n  console.log('1:', error.name);\n}\n\n\u002F\u002F Здесь в f наконец записывается функция.\n\u002F\u002F g это внутреннее имя функционального выражения.\nvar f = function g() {\n  \u002F\u002F Внутри самой функции имя g доступно.\n  console.log('2:', typeof g);\n};\n\n\u002F\u002F Теперь вызов работает.\nf();\n\ntry {\n  \u002F\u002F Снаружи имени g нет в области видимости.\n  g();\n} catch (error) {\n  console.log('3:', error.name);\n}","1: TypeError\n2: function\n3: ReferenceError",{"slug":1390,"title":1391,"source":1392,"exerciseCode":1393,"tutorialCode":1394,"expectedOutput":1395,"executionExplanation":1394,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":1353,"status":13},"types-coercion-symbol-json-ex17","Упражнение 17: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex17","console.log('1:', 2 > 1 > 0);\nconsole.log('2:', 3 > 2 > 1);\nconsole.log('3:', true > 0);\nconsole.log('4:', true > 1);\n","\u002F\u002F Упражнение 17: типы, приведение, Symbol и JSON\n\u002F\u002F Темы цепочка сравнений и boolean как number\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS операторы сравнения https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F09-comparison\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md\n\u002F\u002F MDN Greater than operator\n\u002F\u002F Это не математическая цепочка.\n\u002F\u002F Операторы сравнения выполняются слева направо.\n\u002F\u002F Сначала 2 > 1 дает true.\n\u002F\u002F Потом true > 0, а true становится 1.\nconsole.log('1:', 2 > 1 > 0);\n\n\u002F\u002F Сначала 3 > 2 дает true.\n\u002F\u002F Потом true > 1, то есть 1 > 1.\nconsole.log('2:', 3 > 2 > 1);\n\n\u002F\u002F true при численном сравнении становится 1.\nconsole.log('3:', true > 0);\n\n\u002F\u002F 1 > 1 дает false.\nconsole.log('4:', true > 1);","1 true\n2 false\n3 true\n4 false",{"slug":1397,"title":1398,"source":1399,"exerciseCode":1400,"tutorialCode":1401,"expectedOutput":1402,"executionExplanation":1401,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":1403,"status":13},"collections-iteration-arrays-ex18","Упражнение 18: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex18","const a = ['a2', 'a10', 'a1'];\nconst b = [...a].sort();\nconst c = [...a].sort(new Intl.Collator('ru', { numeric: true }).compare);\n\nconsole.log(b.join(','));\nconsole.log(c.join(','));\n","\u002F\u002F Упражнение 18: коллекции, итерация, массивы и строки\n\u002F\u002F Темы Intl.Collator и сортировка строк\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Intl Collator https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F99-js-misc\u002F08-intl\u002F1-collate-array-sort\u002Ftask.md\n\u002F\u002F MDN Intl.Collator https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fintl\u002Fcollator\u002Findex.md\n\u002F\u002F MDN Array sort https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fsort\u002Findex.md\nconst a = ['a2', 'a10', 'a1'];\n\n\u002F\u002F Обычный sort сравнивает строки лексикографически.\nconst b = [...a].sort();\n\n\u002F\u002F Collator с numeric true учитывает число внутри строки.\nconst c = [...a].sort(new Intl.Collator('ru', { numeric: true }).compare);\n\nconsole.log(b.join(','));\nconsole.log(c.join(','));","a1,a10,a2\na1,a2,a10",18,{"slug":1405,"title":1406,"source":1407,"exerciseCode":1408,"tutorialCode":1409,"expectedOutput":1410,"executionExplanation":1409,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":1403,"status":13},"event-loop-promises-async-await-ex18","Упражнение 18: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex18","async function f() {\n  console.log('1');\n\n  await Promise.resolve().then(() => console.log('2'));\n\n  console.log('3');\n}\n\nf();\n\nPromise.resolve().then(() => console.log('4'));\n\nconsole.log('5');\n","\u002F\u002F Упражнение 18: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы await цепочки then и очередность микрозадач\n\u002F\u002F Читать дальше\n\u002F\u002F MDN async function https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Fasync_function\n\u002F\u002F MDN Using promises https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FGuide\u002FUsing_promises\nasync function f() {\n  console.log('1');\n\n  \u002F\u002F Сначала создается промис от then.\n  \u002F\u002F await ждет именно его, а не просто Promise.resolve().\n  await Promise.resolve().then(() => console.log('2'));\n\n  \u002F\u002F Продолжение функции будет поставлено в микрозадачи после завершения then выше.\n  console.log('3');\n}\n\nf();\n\n\u002F\u002F Эта микрозадача уже стоит в очереди, когда then внутри f завершит работу.\nPromise.resolve().then(() => console.log('4'));\n\nconsole.log('5');","1\n5\n2\n4\n3",{"slug":1412,"title":1413,"source":1414,"exerciseCode":1415,"tutorialCode":1416,"expectedOutput":1417,"executionExplanation":1416,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":1403,"status":13},"event-loop-promises-deep-dive-ex18","Дополнительное упражнение 18: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex18","new Promise((resolve) => {\n  console.log('1');\n\n  resolve('a');\n  throw 'b';\n})\n  .then((a) => {\n    console.log('2:', a);\n\n    return new Promise((resolve) => {\n      console.log('3');\n\n      queueMicrotask(() => {\n        console.log('4');\n        resolve('c');\n      });\n\n      setTimeout(() => console.log('5'), 0);\n    });\n  })\n  .then((a) => console.log('6:', a))\n  .finally(() => console.log('7'));\n\nPromise.resolve().then(() => console.log('8'));\n\nconsole.log('9');\n","\u002F\u002F Дополнительное упражнение 18: углубленная практика по event loop и Promise\n\u002F\u002F Темы executor Promise, однократное завершение и вложенный Promise из then\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS promises basics https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F02-promise-basics\u002Farticle.md\n\u002F\u002F Learn JS promise chaining https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F03-promise-chaining\u002Farticle.md\n\u002F\u002F MDN Promise constructor https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fpromise\u002Findex.md\nnew Promise((resolve) => {\n  console.log('1');\n\n  \u002F\u002F Первый resolve завершает Promise.\n  resolve('a');\n\n  \u002F\u002F Ошибка после resolve уже не меняет состояние Promise.\n  throw 'b';\n})\n  .then((a) => {\n    console.log('2:', a);\n\n    return new Promise((resolve) => {\n      \u002F\u002F Этот executor запускается синхронно внутри then.\n      console.log('3');\n\n      queueMicrotask(() => {\n        console.log('4');\n        resolve('c');\n      });\n\n      setTimeout(() => console.log('5'), 0);\n    });\n  })\n  .then((a) => console.log('6:', a))\n  .finally(() => console.log('7'));\n\nPromise.resolve().then(() => console.log('8'));\n\nconsole.log('9');","1\n9\n2: a\n3\n8\n4\n6: c\n7\n5",{"slug":1419,"title":1420,"source":1421,"exerciseCode":1422,"tutorialCode":1423,"expectedOutput":1424,"executionExplanation":1423,"language":65,"runtime":66,"programSlug":18,"lessonSlug":18,"order":1403,"status":13},"objects-prototypes-classes-ex18","Упражнение 18: свойства объектов, прототипы и классы","mentoring\u002Fobjects-prototypes-classes\u002Fex\u002Fex18","class A {\n  #x = 1;\n\n  y = 2;\n\n  f() {\n    return this.#x;\n  }\n\n  g(x) {\n    this.#x = x;\n  }\n\n  static h(a) {\n    return #x in a;\n  }\n\n  static i(a) {\n    return a.#x;\n  }\n}\n\nconst a = new A();\n\nconsole.log('1:', a.y, a.f());\nconsole.log('2:', Object.keys(a).join(','), A.h(a), A.h({}));\n\na.g(3);\n\nconsole.log('3:', A.i(a));\n\ntry {\n  A.i({});\n} catch (error) {\n  console.log('4:', error.name);\n}\n","\u002F\u002F Упражнение 18: свойства объектов, прототипы и классы\n\u002F\u002F Темы private fields private brand check и public fields\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS private fields https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F04-private-protected-properties-methods\u002Farticle.md\n\u002F\u002F MDN private elements https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fprivate_elements\u002Findex.md\nclass A {\n  \u002F\u002F Private field не является обычным свойством с ключом \"#x\".\n  #x = 1;\n\n  \u002F\u002F Public field будет обычным собственным свойством экземпляра.\n  y = 2;\n\n  f() {\n    return this.#x;\n  }\n\n  g(x) {\n    this.#x = x;\n  }\n\n  static h(a) {\n    \u002F\u002F Проверка #x in a доступна только внутри класса где объявлен #x.\n    return #x in a;\n  }\n\n  static i(a) {\n    \u002F\u002F Читать private field можно только у объекта с private brand класса A.\n    return a.#x;\n  }\n}\n\nconst a = new A();\n\nconsole.log('1:', a.y, a.f());\n\n\u002F\u002F Object.keys видит public field y.\n\u002F\u002F Private field через Object.keys не виден.\nconsole.log('2:', Object.keys(a).join(','), A.h(a), A.h({}));\n\na.g(3);\n\nconsole.log('3:', A.i(a));\n\ntry {\n  \u002F\u002F У обычного объекта нет private brand класса A.\n  A.i({});\n} catch (error) {\n  console.log('4:', error.name);\n}","1 2 1\n2 y true false\n3 3\n4 TypeError",{"slug":1426,"title":1427,"source":1428,"exerciseCode":1429,"tutorialCode":1430,"expectedOutput":1431,"executionExplanation":1430,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1403,"status":13},"rendering-dom-events-forms-ex18","Упражнение 18: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex18","const a = document.createElement('div');\nconst b = document.createElement('div');\nconst c = document.createElement('div');\n\na.style.display = 'flex';\nb.style.display = 'contents';\nc.style.width = '40px';\nc.style.height = '10px';\n\nb.append(c);\na.append(b);\ndocument.body.append(a);\n\nconsole.log(b.offsetWidth);\nconsole.log(c.offsetWidth);\nconsole.log(a.children.length);\nconsole.log(b.children.length);\n","\u002F\u002F Упражнение 18: рендеринг, DOM, события и формы\n\u002F\u002F Темы display contents, DOM tree и box tree\n\u002F\u002F Читать дальше\n\u002F\u002F MDN display contents https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fcss\u002Fguides\u002Fflexible_box_layout\u002Frelationship_with_other_layout_methods\u002Findex.md\n\u002F\u002F MDN visual formatting model https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fcss\u002Fguides\u002Fdisplay\u002Fvisual_formatting_model\u002Findex.md\nconst a = document.createElement('div');\nconst b = document.createElement('div');\nconst c = document.createElement('div');\n\na.style.display = 'flex';\nb.style.display = 'contents';\nc.style.width = '40px';\nc.style.height = '10px';\n\nb.append(c);\na.append(b);\ndocument.body.append(a);\n\n\u002F\u002F display contents убирает собственный box элемента b.\n\u002F\u002F Поэтому у b нет layout-ширины.\nconsole.log(b.offsetWidth);\n\n\u002F\u002F Дочерний элемент c все равно участвует в layout.\nconsole.log(c.offsetWidth);\n\n\u002F\u002F DOM-дерево от этого не меняется.\n\u002F\u002F b остается дочерним элементом a, а c остается дочерним элементом b.\nconsole.log(a.children.length);\nconsole.log(b.children.length);","0\n40\n1\n1",{"slug":1433,"title":1434,"source":1435,"exerciseCode":1436,"tutorialCode":1437,"expectedOutput":1438,"executionExplanation":1437,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":1403,"status":13},"scope-hoisting-closures-this-ex18","Упражнение 18: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex18","f();\n\nfunction f() {\n  console.log('1:', 'a');\n}\n\nfunction f() {\n  console.log('1:', 'b');\n}\n","\u002F\u002F Упражнение 18: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: дубли function declaration и hoisting.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Function Declaration https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F16-function-expressions\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch4.md#L141 раздел Сначала функции\n\u002F\u002F MDN function https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Ffunction\n\n\u002F\u002F Объявления функций всплывают целиком.\n\u002F\u002F Если в одной области несколько function declaration с одним именем,\n\u002F\u002F более позднее объявление перекрывает предыдущее.\nf();\n\nfunction f() {\n  console.log('1:', 'a');\n}\n\n\u002F\u002F Именно эта версия f останется после обработки объявлений.\nfunction f() {\n  console.log('1:', 'b');\n}","1: b",{"slug":1440,"title":1441,"source":1442,"exerciseCode":1443,"tutorialCode":1444,"expectedOutput":1395,"executionExplanation":1444,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":1403,"status":13},"types-coercion-symbol-json-ex18","Упражнение 18: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex18","const a = [42];\nconst b = ['43'];\nconst c = ['42'];\nconst d = ['043'];\n\nconsole.log('1:', a \u003C b);\nconsole.log('2:', c \u003C d);\nconsole.log('3:', Number(c) \u003C Number(d));\nconsole.log('4:', '42' \u003C '043');\n","\u002F\u002F Упражнение 18: типы, приведение, Symbol и JSON\n\u002F\u002F Темы сравнение строк, чисел и массивов\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS операторы сравнения https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F09-comparison\u002Farticle.md\n\u002F\u002F Learn JS не сравнивайте массивы через == https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F04-array\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md\n\u002F\u002F MDN Less than operator\nconst a = [42];\nconst b = ['43'];\nconst c = ['42'];\nconst d = ['043'];\n\n\u002F\u002F Перед сравнением массивы становятся примитивами.\n\u002F\u002F [42] дает строку 42, ['43'] дает строку 43.\n\u002F\u002F Две строки сравниваются посимвольно.\nconsole.log('1:', a \u003C b);\n\n\u002F\u002F Здесь тоже сравниваются строки.\n\u002F\u002F Символ 4 больше символа 0, поэтому результат false.\nconsole.log('2:', c \u003C d);\n\n\u002F\u002F Явное Number делает намерение видимым.\n\u002F\u002F Теперь сравнение будет численным, а не строковым.\nconsole.log('3:', Number(c) \u003C Number(d));\n\n\u002F\u002F То же посимвольное сравнение без массивов.\nconsole.log('4:', '42' \u003C '043');",{"slug":1446,"title":1447,"source":1448,"exerciseCode":1449,"tutorialCode":1450,"expectedOutput":1451,"executionExplanation":1450,"language":65,"runtime":66,"programSlug":17,"lessonSlug":17,"order":1452,"status":13},"collections-iteration-arrays-ex19","Упражнение 19: коллекции, итерация, массивы и строки","mentoring\u002Fcollections-iteration-arrays\u002Fex\u002Fex19","const a = Array(3);\nlet b = 0;\n\na.map(() => {\n  b += 1;\n  return 1;\n});\n\nconst c = [1, 2, 3];\n\ndelete c[1];\n\nconsole.log('1:', 0 in a);\nconsole.log('2:', b);\nconsole.log('3:', c.length);\nconsole.log('4:', 1 in c);\n","\u002F\u002F Упражнение 19: коллекции, итерация, массивы и строки\n\u002F\u002F Темы sparse array, пустые слоты и delete\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS массивы и length https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F04-array\u002Farticle.md\n\u002F\u002F Learn JS delete в массивах https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F05-array-methods\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch3.md\n\u002F\u002F MDN Array sparse arrays https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Findex.md\n\u002F\u002F MDN delete operator https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fdelete\u002Findex.md\n\u002F\u002F Array(3) создает length 3.\n\u002F\u002F Но самих элементов по индексам еще нет.\nconst a = Array(3);\nlet b = 0;\n\n\u002F\u002F map пропускает пустые слоты.\n\u002F\u002F Callback ни разу не выполнится.\na.map(() => {\n  b += 1;\n  return 1;\n});\n\nconst c = [1, 2, 3];\n\n\u002F\u002F delete удаляет свойство массива с ключом 1.\n\u002F\u002F Длина массива при этом не уменьшается.\ndelete c[1];\n\n\u002F\u002F Индекса 0 в a нет, потому что это пустой слот.\nconsole.log('1:', 0 in a);\n\n\u002F\u002F Callback map не запускался.\nconsole.log('2:', b);\n\n\u002F\u002F Длина c осталась 3.\nconsole.log('3:', c.length);\n\n\u002F\u002F Индекс 1 теперь тоже пустой слот.\nconsole.log('4:', 1 in c);","1 false\n2 0\n3 3\n4 false",19,{"slug":1454,"title":1455,"source":1456,"exerciseCode":1457,"tutorialCode":1458,"expectedOutput":1459,"executionExplanation":1458,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":1452,"status":13},"event-loop-promises-async-await-ex19","Упражнение 19: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex19","const a = Promise.resolve('a');\n\nasync function f() {\n  return a;\n}\n\nfunction g() {\n  return Promise.resolve(a);\n}\n\nconsole.log('1:', a === f());\nconsole.log('2:', a === g());\n\nf().then((b) => console.log('3:', b));\n\nconsole.log('4');\n","\u002F\u002F Упражнение 19: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы async function и ссылка на возвращаемый Promise\n\u002F\u002F Читать дальше\n\u002F\u002F MDN async function https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Fasync_function\n\u002F\u002F MDN Promise.resolve https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FPromise\u002Fresolve\nconst a = Promise.resolve('a');\n\nasync function f() {\n  \u002F\u002F async-функция примет результат этого промиса.\n  \u002F\u002F Но наружу она вернет свой новый промис, а не тот же объект a.\n  return a;\n}\n\nfunction g() {\n  \u002F\u002F Promise.resolve возвращает тот же промис, если аргумент уже Promise.\n  return Promise.resolve(a);\n}\n\nconsole.log('1:', a === f());\nconsole.log('2:', a === g());\n\nf().then((b) => console.log('3:', b));\n\nconsole.log('4');","1: false\n2: true\n4\n3: a",{"slug":1461,"title":1462,"source":1463,"exerciseCode":1464,"tutorialCode":1465,"expectedOutput":1466,"executionExplanation":1465,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":1452,"status":13},"event-loop-promises-deep-dive-ex19","Дополнительное упражнение 19: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex19","const a = new AbortController();\n\nfunction f() {\n  return new Promise((resolve, reject) => {\n    a.signal.addEventListener('abort', () => {\n      console.log('1:', a.signal.reason);\n      reject(a.signal.reason);\n    });\n\n    setTimeout(() => {\n      console.log('2');\n      resolve('a');\n    }, 0);\n  });\n}\n\nPromise.race([\n  f().catch((a) => {\n    console.log('3:', a);\n\n    return 'b';\n  }),\n  Promise.resolve().then(() => {\n    console.log('4');\n    a.abort('c');\n\n    return 'd';\n  }),\n]).then((a) => console.log('5:', a));\n\nconsole.log('6');\n","\u002F\u002F Дополнительное упражнение 19: углубленная практика по event loop и Promise\n\u002F\u002F Темы AbortController, Promise.race и порядок микрозадач после abort\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Fetch abort https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F5-network\u002F04-fetch-abort\u002Farticle.md\n\u002F\u002F MDN AbortController https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fabortcontroller\u002Findex.md\n\u002F\u002F MDN Promise.race https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Frace\u002Findex.md\nconst a = new AbortController();\n\nfunction f() {\n  return new Promise((resolve, reject) => {\n    a.signal.addEventListener('abort', () => {\n      \u002F\u002F Событие abort вызывается синхронно во время abort.\n      console.log('1:', a.signal.reason);\n      reject(a.signal.reason);\n    });\n\n    setTimeout(() => {\n      \u002F\u002F Таймер не отменяется сам по себе.\n      console.log('2');\n      resolve('a');\n    }, 0);\n  });\n}\n\nPromise.race([\n  f().catch((a) => {\n    \u002F\u002F catch превращает отмену в успешное значение b.\n    console.log('3:', a);\n\n    return 'b';\n  }),\n  Promise.resolve().then(() => {\n    console.log('4');\n    a.abort('c');\n\n    return 'd';\n  }),\n]).then((a) => console.log('5:', a));\n\nconsole.log('6');","6\n4\n1: c\n3: c\n5: d\n2",{"slug":1468,"title":1469,"source":1470,"exerciseCode":1471,"tutorialCode":1472,"expectedOutput":1473,"executionExplanation":1472,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1452,"status":13},"rendering-dom-events-forms-ex19","Упражнение 19: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex19","const a = document.createElement('div');\nconst b = document.createElement('div');\n\nb.style.height = '50px';\na.append(b);\ndocument.body.append(a);\n\nconsole.log(a.offsetHeight);\n\na.style.contain = 'size';\n\nconsole.log(a.offsetHeight);\n","\u002F\u002F Упражнение 19: рендеринг, DOM, события и формы\n\u002F\u002F Темы contain size и влияние содержимого на размер контейнера\n\u002F\u002F Читать дальше\n\u002F\u002F MDN contain https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fcss\u002Freference\u002Fproperties\u002Fcontain\u002Findex.md\n\u002F\u002F MDN CSS containment https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fcss\u002Fguides\u002Fcontainment\u002Fusing\u002Findex.md\nconst a = document.createElement('div');\nconst b = document.createElement('div');\n\nb.style.height = '50px';\na.append(b);\ndocument.body.append(a);\n\n\u002F\u002F Без size containment высота родителя зависит от содержимого.\nconsole.log(a.offsetHeight);\n\n\u002F\u002F contain size говорит браузеру, что размер контейнера независим от детей.\n\u002F\u002F У a нет заданной высоты, поэтому после containment его layout height становится 0.\na.style.contain = 'size';\n\nconsole.log(a.offsetHeight);","50\n0",{"slug":1475,"title":1476,"source":1477,"exerciseCode":1478,"tutorialCode":1479,"expectedOutput":1480,"executionExplanation":1479,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":1452,"status":13},"scope-hoisting-closures-this-ex19","Упражнение 19: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex19","try {\n  throw 'a';\n} catch (a) {\n  console.log('1:', a);\n}\n\ntry {\n  console.log('2:', a);\n} catch (error) {\n  console.log('2:', error.name);\n}\n","\u002F\u002F Упражнение 19: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: блочная область catch.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS try catch https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F10-error-handling\u002F1-try-catch\u002Farticle.md\n\u002F\u002F Learn JS блочная область https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch3.md#L377 раздел try\u002Fcatch\n\u002F\u002F MDN try catch https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Ftry...catch\n\ntry {\n  throw 'a';\n} catch (a) {\n  \u002F\u002F Параметр catch живет только внутри блока catch.\n  console.log('1:', a);\n}\n\ntry {\n  \u002F\u002F Снаружи catch переменная a недоступна.\n  console.log('2:', a);\n} catch (error) {\n  console.log('2:', error.name);\n}","1: a\n2: ReferenceError",{"slug":1482,"title":1483,"source":1484,"exerciseCode":1485,"tutorialCode":1486,"expectedOutput":1487,"executionExplanation":1486,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":1452,"status":13},"types-coercion-symbol-json-ex19","Упражнение 19: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex19","const a = { x: 1 };\nconst b = { x: 2 };\n\nconsole.log('1:', a \u003C b);\nconsole.log('2:', a > b);\nconsole.log('3:', a == b);\nconsole.log('4:', a \u003C= b);\nconsole.log('5:', a >= b);\n","\u002F\u002F Упражнение 19: типы, приведение, Symbol и JSON\n\u002F\u002F Темы объекты в сравнениях отношений\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS преобразование объектов в примитивы https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F09-object-toprimitive\u002Farticle.md\n\u002F\u002F Learn JS операторы сравнения https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F09-comparison\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md\n\u002F\u002F MDN Less than or equal operator\nconst a = { x: 1 };\nconst b = { x: 2 };\n\n\u002F\u002F В сравнении \u003C оба объекта приводятся к примитивам.\n\u002F\u002F Обычные объекты дают строку [object Object].\n\u002F\u002F Одинаковая строка не меньше другой такой же строки.\nconsole.log('1:', a \u003C b);\n\n\u002F\u002F По той же причине a не больше b.\nconsole.log('2:', a > b);\n\n\u002F\u002F == для двух объектов сравнивает ссылки.\n\u002F\u002F Это два разных объекта, поэтому false.\nconsole.log('3:', a == b);\n\n\u002F\u002F \u003C= в JS не является отдельной проверкой меньше или равно.\n\u002F\u002F По сути это отрицание результата >.\n\u002F\u002F Так как a > b false, результат a \u003C= b становится true.\nconsole.log('4:', a \u003C= b);\n\n\u002F\u002F >= работает похожим образом.\n\u002F\u002F Так как a \u003C b false, результат a >= b становится true.\nconsole.log('5:', a >= b);","1 false\n2 false\n3 false\n4 true\n5 true",{"slug":1489,"title":1490,"source":1491,"exerciseCode":1492,"tutorialCode":1493,"expectedOutput":1494,"executionExplanation":1493,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":1495,"status":13},"event-loop-promises-async-await-ex20","Упражнение 20: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex20","const a = new Promise(async () => {\n  console.log('1');\n\n  return 'a';\n});\n\na.then((b) => console.log('2:', b));\n\nsetTimeout(() => console.log('3'), 0);\n\nconsole.log('4');\n","\u002F\u002F Упражнение 20: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы async executor внутри new Promise и потерянный результат\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Promise constructor https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FPromise\u002FPromise\n\u002F\u002F MDN async function https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Fasync_function\nconst a = new Promise(async () => {\n  \u002F\u002F Executor запускается сразу.\n  console.log('1');\n\n  \u002F\u002F Но Promise constructor игнорирует return value executor.\n  \u002F\u002F Так мы вернули значение из async-функции, но не вызвали resolve внешнего a.\n  return 'a';\n});\n\n\u002F\u002F Этот then не выполнится, потому что внешний a остался pending.\na.then((b) => console.log('2:', b));\n\nsetTimeout(() => console.log('3'), 0);\n\nconsole.log('4');","1\n4\n3",20,{"slug":1497,"title":1498,"source":1499,"exerciseCode":1500,"tutorialCode":1501,"expectedOutput":1502,"executionExplanation":1501,"language":65,"runtime":66,"programSlug":31,"lessonSlug":31,"order":1495,"status":13},"event-loop-promises-deep-dive-ex20","Дополнительное упражнение 20: углубленная практика по event loop и Promise","mentoring\u002Fevent-loop-promises-deep-dive\u002Fex\u002Fex20","async function f(a) {\n  console.log('1:', a);\n\n  await new Promise((resolve) => {\n    setTimeout(() => {\n      console.log('2:', a);\n      resolve(a);\n    }, 0);\n  });\n\n  console.log('3:', a);\n\n  return a;\n}\n\nconst a = f('a');\nconst b = Promise.resolve().then(() => {\n  console.log('4');\n\n  return f('b');\n});\n\nPromise.allSettled([a, b]).then((a) => {\n  console.log('5:', a.map((a) => a.value).join(','));\n});\n\nsetTimeout(() => {\n  console.log('6');\n  Promise.resolve().then(() => console.log('7'));\n}, 0);\n\nconsole.log('8');\n","\u002F\u002F Дополнительное упражнение 20: углубленная практика по event loop и Promise\n\u002F\u002F Темы async функции, Promise.allSettled и таймеры между операциями\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS async await https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md\n\u002F\u002F MDN Promise.allSettled https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fallsettled\u002Findex.md\n\u002F\u002F Learn JS event loop https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F99-ui-misc\u002F03-event-loop\u002Farticle.md\nasync function f(a) {\n  \u002F\u002F Код до первого await выполняется сразу при вызове f.\n  console.log('1:', a);\n\n  await new Promise((resolve) => {\n    setTimeout(() => {\n      console.log('2:', a);\n      resolve(a);\n    }, 0);\n  });\n\n  \u002F\u002F Продолжение после await выполняется как микрозадача после таймера.\n  console.log('3:', a);\n\n  return a;\n}\n\nconst a = f('a');\nconst b = Promise.resolve().then(() => {\n  console.log('4');\n\n  \u002F\u002F f b стартует только в этой микрозадаче, поэтому его таймер будет позже.\n  return f('b');\n});\n\nPromise.allSettled([a, b]).then((a) => {\n  console.log('5:', a.map((a) => a.value).join(','));\n});\n\nsetTimeout(() => {\n  console.log('6');\n  Promise.resolve().then(() => console.log('7'));\n}, 0);\n\nconsole.log('8');","1: a\n8\n4\n1: b\n2: a\n3: a\n6\n7\n2: b\n3: b\n5: a,b",{"slug":1504,"title":1505,"source":1506,"exerciseCode":1507,"tutorialCode":1508,"expectedOutput":1509,"executionExplanation":1508,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1495,"status":13},"rendering-dom-events-forms-ex20","Упражнение 20: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex20","const a = document.createElement('button');\n\nlet b = '1';\n\na.addEventListener('click', () => {\n  b = '2';\n  console.log(b);\n});\n\ndocument.body.append(a);\n\nconsole.log(b);\n\na.click();\n\nconsole.log(b);\n","\u002F\u002F Упражнение 20: рендеринг, DOM, события и формы\n\u002F\u002F Темы addEventListener и синхронный обработчик click\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS browser events https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F01-introduction-browser-events\u002Farticle.md\n\u002F\u002F MDN addEventListener https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Feventtarget\u002Faddeventlistener\u002Findex.md\nconst a = document.createElement('button');\n\nlet b = '1';\n\n\u002F\u002F Мы подписываемся на click.\n\u002F\u002F Сам обработчик пока не выполняется, он только сохраняется у элемента.\na.addEventListener('click', () => {\n  b = '2';\n  console.log(b);\n});\n\ndocument.body.append(a);\n\n\u002F\u002F До клика значение осталось прежним.\nconsole.log(b);\n\n\u002F\u002F click запускает событие на кнопке.\n\u002F\u002F Браузер вызывает подходящие обработчики синхронно внутри этого действия.\na.click();\n\n\u002F\u002F После обработчика переменная уже хранит новое значение.\nconsole.log(b);","1\n2\n2",{"slug":1511,"title":1512,"source":1513,"exerciseCode":378,"tutorialCode":1514,"expectedOutput":380,"executionExplanation":1514,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":1495,"status":13},"scope-hoisting-closures-this-ex20","Упражнение 20: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex20","\u002F\u002F Упражнение 20: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: IIFE и модульный паттерн через замыкание.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS IIFE https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F04-var\u002Farticle.md\n\u002F\u002F Learn JS замыкание https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch3.md#L234 раздел Вызов функциональных выражений по месту\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md#L314 раздел Модули\n\u002F\u002F MDN Closures https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FGuide\u002FClosures\n\n\u002F\u002F Функциональное выражение сразу вызывается.\n\u002F\u002F Такая конструкция называется IIFE.\n\u002F\u002F Здесь IIFE создает приватную область для маленького модуля.\nconst d = (function () {\n  \u002F\u002F Эта переменная приватная для IIFE.\n  \u002F\u002F Снаружи напрямую ее прочитать нельзя.\n  var a = 0;\n\n  \u002F\u002F Возвращаем объект с методами.\n  \u002F\u002F Методы замыкаются на приватную переменную a.\n  return {\n    b() {\n      a++;\n\n      return a;\n    },\n\n    c() {\n      return a;\n    },\n  };\n})();\n\n\u002F\u002F Метод b меняет приватную a.\nconsole.log('1:', d.b());\nconsole.log('2:', d.b());\n\n\u002F\u002F Свойства a в публичном объекте нет.\nconsole.log('3:', d.a);\n\n\u002F\u002F Но метод c все еще имеет доступ к приватной a через замыкание.\nconsole.log('4:', d.c());\n\ntry {\n  \u002F\u002F После выполнения IIFE ее локальная a недоступна снаружи.\n  console.log('5:', a);\n} catch (error) {\n  console.log('5:', error.name);\n}",{"slug":1516,"title":1517,"source":1518,"exerciseCode":1519,"tutorialCode":1520,"expectedOutput":1521,"executionExplanation":1520,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":1495,"status":13},"types-coercion-symbol-json-ex20","Упражнение 20: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex20","const a = Number.MAX_SAFE_INTEGER;\n\nconsole.log('1:', a);\nconsole.log('2:', a + 1);\nconsole.log('3:', a + 2);\nconsole.log('4:', a + 1 === a + 2);\nconsole.log('5:', Number.isSafeInteger(a + 1));\n","\u002F\u002F Упражнение 20: типы, приведение, Symbol и JSON\n\u002F\u002F Темы безопасные целые числа\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS безопасный диапазон number https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F05-types\u002Farticle.md\n\u002F\u002F Learn JS числа и точность https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F02-number\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch2.md\n\u002F\u002F MDN Number.MAX_SAFE_INTEGER\n\u002F\u002F MDN Number.isSafeInteger\n\u002F\u002F Number хранит числа в формате с ограниченной точностью.\n\u002F\u002F MAX_SAFE_INTEGER это последнее целое, которое надежно представимо.\nconst a = Number.MAX_SAFE_INTEGER;\n\nconsole.log('1:', a);\n\n\u002F\u002F После безопасной границы соседние целые могут стать одним значением.\nconsole.log('2:', a + 1);\nconsole.log('3:', a + 2);\n\n\u002F\u002F Поэтому два разных математических результата оказываются одним number.\nconsole.log('4:', a + 1 === a + 2);\n\n\u002F\u002F Проверка safe integer показывает, что значение уже небезопасно.\nconsole.log('5:', Number.isSafeInteger(a + 1));","1 9007199254740991\n2 9007199254740992\n3 9007199254740992\n4 true\n5 false",{"slug":1523,"title":1524,"source":1525,"exerciseCode":1526,"tutorialCode":1527,"expectedOutput":1528,"executionExplanation":1527,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":1529,"status":13},"event-loop-promises-async-await-ex21","Упражнение 21: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex21","Promise.resolve('a')\n  .then(\n    () => {\n      console.log('1');\n      throw 'b';\n    },\n    () => console.log('2'),\n  )\n  .catch((a) => console.log('3:', a));\n\nconsole.log('4');\n","\u002F\u002F Упражнение 21: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы второй аргумент then и ошибка внутри onFulfilled\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Using promises https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FGuide\u002FUsing_promises\n\u002F\u002F MDN Promise.prototype.then https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FPromise\u002Fthen\nPromise.resolve('a')\n  .then(\n    () => {\n      console.log('1');\n\n      \u002F\u002F Эта ошибка возникла внутри первого обработчика then.\n      throw 'b';\n    },\n    \u002F\u002F Второй аргумент этого же then ловит rejection предыдущего промиса.\n    \u002F\u002F Он не ловит ошибку из соседнего onFulfilled.\n    () => console.log('2'),\n  )\n  .catch((a) => console.log('3:', a));\n\nconsole.log('4');","4\n1\n3: b",21,{"slug":1531,"title":1532,"source":1533,"exerciseCode":1534,"tutorialCode":1535,"expectedOutput":1536,"executionExplanation":1535,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1529,"status":13},"rendering-dom-events-forms-ex21","Упражнение 21: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex21","const a = document.createElement('div');\nconst b = document.createElement('button');\nconst c = document.createElement('span');\n\nc.textContent = '1';\nb.append(c);\na.append(b);\ndocument.body.append(a);\n\na.addEventListener('click', (d) => {\n  console.log(d.target === c);\n  console.log(d.currentTarget === a);\n});\n\nc.click();\n","\u002F\u002F Упражнение 21: рендеринг, DOM, события и формы\n\u002F\u002F Темы event.target, event.currentTarget и всплытие\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS bubbling https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F02-bubbling-and-capturing\u002Farticle.md\n\u002F\u002F MDN Event target https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fevent\u002Ftarget\u002Findex.md\n\u002F\u002F MDN Event currentTarget https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fevent\u002Fcurrenttarget\u002Findex.md\nconst a = document.createElement('div');\nconst b = document.createElement('button');\nconst c = document.createElement('span');\n\nc.textContent = '1';\nb.append(c);\na.append(b);\ndocument.body.append(a);\n\na.addEventListener('click', (d) => {\n  \u002F\u002F target это элемент, с которого событие началось.\n  console.log(d.target === c);\n\n  \u002F\u002F currentTarget это элемент, чей обработчик выполняется прямо сейчас.\n  \u002F\u002F Обработчик висит на a, поэтому currentTarget равен a.\n  console.log(d.currentTarget === a);\n});\n\n\u002F\u002F Клик начинается на c, а потом всплывает до a.\nc.click();","true\ntrue",{"slug":1538,"title":1539,"source":1540,"exerciseCode":1541,"tutorialCode":1542,"expectedOutput":1543,"executionExplanation":1542,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":1529,"status":13},"scope-hoisting-closures-this-ex21","Упражнение 21: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex21","var a = 'a';\n\nconst b = {\n  a: 'b',\n  c: {\n    a: 'c',\n  },\n};\n\nfunction f() {\n  var a = 'd';\n\n  console.log('1:', a);\n  console.log('2:', window.a);\n  console.log('3:', b.a);\n  console.log('4:', b.c.a);\n}\n\nf();\n\ndelete window.a;\n","\u002F\u002F Упражнение 21: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: поиск идентификатора, поиск свойств объекта и доступ к window при shadowing.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS поиск переменных https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md\n\u002F\u002F Learn JS свойства объекта https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F01-object\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch2.md#L53 раздел Поиски\n\u002F\u002F MDN Property accessors https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FOperators\u002FProperty_accessors\n\u002F\u002F MDN Window https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FWindow\n\n\u002F\u002F Так мы создаем global var, который становится свойством window.\nvar a = 'a';\n\nconst b = {\n  a: 'b',\n  c: {\n    a: 'c',\n  },\n};\n\nfunction f() {\n  \u002F\u002F Эта локальная a затеняет глобальную a.\n  var a = 'd';\n\n  \u002F\u002F Здесь идет обычный поиск идентификатора a.\n  \u002F\u002F Ближайшая a находится внутри функции.\n  console.log('1:', a);\n\n  \u002F\u002F Здесь сначала ищется идентификатор window.\n  \u002F\u002F Потом a ищется уже как свойство объекта window.\n  \u002F\u002F Так можно добраться до глобального var, даже если имя a затенено.\n  console.log('2:', window.a);\n\n  \u002F\u002F Здесь lexical scope ищет только первый идентификатор b.\n  \u002F\u002F После того как b найден, a ищется как свойство объекта b.\n  console.log('3:', b.a);\n\n  \u002F\u002F Здесь lexical scope снова ищет только b.\n  \u002F\u002F c и a это уже цепочка свойств объекта, а не переменные из области видимости.\n  console.log('4:', b.c.a);\n}\n\nf();\n\n\u002F\u002F Убираем свойство, созданное глобальным var.\ndelete window.a;","1: d\n2: a\n3: b\n4: c",{"slug":1545,"title":1546,"source":1547,"exerciseCode":1548,"tutorialCode":1549,"expectedOutput":1550,"executionExplanation":1549,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":1529,"status":13},"types-coercion-symbol-json-ex21","Упражнение 21: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex21","console.log('1:', 1n == 1);\nconsole.log('2:', 1n === 1);\nconsole.log('3:', 2n > 1);\n\ntry {\n  console.log('4:', 1n + 1);\n} catch (error) {\n  console.log('4:', error.name);\n}\n","\u002F\u002F Упражнение 21: типы, приведение, Symbol и JSON\n\u002F\u002F Темы BigInt, number и смешивание типов\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS BigInt https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F99-js-misc\u002F06-bigint\u002Farticle.md\n\u002F\u002F MDN BigInt\n\u002F\u002F MDN TypeError cannot convert BigInt to number\n\u002F\u002F == может сравнить BigInt и number, если значения совместимы.\nconsole.log('1:', 1n == 1);\n\n\u002F\u002F Строгое равенство не приводит типы.\n\u002F\u002F BigInt и number разные типы.\nconsole.log('2:', 1n === 1);\n\n\u002F\u002F Сравнения отношений между BigInt и number разрешены.\nconsole.log('3:', 2n > 1);\n\ntry {\n  \u002F\u002F Арифметику BigInt и number смешивать нельзя.\n  \u002F\u002F Движок не выбирает тип результата автоматически.\n  console.log('4:', 1n + 1);\n} catch (error) {\n  console.log('4:', error.name);\n}","1 true\n2 false\n3 true\n4 TypeError",{"slug":1552,"title":1553,"source":1554,"exerciseCode":1555,"tutorialCode":1556,"expectedOutput":1557,"executionExplanation":1556,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":1558,"status":13},"event-loop-promises-async-await-ex22","Упражнение 22: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex22","Promise.reject('a')\n  .finally(() => {\n    console.log('1');\n    return 'b';\n  })\n  .catch((a) => console.log('2:', a));\n\nPromise.reject('c')\n  .finally(() => {\n    console.log('3');\n    throw 'd';\n  })\n  .catch((a) => console.log('4:', a));\n\nconsole.log('5');\n","\u002F\u002F Упражнение 22: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы finally при rejected Promise и замена ошибки\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Promise.prototype.finally https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FPromise\u002Ffinally\nPromise.reject('a')\n  .finally(() => {\n    console.log('1');\n\n    \u002F\u002F Обычное значение из finally не заменяет исходную причину rejection.\n    return 'b';\n  })\n  .catch((a) => console.log('2:', a));\n\nPromise.reject('c')\n  .finally(() => {\n    console.log('3');\n\n    \u002F\u002F А вот throw внутри finally заменяет причину ошибки.\n    throw 'd';\n  })\n  .catch((a) => console.log('4:', a));\n\nconsole.log('5');\n\n\u002F\u002F Ветка с обычным return проходит через служебное ожидание результата finally.\n\u002F\u002F Поэтому catch для d успевает выполниться раньше catch для a.","5\n1\n3\n4: d\n2: a",22,{"slug":1560,"title":1561,"source":1562,"exerciseCode":1563,"tutorialCode":1564,"expectedOutput":1565,"executionExplanation":1564,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1558,"status":13},"rendering-dom-events-forms-ex22","Упражнение 22: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex22","const a = document.createElement('div');\nconst b = document.createElement('button');\n\na.append(b);\ndocument.body.append(a);\n\na.addEventListener('click', () => console.log('1'), { capture: true });\nb.addEventListener('click', () => console.log('2'));\na.addEventListener('click', () => console.log('3'));\n\nb.click();\n","\u002F\u002F Упражнение 22: рендеринг, DOM, события и формы\n\u002F\u002F Темы capturing phase, target phase и bubbling phase\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS bubbling and capturing https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F02-bubbling-and-capturing\u002Farticle.md\n\u002F\u002F MDN addEventListener https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Feventtarget\u002Faddeventlistener\u002Findex.md\nconst a = document.createElement('div');\nconst b = document.createElement('button');\n\na.append(b);\ndocument.body.append(a);\n\n\u002F\u002F capture true ставит обработчик на фазу погружения.\n\u002F\u002F Он сработает до обработчика на самой кнопке.\na.addEventListener('click', () => console.log('1'), { capture: true });\n\n\u002F\u002F Это обработчик на target элементе.\nb.addEventListener('click', () => console.log('2'));\n\n\u002F\u002F Это обычный bubbling обработчик на родителе.\n\u002F\u002F Он сработает после target phase.\na.addEventListener('click', () => console.log('3'));\n\nb.click();","1\n2\n3",{"slug":1567,"title":1568,"source":1569,"exerciseCode":1570,"tutorialCode":1571,"expectedOutput":1572,"executionExplanation":1571,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":1558,"status":13},"types-coercion-symbol-json-ex22","Упражнение 22: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex22","console.log('1:', isNaN('a'));\nconsole.log('2:', Number.isNaN('a'));\nconsole.log('3:', isNaN(NaN));\nconsole.log('4:', Number.isNaN(NaN));\nconsole.log('5:', isFinite(''));\nconsole.log('6:', Number.isFinite(''));\nconsole.log('7:', isFinite('1'));\nconsole.log('8:', Number.isFinite(1));\nconsole.log('9:', isFinite(Infinity));\n","\u002F\u002F Упражнение 22: типы, приведение, Symbol и JSON\n\u002F\u002F Темы isNaN, isFinite и Number checks\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS isNaN и isFinite https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F02-number\u002Farticle.md\n\u002F\u002F MDN isNaN\n\u002F\u002F MDN Number.isNaN\n\u002F\u002F MDN isFinite\n\u002F\u002F MDN Number.isFinite\n\u002F\u002F Глобальный isNaN сначала приводит значение к number.\n\u002F\u002F Строка a становится NaN, поэтому результат true.\nconsole.log('1:', isNaN('a'));\n\n\u002F\u002F Number.isNaN не делает приведение.\n\u002F\u002F Строка a это string, а не number NaN.\nconsole.log('2:', Number.isNaN('a'));\n\n\u002F\u002F Здесь значение уже является NaN.\n\u002F\u002F Глобальная и строгая проверка дают true.\nconsole.log('3:', isNaN(NaN));\nconsole.log('4:', Number.isNaN(NaN));\n\n\u002F\u002F Глобальный isFinite тоже сначала приводит значение к number.\n\u002F\u002F Пустая строка становится 0, а 0 это конечное число.\nconsole.log('5:', isFinite(''));\n\n\u002F\u002F Number.isFinite не делает приведение.\n\u002F\u002F Пустая строка остается string, поэтому результат false.\nconsole.log('6:', Number.isFinite(''));\n\n\u002F\u002F Строка 1 при глобальной проверке становится числом 1.\nconsole.log('7:', isFinite('1'));\n\n\u002F\u002F Здесь значение уже number и оно конечное.\nconsole.log('8:', Number.isFinite(1));\n\n\u002F\u002F Infinity это number, но не конечное число.\nconsole.log('9:', isFinite(Infinity));","1 true\n2 false\n3 true\n4 true\n5 true\n6 false\n7 true\n8 true\n9 false",{"slug":1574,"title":1575,"source":1576,"exerciseCode":1577,"tutorialCode":1578,"expectedOutput":1579,"executionExplanation":1578,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":1580,"status":13},"event-loop-promises-async-await-ex23","Упражнение 23: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex23","async function f() {\n  return 'a';\n}\n\nPromise.all([f]).then((a) => console.log('1:', typeof a[0]));\nPromise.all([f()]).then((a) => console.log('2:', a[0]));\n\nconsole.log('3');\n","\u002F\u002F Упражнение 23: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы Promise.all с функциями и промисами\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Promise.all https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FPromise\u002Fall\nasync function f() {\n  return 'a';\n}\n\n\u002F\u002F Promise.all не вызывает функции за нас.\n\u002F\u002F Здесь в массиве лежит сама функция.\nPromise.all([f]).then((a) => console.log('1:', typeof a[0]));\n\n\u002F\u002F Здесь функция уже вызвана, и в массив попал ее Promise.\nPromise.all([f()]).then((a) => console.log('2:', a[0]));\n\nconsole.log('3');","3\n1: function\n2: a",23,{"slug":1582,"title":1583,"source":1584,"exerciseCode":1585,"tutorialCode":1586,"expectedOutput":1587,"executionExplanation":1586,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1580,"status":13},"rendering-dom-events-forms-ex23","Упражнение 23: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex23","const a = document.createElement('div');\nconst b = document.createElement('button');\n\na.append(b);\ndocument.body.append(a);\n\na.addEventListener('click', () => console.log('1'));\nb.addEventListener('click', (c) => {\n  console.log('2');\n  c.stopPropagation();\n});\nb.addEventListener('click', () => console.log('3'));\n\nb.click();\n","\u002F\u002F Упражнение 23: рендеринг, DOM, события и формы\n\u002F\u002F Темы stopPropagation и обработчики на том же элементе\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS bubbling https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F02-bubbling-and-capturing\u002Farticle.md\n\u002F\u002F MDN stopPropagation https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fevent\u002Fstoppropagation\u002Findex.md\nconst a = document.createElement('div');\nconst b = document.createElement('button');\n\na.append(b);\ndocument.body.append(a);\n\n\u002F\u002F Этот обработчик находится выше по DOM-дереву.\na.addEventListener('click', () => console.log('1'));\n\nb.addEventListener('click', (c) => {\n  console.log('2');\n\n  \u002F\u002F stopPropagation останавливает дальнейшее движение события по дереву.\n  \u002F\u002F Но другие обработчики на текущем элементе все еще могут выполниться.\n  c.stopPropagation();\n});\n\nb.addEventListener('click', () => console.log('3'));\n\nb.click();","2\n3",{"slug":1589,"title":1590,"source":1591,"exerciseCode":1592,"tutorialCode":1593,"expectedOutput":1594,"executionExplanation":1593,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":1580,"status":13},"scope-hoisting-closures-this-ex23","Упражнение 23: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex23","if (true) {\n  function f() {\n    console.log('1:', 'a');\n  }\n}\n\nf();\n\nfunction g() {\n  'use strict';\n\n  if (true) {\n    function h() {\n      console.log('2:', 'b');\n    }\n\n    h();\n  }\n\n  try {\n    h();\n  } catch (error) {\n    console.log('3:', error.name);\n  }\n}\n\ng();\n","\u002F\u002F Упражнение 23: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: function declaration внутри блока.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Function Declaration в блоке https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F16-function-expressions\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch4.md#L141 раздел Сначала функции\n\u002F\u002F MDN function https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Ffunction\n\u002F\u002F MDN Strict mode https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStrict_mode\n\n\u002F\u002F В нестрогом script-коде function declaration внутри блока исторически ведет себя странно.\n\u002F\u002F В текущем Node при true-ветке имя f становится доступным снаружи блока.\n\u002F\u002F Это не стиль, который стоит использовать в обычном коде.\nif (true) {\n  function f() {\n    console.log('1:', 'a');\n  }\n}\n\nf();\n\nfunction g() {\n  'use strict';\n\n  if (true) {\n    \u002F\u002F В strict mode function declaration внутри блока имеет блочную область.\n    function h() {\n      console.log('2:', 'b');\n    }\n\n    \u002F\u002F Внутри блока h доступна.\n    h();\n  }\n\n  try {\n    \u002F\u002F Снаружи блока h уже недоступна.\n    h();\n  } catch (error) {\n    console.log('3:', error.name);\n  }\n}\n\ng();","1: a\n2: b\n3: ReferenceError",{"slug":1596,"title":1597,"source":1598,"exerciseCode":1599,"tutorialCode":1600,"expectedOutput":1601,"executionExplanation":1600,"language":65,"runtime":66,"programSlug":21,"lessonSlug":21,"order":1580,"status":13},"types-coercion-symbol-json-ex23","Упражнение 23: типы, приведение, Symbol и JSON","mentoring\u002Ftypes-coercion-symbol-json\u002Fex\u002Fex23","console.log('1:', Number('100x'));\nconsole.log('2:', parseInt('100x', 10));\nconsole.log('3:', parseFloat('12.5x'));\nconsole.log('4:', parseInt('12.3', 10));\nconsole.log('5:', parseFloat('12.3.4'));\nconsole.log('6:', parseInt('ff', 16));\nconsole.log('7:', parseInt('2n9c', 36));\nconsole.log('8:', parseInt('a123', 10));\n","\u002F\u002F Упражнение 23: типы, приведение, Symbol и JSON\n\u002F\u002F Темы Number, parseInt, parseFloat и radix\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS parseInt и parseFloat https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F02-number\u002Farticle.md\n\u002F\u002F MDN Number\n\u002F\u002F MDN parseInt\n\u002F\u002F MDN parseFloat\n\u002F\u002F Number требует чтобы вся строка была числом.\n\u002F\u002F Символ x ломает полное численное приведение.\nconsole.log('1:', Number('100x'));\n\n\u002F\u002F parseInt читает число слева направо.\n\u002F\u002F Он останавливается на x и возвращает уже прочитанное 100.\nconsole.log('2:', parseInt('100x', 10));\n\n\u002F\u002F parseFloat умеет читать дробную часть.\n\u002F\u002F Он тоже останавливается на первом лишнем символе.\nconsole.log('3:', parseFloat('12.5x'));\n\n\u002F\u002F parseInt возвращает только целую часть.\n\u002F\u002F Точка останавливает чтение целого числа.\nconsole.log('4:', parseInt('12.3', 10));\n\n\u002F\u002F parseFloat может встретить только одну десятичную точку.\n\u002F\u002F На второй точке чтение останавливается.\nconsole.log('5:', parseFloat('12.3.4'));\n\n\u002F\u002F Второй аргумент parseInt задает систему счисления.\n\u002F\u002F ff в шестнадцатеричной системе это 255.\nconsole.log('6:', parseInt('ff', 16));\n\n\u002F\u002F В системе с основанием 36 доступны цифры и латинские буквы.\nconsole.log('7:', parseInt('2n9c', 36));\n\n\u002F\u002F Если первая позиция не может быть прочитана как цифра radix 10, результат NaN.\nconsole.log('8:', parseInt('a123', 10));","1 NaN\n2 100\n3 12.5\n4 12\n5 12.3\n6 255\n7 123456\n8 NaN",{"slug":1603,"title":1604,"source":1605,"exerciseCode":1606,"tutorialCode":1607,"expectedOutput":1608,"executionExplanation":1607,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":1609,"status":13},"event-loop-promises-async-await-ex24","Упражнение 24: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex24","Promise.race([new Promise(() => {}), 'a']).then((a) => console.log('1:', a));\n\nPromise.race([]).then(() => console.log('2'));\n\nsetTimeout(() => console.log('4'), 0);\n\nconsole.log('3');\n","\u002F\u002F Упражнение 24: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы Promise.race с обычным значением и пустым входом\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Promise.race https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FPromise\u002Frace\n\u002F\u002F Обычное значение участвует в race через Promise.resolve.\n\u002F\u002F Поэтому оно выигрывает у forever-pending промиса.\nPromise.race([new Promise(() => {}), 'a']).then((a) => console.log('1:', a));\n\n\u002F\u002F Пустой race остается pending навсегда.\n\u002F\u002F Поэтому 2 не выводится.\nPromise.race([]).then(() => console.log('2'));\n\nsetTimeout(() => console.log('4'), 0);\n\nconsole.log('3');","3\n1: a\n4",24,{"slug":1611,"title":1612,"source":1613,"exerciseCode":1614,"tutorialCode":1615,"expectedOutput":1616,"executionExplanation":1615,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1609,"status":13},"rendering-dom-events-forms-ex24","Упражнение 24: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex24","const a = document.createElement('a');\n\na.href = '\u002F';\ndocument.body.append(a);\n\na.addEventListener('click', (b) => {\n  console.log(b.cancelable);\n  b.preventDefault();\n  console.log(b.defaultPrevented);\n});\n\nconst b = new MouseEvent('click', {\n  bubbles: true,\n  cancelable: true,\n});\n\nconsole.log(a.dispatchEvent(b));\n","\u002F\u002F Упражнение 24: рендеринг, DOM, события и формы\n\u002F\u002F Темы preventDefault, cancelable и dispatchEvent\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS default action https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F04-default-browser-action\u002Farticle.md\n\u002F\u002F MDN preventDefault https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fevent\u002Fpreventdefault\u002Findex.md\n\u002F\u002F MDN dispatchEvent https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Feventtarget\u002Fdispatchevent\u002Findex.md\nconst a = document.createElement('a');\n\na.href = '\u002F';\ndocument.body.append(a);\n\na.addEventListener('click', (b) => {\n  \u002F\u002F cancelable показывает, можно ли отменить действие по умолчанию.\n  console.log(b.cancelable);\n\n  \u002F\u002F preventDefault не останавливает событие.\n  \u002F\u002F Он просит браузер не выполнять действие по умолчанию.\n  b.preventDefault();\n\n  console.log(b.defaultPrevented);\n});\n\nconst b = new MouseEvent('click', {\n  bubbles: true,\n  cancelable: true,\n});\n\n\u002F\u002F dispatchEvent возвращает false, если cancelable событие было отменено.\nconsole.log(a.dispatchEvent(b));","true\ntrue\nfalse",{"slug":1618,"title":1619,"source":1620,"exerciseCode":1621,"tutorialCode":1622,"expectedOutput":1623,"executionExplanation":1622,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":1609,"status":13},"scope-hoisting-closures-this-ex24","Упражнение 24: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex24","const a = {\n  x: 'a',\n\n  f(b) {\n    console.log(b, this && this.x);\n  },\n};\n\na.f('1:');\n(a.f)('2:');\na['f']('3:');\n\nconst c = a.f;\n\nc('4:');\n(0, a.f)('5:');\n(a.f || c)('6:');\n","\u002F\u002F Упражнение 24: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: Reference Type и потеря this при вычислении метода как значения.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS Reference Type https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F99-js-misc\u002F04-reference-type\u002Farticle.md\n\u002F\u002F MDN this https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FOperators\u002Fthis\n\u002F\u002F MDN Property accessors https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FOperators\u002FProperty_accessors\n\nconst a = {\n  x: 'a',\n\n  f(b) {\n    \u002F\u002F this зависит не от места объявления функции, а от формы вызова.\n    \u002F\u002F Если вызов сохранил ссылку на свойство объекта, this будет объектом a.\n    console.log(b, this && this.x);\n  },\n};\n\n\u002F\u002F Точка возвращает внутреннюю ссылку на свойство a.f.\n\u002F\u002F Скобки вызова получают из этой ссылки объект a и ставят this равным a.\na.f('1:');\n\n\u002F\u002F Скобки вокруг a.f не превращают метод в обычное значение.\n\u002F\u002F Ссылка на свойство сохраняется, поэтому this все еще a.\n(a.f)('2:');\n\n\u002F\u002F Квадратные скобки работают как точка.\n\u002F\u002F Вызов идет напрямую от свойства объекта.\na['f']('3:');\n\n\u002F\u002F Здесь функция достается из объекта и кладется в переменную.\n\u002F\u002F Связь с объектом a теряется.\nconst c = a.f;\n\n\u002F\u002F Это обычный вызов функции без объекта слева от скобок.\nc('4:');\n\n\u002F\u002F Оператор запятая вычисляет a.f как значение функции.\n\u002F\u002F До вызова внутренняя ссылка на объект уже потеряна.\n(0, a.f)('5:');\n\n\u002F\u002F Логическое ИЛИ тоже возвращает обычное значение функции.\n\u002F\u002F Скобки вызывают уже это значение, а не свойство объекта.\n(a.f || c)('6:');","1: a\n2: a\n3: a\n4: undefined\n5: undefined\n6: undefined",{"slug":1625,"title":1626,"source":1627,"exerciseCode":1628,"tutorialCode":1629,"expectedOutput":1630,"executionExplanation":1629,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":1631,"status":13},"event-loop-promises-async-await-ex25","Упражнение 25: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex25","setTimeout(async () => {\n  console.log('1');\n\n  await 0;\n\n  console.log('2');\n}, 0);\n\nsetTimeout(() => console.log('3'), 0);\n\nconsole.log('4');\n","\u002F\u002F Упражнение 25: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы микрозадача внутри timer task\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Microtask guide https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FHTML_DOM_API\u002FMicrotask_guide\n\u002F\u002F MDN Microtask guide source https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtml_dom_api\u002Fmicrotask_guide\u002Findex.md\nsetTimeout(async () => {\n  console.log('1');\n\n  \u002F\u002F await обычного значения ставит продолжение callback в микрозадачи.\n  await 0;\n\n  console.log('2');\n}, 0);\n\nsetTimeout(() => console.log('3'), 0);\n\nconsole.log('4');\n\n\u002F\u002F После выполнения одной задачи таймера браузер очищает микрозадачи.\n\u002F\u002F Поэтому 2 будет раньше второго таймера 3.","4\n1\n2\n3",25,{"slug":1633,"title":1634,"source":1635,"exerciseCode":1636,"tutorialCode":1637,"expectedOutput":1638,"executionExplanation":1637,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1631,"status":13},"rendering-dom-events-forms-ex25","Упражнение 25: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex25","const a = document.createElement('div');\n\na.addEventListener(\n  'click',\n  (b) => {\n    b.preventDefault();\n    console.log(b.defaultPrevented);\n  },\n  { passive: true },\n);\n\nconst b = new MouseEvent('click', {\n  bubbles: true,\n  cancelable: true,\n});\n\nconsole.log(a.dispatchEvent(b));\nconsole.log(b.defaultPrevented);\n","\u002F\u002F Упражнение 25: рендеринг, DOM, события и формы\n\u002F\u002F Темы passive listener и preventDefault\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS default action https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F04-default-browser-action\u002Farticle.md\n\u002F\u002F MDN addEventListener passive https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Feventtarget\u002Faddeventlistener\u002Findex.md\nconst a = document.createElement('div');\n\na.addEventListener(\n  'click',\n  (b) => {\n    \u002F\u002F passive true означает, что обработчик обещает не отменять действие.\n    \u002F\u002F Поэтому preventDefault внутри такого обработчика не меняет событие.\n    b.preventDefault();\n    console.log(b.defaultPrevented);\n  },\n  { passive: true },\n);\n\nconst b = new MouseEvent('click', {\n  bubbles: true,\n  cancelable: true,\n});\n\n\u002F\u002F Событие не отменено, поэтому dispatchEvent возвращает true.\nconsole.log(a.dispatchEvent(b));\nconsole.log(b.defaultPrevented);","false\ntrue\nfalse",{"slug":1640,"title":1641,"source":1642,"exerciseCode":1643,"tutorialCode":1644,"expectedOutput":1645,"executionExplanation":1644,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":1631,"status":13},"scope-hoisting-closures-this-ex25","Упражнение 25: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex25","const f = function () {\n  const a = 'a';\n\n  return () => a;\n};\n\nconst g = {\n  f() {\n    const a = 'b';\n\n    return new Function('return a;');\n  },\n};\n\nconst b = f();\nconst c = g.f();\n\nconsole.log('1:', b());\n\ntry {\n  console.log('2:', c());\n} catch (error) {\n  console.log('2:', error.name);\n}\n\nwindow.a = 'c';\n\nconsole.log('3:', c());\n\nconst d = new Function('a', 'return a;');\n\nconsole.log('4:', d('d'));\n\ndelete window.a;\n","\u002F\u002F Упражнение 25: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: new Function и глобальное окружение вместо замыкания.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS new Function https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F07-new-function\u002Farticle.md\n\u002F\u002F MDN Function constructor https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FFunction\u002FFunction\n\u002F\u002F MDN Closures https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FGuide\u002FClosures\n\nconst f = function () {\n  const a = 'a';\n\n  \u002F\u002F Стрелка запоминает окружение, где была создана.\n  return () => a;\n};\n\nconst g = {\n  f() {\n    const a = 'b';\n\n    \u002F\u002F Function constructor создает функцию из строки.\n    \u002F\u002F Такая функция не замыкается на локальную переменную a из метода.\n    return new Function('return a;');\n  },\n};\n\nconst b = f();\nconst c = g.f();\n\n\u002F\u002F b помнит переменную a из вызова f.\nconsole.log('1:', b());\n\ntry {\n  \u002F\u002F c ищет a в глобальной области.\n  \u002F\u002F Пока глобальной a нет, получаем ReferenceError.\n  console.log('2:', c());\n} catch (error) {\n  console.log('2:', error.name);\n}\n\n\u002F\u002F Function constructor ищет a в глобальном окружении.\n\u002F\u002F Поэтому добавляем значение на window.\nwindow.a = 'c';\n\n\u002F\u002F Теперь функция, созданная через new Function, находит глобальную a.\nconsole.log('3:', c());\n\n\u002F\u002F Локальные значения нужно передавать такой функции явно через параметры.\nconst d = new Function('a', 'return a;');\n\nconsole.log('4:', d('d'));\n\ndelete window.a;","1: a\n2: ReferenceError\n3: c\n4: d",{"slug":1647,"title":1648,"source":1649,"exerciseCode":1650,"tutorialCode":1651,"expectedOutput":289,"executionExplanation":1651,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":1652,"status":13},"event-loop-promises-async-await-ex26","Упражнение 26: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex26","async function f() {\n  console.log('1');\n\n  await setTimeout(() => console.log('2'), 0);\n\n  console.log('3');\n}\n\nf();\n\nconsole.log('4');\n","\u002F\u002F Упражнение 26: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы await setTimeout и timer id вместо Promise\n\u002F\u002F Читать дальше\n\u002F\u002F MDN setTimeout https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FWindow\u002FsetTimeout\n\u002F\u002F MDN async function https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Fasync_function\nasync function f() {\n  console.log('1');\n\n  \u002F\u002F setTimeout возвращает id таймера, а не Promise.\n  \u002F\u002F await обычного значения не ждет выполнения callback таймера.\n  await setTimeout(() => console.log('2'), 0);\n\n  console.log('3');\n}\n\nf();\n\nconsole.log('4');",26,{"slug":1654,"title":1655,"source":1656,"exerciseCode":1657,"tutorialCode":1658,"expectedOutput":1659,"executionExplanation":1658,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1652,"status":13},"rendering-dom-events-forms-ex26","Упражнение 26: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex26","const a = document.createElement('div');\nconst b = document.createElement('button');\nconst c = document.createElement('span');\n\nb.dataset.x = '1';\nc.textContent = '2';\nb.append(c);\na.append(b);\ndocument.body.append(a);\n\na.addEventListener('click', (d) => {\n  const e = d.target.closest('button');\n\n  if (!e || !a.contains(e)) {\n    return;\n  }\n\n  console.log(e.dataset.x);\n  console.log(d.currentTarget === a);\n});\n\nc.click();\n","\u002F\u002F Упражнение 26: рендеринг, DOM, события и формы\n\u002F\u002F Темы делегирование событий и поиск целевого элемента\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS event delegation https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F03-event-delegation\u002Farticle.md\n\u002F\u002F MDN addEventListener https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Feventtarget\u002Faddeventlistener\u002Findex.md\nconst a = document.createElement('div');\nconst b = document.createElement('button');\nconst c = document.createElement('span');\n\nb.dataset.x = '1';\nc.textContent = '2';\nb.append(c);\na.append(b);\ndocument.body.append(a);\n\n\u002F\u002F Один обработчик висит на общем родителе.\na.addEventListener('click', (d) => {\n  \u002F\u002F Событие могло начаться на вложенном span.\n  \u002F\u002F closest поднимается к ближайшей кнопке.\n  const e = d.target.closest('button');\n\n  if (!e || !a.contains(e)) {\n    return;\n  }\n\n  console.log(e.dataset.x);\n  console.log(d.currentTarget === a);\n});\n\nc.click();","1\ntrue",{"slug":1661,"title":1662,"source":1663,"exerciseCode":1664,"tutorialCode":1665,"expectedOutput":703,"executionExplanation":1665,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":1652,"status":13},"scope-hoisting-closures-this-ex26","Упражнение 26: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex26","\u002F\u002F Исправьте код так, чтобы вывод совпал с ожидаемым.\n\u002F\u002F Ожидаемый вывод:\n\u002F\u002F 1: a\n\u002F\u002F 2: b\n\nconsole.log('1:', a);\n\nlet a = 'a';\n\nfunction f() {\n  console.log('2:', b);\n\n  const b = 'b';\n}\n\nf();\n","\u002F\u002F Упражнение 26: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: TDZ, let, const и порядок чтения переменных.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS переменные https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F04-variables\u002Farticle.md\n\u002F\u002F Learn JS область видимости и замыкание https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md\n\u002F\u002F YDKJS RU hoisting https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch4.md#L2 раздел Поднятие\n\u002F\u002F MDN let https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Flet\n\u002F\u002F MDN const https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Fconst\n\n\u002F\u002F В сломанной версии мы читали a до строки let a.\n\u002F\u002F Такая привязка уже есть в области, но еще не инициализирована.\n\u002F\u002F Поэтому сначала доходим до объявления и кладем значение.\nlet a = 'a';\n\nconsole.log('1:', a);\n\nfunction f() {\n  \u002F\u002F Для b работает то же правило.\n  \u002F\u002F Пока строка const b не выполнена, читать b нельзя.\n  const b = 'b';\n\n  console.log('2:', b);\n}\n\nf();",{"slug":1667,"title":1668,"source":1669,"exerciseCode":1670,"tutorialCode":1671,"expectedOutput":664,"executionExplanation":1671,"language":65,"runtime":66,"programSlug":30,"lessonSlug":30,"order":1672,"status":13},"event-loop-promises-async-await-ex27","Упражнение 27: event loop, Promise и async\u002Fawait","mentoring\u002Fevent-loop-promises-async-await\u002Fex\u002Fex27","const a = {\n  then(resolve) {\n    console.log('1');\n    resolve('a');\n  },\n};\n\nPromise.resolve(a).then((b) => console.log('2:', b));\n\nconsole.log('3');\n","\u002F\u002F Упражнение 27: event loop, Promise и async\u002Fawait\n\u002F\u002F Темы thenable и асинхронное усвоение Promise.resolve\n\u002F\u002F Читать дальше\n\u002F\u002F MDN Promise constructor https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FPromise\u002FPromise\n\u002F\u002F MDN Promise.resolve https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FPromise\u002Fresolve\nconst a = {\n  then(resolve) {\n    console.log('1');\n    resolve('a');\n  },\n};\n\n\u002F\u002F Объект с методом then это thenable.\n\u002F\u002F Promise.resolve примет его результат, но вызов then произойдет асинхронно.\nPromise.resolve(a).then((b) => console.log('2:', b));\n\nconsole.log('3');",27,{"slug":1674,"title":1675,"source":1676,"exerciseCode":1677,"tutorialCode":1678,"expectedOutput":1679,"executionExplanation":1678,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1672,"status":13},"rendering-dom-events-forms-ex27","Упражнение 27: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex27","const a = document.createElement('input');\n\ndocument.body.append(a);\n\na.addEventListener('input', () => console.log(`1:${a.value}`));\na.addEventListener('change', () => console.log(`2:${a.value}`));\n\na.value = '1';\n\nconsole.log(a.value);\n\na.dispatchEvent(new Event('input', { bubbles: true }));\n\na.value = '2';\na.dispatchEvent(new Event('change', { bubbles: true }));\n","\u002F\u002F Упражнение 27: рендеринг, DOM, события и формы\n\u002F\u002F Темы input, change и программное изменение value\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS input and change https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F4-forms-controls\u002F3-events-change-input\u002Farticle.md\n\u002F\u002F MDN input event https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Felement\u002Finput_event\u002Findex.md\n\u002F\u002F MDN change event https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlelement\u002Fchange_event\u002Findex.md\nconst a = document.createElement('input');\n\ndocument.body.append(a);\n\na.addEventListener('input', () => console.log(`1:${a.value}`));\na.addEventListener('change', () => console.log(`2:${a.value}`));\n\n\u002F\u002F Программная запись в value сама по себе не запускает input или change.\na.value = '1';\n\nconsole.log(a.value);\n\n\u002F\u002F Здесь мы явно отправляем input событие.\na.dispatchEvent(new Event('input', { bubbles: true }));\n\n\u002F\u002F change обычно связан с завершением изменения значения пользователем.\n\u002F\u002F В учебном примере мы явно отправляем его через dispatchEvent.\na.value = '2';\na.dispatchEvent(new Event('change', { bubbles: true }));","1\n1:1\n2:2",{"slug":1681,"title":1682,"source":1683,"exerciseCode":1684,"tutorialCode":1685,"expectedOutput":1686,"executionExplanation":1685,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":1672,"status":13},"scope-hoisting-closures-this-ex27","Упражнение 27: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex27","\u002F\u002F Исправьте код так, чтобы вывод совпал с ожидаемым.\n\u002F\u002F Ожидаемый вывод:\n\u002F\u002F 1: 1\n\u002F\u002F 2: 2\n\u002F\u002F 3: 3\n\nfunction f() {\n  return function () {\n    let a = 0;\n\n    a++;\n\n    return a;\n  };\n}\n\nconst g = f();\n\nconsole.log('1:', g());\nconsole.log('2:', g());\nconsole.log('3:', g());\n","\u002F\u002F Упражнение 27: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: замыкание и сохранение состояния между вызовами.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS замыкание https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md#L2 раздел Замыкание области видимости\n\u002F\u002F MDN Closures https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FGuide\u002FClosures\n\nfunction f() {\n  \u002F\u002F Один вызов f создает одну переменную a.\n  \u002F\u002F Внутренняя функция будет помнить доступ к этой переменной.\n  let a = 0;\n\n  return function () {\n    \u002F\u002F При каждом вызове мы меняем ту же самую a.\n    a++;\n\n    return a;\n  };\n}\n\n\u002F\u002F Здесь создается одно окружение функции f.\nconst g = f();\n\n\u002F\u002F Все три вызова g работают с одной и той же переменной a.\nconsole.log('1:', g());\nconsole.log('2:', g());\nconsole.log('3:', g());","1: 1\n2: 2\n3: 3",{"slug":1688,"title":1689,"source":1690,"exerciseCode":1691,"tutorialCode":1692,"expectedOutput":1693,"executionExplanation":1692,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1694,"status":13},"rendering-dom-events-forms-ex28","Упражнение 28: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex28","const a = document.createElement('form');\nconst b = document.createElement('button');\n\nb.type = 'submit';\na.append(b);\ndocument.body.append(a);\n\na.addEventListener('submit', (c) => {\n  console.log(c.submitter === b);\n  c.preventDefault();\n});\n\nconst c = new SubmitEvent('submit', {\n  bubbles: true,\n  cancelable: true,\n  submitter: b,\n});\n\nconsole.log(a.dispatchEvent(c));\nconsole.log(c.defaultPrevented);\n","\u002F\u002F Упражнение 28: рендеринг, DOM, события и формы\n\u002F\u002F Темы submit, submitter и preventDefault\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS form submit https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F4-forms-controls\u002F4-forms-submit\u002Farticle.md\n\u002F\u002F MDN submit event https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlformelement\u002Fsubmit_event\u002Findex.md\n\u002F\u002F MDN SubmitEvent https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fsubmitevent\u002Findex.md\nconst a = document.createElement('form');\nconst b = document.createElement('button');\n\nb.type = 'submit';\na.append(b);\ndocument.body.append(a);\n\na.addEventListener('submit', (c) => {\n  \u002F\u002F submitter показывает кнопку, которая отправила форму.\n  console.log(c.submitter === b);\n\n  \u002F\u002F Для SPA и валидации на клиенте мы часто отменяем обычную отправку.\n  c.preventDefault();\n});\n\nconst c = new SubmitEvent('submit', {\n  bubbles: true,\n  cancelable: true,\n  submitter: b,\n});\n\n\u002F\u002F Из-за preventDefault dispatchEvent возвращает false.\nconsole.log(a.dispatchEvent(c));\nconsole.log(c.defaultPrevented);","true\nfalse\ntrue",28,{"slug":1696,"title":1697,"source":1698,"exerciseCode":1699,"tutorialCode":1700,"expectedOutput":1701,"executionExplanation":1700,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":1694,"status":13},"scope-hoisting-closures-this-ex28","Упражнение 28: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex28","\u002F\u002F Исправьте код так, чтобы вывод совпал с ожидаемым.\n\u002F\u002F Ожидаемый вывод:\n\u002F\u002F 1: 0\n\u002F\u002F 2: 1\n\u002F\u002F 3: 2\n\nconst a = [];\n\nfor (var b = 0; b \u003C 3; b++) {\n  a.push(function () {\n    return b;\n  });\n}\n\nconsole.log('1:', a[0]());\nconsole.log('2:', a[1]());\nconsole.log('3:', a[2]());\n","\u002F\u002F Упражнение 28: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: замыкание в цикле, var и let.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS замыкание https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md\n\u002F\u002F Learn JS var и IIFE https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F04-var\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md#L202 раздел Циклы + замыкание\n\u002F\u002F MDN Closures https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FGuide\u002FClosures\n\u002F\u002F MDN let https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Flet\n\nconst a = [];\n\n\u002F\u002F let в заголовке for создает новую привязку b для каждой итерации.\n\u002F\u002F Каждая функция замыкается на свою b.\nfor (let b = 0; b \u003C 3; b++) {\n  a.push(function () {\n    return b;\n  });\n}\n\n\u002F\u002F В первом вызове видим b из первой итерации.\nconsole.log('1:', a[0]());\n\n\u002F\u002F Во втором вызове видим b из второй итерации.\nconsole.log('2:', a[1]());\n\n\u002F\u002F В третьем вызове видим b из третьей итерации.\nconsole.log('3:', a[2]());","1: 0\n2: 1\n3: 2",{"slug":1703,"title":1704,"source":1705,"exerciseCode":1706,"tutorialCode":1707,"expectedOutput":1708,"executionExplanation":1707,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1709,"status":13},"rendering-dom-events-forms-ex29","Упражнение 29: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex29","const a = document.createElement('div');\nconst b = document.createElement('input');\n\na.append(b);\ndocument.body.append(a);\n\na.addEventListener('focus', () => console.log('1'));\na.addEventListener('blur', () => console.log('2'));\na.addEventListener('focusin', () => console.log('3'));\na.addEventListener('focusout', () => console.log('4'));\n\nb.focus();\nb.blur();\n","\u002F\u002F Упражнение 29: рендеринг, DOM, события и формы\n\u002F\u002F Темы focus, blur, focusin и focusout\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS focus blur https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F4-forms-controls\u002F2-focus-blur\u002Farticle.md\n\u002F\u002F MDN focus event https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Felement\u002Ffocus_event\u002Findex.md\n\u002F\u002F MDN blur event https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Felement\u002Fblur_event\u002Findex.md\nconst a = document.createElement('div');\nconst b = document.createElement('input');\n\na.append(b);\ndocument.body.append(a);\n\n\u002F\u002F focus и blur не всплывают.\n\u002F\u002F Поэтому эти обработчики на родителе не сработают.\na.addEventListener('focus', () => console.log('1'));\na.addEventListener('blur', () => console.log('2'));\n\n\u002F\u002F focusin и focusout всплывают.\n\u002F\u002F Родитель увидит смену фокуса внутри себя.\na.addEventListener('focusin', () => console.log('3'));\na.addEventListener('focusout', () => console.log('4'));\n\nb.focus();\nb.blur();","3\n4",29,{"slug":1711,"title":1712,"source":1713,"exerciseCode":1714,"tutorialCode":1715,"expectedOutput":1238,"executionExplanation":1715,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":1709,"status":13},"scope-hoisting-closures-this-ex29","Упражнение 29: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex29","\u002F\u002F Исправьте код так, чтобы вывод совпал с ожидаемым.\n\u002F\u002F Ожидаемый вывод:\n\u002F\u002F 1: a\n\nconst a = {\n  x: 'a',\n\n  f() {\n    return this.x;\n  },\n\n  g() {\n    const b = this.f;\n\n    return b();\n  },\n};\n\nconsole.log('1:', a.g());\n","\u002F\u002F Упражнение 29: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы: потеря this и bind.\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS методы объекта и this https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F04-object-methods\u002Farticle.md\n\u002F\u002F Learn JS bind https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F10-bind\u002Farticle.md\n\u002F\u002F YDKJS RU лексический this https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002FapC.md#L2\n\u002F\u002F MDN this https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FOperators\u002Fthis\n\u002F\u002F MDN bind https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FFunction\u002Fbind\n\nconst a = {\n  x: 'a',\n\n  f() {\n    \u002F\u002F this должен быть объектом a.\n    return this.x;\n  },\n\n  g() {\n    \u002F\u002F В сломанной версии this.f сохраняли как обычное значение функции.\n    \u002F\u002F При таком вызове связь с объектом терялась.\n    const b = this.f.bind(this);\n\n    \u002F\u002F bind создал функцию с заранее привязанным this.\n    return b();\n  },\n};\n\n\u002F\u002F Вызов a.g ставит this внутри g равным a.\nconsole.log('1:', a.g());",{"slug":1717,"title":1718,"source":1719,"exerciseCode":1720,"tutorialCode":1721,"expectedOutput":1722,"executionExplanation":1721,"language":65,"runtime":66,"programSlug":41,"lessonSlug":41,"order":1723,"status":13},"rendering-dom-events-forms-ex30","Упражнение 30: рендеринг, DOM, события и формы","mentoring\u002Frendering-dom-events-forms\u002Fex\u002Fex30","const a = document.createElement('form');\nconst b = document.createElement('input');\nconst c = document.createElement('input');\n\nb.name = 'x';\nb.value = '1';\nc.name = 'y';\nc.type = 'checkbox';\nc.checked = true;\n\na.append(b, c);\ndocument.body.append(a);\n\nconsole.log(a.elements.length);\nconsole.log(a.elements.x.value);\nconsole.log(a.elements.y.checked);\n","\u002F\u002F Упражнение 30: рендеринг, DOM, события и формы\n\u002F\u002F Темы form.elements и элементы формы\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS form elements https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F4-forms-controls\u002F1-form-elements\u002Farticle.md\n\u002F\u002F MDN HTMLFormElement elements https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlformelement\u002Felements\u002Findex.md\nconst a = document.createElement('form');\nconst b = document.createElement('input');\nconst c = document.createElement('input');\n\nb.name = 'x';\nb.value = '1';\nc.name = 'y';\nc.type = 'checkbox';\nc.checked = true;\n\na.append(b, c);\ndocument.body.append(a);\n\n\u002F\u002F elements хранит элементы управления формы.\nconsole.log(a.elements.length);\n\n\u002F\u002F К элементам можно обращаться по name.\nconsole.log(a.elements.x.value);\nconsole.log(a.elements.y.checked);","2\n1\ntrue",30,{"slug":1725,"title":1726,"source":1727,"exerciseCode":1728,"tutorialCode":1729,"expectedOutput":1730,"executionExplanation":1729,"language":65,"runtime":66,"programSlug":20,"lessonSlug":20,"order":1723,"status":13},"scope-hoisting-closures-this-ex30","Упражнение 30: области видимости, hoisting, замыкания и this","mentoring\u002Fscope-hoisting-closures-this\u002Fex\u002Fex30","function f() {\n  return;\n  {\n    x: 1;\n  }\n}\n\nfunction g() {\n  return {\n    x: 1,\n  };\n}\n\nconsole.log('1:', f());\nconsole.log('2:', g().x);\n","\u002F\u002F Упражнение 30: области видимости, hoisting, замыкания и this\n\u002F\u002F Темы Automatic Semicolon Insertion и return\n\u002F\u002F Читать дальше\n\u002F\u002F Learn JS точка с запятой https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F02-structure\u002Farticle.md\n\u002F\u002F Learn JS return и перенос строки https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F15-function-basics\u002Farticle.md\n\u002F\u002F YDKJS RU https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch5.md\n\u002F\u002F MDN Lexical grammar Automatic semicolon insertion\nfunction f() {\n  \u002F\u002F После return стоит line terminator.\n  \u002F\u002F ASI вставляет точку с запятой после return.\n  \u002F\u002F Объект ниже уже не становится возвращаемым значением.\n  return;\n  {\n    x: 1;\n  }\n}\n\nfunction g() {\n  \u002F\u002F Здесь объект начинается на той же строке, что и return.\n  \u002F\u002F Поэтому функция возвращает объект.\n  return {\n    x: 1,\n  };\n}\n\nconsole.log('1:', f());\nconsole.log('2:', g().x);","1 undefined\n2 1",[1732,1757,1786,1811,1844,1889,1937,1962,1991,2020,2034,2074,2103,2130,2154,2181,2226,2263,2288,2315,2340,2354,2386,2407,2440,2467,2496,2525,2554,2574,2599,2626,2637,2667,2690,2721,2743,2775,2824,2853,2874,2898,2921,2939,2967,2994,3027,3050,3087,3098,3130,3152,3182,3209,3240,3272,3295,3317,3352,3383,3409,3432,3456,3479,3511,3536,3563,3612,3622,3650,3675,3701,3723,3734,3761,3784,3825,3836,3868,3889,3911,3936,3967,3996,4005,4029,4057,4078,4088,4110,4142,4163,4183,4213,4242,4270,4302,4330],{"slug":1733,"title":1734,"baseQuestion":1735,"goodAnswer":1736,"followUps":1737,"references":1747,"programSlug":40,"lessonSlug":40,"order":12,"status":13,"rawBody":1756},"browser-network-q1-chto-takoe-http-zapros","Что такое HTTP-запрос?","Что такое HTTP-запрос в браузере?","Сначала можно объяснить просто: HTTP-запрос это сообщение, которое браузер отправляет серверу, когда нам нужен документ, картинка, JSON, CSS, скрипт или другой ресурс. В запросе есть адрес, метод, заголовки и иногда тело.\n\nНа интервью важно не уходить сразу в `fetch`. `fetch` это JavaScript API, а HTTP-запрос это сетевое сообщение. Один и тот же HTTP-запрос может появиться из загрузки страницы, из тега `img`, из CSS, из `fetch`, из `XMLHttpRequest` или из Service Worker.\n\nХороший ответ должен отделять части запроса:\n\n- URL говорит, куда мы обращаемся.\n- Method говорит, какое действие мы просим выполнить.\n- Headers передают метаданные запроса.\n- Body передает данные, если метод и сценарий это предполагают.\n\nВ Chrome DevTools такой запрос мы обычно ищем во вкладке Network. Там важно смотреть не только имя ресурса, но и Method, Status, Type, Initiator, Payload и Headers.",[1738,1741,1744],{"question":1739,"expected":1740},"Чем URL отличается от заголовков запроса?","кандидат говорит, что URL выбирает ресурс и содержит путь с query-параметрами, а заголовки передают дополнительные метаданные вроде типа данных, авторизации, cookies или правил кеширования.",{"question":1742,"expected":1743},"Почему не каждый запрос появляется из `fetch`?","кандидат объясняет, что браузер сам делает запросы для HTML, CSS, изображений, шрифтов и других ресурсов страницы. JavaScript API это только один из источников запросов.",{"question":1745,"expected":1746},"Что мы сначала смотрим в Network, если кнопка в интерфейсе не загрузила данные?","кандидат говорит, что нужно проверить появился ли запрос, какой у него статус, метод, URL, payload, ответ и что указано в Initiator.",[1748,1752],{"title":1749,"url":1750,"note":1751},"MDN: An overview of HTTP","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Fguides\u002Foverview\u002Findex.md","базовая модель HTTP-сообщений.",{"title":1753,"url":1754,"note":1755},"Chrome DevTools: Inspect network activity","https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fdevtools\u002Fnetwork\u002F","как смотреть запросы во вкладке Network.","# Q1. Что такое HTTP-запрос?\n\n## Базовый вопрос\n\nЧто такое HTTP-запрос в браузере?\n\n## Хороший ответ\n\nСначала можно объяснить просто: HTTP-запрос это сообщение, которое браузер отправляет серверу, когда нам нужен документ, картинка, JSON, CSS, скрипт или другой ресурс. В запросе есть адрес, метод, заголовки и иногда тело.\n\nНа интервью важно не уходить сразу в `fetch`. `fetch` это JavaScript API, а HTTP-запрос это сетевое сообщение. Один и тот же HTTP-запрос может появиться из загрузки страницы, из тега `img`, из CSS, из `fetch`, из `XMLHttpRequest` или из Service Worker.\n\nХороший ответ должен отделять части запроса:\n\n- URL говорит, куда мы обращаемся.\n- Method говорит, какое действие мы просим выполнить.\n- Headers передают метаданные запроса.\n- Body передает данные, если метод и сценарий это предполагают.\n\nВ Chrome DevTools такой запрос мы обычно ищем во вкладке Network. Там важно смотреть не только имя ресурса, но и Method, Status, Type, Initiator, Payload и Headers.\n\n## Уточняющие вопросы\n\n### 1. Чем URL отличается от заголовков запроса?\n\nОжидаем: кандидат говорит, что URL выбирает ресурс и содержит путь с query-параметрами, а заголовки передают дополнительные метаданные вроде типа данных, авторизации, cookies или правил кеширования.\n\n### 2. Почему не каждый запрос появляется из `fetch`?\n\nОжидаем: кандидат объясняет, что браузер сам делает запросы для HTML, CSS, изображений, шрифтов и других ресурсов страницы. JavaScript API это только один из источников запросов.\n\n### 3. Что мы сначала смотрим в Network, если кнопка в интерфейсе не загрузила данные?\n\nОжидаем: кандидат говорит, что нужно проверить появился ли запрос, какой у него статус, метод, URL, payload, ответ и что указано в Initiator.\n\n## Референсы\n\n- [MDN: An overview of HTTP](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Fguides\u002Foverview\u002Findex.md) - базовая модель HTTP-сообщений.\n- [Chrome DevTools: Inspect network activity](https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fdevtools\u002Fnetwork\u002F) - как смотреть запросы во вкладке Network.",{"slug":1758,"title":1759,"baseQuestion":1760,"goodAnswer":1761,"followUps":1762,"references":1772,"programSlug":17,"lessonSlug":17,"order":12,"status":13,"rawBody":1785},"collections-iteration-arrays-q1-chem-map-otlichaetsya-ot-obychnogo-obekta","Чем Map отличается от обычного объекта?","Чем `Map` отличается от обычного объекта, когда мы храним пары ключ-значение?","Сначала можно объяснить просто: обычный объект хорошо подходит для описания сущности с заранее понятными полями, а `Map` лучше подходит для динамической коллекции пар ключ-значение.\n\nВ объекте ключи свойств обычно строки или symbol. Если мы используем объект как ключ через квадратные скобки, он приводится к строке, и разные объекты легко могут превратиться в один и тот же ключ вроде `[object Object]`. В `Map` ключом может быть почти любое значение: объект, функция, число, строка, `NaN`.\n\nУ `Map` есть отдельные методы `set`, `get`, `has`, `delete`, `clear`, свойство `size` и встроенный обход. При обходе `Map` возвращает пары в порядке вставки. Если мы записали новое значение по уже существующему ключу, значение обновится, но ключ не станет новым элементом в конце порядка обхода. Если ключ удалить и добавить снова, тогда он окажется в конце.\n\nНа собеседовании важно не отвечать \"Map всегда лучше объекта\". Объект удобнее для обычной формы данных, JSON, фиксированных полей и доступа через точку. `Map` выбираем, когда ключи динамические, когда ключом должен быть объект или когда нам нужна коллекция с явным размером и нормальным обходом.",[1763,1766,1769],{"question":1764,"expected":1765},"У нас есть два разных пустых объекта, и мы используем их как ключи в обычном объекте. Почему в итоге одно значение может перезаписать другое?","кандидат объясняет, что обычный объект приводит такие ключи к строке. Два разных пустых объекта дадут одинаковое строковое имя свойства, поэтому запись идет в одно и то же место.",{"question":1767,"expected":1768},"Почему `Map` не стоит автоматически выбирать вместо объекта для любого набора данных?","кандидат говорит, что объект лучше подходит для структур с понятными полями, сериализации, передачи данных и доступа через свойства. `Map` нужен именно как коллекция, а не как замена всем объектам.",{"question":1770,"expected":1771},"В `Map` уже есть ключ `x`. Почему после повторного `set(x, 2)` порядок обхода не меняется?","кандидат объясняет, что повторный `set` обновляет значение существующей записи. Новая позиция появляется только если ключ сначала удалить, а потом добавить заново.",[1773,1777,1781],{"title":1774,"url":1775,"note":1776},"ru.javascript.info: Map и Set","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F07-map-set\u002Farticle.md","учебное объяснение отличий `Map` от объекта.",{"title":1778,"url":1779,"note":1780},"MDN: Map","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fmap\u002Findex.md","справочник по API и поведению `Map`.",{"title":1782,"url":1783,"note":1784},"Вы не знаете JS: ES6 и не только — глава 5 Collections","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fes6%20%26%20beyond\u002Fch5.md","дополнительные объяснения про коллекции ES6.","# Q1. Чем Map отличается от обычного объекта?\n\n## Базовый вопрос\n\nЧем `Map` отличается от обычного объекта, когда мы храним пары ключ-значение?\n\n## Хороший ответ\n\nСначала можно объяснить просто: обычный объект хорошо подходит для описания сущности с заранее понятными полями, а `Map` лучше подходит для динамической коллекции пар ключ-значение.\n\nВ объекте ключи свойств обычно строки или symbol. Если мы используем объект как ключ через квадратные скобки, он приводится к строке, и разные объекты легко могут превратиться в один и тот же ключ вроде `[object Object]`. В `Map` ключом может быть почти любое значение: объект, функция, число, строка, `NaN`.\n\nУ `Map` есть отдельные методы `set`, `get`, `has`, `delete`, `clear`, свойство `size` и встроенный обход. При обходе `Map` возвращает пары в порядке вставки. Если мы записали новое значение по уже существующему ключу, значение обновится, но ключ не станет новым элементом в конце порядка обхода. Если ключ удалить и добавить снова, тогда он окажется в конце.\n\nНа собеседовании важно не отвечать \"Map всегда лучше объекта\". Объект удобнее для обычной формы данных, JSON, фиксированных полей и доступа через точку. `Map` выбираем, когда ключи динамические, когда ключом должен быть объект или когда нам нужна коллекция с явным размером и нормальным обходом.\n\n## Уточняющие вопросы\n\n### 1. У нас есть два разных пустых объекта, и мы используем их как ключи в обычном объекте. Почему в итоге одно значение может перезаписать другое?\n\nОжидаем: кандидат объясняет, что обычный объект приводит такие ключи к строке. Два разных пустых объекта дадут одинаковое строковое имя свойства, поэтому запись идет в одно и то же место.\n\n### 2. Почему `Map` не стоит автоматически выбирать вместо объекта для любого набора данных?\n\nОжидаем: кандидат говорит, что объект лучше подходит для структур с понятными полями, сериализации, передачи данных и доступа через свойства. `Map` нужен именно как коллекция, а не как замена всем объектам.\n\n### 3. В `Map` уже есть ключ `x`. Почему после повторного `set(x, 2)` порядок обхода не меняется?\n\nОжидаем: кандидат объясняет, что повторный `set` обновляет значение существующей записи. Новая позиция появляется только если ключ сначала удалить, а потом добавить заново.\n\n## Референсы\n\n- [ru.javascript.info: Map и Set](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F07-map-set\u002Farticle.md) - учебное объяснение отличий `Map` от объекта.\n- [MDN: Map](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fmap\u002Findex.md) - справочник по API и поведению `Map`.\n- [Вы не знаете JS: ES6 и не только — глава 5 Collections](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fes6%20%26%20beyond\u002Fch5.md) - дополнительные объяснения про коллекции ES6.",{"slug":1787,"title":1788,"baseQuestion":1789,"goodAnswer":1790,"followUps":1791,"references":1801,"programSlug":30,"lessonSlug":30,"order":12,"status":13,"rawBody":1810},"event-loop-promises-async-await-q1-chto-takoe-event-loop","Что такое event loop?","Что такое event loop в браузерном JavaScript?","Сначала можно объяснить просто: event loop это механизм браузера, который решает, когда запускать очередной кусок JavaScript-кода. Сам код выполняется не параллельно, а по очереди: сейчас выполняется текущий скрипт или обработчик, а все события, таймеры и продолжения асинхронных операций ждут своего хода.\n\nВ браузере JavaScript-движок сам по себе не \"знает\", когда пользователь кликнул, когда пришел ответ сети или когда истек таймер. Этим занимается браузерное окружение. Оно складывает готовые к выполнению куски работы в очереди, а event loop по очереди передает их движку. Поэтому асинхронность в браузере - это не магическое ожидание внутри строки кода, а договоренность между окружением, очередями и движком.\n\nВ браузере JavaScript-движок выполняет одну задачу до конца. Это правило удобно называть run to completion: пока текущий кусок кода не завершился, другой обработчик не начнет выполняться посреди него. Если в это время истек таймер, пользователь кликнул по странице или пришло другое событие, браузер поставит соответствующую задачу в очередь. Она будет ждать, пока текущий стек вызовов не освободится.\n\nПосле завершения текущей задачи браузер разбирает микрозадачи, например обработчики промисов. Только потом он может перейти к следующей задаче, обновить интерфейс или сделать другую работу окружения. Поэтому порядок \"синхронный код, потом микрозадачи, потом следующая обычная задача\" важнее, чем буквальная задержка в таймере.\n\nЕсли говорить подробнее про термины, `task` это обычная задача event loop на стороне браузерного окружения. Такой задачей может быть выполнение начального script, callback таймера, обработка DOM-события или другая работа, которую браузер поставил в очередь для запуска JavaScript. В учебных материалах такую обычную задачу часто называют `macrotask`, чтобы противопоставить ее `microtask`. Поэтому на собеседовании можно сказать так: в бытовой frontend речи `task` и `macrotask` часто называют одним и тем же уровнем обычных задач, но более аккуратное имя для браузера - `task`.\n\n`microtask` это более мелкое продолжение, которое выполняется не как отдельный будущий проход event loop, а сразу после завершения текущей задачи, когда стек вызовов уже пуст. Типичные источники микрозадач - реакции промисов `.then`, `.catch`, `.finally`, продолжение async-функции после `await` и явный вызов `queueMicrotask`.\n\nПорядок важно проговаривать именно так: текущая задача выполняется до конца, потом браузер очищает очередь микрозадач, и только после этого может перейти к следующей обычной задаче или обновить отрисовку. Если микрозадача добавляет новую микрозадачу, она тоже выполняется в рамках этого же очищения очереди. Поэтому длинная цепочка микрозадач может задержать таймеры, пользовательские события и отрисовку.\n\nОтрисовка страницы не происходит прямо посреди выполняющегося JavaScript. Если мы меняем DOM внутри длинной задачи, пользователь обычно увидит результат только после того, как задача закончится и браузер получит шанс обновить экран. Поэтому длинный синхронный код блокирует не только следующие обработчики, но и реакцию интерфейса.\n\nНа собеседовании важно не отвечать, что event loop \"делает асинхронность параллельной\". Он не запускает обычный JavaScript одновременно в нескольких местах. Он организует порядок выполнения: что идет сейчас, что пойдет после текущего стека, что попадет в микрозадачи, а что дождется следующей задачи.",[1792,1795,1798],{"question":1793,"expected":1794},"Зачем нужен event loop, если JavaScript и так выполняет код сверху вниз?","кандидат объясняет, что код состоит не только из синхронной части. Таймеры, события пользователя, сетевые ответы и другие отложенные действия должны вернуться в выполнение позже. Event loop нужен как механизм координации между браузерным окружением и JavaScript-движком: окружение замечает готовые события, кладет работу в очередь, а движок выполняет ее тогда, когда текущая работа завершена.",{"question":1796,"expected":1797},"Мы запустили длинный `for`, а пользователь в это время кликнул по кнопке. Почему обработчик клика не выполнится сразу?","кандидат объясняет, что длинный `for` выполняется внутри текущей task и занимает стек вызовов. Пока эта task не завершилась, браузер не запускает другой JavaScript-код поверх нее.\n\nКлик при этом не обязан \"пропасть\". Браузер может заметить событие и подготовить задачу для обработчика клика, но выполнить сам обработчик сможет только позже: после завершения длинного синхронного кода, освобождения стека и выполнения микрозадач, которые накопились после текущей task.\n\nГлавная мысль ответа: JavaScript не прерывает выполняющийся синхронный код ради нового обработчика. Поэтому длинные циклы блокируют реакцию интерфейса, даже если пользователь уже совершил действие.",{"question":1799,"expected":1800},"Что такое task, macrotask и microtask?","кандидат объясняет подробно, что `task` это обычная задача, которую браузер запускает через event loop. В бытовых объяснениях ее часто называют `macrotask`, хотя в браузерной модели более аккуратно говорить именно `task`. Примеры таких задач: выполнение начального script, callback `setTimeout`, обработчик пользовательского события, выполнение кода после готовности внешнего script.\n\nКандидат должен отдельно проговорить, что `microtask` это не \"маленький таймер\" и не \"задача с нулевой задержкой\". Это очередь продолжений, которые браузер выполняет после текущей задачи, когда стек вызовов пуст, но до следующей обычной задачи и обычно до отрисовки. Примеры: обработчики `.then`, `.catch`, `.finally`, продолжение после `await`, `queueMicrotask`.\n\nКандидат должен объяснить порядок: сначала весь синхронный код текущей task, затем все microtasks до полного очищения очереди, затем браузер может перейти к следующей task или обновить экран. Поэтому `setTimeout(fn, 0)` не выполняется прямо сейчас: callback таймера попадет в обычную задачу и сможет стартовать только после текущего кода, после микрозадач и после более ранних задач в очереди.",[1802,1806],{"title":1803,"url":1804,"note":1805},"ru.javascript.info: Событийный цикл микрозадачи и макрозадачи","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F99-ui-misc\u002F03-event-loop\u002Farticle.md","учебное объяснение event loop в браузере.",{"title":1807,"url":1808,"note":1809},"Вы не знаете JS: Асинхронность и выполнение - глава 1 Асинхронность сейчас и потом","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fasync%20%26%20performance\u002Fch1.md","ментальная модель \"сейчас\" и \"потом\" в асинхронном JavaScript.","# Q1. Что такое event loop?\n\n## Базовый вопрос\n\nЧто такое event loop в браузерном JavaScript?\n\n## Хороший ответ\n\nСначала можно объяснить просто: event loop это механизм браузера, который решает, когда запускать очередной кусок JavaScript-кода. Сам код выполняется не параллельно, а по очереди: сейчас выполняется текущий скрипт или обработчик, а все события, таймеры и продолжения асинхронных операций ждут своего хода.\n\nВ браузере JavaScript-движок сам по себе не \"знает\", когда пользователь кликнул, когда пришел ответ сети или когда истек таймер. Этим занимается браузерное окружение. Оно складывает готовые к выполнению куски работы в очереди, а event loop по очереди передает их движку. Поэтому асинхронность в браузере - это не магическое ожидание внутри строки кода, а договоренность между окружением, очередями и движком.\n\nВ браузере JavaScript-движок выполняет одну задачу до конца. Это правило удобно называть run to completion: пока текущий кусок кода не завершился, другой обработчик не начнет выполняться посреди него. Если в это время истек таймер, пользователь кликнул по странице или пришло другое событие, браузер поставит соответствующую задачу в очередь. Она будет ждать, пока текущий стек вызовов не освободится.\n\nПосле завершения текущей задачи браузер разбирает микрозадачи, например обработчики промисов. Только потом он может перейти к следующей задаче, обновить интерфейс или сделать другую работу окружения. Поэтому порядок \"синхронный код, потом микрозадачи, потом следующая обычная задача\" важнее, чем буквальная задержка в таймере.\n\nЕсли говорить подробнее про термины, `task` это обычная задача event loop на стороне браузерного окружения. Такой задачей может быть выполнение начального script, callback таймера, обработка DOM-события или другая работа, которую браузер поставил в очередь для запуска JavaScript. В учебных материалах такую обычную задачу часто называют `macrotask`, чтобы противопоставить ее `microtask`. Поэтому на собеседовании можно сказать так: в бытовой frontend речи `task` и `macrotask` часто называют одним и тем же уровнем обычных задач, но более аккуратное имя для браузера - `task`.\n\n`microtask` это более мелкое продолжение, которое выполняется не как отдельный будущий проход event loop, а сразу после завершения текущей задачи, когда стек вызовов уже пуст. Типичные источники микрозадач - реакции промисов `.then`, `.catch`, `.finally`, продолжение async-функции после `await` и явный вызов `queueMicrotask`.\n\nПорядок важно проговаривать именно так: текущая задача выполняется до конца, потом браузер очищает очередь микрозадач, и только после этого может перейти к следующей обычной задаче или обновить отрисовку. Если микрозадача добавляет новую микрозадачу, она тоже выполняется в рамках этого же очищения очереди. Поэтому длинная цепочка микрозадач может задержать таймеры, пользовательские события и отрисовку.\n\nОтрисовка страницы не происходит прямо посреди выполняющегося JavaScript. Если мы меняем DOM внутри длинной задачи, пользователь обычно увидит результат только после того, как задача закончится и браузер получит шанс обновить экран. Поэтому длинный синхронный код блокирует не только следующие обработчики, но и реакцию интерфейса.\n\nНа собеседовании важно не отвечать, что event loop \"делает асинхронность параллельной\". Он не запускает обычный JavaScript одновременно в нескольких местах. Он организует порядок выполнения: что идет сейчас, что пойдет после текущего стека, что попадет в микрозадачи, а что дождется следующей задачи.\n\n## Уточняющие вопросы\n\n### 1. Зачем нужен event loop, если JavaScript и так выполняет код сверху вниз?\n\nОжидаем: кандидат объясняет, что код состоит не только из синхронной части. Таймеры, события пользователя, сетевые ответы и другие отложенные действия должны вернуться в выполнение позже. Event loop нужен как механизм координации между браузерным окружением и JavaScript-движком: окружение замечает готовые события, кладет работу в очередь, а движок выполняет ее тогда, когда текущая работа завершена.\n\n### 2. Мы запустили длинный `for`, а пользователь в это время кликнул по кнопке. Почему обработчик клика не выполнится сразу?\n\nОжидаем: кандидат объясняет, что длинный `for` выполняется внутри текущей task и занимает стек вызовов. Пока эта task не завершилась, браузер не запускает другой JavaScript-код поверх нее.\n\nКлик при этом не обязан \"пропасть\". Браузер может заметить событие и подготовить задачу для обработчика клика, но выполнить сам обработчик сможет только позже: после завершения длинного синхронного кода, освобождения стека и выполнения микрозадач, которые накопились после текущей task.\n\nГлавная мысль ответа: JavaScript не прерывает выполняющийся синхронный код ради нового обработчика. Поэтому длинные циклы блокируют реакцию интерфейса, даже если пользователь уже совершил действие.\n\n### 3. Что такое task, macrotask и microtask?\n\nОжидаем: кандидат объясняет подробно, что `task` это обычная задача, которую браузер запускает через event loop. В бытовых объяснениях ее часто называют `macrotask`, хотя в браузерной модели более аккуратно говорить именно `task`. Примеры таких задач: выполнение начального script, callback `setTimeout`, обработчик пользовательского события, выполнение кода после готовности внешнего script.\n\nКандидат должен отдельно проговорить, что `microtask` это не \"маленький таймер\" и не \"задача с нулевой задержкой\". Это очередь продолжений, которые браузер выполняет после текущей задачи, когда стек вызовов пуст, но до следующей обычной задачи и обычно до отрисовки. Примеры: обработчики `.then`, `.catch`, `.finally`, продолжение после `await`, `queueMicrotask`.\n\nКандидат должен объяснить порядок: сначала весь синхронный код текущей task, затем все microtasks до полного очищения очереди, затем браузер может перейти к следующей task или обновить экран. Поэтому `setTimeout(fn, 0)` не выполняется прямо сейчас: callback таймера попадет в обычную задачу и сможет стартовать только после текущего кода, после микрозадач и после более ранних задач в очереди.\n\n## Референсы\n\n- [ru.javascript.info: Событийный цикл микрозадачи и макрозадачи](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F99-ui-misc\u002F03-event-loop\u002Farticle.md) - учебное объяснение event loop в браузере.\n- [Вы не знаете JS: Асинхронность и выполнение - глава 1 Асинхронность сейчас и потом](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fasync%20%26%20performance\u002Fch1.md) - ментальная модель \"сейчас\" и \"потом\" в асинхронном JavaScript.",{"slug":1812,"title":1813,"baseQuestion":1814,"goodAnswer":1815,"followUps":1816,"references":1826,"programSlug":31,"lessonSlug":31,"order":12,"status":13,"rawBody":1843},"event-loop-promises-deep-dive-q1-pochemu-sinhronnyy-kod-idet-pered-promise-i-taymerom","Почему синхронный код идет перед Promise и таймером?","Есть browser script:\n\n```js\nconsole.log('1');\n\nPromise.resolve().then(() => console.log('2'));\n\nqueueMicrotask(() => console.log('3'));\n\nsetTimeout(() => console.log('4'), 0);\n\nconsole.log('5');\n```\n\nПочему порядок вывода будет `1`, `5`, `2`, `3`, `4`?","Сначала нужно отделить то, что выполняется прямо сейчас, от того, что только планируется на будущее. Мы читаем код сверху вниз и сразу выполняем синхронную часть: обычные `console.log`, тело `new Promise` executor, вызов функции до первого `await`.\n\nВсе, что не выполняется сразу, нужно разложить по очередям. Обработчики промисов, продолжения после `await` и `queueMicrotask` попадают в очередь микрозадач. Callback таймера, обработчик события и похожая работа окружения попадают в обычные задачи event loop.\n\nПосле текущего синхронного кода JavaScript очищает очередь микрозадач. Если микрозадача добавила новую микрозадачу, новая тоже будет выполнена до следующей обычной задачи. Только когда микрозадачи закончились, браузер может перейти к следующей task, например к callback `setTimeout`.\n\nПрактический алгоритм на собеседовании такой:\n\n- Выписываем весь синхронный вывод.\n- Отдельно отмечаем, какие микрозадачи поставлены и в каком порядке.\n- Отдельно отмечаем, какие таймеры и другие task поставлены и в каком порядке.\n- После завершения текущего кода разбираем все микрозадачи до пустой очереди.\n- Потом берем следующую task и после нее снова очищаем микрозадачи.\n\nВажно не думать, что `setTimeout(fn, 0)` означает \"сразу после этой строки\". Он сможет выполниться только после текущей задачи, после всех микрозадач и после более ранних задач в очереди.",[1817,1820,1823],{"question":1818,"expected":1819},"В script есть `console.log('1')`, потом `setTimeout(...)`, потом `console.log('2')`. Почему `2` появится раньше callback таймера?","кандидат объясняет правило run-to-completion: текущая задача выполняется целиком, пока стек вызовов не станет пустым. Выполнение самого browser script уже является task. Внутри этой task `console.log('1')` выполняется сразу, `setTimeout(...)` только регистрирует будущий callback таймера, а `console.log('2')` остается обычным синхронным кодом и тоже выполняется сразу. Даже если таймер указан с задержкой `0`, его callback не может вклиниться между строками текущего script. Браузер сможет взять callback таймера из очереди только после завершения текущей task и после проверки микрозадач.",{"question":1821,"expected":1822},"Мы подписались через `.then` на уже выполненный Promise. Почему обработчик не вызывается прямо в месте подписки?","кандидат говорит, что `.then` не вызывает handler синхронно в момент подписки. Когда Promise уже fulfilled, JavaScript планирует реакцию промиса в очередь микрозадач. Это сохраняет единое правило: обработчики `.then`, `.catch` и `.finally` всегда выполняются асинхронно, после текущего синхронного кода. Поэтому код ниже `.then(...)` успеет выполниться первым, а сам handler запустится на микрозадачном этапе, когда текущая task освободит стек.",{"question":1824,"expected":1825},"Внутри callback таймера мы поставили `Promise.resolve().then(...)`. Почему этот `.then` выполнится до следующего таймера?","кандидат объясняет, что каждый callback таймера запускается как отдельная task. Когда эта task выполняется, код внутри callback может поставить микрозадачи через `Promise.resolve().then(...)` или `queueMicrotask(...)`. После завершения callback браузер не сразу берет следующий таймер. Сначала он делает микрозадачный checkpoint и очищает очередь микрозадач до конца, включая микрозадачи, которые добавили другие микрозадачи. Только после этого event loop может перейти к следующей task, например к следующему callback таймера.",[1827,1829,1833,1835,1839],{"title":1803,"url":1804,"note":1828},"порядок текущей task, микрозадач, таймеров и отрисовки.",{"title":1830,"url":1831,"note":1832},"ru.javascript.info: Микрозадачи","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md","очередь микрозадач и асинхронность обработчиков промисов.",{"title":1807,"url":1808,"note":1834},"ментальная модель \"сейчас\" и \"потом\" в асинхронном коде.",{"title":1836,"url":1837,"note":1838},"MDN: JavaScript execution model","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fexecution_model\u002Findex.md","job queue, event loop и правило run-to-completion.",{"title":1840,"url":1841,"note":1842},"MDN: Using microtasks in JavaScript with queueMicrotask","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtml_dom_api\u002Fmicrotask_guide\u002Findex.md","различие task и microtask, порядок выполнения после завершения task.","# Q1. Почему синхронный код идет перед Promise и таймером?\n\n## Базовый вопрос\n\nЕсть browser script:\n\n```js\nconsole.log('1');\n\nPromise.resolve().then(() => console.log('2'));\n\nqueueMicrotask(() => console.log('3'));\n\nsetTimeout(() => console.log('4'), 0);\n\nconsole.log('5');\n```\n\nПочему порядок вывода будет `1`, `5`, `2`, `3`, `4`?\n\n## Хороший ответ\n\nСначала нужно отделить то, что выполняется прямо сейчас, от того, что только планируется на будущее. Мы читаем код сверху вниз и сразу выполняем синхронную часть: обычные `console.log`, тело `new Promise` executor, вызов функции до первого `await`.\n\nВсе, что не выполняется сразу, нужно разложить по очередям. Обработчики промисов, продолжения после `await` и `queueMicrotask` попадают в очередь микрозадач. Callback таймера, обработчик события и похожая работа окружения попадают в обычные задачи event loop.\n\nПосле текущего синхронного кода JavaScript очищает очередь микрозадач. Если микрозадача добавила новую микрозадачу, новая тоже будет выполнена до следующей обычной задачи. Только когда микрозадачи закончились, браузер может перейти к следующей task, например к callback `setTimeout`.\n\nПрактический алгоритм на собеседовании такой:\n\n- Выписываем весь синхронный вывод.\n- Отдельно отмечаем, какие микрозадачи поставлены и в каком порядке.\n- Отдельно отмечаем, какие таймеры и другие task поставлены и в каком порядке.\n- После завершения текущего кода разбираем все микрозадачи до пустой очереди.\n- Потом берем следующую task и после нее снова очищаем микрозадачи.\n\nВажно не думать, что `setTimeout(fn, 0)` означает \"сразу после этой строки\". Он сможет выполниться только после текущей задачи, после всех микрозадач и после более ранних задач в очереди.\n\n## Уточняющие вопросы\n\n### 1. В script есть `console.log('1')`, потом `setTimeout(...)`, потом `console.log('2')`. Почему `2` появится раньше callback таймера?\n\nОжидаем: кандидат объясняет правило run-to-completion: текущая задача выполняется целиком, пока стек вызовов не станет пустым. Выполнение самого browser script уже является task. Внутри этой task `console.log('1')` выполняется сразу, `setTimeout(...)` только регистрирует будущий callback таймера, а `console.log('2')` остается обычным синхронным кодом и тоже выполняется сразу. Даже если таймер указан с задержкой `0`, его callback не может вклиниться между строками текущего script. Браузер сможет взять callback таймера из очереди только после завершения текущей task и после проверки микрозадач.\n\n### 2. Мы подписались через `.then` на уже выполненный Promise. Почему обработчик не вызывается прямо в месте подписки?\n\nОжидаем: кандидат говорит, что `.then` не вызывает handler синхронно в момент подписки. Когда Promise уже fulfilled, JavaScript планирует реакцию промиса в очередь микрозадач. Это сохраняет единое правило: обработчики `.then`, `.catch` и `.finally` всегда выполняются асинхронно, после текущего синхронного кода. Поэтому код ниже `.then(...)` успеет выполниться первым, а сам handler запустится на микрозадачном этапе, когда текущая task освободит стек.\n\n### 3. Внутри callback таймера мы поставили `Promise.resolve().then(...)`. Почему этот `.then` выполнится до следующего таймера?\n\nОжидаем: кандидат объясняет, что каждый callback таймера запускается как отдельная task. Когда эта task выполняется, код внутри callback может поставить микрозадачи через `Promise.resolve().then(...)` или `queueMicrotask(...)`. После завершения callback браузер не сразу берет следующий таймер. Сначала он делает микрозадачный checkpoint и очищает очередь микрозадач до конца, включая микрозадачи, которые добавили другие микрозадачи. Только после этого event loop может перейти к следующей task, например к следующему callback таймера.\n\n## Референсы\n\n- [ru.javascript.info: Событийный цикл микрозадачи и макрозадачи](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F99-ui-misc\u002F03-event-loop\u002Farticle.md) - порядок текущей task, микрозадач, таймеров и отрисовки.\n- [ru.javascript.info: Микрозадачи](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md) - очередь микрозадач и асинхронность обработчиков промисов.\n- [Вы не знаете JS: Асинхронность и выполнение - глава 1 Асинхронность сейчас и потом](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fasync%20%26%20performance\u002Fch1.md) - ментальная модель \"сейчас\" и \"потом\" в асинхронном коде.\n- [MDN: JavaScript execution model](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fexecution_model\u002Findex.md) - job queue, event loop и правило run-to-completion.\n- [MDN: Using microtasks in JavaScript with queueMicrotask](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtml_dom_api\u002Fmicrotask_guide\u002Findex.md) - различие task и microtask, порядок выполнения после завершения task.",{"slug":1845,"title":1846,"baseQuestion":1847,"goodAnswer":1848,"followUps":1849,"references":1859,"programSlug":59,"lessonSlug":59,"order":12,"status":13,"rawBody":1888},"mock-interview-javascript-core-q1-kakie-tipy-oblastey-vidimosti-byvayut-v-javascript","Какие типы областей видимости бывают в JavaScript?","Какие основные типы областей видимости есть в JavaScript?","В JavaScript область видимости определяет, где имя переменной, функции или параметра доступно для чтения и записи.\n\nОсновные области видимости, которые проверяем в этом вопросе:\n\n- Глобальная область видимости. Это верхний уровень обычного браузерного script, не ES-модуля. В браузере она связана с `window`: глобальный `var` становится свойством `window`, а глобальные `let` и `const` не становятся.\n- Модульная область видимости. Каждый ES-модуль имеет свою область видимости. Объявления верхнего уровня внутри модуля не становятся глобальными переменными и не видны в других модулях без `export` и `import`.\n- Функциональная область видимости. Функция задает отдельную область, а при каждом вызове функции создается новое лексическое окружение для параметров и локальных объявлений. `var`, параметры функции и function declaration внутри функции живут в области этой функции.\n- Блочная область видимости. Ее создают блоки `{}`, например `if`, `for`, `while`, а также `catch`. `let` и `const` живут в блоке, где объявлены.\n\nОтдельно стоит знать специальные случаи:\n\n- `catch` создает отдельную область для параметра ошибки. На базовом уровне это можно считать частным случаем блочной области, но важно помнить, что имя ошибки живет только внутри `catch`.\n- У функций с параметрами и локальными объявлениями могут быть тонкие различия в окружениях. На базовом уровне это относим к функциональной области, но в сложных вопросах нужно помнить, что спецификация описывает это через Environment Record.\n\nГлавная мысль: JavaScript ищет идентификатор от ближайшей области наружу по лексической структуре кода. Он не ищет переменную по месту, откуда функцию вызвали.\n\nВ первом уроке не углубляемся в синтаксис модулей и не требуем спецификационный пересказ всех Environment Record, но кандидат должен знать основные области видимости и понимать, что `catch` является важным специальным случаем.",[1850,1853,1856],{"question":1851,"expected":1852},"Зачем в JavaScript нужны разные уровни области видимости, если можно было бы хранить все имена глобально?","кандидат объясняет, что глобальная область - это общее пространство имен для всей программы. Если хранить все имена там, разные части кода начнут мешать друг другу: можно случайно выбрать одинаковое имя, перезаписать чужое значение, зависеть от порядка загрузки файлов и бояться менять код из-за непонятных связей.\n\nРазные области видимости нужны, чтобы ограничивать место, где имя доступно. Временные переменные функции должны жить внутри этой функции. Переменные внутри условия или цикла не должны торчать наружу, если они нужны только там. Модуль должен показывать наружу только публичные вещи через `export`, а внутренние детали оставлять внутри себя.\n\nХороший ответ связывает scope не только с синтаксисом, но и с архитектурой: области видимости помогают изолировать код, уменьшать конфликты имен, прятать детали реализации, безопаснее рефакторить и читать программу маленькими кусками. При этом кандидат не должен продавать scope как настоящую защиту данных от пользователя: во фронтенде это в первую очередь механизм организации кода и предотвращения ошибок, а не security boundary.",{"question":1854,"expected":1855},"Если функцию вызвали из места, где есть переменная с таким же именем, должна ли эта переменная подменить внешнюю переменную функции?","кандидат говорит, что нет, не должна. Обычный вызов функции не добавляет область видимости вызывающего кода в цепочку поиска имен этой функции.\n\nФункция ищет внешние переменные по месту, где она была создана. У нее есть своя лексическая цепочка: сначала локальные переменные самой функции, потом внешние области, которые окружали функцию в коде при объявлении. Место, откуда функцию вызвали, само по себе эту цепочку не меняет.\n\nЕсли рядом с местом вызова есть переменная с таким же именем, она принадлежит вызывающему коду. Для вызванной функции эта переменная не становится \"ближайшей\", потому что она не находится в ее лексической цепочке. Совпадение имен рядом с вызовом не подменяет внешнюю переменную функции.\n\nТехнически это можно объяснить так: при создании функция сохраняет ссылку на внешнее лексическое окружение. При вызове создается новое окружение самой функции, а его внешняя ссылка берется из сохраненного окружения функции, а не из функции, которая сделала вызов. Поэтому функцию можно передать в другое место, вызвать как callback, сохранить в объекте или вернуть наружу, но поиск внешних переменных все равно пойдет по месту создания.\n\nСлабый ответ: \"функция возьмет переменную рядом с местом вызова\". Такой ответ показывает, что кандидат путает лексическую область видимости с динамической. Хороший ответ должен явно развести эти модели: в JavaScript обычный код использует лексическую область видимости, а не динамическую. На этой же идее держатся замыкания: функция сохраняет доступ к окружению места создания даже после передачи в другое место.",{"question":1857,"expected":1858},"Есть `let x = 1` снаружи функции. Почему после объявления `let x = 2` внутри функции и вызова этой функции переменная снаружи все еще равна `1`?","кандидат говорит, что мы создали новую привязку во внутренней области. Внутри этой области имя будет найдено во внутреннем окружении раньше, чем JavaScript дойдет до внешнего окружения. Поэтому внешняя привязка не исчезает и не меняется, но внутри этой области она перекрыта.\n\nЭто называется shadowing или затенение. Механика простая: JavaScript ищет идентификатор от текущего лексического окружения наружу по цепочке внешних окружений. Как только найдено первое совпадение имени, поиск останавливается. До внешней привязки с таким же именем движок уже не идет.\n\nВажно отделять затенение от переприсваивания. Если мы объявили новое имя во внутренней области, мы не изменили внешнюю переменную - мы создали другую привязку с тем же именем. Если же во внутренней области нет своего объявления, тогда присваивание будет искать уже существующую привязку наружу и может изменить внешнюю переменную.\n\nЕще одна важная оговорка: внутренняя область должна действительно существовать для этого объявления. Функция создает функциональную область, блок с `let` или `const` создает блочную область, `catch` создает область для параметра ошибки. Но `var` в обычном блоке не создает блочную привязку, потому что `var` живет в ближайшей функции или script.\n\nСлабый ответ: \"JavaScript сам поймет, какое значение мы имели в виду\". Хороший ответ должен назвать порядок поиска имени и прямо отделить shadowing от изменения внешней переменной.",[1860,1864,1868,1872,1876,1880,1884],{"title":1861,"url":1862,"note":1863},"Learn JS: Область видимости переменных, замыкание","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md","блоки `{}`, лексическое окружение, внешний `outer` и поиск имени из внутреннего окружения наружу.",{"title":1865,"url":1866,"note":1867},"Learn JS: Устаревшее ключевое слово var","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F04-var\u002Farticle.md","почему `var` не имеет блочной области видимости и ограничивается функцией или script.",{"title":1869,"url":1870,"note":1871},"Learn JS: Глобальный объект","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F05-global-object\u002Farticle.md","связь глобального script с `window` и отличие от модулей.",{"title":1873,"url":1874,"note":1875},"Learn JS: Модули, введение","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F13-modules\u002F01-modules-intro\u002Farticle.md","своя область видимости у каждого ES-модуля и отличие модулей от обычных скриптов.",{"title":1877,"url":1878,"note":1879},"YDKJS: Глава 2. Лексическая область видимости","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch2.md","почему область функции определяется местом объявления, а не местом вызова, и как работает shadowing.",{"title":1881,"url":1882,"note":1883},"YDKJS: Глава 3. Область видимости функции против блоков","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch3.md","function scope, block scope, `let`, `const` и `catch`.",{"title":1885,"url":1886,"note":1887},"MDN: Closures","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Fclosures\u002Findex.md","объяснение лексического окружения, области видимости и цепочки областей.","# Q1. Какие типы областей видимости бывают в JavaScript?\n\n## Базовый вопрос\n\nКакие основные типы областей видимости есть в JavaScript?\n\n## Хороший ответ\n\nВ JavaScript область видимости определяет, где имя переменной, функции или параметра доступно для чтения и записи.\n\nОсновные области видимости, которые проверяем в этом вопросе:\n\n- Глобальная область видимости. Это верхний уровень обычного браузерного script, не ES-модуля. В браузере она связана с `window`: глобальный `var` становится свойством `window`, а глобальные `let` и `const` не становятся.\n- Модульная область видимости. Каждый ES-модуль имеет свою область видимости. Объявления верхнего уровня внутри модуля не становятся глобальными переменными и не видны в других модулях без `export` и `import`.\n- Функциональная область видимости. Функция задает отдельную область, а при каждом вызове функции создается новое лексическое окружение для параметров и локальных объявлений. `var`, параметры функции и function declaration внутри функции живут в области этой функции.\n- Блочная область видимости. Ее создают блоки `{}`, например `if`, `for`, `while`, а также `catch`. `let` и `const` живут в блоке, где объявлены.\n\nОтдельно стоит знать специальные случаи:\n\n- `catch` создает отдельную область для параметра ошибки. На базовом уровне это можно считать частным случаем блочной области, но важно помнить, что имя ошибки живет только внутри `catch`.\n- У функций с параметрами и локальными объявлениями могут быть тонкие различия в окружениях. На базовом уровне это относим к функциональной области, но в сложных вопросах нужно помнить, что спецификация описывает это через Environment Record.\n\nГлавная мысль: JavaScript ищет идентификатор от ближайшей области наружу по лексической структуре кода. Он не ищет переменную по месту, откуда функцию вызвали.\n\nВ первом уроке не углубляемся в синтаксис модулей и не требуем спецификационный пересказ всех Environment Record, но кандидат должен знать основные области видимости и понимать, что `catch` является важным специальным случаем.\n\n## Уточняющие вопросы\n\n### 1. Зачем в JavaScript нужны разные уровни области видимости, если можно было бы хранить все имена глобально?\n\nОжидаем: кандидат объясняет, что глобальная область - это общее пространство имен для всей программы. Если хранить все имена там, разные части кода начнут мешать друг другу: можно случайно выбрать одинаковое имя, перезаписать чужое значение, зависеть от порядка загрузки файлов и бояться менять код из-за непонятных связей.\n\nРазные области видимости нужны, чтобы ограничивать место, где имя доступно. Временные переменные функции должны жить внутри этой функции. Переменные внутри условия или цикла не должны торчать наружу, если они нужны только там. Модуль должен показывать наружу только публичные вещи через `export`, а внутренние детали оставлять внутри себя.\n\nХороший ответ связывает scope не только с синтаксисом, но и с архитектурой: области видимости помогают изолировать код, уменьшать конфликты имен, прятать детали реализации, безопаснее рефакторить и читать программу маленькими кусками. При этом кандидат не должен продавать scope как настоящую защиту данных от пользователя: во фронтенде это в первую очередь механизм организации кода и предотвращения ошибок, а не security boundary.\n\n### 2. Если функцию вызвали из места, где есть переменная с таким же именем, должна ли эта переменная подменить внешнюю переменную функции?\n\nОжидаем: кандидат говорит, что нет, не должна. Обычный вызов функции не добавляет область видимости вызывающего кода в цепочку поиска имен этой функции.\n\nФункция ищет внешние переменные по месту, где она была создана. У нее есть своя лексическая цепочка: сначала локальные переменные самой функции, потом внешние области, которые окружали функцию в коде при объявлении. Место, откуда функцию вызвали, само по себе эту цепочку не меняет.\n\nЕсли рядом с местом вызова есть переменная с таким же именем, она принадлежит вызывающему коду. Для вызванной функции эта переменная не становится \"ближайшей\", потому что она не находится в ее лексической цепочке. Совпадение имен рядом с вызовом не подменяет внешнюю переменную функции.\n\nТехнически это можно объяснить так: при создании функция сохраняет ссылку на внешнее лексическое окружение. При вызове создается новое окружение самой функции, а его внешняя ссылка берется из сохраненного окружения функции, а не из функции, которая сделала вызов. Поэтому функцию можно передать в другое место, вызвать как callback, сохранить в объекте или вернуть наружу, но поиск внешних переменных все равно пойдет по месту создания.\n\nСлабый ответ: \"функция возьмет переменную рядом с местом вызова\". Такой ответ показывает, что кандидат путает лексическую область видимости с динамической. Хороший ответ должен явно развести эти модели: в JavaScript обычный код использует лексическую область видимости, а не динамическую. На этой же идее держатся замыкания: функция сохраняет доступ к окружению места создания даже после передачи в другое место.\n\n### 3. Есть `let x = 1` снаружи функции. Почему после объявления `let x = 2` внутри функции и вызова этой функции переменная снаружи все еще равна `1`?\n\nОжидаем: кандидат говорит, что мы создали новую привязку во внутренней области. Внутри этой области имя будет найдено во внутреннем окружении раньше, чем JavaScript дойдет до внешнего окружения. Поэтому внешняя привязка не исчезает и не меняется, но внутри этой области она перекрыта.\n\nЭто называется shadowing или затенение. Механика простая: JavaScript ищет идентификатор от текущего лексического окружения наружу по цепочке внешних окружений. Как только найдено первое совпадение имени, поиск останавливается. До внешней привязки с таким же именем движок уже не идет.\n\nВажно отделять затенение от переприсваивания. Если мы объявили новое имя во внутренней области, мы не изменили внешнюю переменную - мы создали другую привязку с тем же именем. Если же во внутренней области нет своего объявления, тогда присваивание будет искать уже существующую привязку наружу и может изменить внешнюю переменную.\n\nЕще одна важная оговорка: внутренняя область должна действительно существовать для этого объявления. Функция создает функциональную область, блок с `let` или `const` создает блочную область, `catch` создает область для параметра ошибки. Но `var` в обычном блоке не создает блочную привязку, потому что `var` живет в ближайшей функции или script.\n\nСлабый ответ: \"JavaScript сам поймет, какое значение мы имели в виду\". Хороший ответ должен назвать порядок поиска имени и прямо отделить shadowing от изменения внешней переменной.\n\n## Референсы\n\n- [Learn JS: Область видимости переменных, замыкание](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md) - блоки `{}`, лексическое окружение, внешний `outer` и поиск имени из внутреннего окружения наружу.\n- [Learn JS: Устаревшее ключевое слово var](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F04-var\u002Farticle.md) - почему `var` не имеет блочной области видимости и ограничивается функцией или script.\n- [Learn JS: Глобальный объект](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F05-global-object\u002Farticle.md) - связь глобального script с `window` и отличие от модулей.\n- [Learn JS: Модули, введение](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F13-modules\u002F01-modules-intro\u002Farticle.md) - своя область видимости у каждого ES-модуля и отличие модулей от обычных скриптов.\n- [YDKJS: Глава 2. Лексическая область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch2.md) - почему область функции определяется местом объявления, а не местом вызова, и как работает shadowing.\n- [YDKJS: Глава 3. Область видимости функции против блоков](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch3.md) - function scope, block scope, `let`, `const` и `catch`.\n- [MDN: Closures](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Fclosures\u002Findex.md) - объяснение лексического окружения, области видимости и цепочки областей.",{"slug":1890,"title":1891,"baseQuestion":1891,"goodAnswer":1892,"followUps":1893,"references":1903,"programSlug":18,"lessonSlug":18,"order":12,"status":13,"rawBody":1936},"objects-prototypes-classes-q1-chto-takoe-prototip-obekta-v-javascript","Что такое прототип объекта в JavaScript?","Для обычного объекта прототип - это объект или `null`, на который ссылается внутренний слот `[[Prototype]]`. Объект из этого слота и называется прототипом текущего объекта.\n\nГлавная роль прототипа - дать объекту доступ к общим свойствам и методам без копирования этих свойств в каждый объект. Если при чтении JavaScript не находит собственное свойство, он может продолжить поиск в прототипе. Поэтому прототип - это связь между объектами, а не \"родительский класс\" и не копия набора свойств.\n\nЦепочка прототипов строится из таких ссылок: прототип сам может иметь свой прототип, и так до `null`. У обычного объекта есть только один непосредственный прототип, поэтому обычная цепочка идет по одной линии.\n\nКлючевые мысли:\n\n- У обычного объекта есть внутренний слот `[[Prototype]]`, который хранит ссылку на другой объект или `null`.\n- Объект, на который ссылается `[[Prototype]]`, называется прототипом.\n- Свойство может быть собственным, то есть лежать прямо на объекте.\n- Свойство может быть унаследованным, то есть найденным выше по цепочке прототипов.\n- Унаследованное свойство не копируется в объект. Оно остается там, где было найдено.\n- Свойство функции-конструктора `prototype` - это отдельная вещь: `new` использует его как прототип для будущих экземпляров.\n\nХороший кандидат должен сказать это без магии: объект не получает копии всех свойств прототипа. Он хранит ссылку, по которой JavaScript продолжает поиск, если собственное свойство не найдено. Поэтому \"доступно через прототип\" и \"лежит на самом объекте\" - разные вещи.",[1894,1897,1900],{"question":1895,"expected":1896},"У нас есть `const parent = { x: 1 }` и `const obj = Object.create(parent)`. Почему `obj.x` возвращает `1`, а `Object.hasOwn(obj, 'x')` возвращает `false`?","кандидат объясняет, что JavaScript сначала проверяет сам объект. Если собственного свойства с таким ключом нет, он берет прототип объекта и ищет там. Если свойство найдется в прототипной цепочке, чтение вернет найденное значение. Если свойство нигде не найдется, результатом будет `undefined`.\n\nПоиск идет до первого найденного свойства или до конца цепочки. Конец цепочки - это `null`. Если JavaScript дошел до `null` и нигде не нашел свойство, результатом чтения будет `undefined`.\n\nХороший ответ подчеркивает, что JavaScript не \"берет свойство из класса\" и не копирует его в объект. Он следует по ссылкам между объектами. Поэтому первое найденное свойство останавливает поиск, а более дальние свойства с тем же ключом уже не участвуют в этом чтении.",{"question":1898,"expected":1899},"Чем собственное свойство объекта отличается от свойства, найденного в прототипе?","кандидат говорит, что собственное свойство хранится прямо на самом объекте. Унаследованное свойство на объекте не лежит: оно найдено выше по цепочке `[[Prototype]]`, когда JavaScript не нашел подходящее собственное свойство.\n\nПри обычном чтении разница может быть незаметна: мы обращаемся к свойству и получаем значение. Но для понимания кода важно, где свойство реально находится. Если свойство собственное, объект сам владеет этим ключом. Если свойство унаследованное, объект только связан с другим объектом, в котором это свойство найдено.\n\nХороший ответ добавляет, что эта разница важна для проверок наличия свойства, перечисления ключей и отладки. Например, одни способы обхода работают только с собственными свойствами, а другие могут учитывать унаследованные перечислимые свойства. Поэтому \"мы можем прочитать свойство\" и \"свойство лежит на этом объекте\" - это не одно и то же.",{"question":1901,"expected":1902},"Есть `const parent = { x: 0 }` и `const obj = Object.create(parent)`. Почему после присваивания `obj.x` значения `1` выражение `parent.x` остается `0`?","кандидат объясняет, что в обычном случае значение `1` окажется в самом `obj` как собственное свойство `x`. Прототип от этого не меняется.\n\nДальше кандидат объясняет почему: когда мы пишем значение в свойство, JavaScript пытается выполнить запись для текущего объекта, а не \"пойти наверх и поменять родителя\".\n\nЕсли на текущем объекте уже есть подходящее собственное свойство, меняется оно. Если собственного свойства нет, результат зависит от того, что найдено выше по цепочке. Обычное доступное для записи свойство выше по цепочке обычно приводит к созданию собственного свойства на текущем объекте, и оно начинает затенять унаследованное. Если выше найден accessor с setter, срабатывает setter. Если найдено свойство, которое нельзя записать, запись не проходит: в строгом режиме это может дать ошибку, в нестрогом режиме операция может быть проигнорирована.\n\nХороший ответ не должен сводить запись к одному простому правилу. Неверно говорить и \"присваивание всегда меняет прототип\", и \"присваивание всегда создает собственное свойство\". Правильная мысль: чтение и запись используют связанную механику поиска, но итог записи зависит от найденного свойства и его дескриптора.",[1904,1908,1912,1916,1920,1924,1928,1932],{"title":1905,"url":1906,"note":1907},"Learn JS: Прототипное наследование","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F01-prototype-inheritance\u002Farticle.md","`[[Prototype]]`, цепочка прототипов, чтение свойств через прототип и отличие чтения от записи.",{"title":1909,"url":1910,"note":1911},"Learn JS: Методы прототипов, объекты без свойства **proto**","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F04-prototype-methods\u002Farticle.md","`Object.create`, `Object.getPrototypeOf`, `Object.setPrototypeOf`, собственные свойства и объекты без прототипа.",{"title":1913,"url":1914,"note":1915},"YDKJS: Up & Going, Глава 2","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fup%20%26%20going\u002Fch2.md","простое объяснение прототипов как запасного пути поиска свойства.",{"title":1917,"url":1918,"note":1919},"YDKJS: this и прототипы объектов, Глава 5","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fthis%20%26%20object%20prototypes\u002Fch5.md","`[[Prototype]]`, цепочка объектов, установка и затенение свойств.",{"title":1921,"url":1922,"note":1923},"MDN: Inheritance and the prototype chain","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Finheritance_and_the_prototype_chain\u002Findex.md","`[[Prototype]]`, наследование свойств и поиск по прототипной цепочке.",{"title":1925,"url":1926,"note":1927},"MDN: Property accessors","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fproperty_accessors\u002Findex.md","чтение свойств через точку и квадратные скобки.",{"title":1929,"url":1930,"note":1931},"MDN: Object.defineProperty","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fdefineproperty\u002Findex.md","влияние дескрипторов на запись свойства.",{"title":1933,"url":1934,"note":1935},"ECMA-262: Ordinary Object Internal Methods and Internal Slots","https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html","формальная механика `[[Get]]`, `OrdinaryGet`, `[[Set]]` и `OrdinarySetWithOwnDescriptor`.","# Q1. Что такое прототип объекта в JavaScript?\n\n## Базовый вопрос\n\nЧто такое прототип объекта в JavaScript?\n\n## Хороший ответ\n\nДля обычного объекта прототип - это объект или `null`, на который ссылается внутренний слот `[[Prototype]]`. Объект из этого слота и называется прототипом текущего объекта.\n\nГлавная роль прототипа - дать объекту доступ к общим свойствам и методам без копирования этих свойств в каждый объект. Если при чтении JavaScript не находит собственное свойство, он может продолжить поиск в прототипе. Поэтому прототип - это связь между объектами, а не \"родительский класс\" и не копия набора свойств.\n\nЦепочка прототипов строится из таких ссылок: прототип сам может иметь свой прототип, и так до `null`. У обычного объекта есть только один непосредственный прототип, поэтому обычная цепочка идет по одной линии.\n\nКлючевые мысли:\n\n- У обычного объекта есть внутренний слот `[[Prototype]]`, который хранит ссылку на другой объект или `null`.\n- Объект, на который ссылается `[[Prototype]]`, называется прототипом.\n- Свойство может быть собственным, то есть лежать прямо на объекте.\n- Свойство может быть унаследованным, то есть найденным выше по цепочке прототипов.\n- Унаследованное свойство не копируется в объект. Оно остается там, где было найдено.\n- Свойство функции-конструктора `prototype` - это отдельная вещь: `new` использует его как прототип для будущих экземпляров.\n\nХороший кандидат должен сказать это без магии: объект не получает копии всех свойств прототипа. Он хранит ссылку, по которой JavaScript продолжает поиск, если собственное свойство не найдено. Поэтому \"доступно через прототип\" и \"лежит на самом объекте\" - разные вещи.\n\n## Уточняющие вопросы\n\n### 1. У нас есть `const parent = { x: 1 }` и `const obj = Object.create(parent)`. Почему `obj.x` возвращает `1`, а `Object.hasOwn(obj, 'x')` возвращает `false`?\n\nОжидаем: кандидат объясняет, что JavaScript сначала проверяет сам объект. Если собственного свойства с таким ключом нет, он берет прототип объекта и ищет там. Если свойство найдется в прототипной цепочке, чтение вернет найденное значение. Если свойство нигде не найдется, результатом будет `undefined`.\n\nПоиск идет до первого найденного свойства или до конца цепочки. Конец цепочки - это `null`. Если JavaScript дошел до `null` и нигде не нашел свойство, результатом чтения будет `undefined`.\n\nХороший ответ подчеркивает, что JavaScript не \"берет свойство из класса\" и не копирует его в объект. Он следует по ссылкам между объектами. Поэтому первое найденное свойство останавливает поиск, а более дальние свойства с тем же ключом уже не участвуют в этом чтении.\n\n### 2. Чем собственное свойство объекта отличается от свойства, найденного в прототипе?\n\nОжидаем: кандидат говорит, что собственное свойство хранится прямо на самом объекте. Унаследованное свойство на объекте не лежит: оно найдено выше по цепочке `[[Prototype]]`, когда JavaScript не нашел подходящее собственное свойство.\n\nПри обычном чтении разница может быть незаметна: мы обращаемся к свойству и получаем значение. Но для понимания кода важно, где свойство реально находится. Если свойство собственное, объект сам владеет этим ключом. Если свойство унаследованное, объект только связан с другим объектом, в котором это свойство найдено.\n\nХороший ответ добавляет, что эта разница важна для проверок наличия свойства, перечисления ключей и отладки. Например, одни способы обхода работают только с собственными свойствами, а другие могут учитывать унаследованные перечислимые свойства. Поэтому \"мы можем прочитать свойство\" и \"свойство лежит на этом объекте\" - это не одно и то же.\n\n### 3. Есть `const parent = { x: 0 }` и `const obj = Object.create(parent)`. Почему после присваивания `obj.x` значения `1` выражение `parent.x` остается `0`?\n\nОжидаем: кандидат объясняет, что в обычном случае значение `1` окажется в самом `obj` как собственное свойство `x`. Прототип от этого не меняется.\n\nДальше кандидат объясняет почему: когда мы пишем значение в свойство, JavaScript пытается выполнить запись для текущего объекта, а не \"пойти наверх и поменять родителя\".\n\nЕсли на текущем объекте уже есть подходящее собственное свойство, меняется оно. Если собственного свойства нет, результат зависит от того, что найдено выше по цепочке. Обычное доступное для записи свойство выше по цепочке обычно приводит к созданию собственного свойства на текущем объекте, и оно начинает затенять унаследованное. Если выше найден accessor с setter, срабатывает setter. Если найдено свойство, которое нельзя записать, запись не проходит: в строгом режиме это может дать ошибку, в нестрогом режиме операция может быть проигнорирована.\n\nХороший ответ не должен сводить запись к одному простому правилу. Неверно говорить и \"присваивание всегда меняет прототип\", и \"присваивание всегда создает собственное свойство\". Правильная мысль: чтение и запись используют связанную механику поиска, но итог записи зависит от найденного свойства и его дескриптора.\n\n## Референсы\n\n- [Learn JS: Прототипное наследование](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F01-prototype-inheritance\u002Farticle.md) - `[[Prototype]]`, цепочка прототипов, чтение свойств через прототип и отличие чтения от записи.\n- [Learn JS: Методы прототипов, объекты без свойства **proto**](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F04-prototype-methods\u002Farticle.md) - `Object.create`, `Object.getPrototypeOf`, `Object.setPrototypeOf`, собственные свойства и объекты без прототипа.\n- [YDKJS: Up & Going, Глава 2](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fup%20%26%20going\u002Fch2.md) - простое объяснение прототипов как запасного пути поиска свойства.\n- [YDKJS: this и прототипы объектов, Глава 5](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fthis%20%26%20object%20prototypes\u002Fch5.md) - `[[Prototype]]`, цепочка объектов, установка и затенение свойств.\n- [MDN: Inheritance and the prototype chain](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Finheritance_and_the_prototype_chain\u002Findex.md) - `[[Prototype]]`, наследование свойств и поиск по прототипной цепочке.\n- [MDN: Property accessors](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fproperty_accessors\u002Findex.md) - чтение свойств через точку и квадратные скобки.\n- [MDN: Object.defineProperty](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fdefineproperty\u002Findex.md) - влияние дескрипторов на запись свойства.\n- [ECMA-262: Ordinary Object Internal Methods and Internal Slots](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html) - формальная механика `[[Get]]`, `OrdinaryGet`, `[[Set]]` и `OrdinarySetWithOwnDescriptor`.",{"slug":1938,"title":1939,"baseQuestion":1940,"goodAnswer":1941,"followUps":1942,"references":1952,"programSlug":50,"lessonSlug":50,"order":12,"status":13,"rawBody":1961},"recursion-q1-chto-takoe-rekursiya","Что такое рекурсия?","Что такое рекурсия в JavaScript?","Сначала можно объяснить просто: рекурсия это когда функция решает задачу через такую же задачу меньшего размера. Мы не пытаемся сразу решить все целиком. Мы говорим: если случай уже простой, возвращаем ответ; если нет, уменьшаем задачу и вызываем ту же функцию еще раз.\n\nВ хорошем ответе обязательно должны прозвучать две части:\n\n- базовый случай, где рекурсия останавливается;\n- рекурсивный случай, где функция вызывает себя с более простыми данными.\n\nНа собеседовании важно показать не только определение, но и мысль: рекурсия подходит, когда данные или задача имеют повторяющуюся вложенную структуру. Например число можно уменьшать до нуля, массив можно разбирать по элементам, дерево можно обходить через поддеревья.\n\nТехнически каждый вызов функции получает свой контекст выполнения. Поэтому локальные переменные и параметры разных вызовов не смешиваются. Когда самый глубокий вызов возвращает значение, предыдущие вызовы продолжают работу и собирают итоговый результат назад.",[1943,1946,1949],{"question":1944,"expected":1945},"Зачем рекурсии нужен базовый случай?","кандидат говорит, что без базового случая функция будет вызывать себя бесконечно или пока движок не остановит программу ошибкой переполнения стека.",{"question":1947,"expected":1948},"Почему рекурсивный вызов обычно получает более простые данные?","кандидат объясняет, что каждый шаг должен приближать нас к остановке. Если данные не становятся проще, рекурсия не прогрессирует.",{"question":1950,"expected":1951},"Когда рекурсия читается естественнее цикла?","кандидат приводит смысл вложенной структуры: дерево, вложенный массив, цепочка узлов или задача, где результат собирается из таких же результатов для меньших частей.",[1953,1957],{"title":1954,"url":1955,"note":1956},"MDN: Recursion","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md","базовое определение рекурсии, базового случая и рекурсивного случая.",{"title":1958,"url":1959,"note":1960},"MDN: InternalError too much recursion","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Ferrors\u002Ftoo_much_recursion\u002Findex.md","что происходит, когда рекурсия не останавливается.","# Q1. Что такое рекурсия?\n\n## Базовый вопрос\n\nЧто такое рекурсия в JavaScript?\n\n## Хороший ответ\n\nСначала можно объяснить просто: рекурсия это когда функция решает задачу через такую же задачу меньшего размера. Мы не пытаемся сразу решить все целиком. Мы говорим: если случай уже простой, возвращаем ответ; если нет, уменьшаем задачу и вызываем ту же функцию еще раз.\n\nВ хорошем ответе обязательно должны прозвучать две части:\n\n- базовый случай, где рекурсия останавливается;\n- рекурсивный случай, где функция вызывает себя с более простыми данными.\n\nНа собеседовании важно показать не только определение, но и мысль: рекурсия подходит, когда данные или задача имеют повторяющуюся вложенную структуру. Например число можно уменьшать до нуля, массив можно разбирать по элементам, дерево можно обходить через поддеревья.\n\nТехнически каждый вызов функции получает свой контекст выполнения. Поэтому локальные переменные и параметры разных вызовов не смешиваются. Когда самый глубокий вызов возвращает значение, предыдущие вызовы продолжают работу и собирают итоговый результат назад.\n\n## Уточняющие вопросы\n\n### 1. Зачем рекурсии нужен базовый случай?\n\nОжидаем: кандидат говорит, что без базового случая функция будет вызывать себя бесконечно или пока движок не остановит программу ошибкой переполнения стека.\n\n### 2. Почему рекурсивный вызов обычно получает более простые данные?\n\nОжидаем: кандидат объясняет, что каждый шаг должен приближать нас к остановке. Если данные не становятся проще, рекурсия не прогрессирует.\n\n### 3. Когда рекурсия читается естественнее цикла?\n\nОжидаем: кандидат приводит смысл вложенной структуры: дерево, вложенный массив, цепочка узлов или задача, где результат собирается из таких же результатов для меньших частей.\n\n## Референсы\n\n- [MDN: Recursion](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md) - базовое определение рекурсии, базового случая и рекурсивного случая.\n- [MDN: InternalError too much recursion](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Ferrors\u002Ftoo_much_recursion\u002Findex.md) - что происходит, когда рекурсия не останавливается.",{"slug":1963,"title":1964,"baseQuestion":1965,"goodAnswer":1966,"followUps":1967,"references":1977,"programSlug":41,"lessonSlug":41,"order":12,"status":13,"rawBody":1990},"rendering-dom-events-forms-q1-chto-proishodit-pered-otrisovkoy-stranicy","Что происходит перед отрисовкой страницы?","Что делает браузер перед тем, как показать страницу на экране?","Сначала можно объяснить совсем просто: браузер не показывает HTML напрямую. Он читает HTML и CSS, строит внутренние структуры, понимает какие элементы должны быть видимы, считает их размеры и положение, а потом рисует пиксели на экране.\n\nОбычно этот путь описывают так:\n\n- HTML превращается в DOM.\n- CSS превращается в CSSOM.\n- Из DOM и CSSOM браузер получает дерево видимых элементов.\n- Layout считает размеры и позиции.\n- Paint рисует внешний вид.\n- Compositing собирает итоговый кадр из слоев, если они есть.\n\nНа собеседовании важно не просто перечислить слова. Нужно показать причинную связь: когда мы меняем DOM, текст, класс или стиль, браузеру может понадобиться повторить часть этой работы. Иногда достаточно перерисовать внешний вид, иногда нужно заново посчитать размеры, а иногда обновление может пройти ближе к compositing.\n\nХороший ответ звучит так: мы меняем не пиксели напрямую. Мы меняем данные для браузера, а браузер уже решает, какую часть пути до пикселей нужно пройти заново.",[1968,1971,1974],{"question":1969,"expected":1970},"Почему пользователь не видит просто DOM-дерево?","кандидат говорит, что DOM хранит структуру документа, но экран показывает результат после CSS, расчета размеров и рисования. Один DOM сам по себе еще не говорит, где элемент окажется и как он будет выглядеть.",{"question":1972,"expected":1973},"Зачем браузеру CSSOM, если DOM уже есть?","кандидат объясняет, что DOM отвечает за структуру, а CSSOM за правила оформления. Чтобы понять видимый результат, браузеру нужны и узлы документа, и применимые к ним стили.",{"question":1975,"expected":1976},"Почему изменение класса может быть дороже, чем кажется?","кандидат говорит, что новый класс может изменить применимые стили. Если эти стили влияют на размеры или положение, браузеру придется не только обновить внешний вид, но и заново посчитать layout.",[1978,1982,1986],{"title":1979,"url":1980,"note":1981},"MDN: Critical rendering path","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fperformance\u002Fguides\u002Fcritical_rendering_path\u002Findex.md","путь от HTML, CSS и JavaScript до пикселей на экране.",{"title":1983,"url":1984,"note":1985},"MDN: Document Object Model","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fdocument_object_model\u002Findex.md","DOM как модель структуры документа.",{"title":1987,"url":1988,"note":1989},"MDN: CSS Object Model","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fcss_object_model\u002Findex.md","CSSOM как модель CSS-правил и вычисленных стилей.","# Q1. Что происходит перед отрисовкой страницы?\n\n## Базовый вопрос\n\nЧто делает браузер перед тем, как показать страницу на экране?\n\n## Хороший ответ\n\nСначала можно объяснить совсем просто: браузер не показывает HTML напрямую. Он читает HTML и CSS, строит внутренние структуры, понимает какие элементы должны быть видимы, считает их размеры и положение, а потом рисует пиксели на экране.\n\nОбычно этот путь описывают так:\n\n- HTML превращается в DOM.\n- CSS превращается в CSSOM.\n- Из DOM и CSSOM браузер получает дерево видимых элементов.\n- Layout считает размеры и позиции.\n- Paint рисует внешний вид.\n- Compositing собирает итоговый кадр из слоев, если они есть.\n\nНа собеседовании важно не просто перечислить слова. Нужно показать причинную связь: когда мы меняем DOM, текст, класс или стиль, браузеру может понадобиться повторить часть этой работы. Иногда достаточно перерисовать внешний вид, иногда нужно заново посчитать размеры, а иногда обновление может пройти ближе к compositing.\n\nХороший ответ звучит так: мы меняем не пиксели напрямую. Мы меняем данные для браузера, а браузер уже решает, какую часть пути до пикселей нужно пройти заново.\n\n## Уточняющие вопросы\n\n### 1. Почему пользователь не видит просто DOM-дерево?\n\nОжидаем: кандидат говорит, что DOM хранит структуру документа, но экран показывает результат после CSS, расчета размеров и рисования. Один DOM сам по себе еще не говорит, где элемент окажется и как он будет выглядеть.\n\n### 2. Зачем браузеру CSSOM, если DOM уже есть?\n\nОжидаем: кандидат объясняет, что DOM отвечает за структуру, а CSSOM за правила оформления. Чтобы понять видимый результат, браузеру нужны и узлы документа, и применимые к ним стили.\n\n### 3. Почему изменение класса может быть дороже, чем кажется?\n\nОжидаем: кандидат говорит, что новый класс может изменить применимые стили. Если эти стили влияют на размеры или положение, браузеру придется не только обновить внешний вид, но и заново посчитать layout.\n\n## Референсы\n\n- [MDN: Critical rendering path](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fperformance\u002Fguides\u002Fcritical_rendering_path\u002Findex.md) - путь от HTML, CSS и JavaScript до пикселей на экране.\n- [MDN: Document Object Model](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fdocument_object_model\u002Findex.md) - DOM как модель структуры документа.\n- [MDN: CSS Object Model](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fcss_object_model\u002Findex.md) - CSSOM как модель CSS-правил и вычисленных стилей.",{"slug":1992,"title":1993,"baseQuestion":1994,"goodAnswer":1995,"followUps":1996,"references":2006,"programSlug":19,"lessonSlug":19,"order":12,"status":13,"rawBody":2019},"scope-closures-deep-dive-q1-chem-otlichayutsya-lhs-i-rhs-poisk","Чем отличаются LHS и RHS поиск?","Чем отличаются LHS и RHS поиск в JavaScript?","RHS поиск нужен, когда JavaScript хочет получить значение по имени. Мы читаем переменную, вызываем функцию, передаем значение дальше или используем его в выражении.\n\nLHS поиск нужен, когда JavaScript ищет место, куда можно присвоить значение. Это происходит не только в явном присваивании через `=`, но и при передаче аргумента в параметр функции, потому что параметр тоже получает значение.\n\nГлавная разница простыми словами: RHS спрашивает \"какое значение лежит за этим именем?\", а LHS спрашивает \"куда записать новое значение?\".\n\nЕсли RHS поиск не находит имя, мы получаем `ReferenceError`. Если LHS поиск не находит имя в sloppy mode, браузерный script может создать неявную глобальную переменную. В strict mode такой LHS поиск тоже приводит к `ReferenceError`.\n\nВажно не путать `ReferenceError` и `TypeError`. `ReferenceError` означает, что имя не удалось разрешить. `TypeError` означает, что имя нашли, но с найденным значением пытаются сделать невозможное действие.",[1997,2000,2003],{"question":1998,"expected":1999},"Почему передача значения в параметр функции тоже связана с присваиванием?","кандидат объясняет, что при вызове функции JavaScript создает локальную привязку параметра и кладет в нее переданное значение. Поэтому параметр не просто \"появляется сам\", в него фактически присваивается аргумент вызова.",{"question":2001,"expected":2002},"Почему чтение неизвестного имени дает `ReferenceError`, а вызов найденного числа как функции дает `TypeError`?","кандидат разделяет две стадии. В первом случае JavaScript не смог найти имя ни в одной области видимости. Во втором случае имя найдено, значение получено, но это значение нельзя вызвать как функцию.",{"question":2004,"expected":2005},"Почему в sloppy mode после присваивания в неизвестное имя может появиться глобальная переменная?","кандидат говорит, что это особое поведение нестрогого режима для неразрешенного LHS поиска. JavaScript доходит до глобальной области, не находит привязку и создает глобальное свойство. В strict mode это запрещено.",[2007,2011,2015],{"title":2008,"url":2009,"note":2010},"YDKJS: Глава 1. Что такое область видимости","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch1.md","LHS\u002FRHS поиск, ошибки разрешения имен и неявные глобальные переменные.",{"title":2012,"url":2013,"note":2014},"MDN: ReferenceError","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Freferenceerror\u002Findex.md","ошибка при обращении к несуществующей привязке.",{"title":2016,"url":2017,"note":2018},"MDN: TypeError","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Ftypeerror\u002Findex.md","ошибка при невозможном действии с уже полученным значением.","# Q1. Чем отличаются LHS и RHS поиск?\n\n## Базовый вопрос\n\nЧем отличаются LHS и RHS поиск в JavaScript?\n\n## Хороший ответ\n\nRHS поиск нужен, когда JavaScript хочет получить значение по имени. Мы читаем переменную, вызываем функцию, передаем значение дальше или используем его в выражении.\n\nLHS поиск нужен, когда JavaScript ищет место, куда можно присвоить значение. Это происходит не только в явном присваивании через `=`, но и при передаче аргумента в параметр функции, потому что параметр тоже получает значение.\n\nГлавная разница простыми словами: RHS спрашивает \"какое значение лежит за этим именем?\", а LHS спрашивает \"куда записать новое значение?\".\n\nЕсли RHS поиск не находит имя, мы получаем `ReferenceError`. Если LHS поиск не находит имя в sloppy mode, браузерный script может создать неявную глобальную переменную. В strict mode такой LHS поиск тоже приводит к `ReferenceError`.\n\nВажно не путать `ReferenceError` и `TypeError`. `ReferenceError` означает, что имя не удалось разрешить. `TypeError` означает, что имя нашли, но с найденным значением пытаются сделать невозможное действие.\n\n## Уточняющие вопросы\n\n### 1. Почему передача значения в параметр функции тоже связана с присваиванием?\n\nОжидаем: кандидат объясняет, что при вызове функции JavaScript создает локальную привязку параметра и кладет в нее переданное значение. Поэтому параметр не просто \"появляется сам\", в него фактически присваивается аргумент вызова.\n\n### 2. Почему чтение неизвестного имени дает `ReferenceError`, а вызов найденного числа как функции дает `TypeError`?\n\nОжидаем: кандидат разделяет две стадии. В первом случае JavaScript не смог найти имя ни в одной области видимости. Во втором случае имя найдено, значение получено, но это значение нельзя вызвать как функцию.\n\n### 3. Почему в sloppy mode после присваивания в неизвестное имя может появиться глобальная переменная?\n\nОжидаем: кандидат говорит, что это особое поведение нестрогого режима для неразрешенного LHS поиска. JavaScript доходит до глобальной области, не находит привязку и создает глобальное свойство. В strict mode это запрещено.\n\n## Референсы\n\n- [YDKJS: Глава 1. Что такое область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch1.md) - LHS\u002FRHS поиск, ошибки разрешения имен и неявные глобальные переменные.\n- [MDN: ReferenceError](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Freferenceerror\u002Findex.md) - ошибка при обращении к несуществующей привязке.\n- [MDN: TypeError](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Ftypeerror\u002Findex.md) - ошибка при невозможном действии с уже полученным значением.",{"slug":2021,"title":1846,"baseQuestion":1847,"goodAnswer":1848,"followUps":2022,"references":2026,"programSlug":20,"lessonSlug":20,"order":12,"status":13,"rawBody":1888},"scope-hoisting-closures-this-q1-scope-types",[2023,2024,2025],{"question":1851,"expected":1852},{"question":1854,"expected":1855},{"question":1857,"expected":1858},[2027,2028,2029,2030,2031,2032,2033],{"title":1861,"url":1862,"note":1863},{"title":1865,"url":1866,"note":1867},{"title":1869,"url":1870,"note":1871},{"title":1873,"url":1874,"note":1875},{"title":1877,"url":1878,"note":1879},{"title":1881,"url":1882,"note":1883},{"title":1885,"url":1886,"note":1887},{"slug":2035,"title":2036,"baseQuestion":2036,"goodAnswer":2037,"followUps":2038,"references":2048,"programSlug":21,"lessonSlug":21,"order":12,"status":13,"rawBody":2073},"types-coercion-symbol-json-q1-kakie-tipy-znacheniy-est-v-javascript","Какие типы значений есть в JavaScript?","В JavaScript тип есть у значения, а не у переменной. Одна и та же переменная может сначала хранить строку, потом число, потом объект. Поэтому на собеседовании лучше говорить не \"тип переменной\", а \"тип значения, которое сейчас лежит в переменной\".\n\nНа уровне языка есть восемь основных типов значений:\n\n- `undefined`;\n- `null`;\n- `boolean`;\n- `number`;\n- `bigint`;\n- `string`;\n- `symbol`;\n- `object`.\n\nПервые семь типов относятся к примитивным значениям. Примитивы не являются объектами и не хранят произвольное состояние как обычные объекты. `null` тоже примитивное значение, хотя `typeof null` исторически возвращает `\"object\"`.\n\n`object` - это отдельный непримитивный тип для сложных структур. К нему относятся обычные объекты, массивы, функции, даты, регулярные выражения, `Map`, `Set` и другие встроенные объекты. Поэтому `Map` не является отдельным типом данных языка. Это встроенный объект со своим поведением и внутренними данными. Точно так же массив не является отдельным языковым типом, а является объектом со специальным поведением.\n\nИногда на интервью говорят \"примитивные и ссылочные типы\". Это понятная бытовая формулировка, но точнее говорить \"примитивные значения и объекты\". Объектные значения ведут себя как значения с общей изменяемой сущностью за ними: если две переменные указывают на один объект, изменение через одну переменную будет видно через другую. Но в списке типов языка это все равно один тип `object`, а не отдельные типы `array`, `function`, `map` или `date`.\n\n`typeof` помогает быстро посмотреть на значение, но не является полной классификацией всех встроенных объектов. Он возвращает строку вроде `\"number\"` или `\"string\"`, но для массивов, дат, `Map` и обычных объектов результат будет `\"object\"`. Для функций `typeof` возвращает `\"function\"`, хотя функция все равно является вызываемым объектом, а не отдельным языковым типом.\n\nХороший кандидат должен уверенно назвать все типы, отделить примитивы от объектов и не превращать встроенные классы вроде `Map`, `Array` или `Date` в отдельные типы языка.",[2039,2042,2045],{"question":2040,"expected":2041},"Почему результат `typeof a` меняется после нового присваивания?","кандидат объясняет, что переменная в JavaScript - это имя, через которое мы сейчас достаем какое-то значение. Тип принадлежит именно этому значению. Когда через `a` доступно значение `1`, мы работаем со значением типа `number`. Когда через то же имя доступно значение `\"1\"`, мы работаем уже со значением типа `string`.\n\nХороший ответ отдельно проговаривает, что динамическая типизация не означает \"в JavaScript нет типов\". Типы есть, но они не закреплены за переменной как за контейнером навсегда. Переменная может в разные моменты ссылаться на значения разных типов, а само значение не меняет свой тип от того, в какую переменную мы его положили.\n\n`typeof a` поэтому не читает декларацию переменной и не отвечает на вопрос \"какого типа переменная `a`\". Он вычисляет выражение `a`, получает текущее значение и возвращает строку по типу этого значения. Если мы сначала присвоили `a` значение `1`, `typeof a` даст `\"number\"`. Если потом присвоили `a` значение `\"1\"`, `typeof a` даст `\"string\"`.\n\nПрактический смысл для собеседования: когда мы рассуждаем о коде, мы каждый раз спрашиваем \"какое значение сейчас лежит за этим именем\". Ошибка слабого ответа - говорить так, будто переменная один раз стала \"числовой\" или \"строковой\" и дальше обязана такой оставаться.",{"question":2043,"expected":2044},"Почему `typeof []` и `typeof new Map()` возвращают `\"object\"`?","кандидат говорит, что массив и `Map` - это разные разновидности объектных значений, но на уровне языковых типов они оба относятся к типу `object`. `typeof` не обязан показывать конкретный встроенный объект или коллекцию. Для большинства объектов он дает общий ответ `\"object\"`.\n\nХороший ответ отделяет языковой тип от конкретной формы объекта. Массив - объект со специальным поведением для индексов и `length`. `Map` - встроенный объект со своим прототипом и внутренним хранилищем пар ключ-значение. Это важно для практики, но не добавляет в список типов языка новые пункты `array` или `map`.\n\nПрактический вывод: если нам нужно отличить массив от обычного объекта, используем специальную проверку вроде `Array.isArray(value)`. Если нам нужно понять, что перед нами `Map`, проверяем именно принадлежность к этой встроенной коллекции, а не ждем от `typeof` строки `\"map\"`.",{"question":2046,"expected":2047},"Почему `typeof null` возвращает `\"object\"`, если `null` - примитив?","кандидат сначала отделяет два уровня. По типам языка `null` - отдельное примитивное значение типа `Null`, а не объект. Но оператор `typeof` для него возвращает строку `\"object\"`, потому что это старое поведение JavaScript, которое сохранили ради совместимости с существующим кодом.\n\nХороший ответ объясняет происхождение ловушки: в первой реализации JavaScript значения хранились как пара из тега типа и самого значения. У объектов тег был `0`, а `null` представлялся как нулевой указатель. Из-за этого проверка через `typeof` тоже давала объектный тег. Сейчас это поведение уже закреплено в спецификации: алгоритм `typeof` прямо возвращает `\"object\"`, если значение равно `null`.\n\nПрактический вывод: `typeof value === \"object\"` не доказывает, что перед нами обычный объект, потому что туда попадет и `null`. Если нам нужно проверить именно `null`, используем `value === null`. Если нам нужно проверить объектное значение, обычно отдельно отсекаем `null`, например рассуждаем в духе `value !== null` и дальше уже проверяем объектность нужным способом.\n\nСлабый ответ: \"`null` это объект\". Хороший ответ прямо говорит, что `\"object\"` - результат старого оператора, а не настоящий тип `null`.",[2049,2053,2057,2061,2065,2069],{"title":2050,"url":2051,"note":2052},"ru.javascript.info: Типы данных","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F05-types\u002Farticle.md","список основных типов значений, динамическая типизация и специальные случаи `typeof`.",{"title":2054,"url":2055,"note":2056},"YDKJS: Типы и грамматика, глава 1","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch1.md","идея \"значения имеют типы, переменные не имеют типов\" и отличие объектов от примитивов.",{"title":2058,"url":2059,"note":2060},"ECMA-262: ECMAScript Data Types and Values","https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-ecmascript-data-types-and-values","формальный список языковых типов ECMAScript.",{"title":2062,"url":2063,"note":2064},"ECMA-262: The typeof Operator","https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-typeof-operator","формальное правило, по которому `typeof null` возвращает `\"object\"`.",{"title":2066,"url":2067,"note":2068},"MDN: typeof","https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FOperators\u002Ftypeof","таблица результатов `typeof` и историческое объяснение поведения `typeof null`.",{"title":2070,"url":2071,"note":2072},"ECMA-262: Map Objects","https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-map-objects","`Map` как встроенный объект с внутренним слотом `[[MapData]]`.","# Q1. Какие типы значений есть в JavaScript?\n\n## Базовый вопрос\n\nКакие типы значений есть в JavaScript?\n\n## Хороший ответ\n\nВ JavaScript тип есть у значения, а не у переменной. Одна и та же переменная может сначала хранить строку, потом число, потом объект. Поэтому на собеседовании лучше говорить не \"тип переменной\", а \"тип значения, которое сейчас лежит в переменной\".\n\nНа уровне языка есть восемь основных типов значений:\n\n- `undefined`;\n- `null`;\n- `boolean`;\n- `number`;\n- `bigint`;\n- `string`;\n- `symbol`;\n- `object`.\n\nПервые семь типов относятся к примитивным значениям. Примитивы не являются объектами и не хранят произвольное состояние как обычные объекты. `null` тоже примитивное значение, хотя `typeof null` исторически возвращает `\"object\"`.\n\n`object` - это отдельный непримитивный тип для сложных структур. К нему относятся обычные объекты, массивы, функции, даты, регулярные выражения, `Map`, `Set` и другие встроенные объекты. Поэтому `Map` не является отдельным типом данных языка. Это встроенный объект со своим поведением и внутренними данными. Точно так же массив не является отдельным языковым типом, а является объектом со специальным поведением.\n\nИногда на интервью говорят \"примитивные и ссылочные типы\". Это понятная бытовая формулировка, но точнее говорить \"примитивные значения и объекты\". Объектные значения ведут себя как значения с общей изменяемой сущностью за ними: если две переменные указывают на один объект, изменение через одну переменную будет видно через другую. Но в списке типов языка это все равно один тип `object`, а не отдельные типы `array`, `function`, `map` или `date`.\n\n`typeof` помогает быстро посмотреть на значение, но не является полной классификацией всех встроенных объектов. Он возвращает строку вроде `\"number\"` или `\"string\"`, но для массивов, дат, `Map` и обычных объектов результат будет `\"object\"`. Для функций `typeof` возвращает `\"function\"`, хотя функция все равно является вызываемым объектом, а не отдельным языковым типом.\n\nХороший кандидат должен уверенно назвать все типы, отделить примитивы от объектов и не превращать встроенные классы вроде `Map`, `Array` или `Date` в отдельные типы языка.\n\n## Уточняющие вопросы\n\n### 1. Почему результат `typeof a` меняется после нового присваивания?\n\nУ `a` сначала было значение `1`, и `typeof a` давал `\"number\"`. Потом мы присвоили `a` значение `\"1\"`, и `typeof a` стал давать `\"string\"`. Почему результат изменился, если имя переменной осталось тем же?\n\nОжидаем: кандидат объясняет, что переменная в JavaScript - это имя, через которое мы сейчас достаем какое-то значение. Тип принадлежит именно этому значению. Когда через `a` доступно значение `1`, мы работаем со значением типа `number`. Когда через то же имя доступно значение `\"1\"`, мы работаем уже со значением типа `string`.\n\nХороший ответ отдельно проговаривает, что динамическая типизация не означает \"в JavaScript нет типов\". Типы есть, но они не закреплены за переменной как за контейнером навсегда. Переменная может в разные моменты ссылаться на значения разных типов, а само значение не меняет свой тип от того, в какую переменную мы его положили.\n\n`typeof a` поэтому не читает декларацию переменной и не отвечает на вопрос \"какого типа переменная `a`\". Он вычисляет выражение `a`, получает текущее значение и возвращает строку по типу этого значения. Если мы сначала присвоили `a` значение `1`, `typeof a` даст `\"number\"`. Если потом присвоили `a` значение `\"1\"`, `typeof a` даст `\"string\"`.\n\nПрактический смысл для собеседования: когда мы рассуждаем о коде, мы каждый раз спрашиваем \"какое значение сейчас лежит за этим именем\". Ошибка слабого ответа - говорить так, будто переменная один раз стала \"числовой\" или \"строковой\" и дальше обязана такой оставаться.\n\n### 2. Почему `typeof []` и `typeof new Map()` возвращают `\"object\"`?\n\nОжидаем: кандидат говорит, что массив и `Map` - это разные разновидности объектных значений, но на уровне языковых типов они оба относятся к типу `object`. `typeof` не обязан показывать конкретный встроенный объект или коллекцию. Для большинства объектов он дает общий ответ `\"object\"`.\n\nХороший ответ отделяет языковой тип от конкретной формы объекта. Массив - объект со специальным поведением для индексов и `length`. `Map` - встроенный объект со своим прототипом и внутренним хранилищем пар ключ-значение. Это важно для практики, но не добавляет в список типов языка новые пункты `array` или `map`.\n\nПрактический вывод: если нам нужно отличить массив от обычного объекта, используем специальную проверку вроде `Array.isArray(value)`. Если нам нужно понять, что перед нами `Map`, проверяем именно принадлежность к этой встроенной коллекции, а не ждем от `typeof` строки `\"map\"`.\n\n### 3. Почему `typeof null` возвращает `\"object\"`, если `null` - примитив?\n\nОжидаем: кандидат сначала отделяет два уровня. По типам языка `null` - отдельное примитивное значение типа `Null`, а не объект. Но оператор `typeof` для него возвращает строку `\"object\"`, потому что это старое поведение JavaScript, которое сохранили ради совместимости с существующим кодом.\n\nХороший ответ объясняет происхождение ловушки: в первой реализации JavaScript значения хранились как пара из тега типа и самого значения. У объектов тег был `0`, а `null` представлялся как нулевой указатель. Из-за этого проверка через `typeof` тоже давала объектный тег. Сейчас это поведение уже закреплено в спецификации: алгоритм `typeof` прямо возвращает `\"object\"`, если значение равно `null`.\n\nПрактический вывод: `typeof value === \"object\"` не доказывает, что перед нами обычный объект, потому что туда попадет и `null`. Если нам нужно проверить именно `null`, используем `value === null`. Если нам нужно проверить объектное значение, обычно отдельно отсекаем `null`, например рассуждаем в духе `value !== null` и дальше уже проверяем объектность нужным способом.\n\nСлабый ответ: \"`null` это объект\". Хороший ответ прямо говорит, что `\"object\"` - результат старого оператора, а не настоящий тип `null`.\n\n## Референсы\n\n- [ru.javascript.info: Типы данных](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F05-types\u002Farticle.md) - список основных типов значений, динамическая типизация и специальные случаи `typeof`.\n- [YDKJS: Типы и грамматика, глава 1](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch1.md) - идея \"значения имеют типы, переменные не имеют типов\" и отличие объектов от примитивов.\n- [ECMA-262: ECMAScript Data Types and Values](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-ecmascript-data-types-and-values) - формальный список языковых типов ECMAScript.\n- [ECMA-262: The typeof Operator](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-typeof-operator) - формальное правило, по которому `typeof null` возвращает `\"object\"`.\n- [MDN: typeof](https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FOperators\u002Ftypeof) - таблица результатов `typeof` и историческое объяснение поведения `typeof null`.\n- [ECMA-262: Map Objects](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-map-objects) - `Map` как встроенный объект с внутренним слотом `[[MapData]]`.",{"slug":2075,"title":2076,"baseQuestion":2077,"goodAnswer":2078,"followUps":2079,"references":2089,"programSlug":40,"lessonSlug":40,"order":26,"status":13,"rawBody":2102},"browser-network-q2-kakie-metody-http-est","Какие методы HTTP есть?","Назовите основные методы HTTP и кратко объясните, для чего нужен каждый.","Сначала можно ответить как пользователь браузера и API: метод HTTP говорит серверу, что мы хотим сделать с ресурсом. На собеседовании важно назвать не только `GET` и `POST`, а полный базовый набор методов, которые встречаются в HTTP и веб-разработке.\n\nОсновные методы:\n\n- `GET` — получить ресурс.\n- `HEAD` — получить только заголовки ответа без тела.\n- `POST` — отправить данные для обработки или создания действия.\n- `PUT` — полностью заменить ресурс или создать его по известному адресу.\n- `PATCH` — частично изменить ресурс.\n- `DELETE` — удалить ресурс.\n- `OPTIONS` — узнать, какие методы и возможности доступны для ресурса.\n- `CONNECT` — установить туннель, обычно для проксирования.\n- `TRACE` — диагностически вернуть путь запроса, в обычной frontend-разработке почти не используется.\n\nДальше нужно объяснить, что метод сам по себе не делает магию. Сервер решает, как обработать запрос, но метод задает договор и ожидания для клиента, сервера, кешей, прокси, CORS и инструментов вроде Chrome DevTools.\n\nДля frontend особенно важны `GET`, `POST`, `PUT`, `PATCH`, `DELETE` и `OPTIONS`. `OPTIONS` часто всплывает в браузере из-за CORS preflight, когда браузер заранее проверяет, разрешен ли будущий cross-origin запрос.",[2080,2083,2086],{"question":2081,"expected":2082},"Почему на frontend-собеседовании мало просто сказать `GET` и `POST`?","кандидат говорит, что реальные API используют разные методы для чтения, создания, замены, частичного изменения и удаления. Еще важно понимать `OPTIONS`, потому что браузер сам может отправлять preflight.",{"question":2084,"expected":2085},"Чем `PUT` отличается от `PATCH` простыми словами?","кандидат объясняет, что `PUT` обычно означает замену ресурса целиком, а `PATCH` частичное изменение. Конкретные детали все равно задает контракт API.",{"question":2087,"expected":2088},"Почему `HEAD` может быть полезен, если он не возвращает тело?","кандидат говорит, что через `HEAD` можно проверить метаданные ресурса, например существование, размер, тип или кеш-заголовки, не скачивая само тело ответа.",[2090,2094,2098],{"title":2091,"url":2092,"note":2093},"MDN: HTTP request methods","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Freference\u002Fmethods\u002Findex.md","список стандартных HTTP-методов и их назначение.",{"title":2095,"url":2096,"note":2097},"MDN: OPTIONS","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Freference\u002Fmethods\u002Foptions\u002Findex.md","метод `OPTIONS` и связь с проверкой возможностей запроса.",{"title":2099,"url":2100,"note":2101},"MDN: CORS","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Fguides\u002Fcors\u002Findex.md","почему браузер может отправлять preflight `OPTIONS`.","# Q2. Какие методы HTTP есть?\n\n## Базовый вопрос\n\nНазовите основные методы HTTP и кратко объясните, для чего нужен каждый.\n\n## Хороший ответ\n\nСначала можно ответить как пользователь браузера и API: метод HTTP говорит серверу, что мы хотим сделать с ресурсом. На собеседовании важно назвать не только `GET` и `POST`, а полный базовый набор методов, которые встречаются в HTTP и веб-разработке.\n\nОсновные методы:\n\n- `GET` — получить ресурс.\n- `HEAD` — получить только заголовки ответа без тела.\n- `POST` — отправить данные для обработки или создания действия.\n- `PUT` — полностью заменить ресурс или создать его по известному адресу.\n- `PATCH` — частично изменить ресурс.\n- `DELETE` — удалить ресурс.\n- `OPTIONS` — узнать, какие методы и возможности доступны для ресурса.\n- `CONNECT` — установить туннель, обычно для проксирования.\n- `TRACE` — диагностически вернуть путь запроса, в обычной frontend-разработке почти не используется.\n\nДальше нужно объяснить, что метод сам по себе не делает магию. Сервер решает, как обработать запрос, но метод задает договор и ожидания для клиента, сервера, кешей, прокси, CORS и инструментов вроде Chrome DevTools.\n\nДля frontend особенно важны `GET`, `POST`, `PUT`, `PATCH`, `DELETE` и `OPTIONS`. `OPTIONS` часто всплывает в браузере из-за CORS preflight, когда браузер заранее проверяет, разрешен ли будущий cross-origin запрос.\n\n## Уточняющие вопросы\n\n### 1. Почему на frontend-собеседовании мало просто сказать `GET` и `POST`?\n\nОжидаем: кандидат говорит, что реальные API используют разные методы для чтения, создания, замены, частичного изменения и удаления. Еще важно понимать `OPTIONS`, потому что браузер сам может отправлять preflight.\n\n### 2. Чем `PUT` отличается от `PATCH` простыми словами?\n\nОжидаем: кандидат объясняет, что `PUT` обычно означает замену ресурса целиком, а `PATCH` частичное изменение. Конкретные детали все равно задает контракт API.\n\n### 3. Почему `HEAD` может быть полезен, если он не возвращает тело?\n\nОжидаем: кандидат говорит, что через `HEAD` можно проверить метаданные ресурса, например существование, размер, тип или кеш-заголовки, не скачивая само тело ответа.\n\n## Референсы\n\n- [MDN: HTTP request methods](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Freference\u002Fmethods\u002Findex.md) - список стандартных HTTP-методов и их назначение.\n- [MDN: OPTIONS](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Freference\u002Fmethods\u002Foptions\u002Findex.md) - метод `OPTIONS` и связь с проверкой возможностей запроса.\n- [MDN: CORS](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Fguides\u002Fcors\u002Findex.md) - почему браузер может отправлять preflight `OPTIONS`.",{"slug":2104,"title":2105,"baseQuestion":2106,"goodAnswer":2107,"followUps":2108,"references":2118,"programSlug":17,"lessonSlug":17,"order":26,"status":13,"rawBody":2129},"collections-iteration-arrays-q2-kak-set-ponimaet-chto-znachenie-uzhe-est","Как Set понимает что значение уже есть?","Как `Set` решает, что добавляемое значение уже есть в коллекции?","`Set` хранит уникальные значения. Когда мы добавляем значение, он сравнивает его с уже существующими значениями не через приведение типов, а по алгоритму SameValueZero.\n\nПрактически это близко к строгому сравнению: число `1` и строка `'1'` остаются разными значениями. Объекты сравниваются по ссылке, поэтому два пустых объекта считаются разными. Но есть важные особенности: `NaN` считается равным `NaN`, а `+0` и `-0` считаются одним и тем же значением.\n\nПорядок обхода `Set` идет по порядку первого успешного добавления значений. Повторное добавление уже существующего значения не создает новый элемент и не переносит значение в конец.\n\nХороший ответ должен показать, что `Set` не \"магически убирает похожие значения\". Он убирает только значения, которые для этого алгоритма действительно одинаковые.",[2109,2112,2115],{"question":2110,"expected":2111},"Почему у `new Set([1, '1'])` размер равен `2`?","кандидат говорит, что `Set` не приводит типы. Число `1` и строка `'1'` это разные значения.",{"question":2113,"expected":2114},"Почему у `new Set([NaN, NaN])` размер равен `1`, хотя `NaN === NaN` дает `false`?","кандидат объясняет, что `Set` использует SameValueZero, где `NaN` считается равным `NaN`.",{"question":2116,"expected":2117},"Почему два пустых объекта в `Set` остаются двумя разными значениями?","кандидат говорит, что объекты сравниваются по ссылке. Два литерала создают две разные ссылки, даже если структура у них одинаковая.",[2119,2121,2125],{"title":1774,"url":1775,"note":2120},"учебное объяснение `Set` и уникальности значений.",{"title":2122,"url":2123,"note":2124},"MDN: Set","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fset\u002Findex.md","справочник по `Set`.",{"title":2126,"url":2127,"note":2128},"ECMA-262: SameValueZero","https:\u002F\u002Ftc39.es\u002Fecma262\u002F#sec-samevaluezero","формальное описание алгоритма сравнения.","# Q2. Как Set понимает что значение уже есть?\n\n## Базовый вопрос\n\nКак `Set` решает, что добавляемое значение уже есть в коллекции?\n\n## Хороший ответ\n\n`Set` хранит уникальные значения. Когда мы добавляем значение, он сравнивает его с уже существующими значениями не через приведение типов, а по алгоритму SameValueZero.\n\nПрактически это близко к строгому сравнению: число `1` и строка `'1'` остаются разными значениями. Объекты сравниваются по ссылке, поэтому два пустых объекта считаются разными. Но есть важные особенности: `NaN` считается равным `NaN`, а `+0` и `-0` считаются одним и тем же значением.\n\nПорядок обхода `Set` идет по порядку первого успешного добавления значений. Повторное добавление уже существующего значения не создает новый элемент и не переносит значение в конец.\n\nХороший ответ должен показать, что `Set` не \"магически убирает похожие значения\". Он убирает только значения, которые для этого алгоритма действительно одинаковые.\n\n## Уточняющие вопросы\n\n### 1. Почему у `new Set([1, '1'])` размер равен `2`?\n\nОжидаем: кандидат говорит, что `Set` не приводит типы. Число `1` и строка `'1'` это разные значения.\n\n### 2. Почему у `new Set([NaN, NaN])` размер равен `1`, хотя `NaN === NaN` дает `false`?\n\nОжидаем: кандидат объясняет, что `Set` использует SameValueZero, где `NaN` считается равным `NaN`.\n\n### 3. Почему два пустых объекта в `Set` остаются двумя разными значениями?\n\nОжидаем: кандидат говорит, что объекты сравниваются по ссылке. Два литерала создают две разные ссылки, даже если структура у них одинаковая.\n\n## Референсы\n\n- [ru.javascript.info: Map и Set](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F07-map-set\u002Farticle.md) - учебное объяснение `Set` и уникальности значений.\n- [MDN: Set](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fset\u002Findex.md) - справочник по `Set`.\n- [ECMA-262: SameValueZero](https:\u002F\u002Ftc39.es\u002Fecma262\u002F#sec-samevaluezero) - формальное описание алгоритма сравнения.",{"slug":2131,"title":2132,"baseQuestion":2133,"goodAnswer":2134,"followUps":2135,"references":2145,"programSlug":30,"lessonSlug":30,"order":26,"status":13,"rawBody":2153},"event-loop-promises-async-await-q2-chem-mikrozadachi-otlichayutsya-ot-zadach-event-loop","Чем микрозадачи отличаются от задач event loop?","Чем микрозадачи отличаются от обычных задач event loop?","Простой ответ: обычная задача это крупный кусок работы для event loop, например выполнение скрипта, обработчик события или callback таймера. Микрозадача это более мелкое продолжение, которое должно выполниться после текущего кода, но до следующей обычной задачи.\n\nОбычная задача приходит из браузерного окружения: начальный script, таймер, DOM-событие, выполнение внешнего script после загрузки. Когда event loop выбирает такую задачу, JavaScript выполняет ее полностью. Внутри этой задачи могут появляться новые работы на будущее: таймер может поставить обычную задачу, а промис может поставить микрозадачу.\n\nМикрозадачи обычно приходят из промисной модели JavaScript. В браузере обработчики `.then`, `.catch`, `.finally`, явный `queueMicrotask` и продолжения после `await` попадают в очередь микрозадач. Когда текущая обычная задача завершилась и стек вызовов пуст, браузер выполняет все накопившиеся микрозадачи.\n\nГлавное отличие не в том, что микрозадача \"быстрее\", а в ее месте в расписании. Микрозадачи выполняются до следующей обычной задачи. Если микрозадача добавила новую микрозадачу, она тоже будет выполнена в этой же фазе, пока очередь не опустеет. Поэтому микрозадачи имеют высокий приоритет относительно таймеров и событий, которые ждут следующую task.\n\nИз-за этого промисы обычно \"обгоняют\" таймеры с нулевой задержкой: callback `setTimeout` будет обычной задачей, а обработчик выполненного промиса будет микрозадачей.\n\nНа практике важно помнить, что микрозадачи тоже выполняются в основном потоке. Если бесконечно добавлять новые микрозадачи, браузер долго не перейдет к следующей задаче и не сможет нормально обновлять страницу. Это та же проблема блокировки интерфейса, только созданная не длинным циклом, а бесконечной или слишком большой цепочкой микрозадач.\n\nЕще один важный момент: обработчики промисов всегда асинхронны относительно текущего стека. Даже если Promise уже fulfilled, его `.then` не вызывается немедленно в месте подписки. Обработчик попадет в очередь микрозадач и выполнится после синхронного кода.",[2136,2139,2142],{"question":2137,"expected":2138},"Почему `.then` у уже выполненного Promise все равно выполняется после синхронного кода?","кандидат говорит, что обработчик промиса не вызывается сразу в той же строке. Даже уже выполненный Promise планирует реакцию через очередь микрозадач. Поэтому сначала заканчивается текущий синхронный код, стек становится пустым, и только потом браузер берет обработчик из очереди микрозадач.",{"question":2140,"expected":2141},"Почему callback таймера может ждать, пока выполнятся все обработчики промисов?","кандидат объясняет, что перед переходом к следующей обычной задаче браузер очищает очередь микрозадач. Таймер с нулевой задержкой планирует обычную задачу, а `.then` планирует микрозадачу. Поэтому уже накопившиеся микрозадачи будут выполнены раньше callback таймера.",{"question":2143,"expected":2144},"Когда `queueMicrotask` ближе по смыслу к `.then`, чем к `setTimeout`?","кандидат говорит, что `queueMicrotask` явно планирует работу в очередь микрозадач: после текущего стека, но до следующей обычной задачи и до обычного шанса на отрисовку. `setTimeout` планирует отдельную обычную задачу на будущий проход event loop, поэтому он стоит ниже по очередности.",[2146,2147,2149],{"title":1830,"url":1831,"note":1832},{"title":1803,"url":1804,"note":2148},"порядок задач, микрозадач и отрисовки.",{"title":2150,"url":2151,"note":2152},"ECMA-262: Jobs and Job Queues","https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-jobs-and-job-queues","формальная база для очередей job в ECMAScript.","# Q2. Чем микрозадачи отличаются от задач event loop?\n\n## Базовый вопрос\n\nЧем микрозадачи отличаются от обычных задач event loop?\n\n## Хороший ответ\n\nПростой ответ: обычная задача это крупный кусок работы для event loop, например выполнение скрипта, обработчик события или callback таймера. Микрозадача это более мелкое продолжение, которое должно выполниться после текущего кода, но до следующей обычной задачи.\n\nОбычная задача приходит из браузерного окружения: начальный script, таймер, DOM-событие, выполнение внешнего script после загрузки. Когда event loop выбирает такую задачу, JavaScript выполняет ее полностью. Внутри этой задачи могут появляться новые работы на будущее: таймер может поставить обычную задачу, а промис может поставить микрозадачу.\n\nМикрозадачи обычно приходят из промисной модели JavaScript. В браузере обработчики `.then`, `.catch`, `.finally`, явный `queueMicrotask` и продолжения после `await` попадают в очередь микрозадач. Когда текущая обычная задача завершилась и стек вызовов пуст, браузер выполняет все накопившиеся микрозадачи.\n\nГлавное отличие не в том, что микрозадача \"быстрее\", а в ее месте в расписании. Микрозадачи выполняются до следующей обычной задачи. Если микрозадача добавила новую микрозадачу, она тоже будет выполнена в этой же фазе, пока очередь не опустеет. Поэтому микрозадачи имеют высокий приоритет относительно таймеров и событий, которые ждут следующую task.\n\nИз-за этого промисы обычно \"обгоняют\" таймеры с нулевой задержкой: callback `setTimeout` будет обычной задачей, а обработчик выполненного промиса будет микрозадачей.\n\nНа практике важно помнить, что микрозадачи тоже выполняются в основном потоке. Если бесконечно добавлять новые микрозадачи, браузер долго не перейдет к следующей задаче и не сможет нормально обновлять страницу. Это та же проблема блокировки интерфейса, только созданная не длинным циклом, а бесконечной или слишком большой цепочкой микрозадач.\n\nЕще один важный момент: обработчики промисов всегда асинхронны относительно текущего стека. Даже если Promise уже fulfilled, его `.then` не вызывается немедленно в месте подписки. Обработчик попадет в очередь микрозадач и выполнится после синхронного кода.\n\n## Уточняющие вопросы\n\n### 1. Почему `.then` у уже выполненного Promise все равно выполняется после синхронного кода?\n\nОжидаем: кандидат говорит, что обработчик промиса не вызывается сразу в той же строке. Даже уже выполненный Promise планирует реакцию через очередь микрозадач. Поэтому сначала заканчивается текущий синхронный код, стек становится пустым, и только потом браузер берет обработчик из очереди микрозадач.\n\n### 2. Почему callback таймера может ждать, пока выполнятся все обработчики промисов?\n\nОжидаем: кандидат объясняет, что перед переходом к следующей обычной задаче браузер очищает очередь микрозадач. Таймер с нулевой задержкой планирует обычную задачу, а `.then` планирует микрозадачу. Поэтому уже накопившиеся микрозадачи будут выполнены раньше callback таймера.\n\n### 3. Когда `queueMicrotask` ближе по смыслу к `.then`, чем к `setTimeout`?\n\nОжидаем: кандидат говорит, что `queueMicrotask` явно планирует работу в очередь микрозадач: после текущего стека, но до следующей обычной задачи и до обычного шанса на отрисовку. `setTimeout` планирует отдельную обычную задачу на будущий проход event loop, поэтому он стоит ниже по очередности.\n\n## Референсы\n\n- [ru.javascript.info: Микрозадачи](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md) - очередь микрозадач и асинхронность обработчиков промисов.\n- [ru.javascript.info: Событийный цикл микрозадачи и макрозадачи](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F99-ui-misc\u002F03-event-loop\u002Farticle.md) - порядок задач, микрозадач и отрисовки.\n- [ECMA-262: Jobs and Job Queues](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-jobs-and-job-queues) - формальная база для очередей job в ECMAScript.",{"slug":2155,"title":2156,"baseQuestion":2157,"goodAnswer":2158,"followUps":2159,"references":2169,"programSlug":31,"lessonSlug":31,"order":26,"status":13,"rawBody":2180},"event-loop-promises-deep-dive-q2-pochemu-taymer-zhdet-vsyu-ochered-mikrozadach","Почему таймер ждет всю очередь микрозадач?","Есть browser script:\n\n```js\nsetTimeout(() => console.log('1'), 0);\n\nPromise.resolve().then(() => {\n  console.log('2');\n  queueMicrotask(() => console.log('3'));\n});\n\nqueueMicrotask(() => console.log('4'));\n\nconsole.log('5');\n```\n\nПочему порядок вывода будет `5`, `2`, `4`, `3`, `1`?","Простой ответ: перед переходом к следующей обычной task браузер должен очистить очередь микрозадач. Таймер с нулевой задержкой попадает в очередь обычных задач, а `.then`, `.catch`, `.finally`, продолжение после `await` и `queueMicrotask` попадают в очередь микрозадач.\n\nЕсли после синхронного кода уже есть микрозадачи, они выполнятся раньше callback таймера. Если одна микрозадача добавляет другую микрозадачу, новая микрозадача тоже будет выполнена в этом же цикле очистки очереди. Поэтому большая цепочка промисов может долго не давать браузеру перейти к таймеру, событию пользователя или отрисовке.\n\nЭто не значит, что микрозадачи выполняются в отдельном потоке. Они выполняются в том же основном потоке JavaScript. Разница только в месте расписания: микрозадачи стоят перед следующей обычной задачей.\n\nНа практике это важно для UI. Если мы бесконечно планируем микрозадачи, интерфейс может не получить шанс обновиться, а таймеры будут ждать, хотя их задержка уже истекла.",[2160,2163,2166],{"question":2161,"expected":2162},"В одном script вызвали `Promise.resolve().then(fn)`, `queueMicrotask(g)` и `setTimeout(h, 0)`. Почему `fn` и `g` выполнятся перед `h`?","кандидат разделяет две очереди. `Promise.resolve().then(fn)` не вызывает `fn` сразу, а планирует реакцию Promise как микрозадачу. `queueMicrotask(g)` явно кладет `g` в ту же очередь микрозадач. `setTimeout(h, 0)` планирует `h` как обычную task таймера на будущий проход event loop. После завершения текущего script браузер сначала очищает микрозадачи в порядке их добавления, поэтому выполнятся `fn` и `g`, и только потом event loop сможет перейти к timer task с `h`.",{"question":2164,"expected":2165},"Микрозадача внутри себя снова вызывает `queueMicrotask`. Почему таймер ждет и эту новую микрозадачу?","кандидат говорит, что очередь микрозадач очищается не только по элементам, которые были в ней в начале. После каждой выполненной микрозадачи event loop снова смотрит, не появились ли новые микрозадачи. Если текущая микрозадача вызвала `queueMicrotask`, новая задача добавляется в конец той же microtask queue и тоже выполняется до перехода к следующей обычной task. Поэтому таймер ждет не только исходные микрозадачи, но и те, которые они добавили. Если микрозадачи бесконечно добавляют новые микрозадачи, таймеры, пользовательские события и отрисовка могут долго не получить управление.",{"question":2167,"expected":2168},"Таймер с задержкой `0` уже готов, но очередь микрозадач еще не пустая. Почему callback таймера все равно не стартует?","кандидат объясняет, что `setTimeout(h, 0)` означает \"сделать timer task доступной как можно раньше\", а не \"выполнить `h` прямо сейчас\" и не \"поставить `h` перед микрозадачами\". Таймер может стать готовым, пока текущий script или микрозадачи еще выполняются, но JavaScript не прерывает текущую работу ради него. Callback таймера стартует только когда текущая task завершилась, стек пуст, и очередь микрозадач очищена. Поэтому готовность таймера и фактический запуск callback - разные моменты.",[2170,2172,2174,2178],{"title":1803,"url":1804,"note":2171},"отношение task, microtask и отрисовки.",{"title":1830,"url":1831,"note":2173},"выполнение микрозадач до следующей обычной задачи.",{"title":2175,"url":2176,"note":2177},"MDN: queueMicrotask","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fwindow\u002Fqueuemicrotask\u002Findex.md","справочник по явному планированию микрозадачи.",{"title":1840,"url":1841,"note":2179},"различие task и microtask, очистка очереди микрозадач до пустого состояния.","# Q2. Почему таймер ждет всю очередь микрозадач?\n\n## Базовый вопрос\n\nЕсть browser script:\n\n```js\nsetTimeout(() => console.log('1'), 0);\n\nPromise.resolve().then(() => {\n  console.log('2');\n  queueMicrotask(() => console.log('3'));\n});\n\nqueueMicrotask(() => console.log('4'));\n\nconsole.log('5');\n```\n\nПочему порядок вывода будет `5`, `2`, `4`, `3`, `1`?\n\n## Хороший ответ\n\nПростой ответ: перед переходом к следующей обычной task браузер должен очистить очередь микрозадач. Таймер с нулевой задержкой попадает в очередь обычных задач, а `.then`, `.catch`, `.finally`, продолжение после `await` и `queueMicrotask` попадают в очередь микрозадач.\n\nЕсли после синхронного кода уже есть микрозадачи, они выполнятся раньше callback таймера. Если одна микрозадача добавляет другую микрозадачу, новая микрозадача тоже будет выполнена в этом же цикле очистки очереди. Поэтому большая цепочка промисов может долго не давать браузеру перейти к таймеру, событию пользователя или отрисовке.\n\nЭто не значит, что микрозадачи выполняются в отдельном потоке. Они выполняются в том же основном потоке JavaScript. Разница только в месте расписания: микрозадачи стоят перед следующей обычной задачей.\n\nНа практике это важно для UI. Если мы бесконечно планируем микрозадачи, интерфейс может не получить шанс обновиться, а таймеры будут ждать, хотя их задержка уже истекла.\n\n## Уточняющие вопросы\n\n### 1. В одном script вызвали `Promise.resolve().then(fn)`, `queueMicrotask(g)` и `setTimeout(h, 0)`. Почему `fn` и `g` выполнятся перед `h`?\n\nОжидаем: кандидат разделяет две очереди. `Promise.resolve().then(fn)` не вызывает `fn` сразу, а планирует реакцию Promise как микрозадачу. `queueMicrotask(g)` явно кладет `g` в ту же очередь микрозадач. `setTimeout(h, 0)` планирует `h` как обычную task таймера на будущий проход event loop. После завершения текущего script браузер сначала очищает микрозадачи в порядке их добавления, поэтому выполнятся `fn` и `g`, и только потом event loop сможет перейти к timer task с `h`.\n\n### 2. Микрозадача внутри себя снова вызывает `queueMicrotask`. Почему таймер ждет и эту новую микрозадачу?\n\nОжидаем: кандидат говорит, что очередь микрозадач очищается не только по элементам, которые были в ней в начале. После каждой выполненной микрозадачи event loop снова смотрит, не появились ли новые микрозадачи. Если текущая микрозадача вызвала `queueMicrotask`, новая задача добавляется в конец той же microtask queue и тоже выполняется до перехода к следующей обычной task. Поэтому таймер ждет не только исходные микрозадачи, но и те, которые они добавили. Если микрозадачи бесконечно добавляют новые микрозадачи, таймеры, пользовательские события и отрисовка могут долго не получить управление.\n\n### 3. Таймер с задержкой `0` уже готов, но очередь микрозадач еще не пустая. Почему callback таймера все равно не стартует?\n\nОжидаем: кандидат объясняет, что `setTimeout(h, 0)` означает \"сделать timer task доступной как можно раньше\", а не \"выполнить `h` прямо сейчас\" и не \"поставить `h` перед микрозадачами\". Таймер может стать готовым, пока текущий script или микрозадачи еще выполняются, но JavaScript не прерывает текущую работу ради него. Callback таймера стартует только когда текущая task завершилась, стек пуст, и очередь микрозадач очищена. Поэтому готовность таймера и фактический запуск callback - разные моменты.\n\n## Референсы\n\n- [ru.javascript.info: Событийный цикл микрозадачи и макрозадачи](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F99-ui-misc\u002F03-event-loop\u002Farticle.md) - отношение task, microtask и отрисовки.\n- [ru.javascript.info: Микрозадачи](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md) - выполнение микрозадач до следующей обычной задачи.\n- [MDN: queueMicrotask](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fwindow\u002Fqueuemicrotask\u002Findex.md) - справочник по явному планированию микрозадачи.\n- [MDN: Using microtasks in JavaScript with queueMicrotask](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtml_dom_api\u002Fmicrotask_guide\u002Findex.md) - различие task и microtask, очистка очереди микрозадач до пустого состояния.",{"slug":2182,"title":2183,"baseQuestion":2184,"goodAnswer":2185,"followUps":2186,"references":2196,"programSlug":59,"lessonSlug":59,"order":26,"status":13,"rawBody":2225},"mock-interview-javascript-core-q2-chem-otlichayutsya-obychnaya-funkciya-i-strelochnaya-funkciya","Чем отличаются обычная функция и стрелочная функция?","Чем обычная функция отличается от стрелочной функции в JavaScript?","Стрелочная функция - это не просто короткий синтаксис для обычной функции. У нее другой набор правил, поэтому выбирать ее нужно не только по длине записи.\n\nГлавные отличия:\n\n- `this`. У обычной функции есть свое `this`, которое определяется способом вызова: обычный вызов, вызов как метода, `call`, `apply`, `bind`, `new`. У стрелочной функции своего `this` нет, она берет `this` из внешнего лексического окружения.\n- `arguments`. У обычной функции есть свой объект `arguments`. У стрелочной функции своего `arguments` нет, поэтому для списка аргументов обычно используют rest-параметры.\n- `new`. Обычная функция, созданная через function declaration или function expression, может быть конструктором, если это обычная constructable function. Стрелочную функцию нельзя вызвать с `new`.\n- `prototype`. У constructable обычной функции есть `prototype`, который используется при создании объектов через `new`. У стрелочной функции нет собственного `prototype` для конструкторского сценария.\n- `call`, `apply`, `bind`. Для обычной функции эти методы могут менять или фиксировать `this`. Для стрелочной функции они не создают новый `this`, потому что у стрелки его нет.\n- Возврат значения. У стрелочной функции с кратким телом есть неявный `return`. Если тело в `{}`, `return` нужно писать явно, как и в обычной функции.\n- Hoisting. Function declaration можно вызвать до объявления. Стрелочная функция обычно создается как function expression, присвоенная переменной, поэтому ее доступность зависит от `let`, `const` или `var`. Это отличие не между \"обычной\" и \"стрелочной\" функцией вообще, а между declaration и expression.\n\nГлавная мысль: обычную функцию выбирают, когда нужен собственный динамический `this`, `arguments`, конструкторский вызов или declaration-hoisting. Стрелочную функцию выбирают для коротких callback-функций и случаев, когда нужно сохранить внешний `this`.",[2187,2190,2193],{"question":2188,"expected":2189},"Чем отличается `this` в обычной функции и в стрелочной функции?","кандидат говорит, что у обычной функции есть свой `this`, и он зависит от способа вызова. Если обычную функцию вызвать как метод объекта, `this` будет связан с объектом вызова. Если вызвать отдельно, через `call`, `apply`, `bind` или `new`, правила будут другими.\n\nУ стрелочной функции своего `this` нет. Когда внутри стрелки мы обращаемся к `this`, она берет его снаружи, из места, где была создана. Поэтому стрелка не получает новый `this` при вызове и не работает с `this` так же, как обычная функция.\n\nХороший ответ не говорит, что стрелка берет `this` у \"родительского объекта\". Объект сам по себе не создает `this` для стрелки. Также хороший ответ отделяет стрелку от `bind`: `bind` создает новую связанную функцию с фиксированным `this`, а стрелка ничего не привязывает, у нее просто нет своего `this`.\n\nСлабый ответ: \"у стрелки `this` всегда родительский\" или \"стрелку можно нормально забиндить\". Это показывает, что кандидат помнит бытовую формулу, но не понимает механизм.",{"question":2191,"expected":2192},"Почему стрелочную функцию обычно не используют как метод объекта, если внутри метода нужен `this`?","кандидат говорит, что обычная функция или методный синтаксис лучше подходят, когда методу нужен собственный `this`, зависящий от объекта вызова. Метод обычно должен работать относительно объекта, через который мы его вызвали. Для этого нужен обычный механизм `this`, а стрелочная функция его не дает.\n\nСтрелочная функция здесь плохой выбор, потому что она не получит объект вызова как свой контекст. Если мы сделаем метод стрелкой, она возьмет `this` снаружи, из места создания, и это часто окажется не тот объект, который кандидат ожидает.\n\nХороший ответ добавляет границу применения: стрелка часто удобна внутри метода для короткого callback, которому нужно сохранить внешний `this` метода. Но сам метод объекта, прототипный метод или метод класса обычно должен быть обычной функцией или методным синтаксисом, если он работает через `this`.\n\nСильный кандидат также упоминает похожие случаи: стрелка не подходит, если функцию нужно вызывать с разным `this` через `call`, `apply`, `bind`, использовать как конструктор через `new`, или если функции нужен собственный `arguments`.",{"question":2194,"expected":2195},"Чем `function declaration` отличается от стрелочной функции, записанной в переменную?","кандидат говорит, что здесь смешаны два разных различия. Первое различие - обычная функция против стрелочной: собственный `this`, `arguments`, возможность `new`, `prototype` и поведение `call`, `apply`, `bind`. Второе различие - declaration против expression: когда функция создается и когда имя становится доступным.\n\nFunction declaration обрабатывается на стадии подготовки области видимости, поэтому такую функцию обычно можно использовать до места объявления в тексте. Стрелочная функция почти всегда появляется как function expression, которую мы кладем в переменную. Поэтому доступность зависит от самой переменной: у `let` и `const` будет TDZ до строки инициализации, а у `var` имя появится раньше, но значение функции появится только когда выполнение дойдет до присваивания.\n\nХороший ответ не говорит \"стрелка не hoist-ится\" слишком грубо. Точнее так: hoisting относится к привязке переменной, в которую мы положили стрелочную функцию, а сама функция создается как выражение в момент выполнения этой строки. Поэтому отличие не только в форме записи, а в моменте доступности имени и наборе правил самой функции.",[2197,2201,2205,2209,2213,2217,2221],{"title":2198,"url":2199,"note":2200},"Learn JS: Стрелочные функции, основы","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F17-arrow-functions-basics\u002Farticle.md","краткий синтаксис, неявный `return` и многострочные стрелочные функции.",{"title":2202,"url":2203,"note":2204},"Learn JS: Function Expression","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F16-function-expressions\u002Farticle.md","функция как значение, Function Declaration против Function Expression и момент создания функции.",{"title":2206,"url":2207,"note":2208},"Learn JS: Повторяем стрелочные функции","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F12-arrow-functions\u002Farticle.md","отсутствие собственного `this`, `arguments` и невозможность вызова с `new`.",{"title":2210,"url":2211,"note":2212},"Learn JS: Rest параметры и arguments","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F02-rest-parameters-spread-operator\u002Farticle.md","объект `arguments` у обычных функций и его отсутствие у стрелочных.",{"title":2214,"url":2215,"note":2216},"Learn JS: Привязка контекста к функции","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F10-bind\u002Farticle.md","`bind`, потеря `this` и фиксация контекста обычной функции.",{"title":2218,"url":2219,"note":2220},"YDKJS: Глава 2. Весь this теперь приобретает смысл","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fthis%20%26%20object%20prototypes\u002Fch2.md","правила привязки `this` у обычных функций и отличие стрелок как лексического `this`.",{"title":2222,"url":2223,"note":2224},"MDN: Arrow functions","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Ffunctions\u002Farrow_functions\u002Findex.md","поведение стрелочных функций и отсутствие собственного `this`.","# Q2. Чем отличаются обычная функция и стрелочная функция?\n\n## Базовый вопрос\n\nЧем обычная функция отличается от стрелочной функции в JavaScript?\n\n## Хороший ответ\n\nСтрелочная функция - это не просто короткий синтаксис для обычной функции. У нее другой набор правил, поэтому выбирать ее нужно не только по длине записи.\n\nГлавные отличия:\n\n- `this`. У обычной функции есть свое `this`, которое определяется способом вызова: обычный вызов, вызов как метода, `call`, `apply`, `bind`, `new`. У стрелочной функции своего `this` нет, она берет `this` из внешнего лексического окружения.\n- `arguments`. У обычной функции есть свой объект `arguments`. У стрелочной функции своего `arguments` нет, поэтому для списка аргументов обычно используют rest-параметры.\n- `new`. Обычная функция, созданная через function declaration или function expression, может быть конструктором, если это обычная constructable function. Стрелочную функцию нельзя вызвать с `new`.\n- `prototype`. У constructable обычной функции есть `prototype`, который используется при создании объектов через `new`. У стрелочной функции нет собственного `prototype` для конструкторского сценария.\n- `call`, `apply`, `bind`. Для обычной функции эти методы могут менять или фиксировать `this`. Для стрелочной функции они не создают новый `this`, потому что у стрелки его нет.\n- Возврат значения. У стрелочной функции с кратким телом есть неявный `return`. Если тело в `{}`, `return` нужно писать явно, как и в обычной функции.\n- Hoisting. Function declaration можно вызвать до объявления. Стрелочная функция обычно создается как function expression, присвоенная переменной, поэтому ее доступность зависит от `let`, `const` или `var`. Это отличие не между \"обычной\" и \"стрелочной\" функцией вообще, а между declaration и expression.\n\nГлавная мысль: обычную функцию выбирают, когда нужен собственный динамический `this`, `arguments`, конструкторский вызов или declaration-hoisting. Стрелочную функцию выбирают для коротких callback-функций и случаев, когда нужно сохранить внешний `this`.\n\n## Уточняющие вопросы\n\n### 1. Чем отличается `this` в обычной функции и в стрелочной функции?\n\nОжидаем: кандидат говорит, что у обычной функции есть свой `this`, и он зависит от способа вызова. Если обычную функцию вызвать как метод объекта, `this` будет связан с объектом вызова. Если вызвать отдельно, через `call`, `apply`, `bind` или `new`, правила будут другими.\n\nУ стрелочной функции своего `this` нет. Когда внутри стрелки мы обращаемся к `this`, она берет его снаружи, из места, где была создана. Поэтому стрелка не получает новый `this` при вызове и не работает с `this` так же, как обычная функция.\n\nХороший ответ не говорит, что стрелка берет `this` у \"родительского объекта\". Объект сам по себе не создает `this` для стрелки. Также хороший ответ отделяет стрелку от `bind`: `bind` создает новую связанную функцию с фиксированным `this`, а стрелка ничего не привязывает, у нее просто нет своего `this`.\n\nСлабый ответ: \"у стрелки `this` всегда родительский\" или \"стрелку можно нормально забиндить\". Это показывает, что кандидат помнит бытовую формулу, но не понимает механизм.\n\n### 2. Почему стрелочную функцию обычно не используют как метод объекта, если внутри метода нужен `this`?\n\nОжидаем: кандидат говорит, что обычная функция или методный синтаксис лучше подходят, когда методу нужен собственный `this`, зависящий от объекта вызова. Метод обычно должен работать относительно объекта, через который мы его вызвали. Для этого нужен обычный механизм `this`, а стрелочная функция его не дает.\n\nСтрелочная функция здесь плохой выбор, потому что она не получит объект вызова как свой контекст. Если мы сделаем метод стрелкой, она возьмет `this` снаружи, из места создания, и это часто окажется не тот объект, который кандидат ожидает.\n\nХороший ответ добавляет границу применения: стрелка часто удобна внутри метода для короткого callback, которому нужно сохранить внешний `this` метода. Но сам метод объекта, прототипный метод или метод класса обычно должен быть обычной функцией или методным синтаксисом, если он работает через `this`.\n\nСильный кандидат также упоминает похожие случаи: стрелка не подходит, если функцию нужно вызывать с разным `this` через `call`, `apply`, `bind`, использовать как конструктор через `new`, или если функции нужен собственный `arguments`.\n\n### 3. Чем `function declaration` отличается от стрелочной функции, записанной в переменную?\n\nОжидаем: кандидат говорит, что здесь смешаны два разных различия. Первое различие - обычная функция против стрелочной: собственный `this`, `arguments`, возможность `new`, `prototype` и поведение `call`, `apply`, `bind`. Второе различие - declaration против expression: когда функция создается и когда имя становится доступным.\n\nFunction declaration обрабатывается на стадии подготовки области видимости, поэтому такую функцию обычно можно использовать до места объявления в тексте. Стрелочная функция почти всегда появляется как function expression, которую мы кладем в переменную. Поэтому доступность зависит от самой переменной: у `let` и `const` будет TDZ до строки инициализации, а у `var` имя появится раньше, но значение функции появится только когда выполнение дойдет до присваивания.\n\nХороший ответ не говорит \"стрелка не hoist-ится\" слишком грубо. Точнее так: hoisting относится к привязке переменной, в которую мы положили стрелочную функцию, а сама функция создается как выражение в момент выполнения этой строки. Поэтому отличие не только в форме записи, а в моменте доступности имени и наборе правил самой функции.\n\n## Референсы\n\n- [Learn JS: Стрелочные функции, основы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F17-arrow-functions-basics\u002Farticle.md) - краткий синтаксис, неявный `return` и многострочные стрелочные функции.\n- [Learn JS: Function Expression](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F16-function-expressions\u002Farticle.md) - функция как значение, Function Declaration против Function Expression и момент создания функции.\n- [Learn JS: Повторяем стрелочные функции](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F12-arrow-functions\u002Farticle.md) - отсутствие собственного `this`, `arguments` и невозможность вызова с `new`.\n- [Learn JS: Rest параметры и arguments](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F02-rest-parameters-spread-operator\u002Farticle.md) - объект `arguments` у обычных функций и его отсутствие у стрелочных.\n- [Learn JS: Привязка контекста к функции](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F10-bind\u002Farticle.md) - `bind`, потеря `this` и фиксация контекста обычной функции.\n- [YDKJS: Глава 2. Весь this теперь приобретает смысл](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fthis%20%26%20object%20prototypes\u002Fch2.md) - правила привязки `this` у обычных функций и отличие стрелок как лексического `this`.\n- [MDN: Arrow functions](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Ffunctions\u002Farrow_functions\u002Findex.md) - поведение стрелочных функций и отсутствие собственного `this`.",{"slug":2227,"title":2228,"baseQuestion":2229,"goodAnswer":2230,"followUps":2231,"references":2241,"programSlug":18,"lessonSlug":18,"order":26,"status":13,"rawBody":2262},"objects-prototypes-classes-q2-chem-otlichayutsya-prototype-proto-i-fn-prototype","Чем отличаются `[[Prototype]]`, `__proto__` и `Fn.prototype`?","В чем разница между внутренним `[[Prototype]]` объекта, записью `obj.__proto__` и свойством функции-конструктора `Fn.prototype`?","`[[Prototype]]` - это внутренний слот объекта. В нем хранится ссылка на другой объект или `null`. Эта ссылка участвует в поиске свойств: если собственного свойства нет на текущем объекте, JavaScript продолжает поиск в объекте, который лежит в `[[Prototype]]`.\n\n`__proto__` - это исторический accessor property для чтения и изменения `[[Prototype]]`. Он не является самим внутренним слотом. Обычно `__proto__` приходит из `Object.prototype`, поэтому при чтении или записи мы вызываем getter или setter, а не читаем обычное собственное поле объекта. В современном коде для явной работы с прототипом лучше использовать `Object.getPrototypeOf`, `Object.setPrototypeOf` и `Object.create`.\n\n`prototype` - это обычное свойство функции, если эту функцию можно использовать как конструктор. Оно не является прототипом самой функции. Это значение, которое `new` использует для настройки `[[Prototype]]` нового объекта. Если мы создаем объект через `new foo`, JavaScript берет `foo.prototype`; если там объект, он становится `[[Prototype]]` нового объекта.\n\nГлавная мысль: `[[Prototype]]` - это внутренняя ссылка уже существующего объекта, а `prototype` у функции-конструктора - это обычное свойство функции, которое будет использовано как `[[Prototype]]` для будущих объектов, созданных через `new`.\n\nКлючевые различия:\n\n- `[[Prototype]]` есть у обычных объектов как внутренняя ссылка на следующий объект в цепочке поиска.\n- `__proto__` - исторический геттер и сеттер для чтения и изменения этой внутренней ссылки.\n- `prototype` у функции-конструктора - обычное свойство, которое `new` использует для новых объектов.\n- Изменение `foo.prototype` влияет на объекты, которые мы создадим через `new foo` после изменения. Уже созданные объекты сохраняют тот `[[Prototype]]`, который получили при создании.\n- Не у всех функций есть собственное свойство `prototype`: например, стрелочные функции не являются конструкторами.\n- У обычного объекта свойство с именем `prototype` не имеет специального смысла, если мы сами его туда положили.\n- У самой функции тоже есть свой `[[Prototype]]`, обычно связанный с `Function.prototype`; это отдельная связь и ее нельзя путать со свойством функции `prototype`.\n\nХороший кандидат не обязан цитировать спецификацию, но должен уверенно развести три вещи: внутренняя ссылка объекта, исторический доступ к этой ссылке и свойство функции-конструктора для будущих объектов.",[2232,2235,2238],{"question":2233,"expected":2234},"Есть `const obj = {}` и `const other = { x: 1 }`. Почему после `obj.prototype = other` выражение `obj.x` дает `undefined`, а `obj.prototype.x` дает `1`?","кандидат объясняет, что из-за одного только `obj.prototype = other` JavaScript не будет искать `x` в `other`.\n\nПричина в том, что у обычного объекта свойство с именем `prototype` - это просто обычное поле. Мы можем записать туда что угодно, и потом `obj.prototype` действительно вернет `other`. Но это не меняет внутренний `[[Prototype]]` объекта `obj`.\n\nКогда JavaScript читает `obj.x`, он сначала ищет собственное свойство `x` в самом `obj`. Если такого свойства нет, он идет не в `obj.prototype`, а во внутренний `[[Prototype]]` объекта. Именно этот внутренний `[[Prototype]]` участвует в поиске свойств.\n\nПоэтому `x` будет найден в `other` только если `other` реально является прототипом `obj`, например объект был создан через `Object.create(other)` или прототип был явно установлен через `Object.setPrototypeOf(obj, other)`. Простое присваивание `obj.prototype = other` этого не делает.\n\nХороший ответ добавляет отличие от функции-конструктора: `Fn.prototype` становится особым только в связке с `new Fn()`. Тогда значение `Fn.prototype` используется как внутренний `[[Prototype]]` нового объекта. У обычного объекта такой магии у свойства `prototype` нет.",{"question":2236,"expected":2237},"Есть `function Fn() {}` и `const proto = {}`. Почему после `Fn.prototype = proto` и `const a = new Fn()` выражение `Object.getPrototypeOf(a) === proto` дает `true`?","кандидат объясняет, что `proto` стал прототипом `a`, потому что `Fn.prototype` используется при создании новых объектов через `new Fn()`.\n\nМеханика такая: `Fn` - это функция-конструктор. У нее есть обычное свойство с именем `prototype`. Когда мы выполняем `new Fn()`, JavaScript создает новый объект и смотрит на `Fn.prototype`. Если там лежит объект, этот объект становится внутренним `[[Prototype]]` нового объекта.\n\nЭто не копирование свойств из `proto` в `a`. `a` просто получает ссылку на `proto` как на свой прототип. Поэтому если мы читаем свойство у `a` и не находим его прямо в `a`, JavaScript сможет искать это свойство в `proto`.\n\nВажно не перепутать две разные вещи:\n\n- `Fn.prototype` - обычное свойство функции `Fn`, которое `new Fn()` использует для новых объектов;\n- собственный `[[Prototype]]` самой функции `Fn` - это другая связь, потому что функция сама является объектом и обычно наследует от `Function.prototype`.\n\nЕсли после создания `a` мы присвоим `Fn.prototype` другое значение, прототип уже созданного `a` не поменяется. Новое значение `Fn.prototype` будет использоваться для следующих объектов, созданных через `new Fn()`.\n\nСлабый ответ смешивает это в одну линию и говорит, что `foo.prototype` - это прототип самой функции `foo`.",{"question":2239,"expected":2240},"Есть `const obj = {}`. Почему после присваивания `obj[\"__proto__\"]` значения `\"x\"` выражение `obj[\"__proto__\"] === \"x\"` дает `false`?","кандидат объясняет, что у обычного объекта `{}` имя `__proto__` обычно уже не свободное обычное поле. Оно находится выше по цепочке, в `Object.prototype`, как историческое свойство-аксессор для работы с внутренним `[[Prototype]]`.\n\nКогда мы присваиваем `obj[\"__proto__\"]` значение `\"x\"`, JavaScript не обязан создавать собственное поле `__proto__` на `obj`. Он находит унаследованный сеттер `Object.prototype.__proto__` и вызывает его.\n\nЭтот сеттер умеет менять прототип только на объект или на `null`. Строка `\"x\"` не подходит на роль прототипа, поэтому такое присваивание не сохраняет строку как обычное поле и не меняет прототип.\n\nКогда потом мы читаем `obj[\"__proto__\"]`, срабатывает унаследованный геттер `Object.prototype.__proto__`. Он возвращает текущий прототип объекта, а не строку `\"x\"`. У обычного объекта это обычно `Object.prototype`.\n\nХороший ответ отдельно проговаривает риск: если вместо строки присвоить объект или `null`, можно реально поменять прототип `obj`. Поэтому `__proto__` плохо подходит как обычный пользовательский ключ в словаре.\n\nДля явной работы с прототипами лучше использовать `Object.getPrototypeOf`, `Object.setPrototypeOf` и `Object.create`. Для словарей с произвольными ключами часто удобнее `Map` или объект без прототипа через `Object.create(null)`: тогда у объекта нет унаследованного аксессора `__proto__`, и такой ключ можно хранить как обычное поле.",[2242,2246,2248,2250,2252,2256,2258],{"title":2243,"url":2244,"note":2245},"Learn JS: F.prototype","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F02-function-prototype\u002Farticle.md","отличие `F.prototype` от `[[Prototype]]` и роль `prototype` при вызове `new F()`.",{"title":1905,"url":1906,"note":2247},"`[[Prototype]]`, `__proto__`, цепочка прототипов и ограничения прототипной связи.",{"title":1909,"url":1910,"note":2249},"почему `__proto__` считается устаревшим аксессором и какие методы использовать вместо него.",{"title":1917,"url":1918,"note":2251},"различие между `[[Prototype]]`, `.prototype`, `.constructor` и объектными ссылками.",{"title":2253,"url":2254,"note":2255},"MDN: Function.prototype","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Ffunction\u002Fprototype\u002Findex.md","свойство `prototype` у функций-конструкторов.",{"title":1921,"url":1922,"note":2257},"как объект связывается с прототипом при создании.",{"title":2259,"url":2260,"note":2261},"MDN: Object.prototype.__proto__","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fproto\u002Findex.md","`__proto__` как legacy accessor property.","# Q2. Чем отличаются `[[Prototype]]`, `__proto__` и `Fn.prototype`?\n\n## Базовый вопрос\n\nВ чем разница между внутренним `[[Prototype]]` объекта, записью `obj.__proto__` и свойством функции-конструктора `Fn.prototype`?\n\n## Хороший ответ\n\n`[[Prototype]]` - это внутренний слот объекта. В нем хранится ссылка на другой объект или `null`. Эта ссылка участвует в поиске свойств: если собственного свойства нет на текущем объекте, JavaScript продолжает поиск в объекте, который лежит в `[[Prototype]]`.\n\n`__proto__` - это исторический accessor property для чтения и изменения `[[Prototype]]`. Он не является самим внутренним слотом. Обычно `__proto__` приходит из `Object.prototype`, поэтому при чтении или записи мы вызываем getter или setter, а не читаем обычное собственное поле объекта. В современном коде для явной работы с прототипом лучше использовать `Object.getPrototypeOf`, `Object.setPrototypeOf` и `Object.create`.\n\n`prototype` - это обычное свойство функции, если эту функцию можно использовать как конструктор. Оно не является прототипом самой функции. Это значение, которое `new` использует для настройки `[[Prototype]]` нового объекта. Если мы создаем объект через `new foo`, JavaScript берет `foo.prototype`; если там объект, он становится `[[Prototype]]` нового объекта.\n\nГлавная мысль: `[[Prototype]]` - это внутренняя ссылка уже существующего объекта, а `prototype` у функции-конструктора - это обычное свойство функции, которое будет использовано как `[[Prototype]]` для будущих объектов, созданных через `new`.\n\nКлючевые различия:\n\n- `[[Prototype]]` есть у обычных объектов как внутренняя ссылка на следующий объект в цепочке поиска.\n- `__proto__` - исторический геттер и сеттер для чтения и изменения этой внутренней ссылки.\n- `prototype` у функции-конструктора - обычное свойство, которое `new` использует для новых объектов.\n- Изменение `foo.prototype` влияет на объекты, которые мы создадим через `new foo` после изменения. Уже созданные объекты сохраняют тот `[[Prototype]]`, который получили при создании.\n- Не у всех функций есть собственное свойство `prototype`: например, стрелочные функции не являются конструкторами.\n- У обычного объекта свойство с именем `prototype` не имеет специального смысла, если мы сами его туда положили.\n- У самой функции тоже есть свой `[[Prototype]]`, обычно связанный с `Function.prototype`; это отдельная связь и ее нельзя путать со свойством функции `prototype`.\n\nХороший кандидат не обязан цитировать спецификацию, но должен уверенно развести три вещи: внутренняя ссылка объекта, исторический доступ к этой ссылке и свойство функции-конструктора для будущих объектов.\n\n## Уточняющие вопросы\n\n### 1. Есть `const obj = {}` и `const other = { x: 1 }`. Почему после `obj.prototype = other` выражение `obj.x` дает `undefined`, а `obj.prototype.x` дает `1`?\n\nОжидаем: кандидат объясняет, что из-за одного только `obj.prototype = other` JavaScript не будет искать `x` в `other`.\n\nПричина в том, что у обычного объекта свойство с именем `prototype` - это просто обычное поле. Мы можем записать туда что угодно, и потом `obj.prototype` действительно вернет `other`. Но это не меняет внутренний `[[Prototype]]` объекта `obj`.\n\nКогда JavaScript читает `obj.x`, он сначала ищет собственное свойство `x` в самом `obj`. Если такого свойства нет, он идет не в `obj.prototype`, а во внутренний `[[Prototype]]` объекта. Именно этот внутренний `[[Prototype]]` участвует в поиске свойств.\n\nПоэтому `x` будет найден в `other` только если `other` реально является прототипом `obj`, например объект был создан через `Object.create(other)` или прототип был явно установлен через `Object.setPrototypeOf(obj, other)`. Простое присваивание `obj.prototype = other` этого не делает.\n\nХороший ответ добавляет отличие от функции-конструктора: `Fn.prototype` становится особым только в связке с `new Fn()`. Тогда значение `Fn.prototype` используется как внутренний `[[Prototype]]` нового объекта. У обычного объекта такой магии у свойства `prototype` нет.\n\n### 2. Есть `function Fn() {}` и `const proto = {}`. Почему после `Fn.prototype = proto` и `const a = new Fn()` выражение `Object.getPrototypeOf(a) === proto` дает `true`?\n\nОжидаем: кандидат объясняет, что `proto` стал прототипом `a`, потому что `Fn.prototype` используется при создании новых объектов через `new Fn()`.\n\nМеханика такая: `Fn` - это функция-конструктор. У нее есть обычное свойство с именем `prototype`. Когда мы выполняем `new Fn()`, JavaScript создает новый объект и смотрит на `Fn.prototype`. Если там лежит объект, этот объект становится внутренним `[[Prototype]]` нового объекта.\n\nЭто не копирование свойств из `proto` в `a`. `a` просто получает ссылку на `proto` как на свой прототип. Поэтому если мы читаем свойство у `a` и не находим его прямо в `a`, JavaScript сможет искать это свойство в `proto`.\n\nВажно не перепутать две разные вещи:\n\n- `Fn.prototype` - обычное свойство функции `Fn`, которое `new Fn()` использует для новых объектов;\n- собственный `[[Prototype]]` самой функции `Fn` - это другая связь, потому что функция сама является объектом и обычно наследует от `Function.prototype`.\n\nЕсли после создания `a` мы присвоим `Fn.prototype` другое значение, прототип уже созданного `a` не поменяется. Новое значение `Fn.prototype` будет использоваться для следующих объектов, созданных через `new Fn()`.\n\nСлабый ответ смешивает это в одну линию и говорит, что `foo.prototype` - это прототип самой функции `foo`.\n\n### 3. Есть `const obj = {}`. Почему после присваивания `obj[\"__proto__\"]` значения `\"x\"` выражение `obj[\"__proto__\"] === \"x\"` дает `false`?\n\nОжидаем: кандидат объясняет, что у обычного объекта `{}` имя `__proto__` обычно уже не свободное обычное поле. Оно находится выше по цепочке, в `Object.prototype`, как историческое свойство-аксессор для работы с внутренним `[[Prototype]]`.\n\nКогда мы присваиваем `obj[\"__proto__\"]` значение `\"x\"`, JavaScript не обязан создавать собственное поле `__proto__` на `obj`. Он находит унаследованный сеттер `Object.prototype.__proto__` и вызывает его.\n\nЭтот сеттер умеет менять прототип только на объект или на `null`. Строка `\"x\"` не подходит на роль прототипа, поэтому такое присваивание не сохраняет строку как обычное поле и не меняет прототип.\n\nКогда потом мы читаем `obj[\"__proto__\"]`, срабатывает унаследованный геттер `Object.prototype.__proto__`. Он возвращает текущий прототип объекта, а не строку `\"x\"`. У обычного объекта это обычно `Object.prototype`.\n\nХороший ответ отдельно проговаривает риск: если вместо строки присвоить объект или `null`, можно реально поменять прототип `obj`. Поэтому `__proto__` плохо подходит как обычный пользовательский ключ в словаре.\n\nДля явной работы с прототипами лучше использовать `Object.getPrototypeOf`, `Object.setPrototypeOf` и `Object.create`. Для словарей с произвольными ключами часто удобнее `Map` или объект без прототипа через `Object.create(null)`: тогда у объекта нет унаследованного аксессора `__proto__`, и такой ключ можно хранить как обычное поле.\n\n## Референсы\n\n- [Learn JS: F.prototype](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F02-function-prototype\u002Farticle.md) - отличие `F.prototype` от `[[Prototype]]` и роль `prototype` при вызове `new F()`.\n- [Learn JS: Прототипное наследование](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F01-prototype-inheritance\u002Farticle.md) - `[[Prototype]]`, `__proto__`, цепочка прототипов и ограничения прототипной связи.\n- [Learn JS: Методы прототипов, объекты без свойства **proto**](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F08-prototypes\u002F04-prototype-methods\u002Farticle.md) - почему `__proto__` считается устаревшим аксессором и какие методы использовать вместо него.\n- [YDKJS: this и прототипы объектов, Глава 5](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fthis%20%26%20object%20prototypes\u002Fch5.md) - различие между `[[Prototype]]`, `.prototype`, `.constructor` и объектными ссылками.\n- [MDN: Function.prototype](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Ffunction\u002Fprototype\u002Findex.md) - свойство `prototype` у функций-конструкторов.\n- [MDN: Inheritance and the prototype chain](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Finheritance_and_the_prototype_chain\u002Findex.md) - как объект связывается с прототипом при создании.\n- [MDN: Object.prototype.__proto__](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fproto\u002Findex.md) - `__proto__` как legacy accessor property.",{"slug":2264,"title":2265,"baseQuestion":2266,"goodAnswer":2267,"followUps":2268,"references":2278,"programSlug":50,"lessonSlug":50,"order":26,"status":13,"rawBody":2287},"recursion-q2-kak-rekursiya-svyazana-so-stekom-vyzovov","Как рекурсия связана со стеком вызовов?","Как стек вызовов влияет на выполнение рекурсивной функции?","Простыми словами: каждый рекурсивный вызов временно ставится поверх предыдущего. Верхний вызов должен завершиться, чтобы программа вернулась к тому месту, где он был вызван.\n\nЕсли мы вызываем функцию из самой себя пять раз, у нас появляется цепочка из пяти активных вызовов. У каждого вызова свои параметры, свои локальные переменные и свое место возврата. Поэтому рекурсия может как бы \"спускаться вниз\", пока не встретит базовый случай, а потом \"подниматься назад\", возвращая значения предыдущим вызовам.\n\nВажно понимать ограничение: стек вызовов не бесконечный. Если рекурсия слишком глубокая или не двигается к базовому случаю, браузер остановит выполнение ошибкой вроде `RangeError: Maximum call stack size exceeded` или похожей ошибкой в зависимости от движка.\n\nНа интервью хороший ответ связывает стек не только с ошибкой, но и с порядком вывода: код до рекурсивного вызова выполняется при спуске, а код после рекурсивного вызова выполняется при возврате назад.",[2269,2272,2275],{"question":2270,"expected":2271},"Почему локальные переменные разных рекурсивных вызовов не перетирают друг друга?","кандидат говорит, что каждый вызов функции имеет свой отдельный контекст выполнения с собственными параметрами и локальными привязками.",{"question":2273,"expected":2274},"Почему код после рекурсивного вызова выполняется не сразу?","кандидат объясняет, что текущий вызов ждет результат внутреннего вызова. Продолжение текущей функции возможно только после возврата из более глубокого вызова.",{"question":2276,"expected":2277},"Почему нельзя рассчитывать на точное число допустимых рекурсивных вызовов?","кандидат говорит, что лимит стека зависит от движка, браузера, устройства и конкретных условий выполнения, а не от стабильного правила языка.",[2279,2281,2283],{"title":1954,"url":1955,"note":2280},"пример рекурсии и упоминание ограничения стека.",{"title":1958,"url":1959,"note":2282},"ошибки при слишком глубокой рекурсии.",{"title":2284,"url":2285,"note":2286},"Вы не знаете JS: ES6 и дальше — глава 7 Meta Programming","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fes6%20%26%20beyond\u002Fch7.md","объяснение стека вызовов, рекурсии и хвостовых вызовов.","# Q2. Как рекурсия связана со стеком вызовов?\n\n## Базовый вопрос\n\nКак стек вызовов влияет на выполнение рекурсивной функции?\n\n## Хороший ответ\n\nПростыми словами: каждый рекурсивный вызов временно ставится поверх предыдущего. Верхний вызов должен завершиться, чтобы программа вернулась к тому месту, где он был вызван.\n\nЕсли мы вызываем функцию из самой себя пять раз, у нас появляется цепочка из пяти активных вызовов. У каждого вызова свои параметры, свои локальные переменные и свое место возврата. Поэтому рекурсия может как бы \"спускаться вниз\", пока не встретит базовый случай, а потом \"подниматься назад\", возвращая значения предыдущим вызовам.\n\nВажно понимать ограничение: стек вызовов не бесконечный. Если рекурсия слишком глубокая или не двигается к базовому случаю, браузер остановит выполнение ошибкой вроде `RangeError: Maximum call stack size exceeded` или похожей ошибкой в зависимости от движка.\n\nНа интервью хороший ответ связывает стек не только с ошибкой, но и с порядком вывода: код до рекурсивного вызова выполняется при спуске, а код после рекурсивного вызова выполняется при возврате назад.\n\n## Уточняющие вопросы\n\n### 1. Почему локальные переменные разных рекурсивных вызовов не перетирают друг друга?\n\nОжидаем: кандидат говорит, что каждый вызов функции имеет свой отдельный контекст выполнения с собственными параметрами и локальными привязками.\n\n### 2. Почему код после рекурсивного вызова выполняется не сразу?\n\nОжидаем: кандидат объясняет, что текущий вызов ждет результат внутреннего вызова. Продолжение текущей функции возможно только после возврата из более глубокого вызова.\n\n### 3. Почему нельзя рассчитывать на точное число допустимых рекурсивных вызовов?\n\nОжидаем: кандидат говорит, что лимит стека зависит от движка, браузера, устройства и конкретных условий выполнения, а не от стабильного правила языка.\n\n## Референсы\n\n- [MDN: Recursion](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md) - пример рекурсии и упоминание ограничения стека.\n- [MDN: InternalError too much recursion](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Ferrors\u002Ftoo_much_recursion\u002Findex.md) - ошибки при слишком глубокой рекурсии.\n- [Вы не знаете JS: ES6 и дальше — глава 7 Meta Programming](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fes6%20%26%20beyond\u002Fch7.md) - объяснение стека вызовов, рекурсии и хвостовых вызовов.",{"slug":2289,"title":2290,"baseQuestion":2291,"goodAnswer":2292,"followUps":2293,"references":2303,"programSlug":41,"lessonSlug":41,"order":26,"status":13,"rawBody":2314},"rendering-dom-events-forms-q2-chto-takoe-layout","Что такое layout?","Что такое layout в браузере?","Layout - это этап, где браузер считает геометрию элементов: ширину, высоту, координаты и влияние элементов друг на друга. Если сказать проще, браузер решает, сколько места занимает каждый видимый элемент и где он должен стоять.\n\nСлово reflow часто используют как старое или разговорное название повторного layout. На интервью обычно ждут именно понимания механики: если мы поменяли то, что влияет на размер или положение, браузеру нужно обновить расчеты.\n\nLayout может понадобиться после изменения `width`, `height`, `padding`, `border`, `font-size`, `display`, текста, состава DOM-узлов или других вещей, которые меняют место элемента на странице. Важная деталь: изменение одного элемента может сдвинуть соседей, изменить размер родителя или scroll-область.\n\nХороший кандидат должен отделять layout от paint. Layout отвечает на вопрос \"где и какого размера\", а paint отвечает на вопрос \"как это нарисовать\".",[2294,2297,2300],{"question":2295,"expected":2296},"Почему изменение ширины одного блока может повлиять на другие блоки?","кандидат говорит, что элементы в документе часто зависят друг от друга. Если один блок стал шире или выше, соседние элементы, родитель или переносы текста могут измениться.",{"question":2298,"expected":2299},"Чем `display: none` отличается от `visibility: hidden` для layout?","кандидат объясняет, что `display: none` убирает элемент из раскладки, поэтому место под него не считается. `visibility: hidden` прячет элемент, но его место остается.",{"question":2301,"expected":2302},"Почему `transform: scale(2)` не обязан менять место элемента в потоке?","кандидат говорит, что `transform` меняет визуальное отображение уже рассчитанного элемента. Его layout-размер для соседей обычно остается прежним, хотя визуальный прямоугольник может стать другим.",[2304,2306,2310],{"title":1979,"url":1980,"note":2305},"роль layout в рендеринге страницы.",{"title":2307,"url":2308,"note":2309},"MDN: CSS performance optimization","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Flearn_web_development\u002Fextensions\u002Fperformance\u002Fcss\u002Findex.md","CSS-свойства, которые могут запускать reflow и repaint.",{"title":2311,"url":2312,"note":2313},"MDN: HTMLElement.offsetWidth","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlelement\u002Foffsetwidth\u002Findex.md","пример свойства, которое зависит от layout.","# Q2. Что такое layout?\n\n## Базовый вопрос\n\nЧто такое layout в браузере?\n\n## Хороший ответ\n\nLayout - это этап, где браузер считает геометрию элементов: ширину, высоту, координаты и влияние элементов друг на друга. Если сказать проще, браузер решает, сколько места занимает каждый видимый элемент и где он должен стоять.\n\nСлово reflow часто используют как старое или разговорное название повторного layout. На интервью обычно ждут именно понимания механики: если мы поменяли то, что влияет на размер или положение, браузеру нужно обновить расчеты.\n\nLayout может понадобиться после изменения `width`, `height`, `padding`, `border`, `font-size`, `display`, текста, состава DOM-узлов или других вещей, которые меняют место элемента на странице. Важная деталь: изменение одного элемента может сдвинуть соседей, изменить размер родителя или scroll-область.\n\nХороший кандидат должен отделять layout от paint. Layout отвечает на вопрос \"где и какого размера\", а paint отвечает на вопрос \"как это нарисовать\".\n\n## Уточняющие вопросы\n\n### 1. Почему изменение ширины одного блока может повлиять на другие блоки?\n\nОжидаем: кандидат говорит, что элементы в документе часто зависят друг от друга. Если один блок стал шире или выше, соседние элементы, родитель или переносы текста могут измениться.\n\n### 2. Чем `display: none` отличается от `visibility: hidden` для layout?\n\nОжидаем: кандидат объясняет, что `display: none` убирает элемент из раскладки, поэтому место под него не считается. `visibility: hidden` прячет элемент, но его место остается.\n\n### 3. Почему `transform: scale(2)` не обязан менять место элемента в потоке?\n\nОжидаем: кандидат говорит, что `transform` меняет визуальное отображение уже рассчитанного элемента. Его layout-размер для соседей обычно остается прежним, хотя визуальный прямоугольник может стать другим.\n\n## Референсы\n\n- [MDN: Critical rendering path](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fperformance\u002Fguides\u002Fcritical_rendering_path\u002Findex.md) - роль layout в рендеринге страницы.\n- [MDN: CSS performance optimization](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Flearn_web_development\u002Fextensions\u002Fperformance\u002Fcss\u002Findex.md) - CSS-свойства, которые могут запускать reflow и repaint.\n- [MDN: HTMLElement.offsetWidth](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlelement\u002Foffsetwidth\u002Findex.md) - пример свойства, которое зависит от layout.",{"slug":2316,"title":2317,"baseQuestion":2318,"goodAnswer":2319,"followUps":2320,"references":2330,"programSlug":19,"lessonSlug":19,"order":26,"status":13,"rawBody":2339},"scope-closures-deep-dive-q2-chto-znachit-leksicheskaya-oblast-vidimosti","Что значит лексическая область видимости?","Что значит, что в JavaScript область видимости лексическая?","Лексическая область видимости означает, что JavaScript определяет внешние области функции по месту, где функция написана в коде, а не по месту, откуда ее потом вызвали.\n\nКогда функция обращается к имени, JavaScript сначала ищет это имя внутри самой функции. Если не находит, идет наружу по тем областям, которые окружали функцию при объявлении. Этот порядок можно увидеть в тексте программы до выполнения.\n\nПоэтому функция не начинает видеть локальные переменные вызывающей функции только потому, что ее вызвали оттуда. Место вызова влияет на обычный `this`, аргументы и порядок выполнения, но не перестраивает цепочку поиска обычных переменных.\n\nДинамическая область видимости работала бы иначе: она искала бы имена по цепочке вызовов во время выполнения. В обычном JavaScript такой модели для переменных нет. Эта разница важна для понимания замыканий: функция сохраняет доступ к месту создания, даже если ее передали и вызвали где-то еще.",[2321,2324,2327],{"question":2322,"expected":2323},"Почему функция ищет внешнюю переменную по месту создания, а не по месту вызова?","кандидат говорит, что функция создается вместе со ссылкой на внешнее лексическое окружение. При вызове создается новая локальная область самой функции, а внешняя ссылка берется из функции, а не из текущего вызывающего кода.",{"question":2325,"expected":2326},"Есть глобальная `a` со значением `1`, функция читает `a`, а вызывающая функция имеет локальную `a` со значением `2`. Почему вызванная функция читает `1`?","кандидат объясняет, что локальная `a` вызывающей функции не находится в лексической цепочке вызванной функции. Если вызванная функция объявлена в глобальной области, ее внешний поиск идет в глобальную область.",{"question":2328,"expected":2329},"Чем лексическая область видимости отличается от динамической простыми словами?","кандидат формулирует разницу через \"где написали\" против \"откуда вызвали\". Лексическая модель определяется структурой кода, динамическая модель зависела бы от цепочки вызовов во время выполнения.",[2331,2333,2337],{"title":1877,"url":1878,"note":2332},"поиск имен по вложенным областям и shadowing.",{"title":2334,"url":2335,"note":2336},"YDKJS: Приложение A. Динамическая область видимости","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002FapA.md","сравнение лексической и динамической модели.",{"title":1885,"url":1886,"note":2338},"связь лексической области видимости с замыканиями.","# Q2. Что значит лексическая область видимости?\n\n## Базовый вопрос\n\nЧто значит, что в JavaScript область видимости лексическая?\n\n## Хороший ответ\n\nЛексическая область видимости означает, что JavaScript определяет внешние области функции по месту, где функция написана в коде, а не по месту, откуда ее потом вызвали.\n\nКогда функция обращается к имени, JavaScript сначала ищет это имя внутри самой функции. Если не находит, идет наружу по тем областям, которые окружали функцию при объявлении. Этот порядок можно увидеть в тексте программы до выполнения.\n\nПоэтому функция не начинает видеть локальные переменные вызывающей функции только потому, что ее вызвали оттуда. Место вызова влияет на обычный `this`, аргументы и порядок выполнения, но не перестраивает цепочку поиска обычных переменных.\n\nДинамическая область видимости работала бы иначе: она искала бы имена по цепочке вызовов во время выполнения. В обычном JavaScript такой модели для переменных нет. Эта разница важна для понимания замыканий: функция сохраняет доступ к месту создания, даже если ее передали и вызвали где-то еще.\n\n## Уточняющие вопросы\n\n### 1. Почему функция ищет внешнюю переменную по месту создания, а не по месту вызова?\n\nОжидаем: кандидат говорит, что функция создается вместе со ссылкой на внешнее лексическое окружение. При вызове создается новая локальная область самой функции, а внешняя ссылка берется из функции, а не из текущего вызывающего кода.\n\n### 2. Есть глобальная `a` со значением `1`, функция читает `a`, а вызывающая функция имеет локальную `a` со значением `2`. Почему вызванная функция читает `1`?\n\nОжидаем: кандидат объясняет, что локальная `a` вызывающей функции не находится в лексической цепочке вызванной функции. Если вызванная функция объявлена в глобальной области, ее внешний поиск идет в глобальную область.\n\n### 3. Чем лексическая область видимости отличается от динамической простыми словами?\n\nОжидаем: кандидат формулирует разницу через \"где написали\" против \"откуда вызвали\". Лексическая модель определяется структурой кода, динамическая модель зависела бы от цепочки вызовов во время выполнения.\n\n## Референсы\n\n- [YDKJS: Глава 2. Лексическая область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch2.md) - поиск имен по вложенным областям и shadowing.\n- [YDKJS: Приложение A. Динамическая область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002FapA.md) - сравнение лексической и динамической модели.\n- [MDN: Closures](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Fclosures\u002Findex.md) - связь лексической области видимости с замыканиями.",{"slug":2341,"title":2183,"baseQuestion":2184,"goodAnswer":2185,"followUps":2342,"references":2346,"programSlug":20,"lessonSlug":20,"order":26,"status":13,"rawBody":2225},"scope-hoisting-closures-this-q2-regular-function-vs-arrow-function",[2343,2344,2345],{"question":2188,"expected":2189},{"question":2191,"expected":2192},{"question":2194,"expected":2195},[2347,2348,2349,2350,2351,2352,2353],{"title":2198,"url":2199,"note":2200},{"title":2202,"url":2203,"note":2204},{"title":2206,"url":2207,"note":2208},{"title":2210,"url":2211,"note":2212},{"title":2214,"url":2215,"note":2216},{"title":2218,"url":2219,"note":2220},{"title":2222,"url":2223,"note":2224},{"slug":2355,"title":2356,"baseQuestion":2356,"goodAnswer":2357,"followUps":2358,"references":2368,"programSlug":21,"lessonSlug":21,"order":26,"status":13,"rawBody":2385},"types-coercion-symbol-json-q2-kak-primitivy-poluchayut-dostup-k-metodam","Как примитивы получают доступ к методам?","Примитивное значение само по себе не является объектом и не хранит набор произвольных свойств. Но JavaScript позволяет читать свойства и вызывать методы у большинства примитивов так, как будто рядом есть объект.\n\nКогда мы обращаемся к свойству строки, числа, boolean, symbol или bigint, движок работает так, как будто временно создает объектную оболочку для этого примитива. Для строки это оболочка `String`, для числа - `Number`, для boolean - `Boolean`. Через эту временную оболочку можно найти свойства и методы в соответствующем прототипе. Потом оболочка исчезает, а примитив остается примитивом.\n\nНапример, когда мы читаем длину строки, мы не превращаем строку навсегда в объект. Мы просто получаем доступ к поведению, которое доступно через временную оболочку.\n\nЗапись свойства на примитив не сохраняется. Если мы сделали что-то вроде присваивания свойства строковому примитиву в нестрогом режиме, временная оболочка исчезнет сразу после операции. При следующем чтении будет создана другая оболочка, и ранее записанного свойства там не будет. В strict mode такая запись может приводить к ошибке.\n\n`null` и `undefined` - исключения. Для них нет объектных оболочек, поэтому доступ к свойствам у них невозможен.\n\nОтдельно важно отличать временную упаковку от явного создания объектной оболочки через `new String`, `new Number` или `new Boolean`. Такие значения уже являются объектами, `typeof` для них вернет `\"object\"`, а их внутренний примитив можно достать через `valueOf()`. В обычном коде такие оболочки почти никогда не нужны, потому что они легко путают поведение.",[2359,2362,2365],{"question":2360,"expected":2361},"Почему `'abc'.toUpperCase()` работает, хотя `'abc'` - примитив?","кандидат говорит, что при доступе к методу строковый примитив временно упаковывается в объектную оболочку. Метод находится через эту оболочку, выполняется и возвращает новое значение.\n\nХороший ответ добавляет, что исходная строка не становится постоянным объектом.",{"question":2363,"expected":2364},"Почему свойство, записанное в примитив, не остается при следующем чтении?","кандидат объясняет, что временная оболочка живет только во время конкретной операции доступа. После записи она исчезает. При новом чтении создается другая оболочка, где этого свойства нет.\n\nСлабый ответ: \"строка просто запрещает свойства\". Хороший ответ проговаривает именно временную упаковку и исчезновение оболочки.",{"question":2366,"expected":2367},"Зачем у объектной оболочки есть `valueOf()`?","кандидат говорит, что `valueOf()` возвращает примитив, который лежит внутри оболочки. Например, у `new Boolean(false)` можно получить обычный boolean `false`.\n\nХороший ответ должен отделять сам объект-оболочку от примитива внутри него: объект может быть truthy, даже если его `valueOf()` возвращает `false`.",[2369,2373,2377,2381],{"title":2370,"url":2371,"note":2372},"Learn JS: Методы примитивов","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F01-primitives-methods\u002Farticle.md","временные объектные оболочки, методы примитивов и почему `new Boolean` не стоит использовать в обычном коде.",{"title":2374,"url":2375,"note":2376},"YDKJS: Типы и грамматика, глава 3","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch3.md","boxing, object wrappers и распаковка через `valueOf`.",{"title":2378,"url":2379,"note":2380},"MDN: Primitive values","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Fdata_structures\u002Findex.md","примитивы и объектные оболочки при доступе к объектному поведению.",{"title":2382,"url":2383,"note":2384},"MDN: Object.prototype.valueOf","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fvalueof\u002Findex.md","базовый метод `valueOf` и его связь с объектным значением.","# Q2. Как примитивы получают доступ к методам?\n\n## Базовый вопрос\n\nКак примитивы получают доступ к методам?\n\n## Хороший ответ\n\nПримитивное значение само по себе не является объектом и не хранит набор произвольных свойств. Но JavaScript позволяет читать свойства и вызывать методы у большинства примитивов так, как будто рядом есть объект.\n\nКогда мы обращаемся к свойству строки, числа, boolean, symbol или bigint, движок работает так, как будто временно создает объектную оболочку для этого примитива. Для строки это оболочка `String`, для числа - `Number`, для boolean - `Boolean`. Через эту временную оболочку можно найти свойства и методы в соответствующем прототипе. Потом оболочка исчезает, а примитив остается примитивом.\n\nНапример, когда мы читаем длину строки, мы не превращаем строку навсегда в объект. Мы просто получаем доступ к поведению, которое доступно через временную оболочку.\n\nЗапись свойства на примитив не сохраняется. Если мы сделали что-то вроде присваивания свойства строковому примитиву в нестрогом режиме, временная оболочка исчезнет сразу после операции. При следующем чтении будет создана другая оболочка, и ранее записанного свойства там не будет. В strict mode такая запись может приводить к ошибке.\n\n`null` и `undefined` - исключения. Для них нет объектных оболочек, поэтому доступ к свойствам у них невозможен.\n\nОтдельно важно отличать временную упаковку от явного создания объектной оболочки через `new String`, `new Number` или `new Boolean`. Такие значения уже являются объектами, `typeof` для них вернет `\"object\"`, а их внутренний примитив можно достать через `valueOf()`. В обычном коде такие оболочки почти никогда не нужны, потому что они легко путают поведение.\n\n## Уточняющие вопросы\n\n### 1. Почему `'abc'.toUpperCase()` работает, хотя `'abc'` - примитив?\n\nОжидаем: кандидат говорит, что при доступе к методу строковый примитив временно упаковывается в объектную оболочку. Метод находится через эту оболочку, выполняется и возвращает новое значение.\n\nХороший ответ добавляет, что исходная строка не становится постоянным объектом.\n\n### 2. Почему свойство, записанное в примитив, не остается при следующем чтении?\n\nОжидаем: кандидат объясняет, что временная оболочка живет только во время конкретной операции доступа. После записи она исчезает. При новом чтении создается другая оболочка, где этого свойства нет.\n\nСлабый ответ: \"строка просто запрещает свойства\". Хороший ответ проговаривает именно временную упаковку и исчезновение оболочки.\n\n### 3. Зачем у объектной оболочки есть `valueOf()`?\n\nОжидаем: кандидат говорит, что `valueOf()` возвращает примитив, который лежит внутри оболочки. Например, у `new Boolean(false)` можно получить обычный boolean `false`.\n\nХороший ответ должен отделять сам объект-оболочку от примитива внутри него: объект может быть truthy, даже если его `valueOf()` возвращает `false`.\n\n## Референсы\n\n- [Learn JS: Методы примитивов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F01-primitives-methods\u002Farticle.md) - временные объектные оболочки, методы примитивов и почему `new Boolean` не стоит использовать в обычном коде.\n- [YDKJS: Типы и грамматика, глава 3](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch3.md) - boxing, object wrappers и распаковка через `valueOf`.\n- [MDN: Primitive values](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Fdata_structures\u002Findex.md) - примитивы и объектные оболочки при доступе к объектному поведению.\n- [MDN: Object.prototype.valueOf](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fvalueof\u002Findex.md) - базовый метод `valueOf` и его связь с объектным значением.",{"slug":2387,"title":2388,"baseQuestion":2389,"goodAnswer":2390,"followUps":2391,"references":2401,"programSlug":40,"lessonSlug":40,"order":36,"status":13,"rawBody":2406},"browser-network-q3-chem-otlichayutsya-metody-http","Чем отличаются методы HTTP?","Зачем HTTP-запросу нужен method?","Простой ответ: method показывает смысл запроса. Мы можем получать данные, отправлять новые данные, менять существующие или удалять ресурс. Браузер и сервер видят не только URL, но и метод, поэтому `GET \u002Fa` и `POST \u002Fa` это разные запросы по смыслу.\n\nНа собеседовании важно объяснить не список всех методов, а саму идею семантики. `GET` обычно используют для получения ресурса без изменения состояния на сервере. `POST` часто используют для отправки данных и создания действия. `PUT`, `PATCH`, `DELETE`, `OPTIONS` имеют свои роли, но конкретный контракт задает API.\n\nДля браузера метод влияет и на поведение вокруг CORS. Некоторые комбинации метода, заголовков и типа тела требуют preflight-запроса `OPTIONS`, чтобы сервер заранее подтвердил, что такой cross-origin запрос разрешен.",[2392,2395,2398],{"question":2393,"expected":2394},"Почему данные для чтения обычно не отправляют через `POST`, если технически это возможно?","кандидат говорит про семантику, кеширование, читаемость контракта и ожидания инструментов. Техническая возможность не значит хороший API-договор.",{"question":2396,"expected":2397},"Чем `GET` с query-параметрами отличается от body в запросе?","кандидат объясняет, что query является частью URL и виден в адресе запроса, а body это отдельная часть сообщения. Для `GET` тело в обычной веб-практике не используют.",{"question":2399,"expected":2400},"Зачем браузер может отправить `OPTIONS` перед основным запросом?","кандидат говорит, что это preflight для CORS. Браузер проверяет разрешение сервера до отправки основного cross-origin запроса.",[2402,2404],{"title":2091,"url":2092,"note":2403},"назначение основных HTTP-методов.",{"title":2099,"url":2100,"note":2405},"preflight и ограничения браузера.","# Q3. Чем отличаются методы HTTP?\n\n## Базовый вопрос\n\nЗачем HTTP-запросу нужен method?\n\n## Хороший ответ\n\nПростой ответ: method показывает смысл запроса. Мы можем получать данные, отправлять новые данные, менять существующие или удалять ресурс. Браузер и сервер видят не только URL, но и метод, поэтому `GET \u002Fa` и `POST \u002Fa` это разные запросы по смыслу.\n\nНа собеседовании важно объяснить не список всех методов, а саму идею семантики. `GET` обычно используют для получения ресурса без изменения состояния на сервере. `POST` часто используют для отправки данных и создания действия. `PUT`, `PATCH`, `DELETE`, `OPTIONS` имеют свои роли, но конкретный контракт задает API.\n\nДля браузера метод влияет и на поведение вокруг CORS. Некоторые комбинации метода, заголовков и типа тела требуют preflight-запроса `OPTIONS`, чтобы сервер заранее подтвердил, что такой cross-origin запрос разрешен.\n\n## Уточняющие вопросы\n\n### 1. Почему данные для чтения обычно не отправляют через `POST`, если технически это возможно?\n\nОжидаем: кандидат говорит про семантику, кеширование, читаемость контракта и ожидания инструментов. Техническая возможность не значит хороший API-договор.\n\n### 2. Чем `GET` с query-параметрами отличается от body в запросе?\n\nОжидаем: кандидат объясняет, что query является частью URL и виден в адресе запроса, а body это отдельная часть сообщения. Для `GET` тело в обычной веб-практике не используют.\n\n### 3. Зачем браузер может отправить `OPTIONS` перед основным запросом?\n\nОжидаем: кандидат говорит, что это preflight для CORS. Браузер проверяет разрешение сервера до отправки основного cross-origin запроса.\n\n## Референсы\n\n- [MDN: HTTP request methods](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Freference\u002Fmethods\u002Findex.md) - назначение основных HTTP-методов.\n- [MDN: CORS](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Fguides\u002Fcors\u002Findex.md) - preflight и ограничения браузера.",{"slug":2408,"title":2409,"baseQuestion":2410,"goodAnswer":2411,"followUps":2412,"references":2422,"programSlug":17,"lessonSlug":17,"order":36,"status":13,"rawBody":2439},"collections-iteration-arrays-q3-chto-takoe-iterable-v-javascript","Что такое iterable в JavaScript?","Что значит, что значение является iterable?","Iterable это значение, из которого JavaScript может последовательно получать элементы через общий протокол. У такого значения есть метод по ключу `Symbol.iterator`. Этот метод возвращает iterator, а у iterator есть метод `next()`. Каждый вызов `next()` возвращает объект с `value` и `done`.\n\n`for...of`, spread, `Array.from`, `Map`, `Set`, строки и генераторы опираются на эту идею. `for...of` сначала берет iterator, а потом синхронно вызывает `next()`, пока не увидит `done: true`.\n\nВажно отличать iterable от array-like. Array-like объект имеет индексы и `length`, но может не иметь `Symbol.iterator`. Поэтому он может подходить для `Array.from`, но падать в `for...of`. Строки одновременно имеют индексы и являются iterable. При этом строковый iterator идет по Unicode code points, а `length` считает UTF-16 code units, поэтому на символах вне BMP результаты могут отличаться.\n\nГенератор удобен тем, что сам создает iterator и умеет отдавать значения лениво через `yield`.",[2413,2416,2419],{"question":2414,"expected":2415},"Почему `for...of` падает на объекте с `0: 'a'` и `length: 1`, если у него нет `Symbol.iterator`?","кандидат объясняет, что индексов и `length` достаточно для array-like, но не для iterable. `for...of` требует метод `Symbol.iterator`.",{"question":2417,"expected":2418},"Почему `Array.from` может принять и строку, и простой объект с индексами и `length`?","кандидат говорит, что `Array.from` умеет работать и с iterable, и с array-like. Строка дает iterator, а объект с индексами читается через `length`.",{"question":2420,"expected":2421},"Почему у строки с одним emoji `length` может быть `2`, а `Array.from(str).length` может быть `1`?","кандидат объясняет разницу между UTF-16 code units и обходом строки через iterator по Unicode code points.",[2423,2427,2431,2435],{"title":2424,"url":2425,"note":2426},"ru.javascript.info: Перебираемые объекты","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F06-iterable\u002Farticle.md","учебное объяснение iterable, iterator и array-like.",{"title":2428,"url":2429,"note":2430},"MDN: Iteration protocols","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fiteration_protocols\u002Findex.md","справочник по протоколам итерации.",{"title":2432,"url":2433,"note":2434},"ru.javascript.info: Генераторы","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F12-generators-iterators\u002F1-generators\u002Farticle.md","учебное объяснение синхронных генераторов.",{"title":2436,"url":2437,"note":2438},"Вы не знаете JS: ES6 и не только — глава 3 Organization","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fes6%20%26%20beyond\u002Fch3.md","дополнительные объяснения про iterators и generators.","# Q3. Что такое iterable в JavaScript?\n\n## Базовый вопрос\n\nЧто значит, что значение является iterable?\n\n## Хороший ответ\n\nIterable это значение, из которого JavaScript может последовательно получать элементы через общий протокол. У такого значения есть метод по ключу `Symbol.iterator`. Этот метод возвращает iterator, а у iterator есть метод `next()`. Каждый вызов `next()` возвращает объект с `value` и `done`.\n\n`for...of`, spread, `Array.from`, `Map`, `Set`, строки и генераторы опираются на эту идею. `for...of` сначала берет iterator, а потом синхронно вызывает `next()`, пока не увидит `done: true`.\n\nВажно отличать iterable от array-like. Array-like объект имеет индексы и `length`, но может не иметь `Symbol.iterator`. Поэтому он может подходить для `Array.from`, но падать в `for...of`. Строки одновременно имеют индексы и являются iterable. При этом строковый iterator идет по Unicode code points, а `length` считает UTF-16 code units, поэтому на символах вне BMP результаты могут отличаться.\n\nГенератор удобен тем, что сам создает iterator и умеет отдавать значения лениво через `yield`.\n\n## Уточняющие вопросы\n\n### 1. Почему `for...of` падает на объекте с `0: 'a'` и `length: 1`, если у него нет `Symbol.iterator`?\n\nОжидаем: кандидат объясняет, что индексов и `length` достаточно для array-like, но не для iterable. `for...of` требует метод `Symbol.iterator`.\n\n### 2. Почему `Array.from` может принять и строку, и простой объект с индексами и `length`?\n\nОжидаем: кандидат говорит, что `Array.from` умеет работать и с iterable, и с array-like. Строка дает iterator, а объект с индексами читается через `length`.\n\n### 3. Почему у строки с одним emoji `length` может быть `2`, а `Array.from(str).length` может быть `1`?\n\nОжидаем: кандидат объясняет разницу между UTF-16 code units и обходом строки через iterator по Unicode code points.\n\n## Референсы\n\n- [ru.javascript.info: Перебираемые объекты](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F06-iterable\u002Farticle.md) - учебное объяснение iterable, iterator и array-like.\n- [MDN: Iteration protocols](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fiteration_protocols\u002Findex.md) - справочник по протоколам итерации.\n- [ru.javascript.info: Генераторы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F12-generators-iterators\u002F1-generators\u002Farticle.md) - учебное объяснение синхронных генераторов.\n- [Вы не знаете JS: ES6 и не только — глава 3 Organization](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fes6%20%26%20beyond\u002Fch3.md) - дополнительные объяснения про iterators и generators.",{"slug":2441,"title":2442,"baseQuestion":2443,"goodAnswer":2444,"followUps":2445,"references":2455,"programSlug":30,"lessonSlug":30,"order":36,"status":13,"rawBody":2466},"event-loop-promises-async-await-q3-pochemu-promise-zamenili-callback","Почему Promise заменили callback?","Почему в асинхронном JavaScript стали использовать Promise вместо callback?","Сначала можно объяснить просто: callback был первым естественным способом сказать \"выполни эту функцию позже, когда асинхронная работа закончится\". Мы передавали функцию в другую функцию, например в загрузку скрипта, таймер или запрос, а браузер вызывал ее после завершения операции.\n\nCallback сам по себе не плохой. Он хорошо работает для одного простого действия: \"загрузи скрипт и потом вызови функцию\", \"по клику выполни обработчик\", \"после таймера запусти код\". Проблемы начинаются, когда асинхронных шагов становится много, когда нужно связать их в последовательность, обработать ошибки и передать результат дальше.\n\nГлавная боль callback-подхода - управление потоком выполнения размазано по вложенным функциям. Если нам нужно сделать шаг 1, потом шаг 2, потом шаг 3, мы часто вкладываем callback в callback. Код быстро превращается в пирамиду вложенности: сложнее читать порядок действий, сложнее обрабатывать ошибки, сложнее добавить новый шаг или выйти из цепочки.\n\nВторая проблема - нет единого стандартного объекта, который представляет будущий результат. Callback - это просто функция, которую кто-то когда-то должен вызвать. Мы должны доверять чужой функции: что она вызовет callback ровно один раз, не вызовет слишком рано, не вызовет и успех и ошибку, не потеряет ошибку, не перепутает порядок аргументов. В больших цепочках это быстро становится хрупким контрактом.\n\nТретья проблема - обработка ошибок. В классическом error-first callback первый аргумент отдают под ошибку, а следующие под результат. Это рабочий паттерн, но его нужно вручную поддерживать в каждом callback. Ошибка не проходит по цепочке сама, как в Promise. При вложенности приходится повторять проверки `if (error)` на каждом уровне или выносить отдельные функции, чтобы код оставался читаемым.\n\nPromise решает эти проблемы тем, что дает отдельный объект будущего результата. У него есть понятные состояния, он завершается один раз, хранит либо успешное значение, либо ошибку, а потребители подписываются на результат через `.then`, `.catch`, `.finally` или ждут его через `await`.\n\nPromise также делает композицию удобнее. Вместо вложенной пирамиды мы можем писать цепочку `.then`, где каждый шаг возвращает значение или новый Promise. Ошибки можно ловить ближе к месту восстановления или одним `.catch` в конце цепочки. Для групп операций есть `Promise.all`, `Promise.allSettled` и другие методы.\n\nНа собеседовании важно не говорить, что callback \"устарели и больше не нужны\". Callback до сих пор используются в событиях, таймерах, array methods и многих API. Но для представления результата асинхронной операции Promise оказался удобнее, потому что он стандартизирует итог, ошибку, одноразовое завершение и композицию.",[2446,2449,2452],{"question":2447,"expected":2448},"Почему callback хорошо подходит для одного действия, но плохо масштабируется на цепочку действий?","кандидат говорит, что один callback легко прочитать: действие завершилось, функция вызвалась. Но когда шагов несколько, callback-и начинают вкладываться друг в друга. Порядок выполнения, обработка ошибок и передача результатов оказываются размазаны по уровням вложенности.",{"question":2450,"expected":2451},"В чем проблема фразы \"callback просто вызовут потом\"?","кандидат объясняет, что callback не дает отдельного объекта будущего результата. Мы зависим от вызывающей функции: она должна вызвать callback один раз, с правильными аргументами, в правильный момент и с корректной обработкой ошибки. Promise делает этот контракт более явным и единообразным.",{"question":2453,"expected":2454},"Как Promise помогает с ошибками по сравнению с error-first callback?","кандидат говорит, что в error-first callback ошибку нужно проверять вручную на каждом шаге. В Promise ошибка переводит цепочку в rejected-ветку и идет к ближайшему обработчику ошибки. Это не отменяет необходимость думать об ошибках, но делает их распространение и обработку более единообразными.",[2456,2460,2464],{"title":2457,"url":2458,"note":2459},"ru.javascript.info: Введение колбэки","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F01-callbacks\u002Farticle.md","показывает callback-подход, error-first callback и пирамиду вызовов.",{"title":2461,"url":2462,"note":2463},"ru.javascript.info: Промисы","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F02-promise-basics\u002Farticle.md","объясняет Promise как объект будущего результата с `resolve` и `reject`.",{"title":1807,"url":1808,"note":2465},"объясняет callback как раннюю модель асинхронности и проблему роста сложности.","# Q3. Почему Promise заменили callback?\n\n## Базовый вопрос\n\nПочему в асинхронном JavaScript стали использовать Promise вместо callback?\n\n## Хороший ответ\n\nСначала можно объяснить просто: callback был первым естественным способом сказать \"выполни эту функцию позже, когда асинхронная работа закончится\". Мы передавали функцию в другую функцию, например в загрузку скрипта, таймер или запрос, а браузер вызывал ее после завершения операции.\n\nCallback сам по себе не плохой. Он хорошо работает для одного простого действия: \"загрузи скрипт и потом вызови функцию\", \"по клику выполни обработчик\", \"после таймера запусти код\". Проблемы начинаются, когда асинхронных шагов становится много, когда нужно связать их в последовательность, обработать ошибки и передать результат дальше.\n\nГлавная боль callback-подхода - управление потоком выполнения размазано по вложенным функциям. Если нам нужно сделать шаг 1, потом шаг 2, потом шаг 3, мы часто вкладываем callback в callback. Код быстро превращается в пирамиду вложенности: сложнее читать порядок действий, сложнее обрабатывать ошибки, сложнее добавить новый шаг или выйти из цепочки.\n\nВторая проблема - нет единого стандартного объекта, который представляет будущий результат. Callback - это просто функция, которую кто-то когда-то должен вызвать. Мы должны доверять чужой функции: что она вызовет callback ровно один раз, не вызовет слишком рано, не вызовет и успех и ошибку, не потеряет ошибку, не перепутает порядок аргументов. В больших цепочках это быстро становится хрупким контрактом.\n\nТретья проблема - обработка ошибок. В классическом error-first callback первый аргумент отдают под ошибку, а следующие под результат. Это рабочий паттерн, но его нужно вручную поддерживать в каждом callback. Ошибка не проходит по цепочке сама, как в Promise. При вложенности приходится повторять проверки `if (error)` на каждом уровне или выносить отдельные функции, чтобы код оставался читаемым.\n\nPromise решает эти проблемы тем, что дает отдельный объект будущего результата. У него есть понятные состояния, он завершается один раз, хранит либо успешное значение, либо ошибку, а потребители подписываются на результат через `.then`, `.catch`, `.finally` или ждут его через `await`.\n\nPromise также делает композицию удобнее. Вместо вложенной пирамиды мы можем писать цепочку `.then`, где каждый шаг возвращает значение или новый Promise. Ошибки можно ловить ближе к месту восстановления или одним `.catch` в конце цепочки. Для групп операций есть `Promise.all`, `Promise.allSettled` и другие методы.\n\nНа собеседовании важно не говорить, что callback \"устарели и больше не нужны\". Callback до сих пор используются в событиях, таймерах, array methods и многих API. Но для представления результата асинхронной операции Promise оказался удобнее, потому что он стандартизирует итог, ошибку, одноразовое завершение и композицию.\n\n## Уточняющие вопросы\n\n### 1. Почему callback хорошо подходит для одного действия, но плохо масштабируется на цепочку действий?\n\nОжидаем: кандидат говорит, что один callback легко прочитать: действие завершилось, функция вызвалась. Но когда шагов несколько, callback-и начинают вкладываться друг в друга. Порядок выполнения, обработка ошибок и передача результатов оказываются размазаны по уровням вложенности.\n\n### 2. В чем проблема фразы \"callback просто вызовут потом\"?\n\nОжидаем: кандидат объясняет, что callback не дает отдельного объекта будущего результата. Мы зависим от вызывающей функции: она должна вызвать callback один раз, с правильными аргументами, в правильный момент и с корректной обработкой ошибки. Promise делает этот контракт более явным и единообразным.\n\n### 3. Как Promise помогает с ошибками по сравнению с error-first callback?\n\nОжидаем: кандидат говорит, что в error-first callback ошибку нужно проверять вручную на каждом шаге. В Promise ошибка переводит цепочку в rejected-ветку и идет к ближайшему обработчику ошибки. Это не отменяет необходимость думать об ошибках, но делает их распространение и обработку более единообразными.\n\n## Референсы\n\n- [ru.javascript.info: Введение колбэки](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F01-callbacks\u002Farticle.md) - показывает callback-подход, error-first callback и пирамиду вызовов.\n- [ru.javascript.info: Промисы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F02-promise-basics\u002Farticle.md) - объясняет Promise как объект будущего результата с `resolve` и `reject`.\n- [Вы не знаете JS: Асинхронность и выполнение - глава 1 Асинхронность сейчас и потом](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fasync%20%26%20performance\u002Fch1.md) - объясняет callback как раннюю модель асинхронности и проблему роста сложности.",{"slug":2468,"title":2469,"baseQuestion":2470,"goodAnswer":2471,"followUps":2472,"references":2482,"programSlug":31,"lessonSlug":31,"order":36,"status":13,"rawBody":2495},"event-loop-promises-deep-dive-q3-pochemu-await-raspakovyvaet-obekt-s-then","Почему await распаковывает объект с then?","Есть объект и async-функция:\n\n```js\nconst a = {\n  then(resolve) {\n    resolve('b');\n  },\n};\n\nasync function f() {\n  const b = await a;\n\n  console.log(b);\n}\n\nf();\n```\n\nПочему `console.log` выведет `'b'`, а не сам объект `a`?","Thenable - это объект или функция, у которой есть метод `then`. Он не обязан быть настоящим экземпляром `Promise`. Для промисной механики важно, что у такого значения можно вызвать `then` и передать туда функции для успешного и ошибочного завершения.\n\nJavaScript использует thenable для совместимости. Если мы передаем thenable в `Promise.resolve` или пишем `await` перед thenable, движок пытается \"усвоить\" его результат: вызывает его `then`, передает служебные `resolve` и `reject`, а затем ждет, какая из этих функций будет вызвана.\n\nЭто удобно, потому что промисы могут работать не только с нативными `Promise`, но и с похожими объектами из библиотек или старого кода.\n\nГлавная мысль для собеседования: thenable - это не \"почти Promise по названию\", а объект с конкретным контрактом. Если у значения есть вызываемый `then`, промисная механика будет относиться к нему как к источнику будущего результата.\n\nВажно помнить и про порядок. Усвоение thenable через `Promise.resolve` не означает, что пользовательский `then` обязательно вызовется прямо в текущей строке. Его обработка идет через асинхронную промисную работу, поэтому рядом с другими микрозадачами порядок может быть неочевидным.",[2473,2476,2479],{"question":2474,"expected":2475},"Объект создан обычным литералом, но у него есть метод `then(resolve, reject)`. Почему `await` относится к нему как к промису?","кандидат объясняет, что `await` работает не только с настоящими экземплярами `Promise`. Он умеет ждать промис-совместимые объекты, то есть thenable.\n\nThenable - это объект или функция, у которой есть вызываемый метод `then`. Когда `await` получает такое значение, JavaScript не требует, чтобы оно было создано через `new Promise`. Вместо этого он использует промисную механику усвоения результата: вызывает `then` и передает туда две служебные функции, похожие на `resolve` и `reject`.\n\nЕсли thenable вызовет `resolve`, выполнение async-функции продолжится с успешным значением. Если вызовет `reject` или если внутри `then` произойдет ошибка до успешного завершения, ожидание завершится ошибкой, как отклоненный Promise.\n\nЭто нужно для совместимости. Старый код или библиотека может вернуть не нативный `Promise`, а объект с методом `then`. Для `await` такого контракта достаточно, чтобы воспринимать значение как будущий результат.\n\nХороший ответ должен не сводиться к фразе \"`await` ждет все\". Точнее так: `await` обычное значение превращает в уже готовый результат, а thenable обрабатывает через его метод `then`.",{"question":2477,"expected":2478},"Почему `await { x: 1 }` возвращает сам объект, а `await` объекта с `then(resolve)` возвращает значение из `resolve`?","кандидат говорит, что обычное значение не имеет промисного контракта. Если мы передаем в `await` число, строку, объект без `then` или другое не-thenable значение, JavaScript считает это уже готовым успешным результатом. Async-функция все равно продолжится позже, но итоговым значением будет само это значение.\n\nThenable отличается тем, что у него есть метод `then`, и именно этот метод меняет смысл значения. JavaScript воспринимает thenable не как обычный готовый объект, а как источник будущего результата. Поэтому он вызывает `then` и ждет, что thenable сам сообщит итог через переданные функции.\n\nНапример, объект `{ x: 1 }` после `await` даст сам объект. А объект с методом `then(resolve) { resolve(1) }` после `await` даст уже не сам объект, а значение `1`, потому что JavaScript попробует распаковать thenable.\n\nВажная мысль: thenable может выглядеть как обычный объект, но наличие вызываемого `then` переводит его в промисную механику. Поэтому свойство `then` - не просто поле с именем, а сигнал для `await` и `Promise.resolve`.",{"question":2480,"expected":2481},"В методе `then` у thenable есть `console.log` и изменение внешней переменной. Почему эти действия выполняются при `await` или `Promise.resolve`?","кандидат объясняет, что `then` у thenable - это обычный пользовательский метод. Когда JavaScript усваивает thenable через `await` или `Promise.resolve`, он фактически вызывает этот метод. Значит, внутри `then` может выполниться любой пользовательский код: логирование, изменение внешнего состояния, запуск таймеров, повторный вызов `resolve`, ошибка через `throw`.\n\nПо референсам, `Promise.resolve` при thenable вызывает его `then` с подготовленными callback-функциями. Спецификация дополнительно подчеркивает, что вызов `then` выполняется как отдельная promise job после окружающего кода. Из-за этого порядок логов рядом с микрозадачами может быть не таким, как ожидает новичок.\n\nЕсть еще один нюанс: если thenable сначала вызвал `resolve`, а потом бросил ошибку, состояние уже могло быть зафиксировано успешным результатом. А если ошибка произошла до успешного завершения, итог станет ошибкой. Поэтому thenable может вести себя как \"чужой маленький executor\", и к нему надо относиться осторожно.\n\nХороший кандидат должен сказать не только \"у thenable есть then\", но и риск: мы не просто читаем значение, мы запускаем метод, написанный кем-то еще. Поэтому thenable может создавать побочные эффекты и усложнять порядок выполнения.",[2483,2487,2491],{"title":2484,"url":2485,"note":2486},"ru.javascript.info: Async await","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md","раздел про работу `await` с thenable-объектами.",{"title":2488,"url":2489,"note":2490},"MDN: Promise.resolve","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fresolve\u002Findex.md","усвоение thenable через `Promise.resolve`.",{"title":2492,"url":2493,"note":2494},"ECMA-262: Promise Resolve Functions","https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-promise-resolve-functions","формальная механика thenable assimilation.","# Q3. Почему await распаковывает объект с then?\n\n## Базовый вопрос\n\nЕсть объект и async-функция:\n\n```js\nconst a = {\n  then(resolve) {\n    resolve('b');\n  },\n};\n\nasync function f() {\n  const b = await a;\n\n  console.log(b);\n}\n\nf();\n```\n\nПочему `console.log` выведет `'b'`, а не сам объект `a`?\n\n## Хороший ответ\n\nThenable - это объект или функция, у которой есть метод `then`. Он не обязан быть настоящим экземпляром `Promise`. Для промисной механики важно, что у такого значения можно вызвать `then` и передать туда функции для успешного и ошибочного завершения.\n\nJavaScript использует thenable для совместимости. Если мы передаем thenable в `Promise.resolve` или пишем `await` перед thenable, движок пытается \"усвоить\" его результат: вызывает его `then`, передает служебные `resolve` и `reject`, а затем ждет, какая из этих функций будет вызвана.\n\nЭто удобно, потому что промисы могут работать не только с нативными `Promise`, но и с похожими объектами из библиотек или старого кода.\n\nГлавная мысль для собеседования: thenable - это не \"почти Promise по названию\", а объект с конкретным контрактом. Если у значения есть вызываемый `then`, промисная механика будет относиться к нему как к источнику будущего результата.\n\nВажно помнить и про порядок. Усвоение thenable через `Promise.resolve` не означает, что пользовательский `then` обязательно вызовется прямо в текущей строке. Его обработка идет через асинхронную промисную работу, поэтому рядом с другими микрозадачами порядок может быть неочевидным.\n\n## Уточняющие вопросы\n\n### 1. Объект создан обычным литералом, но у него есть метод `then(resolve, reject)`. Почему `await` относится к нему как к промису?\n\nОжидаем: кандидат объясняет, что `await` работает не только с настоящими экземплярами `Promise`. Он умеет ждать промис-совместимые объекты, то есть thenable.\n\nThenable - это объект или функция, у которой есть вызываемый метод `then`. Когда `await` получает такое значение, JavaScript не требует, чтобы оно было создано через `new Promise`. Вместо этого он использует промисную механику усвоения результата: вызывает `then` и передает туда две служебные функции, похожие на `resolve` и `reject`.\n\nЕсли thenable вызовет `resolve`, выполнение async-функции продолжится с успешным значением. Если вызовет `reject` или если внутри `then` произойдет ошибка до успешного завершения, ожидание завершится ошибкой, как отклоненный Promise.\n\nЭто нужно для совместимости. Старый код или библиотека может вернуть не нативный `Promise`, а объект с методом `then`. Для `await` такого контракта достаточно, чтобы воспринимать значение как будущий результат.\n\nХороший ответ должен не сводиться к фразе \"`await` ждет все\". Точнее так: `await` обычное значение превращает в уже готовый результат, а thenable обрабатывает через его метод `then`.\n\n### 2. Почему `await { x: 1 }` возвращает сам объект, а `await` объекта с `then(resolve)` возвращает значение из `resolve`?\n\nОжидаем: кандидат говорит, что обычное значение не имеет промисного контракта. Если мы передаем в `await` число, строку, объект без `then` или другое не-thenable значение, JavaScript считает это уже готовым успешным результатом. Async-функция все равно продолжится позже, но итоговым значением будет само это значение.\n\nThenable отличается тем, что у него есть метод `then`, и именно этот метод меняет смысл значения. JavaScript воспринимает thenable не как обычный готовый объект, а как источник будущего результата. Поэтому он вызывает `then` и ждет, что thenable сам сообщит итог через переданные функции.\n\nНапример, объект `{ x: 1 }` после `await` даст сам объект. А объект с методом `then(resolve) { resolve(1) }` после `await` даст уже не сам объект, а значение `1`, потому что JavaScript попробует распаковать thenable.\n\nВажная мысль: thenable может выглядеть как обычный объект, но наличие вызываемого `then` переводит его в промисную механику. Поэтому свойство `then` - не просто поле с именем, а сигнал для `await` и `Promise.resolve`.\n\n### 3. В методе `then` у thenable есть `console.log` и изменение внешней переменной. Почему эти действия выполняются при `await` или `Promise.resolve`?\n\nОжидаем: кандидат объясняет, что `then` у thenable - это обычный пользовательский метод. Когда JavaScript усваивает thenable через `await` или `Promise.resolve`, он фактически вызывает этот метод. Значит, внутри `then` может выполниться любой пользовательский код: логирование, изменение внешнего состояния, запуск таймеров, повторный вызов `resolve`, ошибка через `throw`.\n\nПо референсам, `Promise.resolve` при thenable вызывает его `then` с подготовленными callback-функциями. Спецификация дополнительно подчеркивает, что вызов `then` выполняется как отдельная promise job после окружающего кода. Из-за этого порядок логов рядом с микрозадачами может быть не таким, как ожидает новичок.\n\nЕсть еще один нюанс: если thenable сначала вызвал `resolve`, а потом бросил ошибку, состояние уже могло быть зафиксировано успешным результатом. А если ошибка произошла до успешного завершения, итог станет ошибкой. Поэтому thenable может вести себя как \"чужой маленький executor\", и к нему надо относиться осторожно.\n\nХороший кандидат должен сказать не только \"у thenable есть then\", но и риск: мы не просто читаем значение, мы запускаем метод, написанный кем-то еще. Поэтому thenable может создавать побочные эффекты и усложнять порядок выполнения.\n\n## Референсы\n\n- [ru.javascript.info: Async await](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md) - раздел про работу `await` с thenable-объектами.\n- [MDN: Promise.resolve](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fresolve\u002Findex.md) - усвоение thenable через `Promise.resolve`.\n- [ECMA-262: Promise Resolve Functions](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-promise-resolve-functions) - формальная механика thenable assimilation.",{"slug":2497,"title":2498,"baseQuestion":2499,"goodAnswer":2500,"followUps":2501,"references":2511,"programSlug":59,"lessonSlug":59,"order":36,"status":13,"rawBody":2524},"mock-interview-javascript-core-q3-chto-takoe-zamykanie","Что такое замыкание?","Что такое замыкание в JavaScript?","Замыкание - это способность функции запоминать лексическое окружение, в котором она была создана, и обращаться к внешним переменным из этого окружения даже после того, как внешний код уже выполнился.\n\nВ JavaScript функция при создании получает внутреннюю ссылку на свое лексическое окружение. Через эту ссылку она потом ищет внешние переменные. Поэтому важно говорить не \"функция запомнила значение\", а \"функция сохранила доступ к привязкам во внешнем лексическом окружении\".\n\nКлючевые мысли:\n\n- Замыкание связано с лексической областью видимости. Функция смотрит туда, где была создана, а не туда, откуда ее потом вызвали.\n- Замыкание сохраняет доступ к внешним привязкам, а не обязательно копирует значения. Если внешняя переменная меняется, функция работает с актуальным значением этой привязки.\n- Каждый вызов внешней функции создает свое лексическое окружение. Поэтому несколько функций, созданных разными вызовами, могут иметь независимое состояние.\n- Лексическое окружение живет дольше обычного, если на него еще есть ссылка из функции. Когда доступных функций больше нет, окружение может быть очищено сборщиком мусора.\n- Замыкания используют для приватного состояния, фабрик функций, callbacks, обработчиков событий, декораторов, модульного паттерна и сохранения контекста между вызовами.\n- `new Function` - важное исключение: такая функция не замыкается на локальное окружение места создания, а работает через глобальное окружение.\n\nГлавная мысль: замыкание объясняет, почему функция может помнить \"свой мир\" после выхода из внешней функции.",[2502,2505,2508],{"question":2503,"expected":2504},"Почему функция может пользоваться внешними переменными даже после того, как внешняя функция уже завершилась?","кандидат говорит, что при создании функция получает доступ к внешнему лексическому окружению. Если сама функция еще доступна и может быть вызвана позже, нужное ей окружение не исчезает сразу после завершения внешней функции.\n\nЭто и есть важная часть замыкания: функция продолжает видеть переменные из места, где мы ее создали, даже если вызываем ее позже и уже из другого места. Хороший ответ не сводит замыкание к фразе \"функция внутри функции\". Вложенность часто есть в примерах, но сама по себе она еще не объясняет, почему внешние переменные остаются доступны.\n\nСлабый ответ: \"потому что функция просто запомнила значение\". Это неточно: функция сохраняет доступ к окружению, а не обязательно копирует все значения.",{"question":2506,"expected":2507},"Функция с замыканием хранит копию значения или продолжает работать с той же внешней переменной?","кандидат говорит, что замыкание обычно не означает \"снимок значения на момент создания функции\". Функция продолжает работать с той же внешней переменной из лексического окружения.\n\nЕсли эта внешняя переменная меняется, функция увидит актуальное значение этой переменной. Поэтому лучше говорить \"функция сохранила доступ к внешней переменной\", а не \"функция скопировала значение\".\n\nСлабый ответ: \"замыкание всегда запоминает старое значение\". Такой ответ показывает, что кандидат путает доступ к переменной со снимком значения.",{"question":2509,"expected":2510},"Чем замыкание полезно в реальном фронтенд-коде?","кандидат называет сохранение состояния между вызовами, обработчики событий, callbacks, фабрики функций, декораторы, модульный паттерн и инкапсуляцию без глобальных переменных.",[2512,2514,2518,2522],{"title":1861,"url":1862,"note":2513},"лексическое окружение, `[[Environment]]`, сохранение внешних переменных и сборка мусора.",{"title":2515,"url":2516,"note":2517},"Learn JS: Синтаксис new Function","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F07-new-function\u002Farticle.md","почему `new Function` использует глобальное окружение, а не локальное окружение места создания.",{"title":2519,"url":2520,"note":2521},"YDKJS: Глава 5. Замыкание области видимости","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md","замыкание как доступ функции к своей лексической области видимости при вызове вне нее.",{"title":1885,"url":1886,"note":2523},"как функция сохраняет доступ к внешнему лексическому окружению.","# Q3. Что такое замыкание?\n\n## Базовый вопрос\n\nЧто такое замыкание в JavaScript?\n\n## Хороший ответ\n\nЗамыкание - это способность функции запоминать лексическое окружение, в котором она была создана, и обращаться к внешним переменным из этого окружения даже после того, как внешний код уже выполнился.\n\nВ JavaScript функция при создании получает внутреннюю ссылку на свое лексическое окружение. Через эту ссылку она потом ищет внешние переменные. Поэтому важно говорить не \"функция запомнила значение\", а \"функция сохранила доступ к привязкам во внешнем лексическом окружении\".\n\nКлючевые мысли:\n\n- Замыкание связано с лексической областью видимости. Функция смотрит туда, где была создана, а не туда, откуда ее потом вызвали.\n- Замыкание сохраняет доступ к внешним привязкам, а не обязательно копирует значения. Если внешняя переменная меняется, функция работает с актуальным значением этой привязки.\n- Каждый вызов внешней функции создает свое лексическое окружение. Поэтому несколько функций, созданных разными вызовами, могут иметь независимое состояние.\n- Лексическое окружение живет дольше обычного, если на него еще есть ссылка из функции. Когда доступных функций больше нет, окружение может быть очищено сборщиком мусора.\n- Замыкания используют для приватного состояния, фабрик функций, callbacks, обработчиков событий, декораторов, модульного паттерна и сохранения контекста между вызовами.\n- `new Function` - важное исключение: такая функция не замыкается на локальное окружение места создания, а работает через глобальное окружение.\n\nГлавная мысль: замыкание объясняет, почему функция может помнить \"свой мир\" после выхода из внешней функции.\n\n## Уточняющие вопросы\n\n### 1. Почему функция может пользоваться внешними переменными даже после того, как внешняя функция уже завершилась?\n\nОжидаем: кандидат говорит, что при создании функция получает доступ к внешнему лексическому окружению. Если сама функция еще доступна и может быть вызвана позже, нужное ей окружение не исчезает сразу после завершения внешней функции.\n\nЭто и есть важная часть замыкания: функция продолжает видеть переменные из места, где мы ее создали, даже если вызываем ее позже и уже из другого места. Хороший ответ не сводит замыкание к фразе \"функция внутри функции\". Вложенность часто есть в примерах, но сама по себе она еще не объясняет, почему внешние переменные остаются доступны.\n\nСлабый ответ: \"потому что функция просто запомнила значение\". Это неточно: функция сохраняет доступ к окружению, а не обязательно копирует все значения.\n\n### 2. Функция с замыканием хранит копию значения или продолжает работать с той же внешней переменной?\n\nОжидаем: кандидат говорит, что замыкание обычно не означает \"снимок значения на момент создания функции\". Функция продолжает работать с той же внешней переменной из лексического окружения.\n\nЕсли эта внешняя переменная меняется, функция увидит актуальное значение этой переменной. Поэтому лучше говорить \"функция сохранила доступ к внешней переменной\", а не \"функция скопировала значение\".\n\nСлабый ответ: \"замыкание всегда запоминает старое значение\". Такой ответ показывает, что кандидат путает доступ к переменной со снимком значения.\n\n### 3. Чем замыкание полезно в реальном фронтенд-коде?\n\nОжидаем: кандидат называет сохранение состояния между вызовами, обработчики событий, callbacks, фабрики функций, декораторы, модульный паттерн и инкапсуляцию без глобальных переменных.\n\n## Референсы\n\n- [Learn JS: Область видимости переменных, замыкание](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md) - лексическое окружение, `[[Environment]]`, сохранение внешних переменных и сборка мусора.\n- [Learn JS: Синтаксис new Function](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F07-new-function\u002Farticle.md) - почему `new Function` использует глобальное окружение, а не локальное окружение места создания.\n- [YDKJS: Глава 5. Замыкание области видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md) - замыкание как доступ функции к своей лексической области видимости при вызове вне нее.\n- [MDN: Closures](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Fclosures\u002Findex.md) - как функция сохраняет доступ к внешнему лексическому окружению.",{"slug":2526,"title":2527,"baseQuestion":2527,"goodAnswer":2528,"followUps":2529,"references":2539,"programSlug":18,"lessonSlug":18,"order":36,"status":13,"rawBody":2553},"objects-prototypes-classes-q3-chto-takoe-deskriptor-svoystva","Что такое дескриптор свойства?","Дескриптор свойства - это объектное описание внутреннего устройства свойства. Для свойства данных дескриптор может содержать `value`, `writable`, `enumerable` и `configurable`. Для свойства-аксессора вместо `value` и `writable` используются `get` и `set`.\n\nЕсли мы создаем свойство обычным присваиванием или в литерале объекта, для свойства данных обычно получаются флаги:\n\n- `writable: true`;\n- `enumerable: true`;\n- `configurable: true`.\n\nЕсли мы создаем новое свойство через `Object.defineProperty` и не указываем флаги явно, неуказанные флаги получают значения по умолчанию. Для `writable`, `enumerable` и `configurable` это `false`.\n\nПоэтому эти два способа не равны по смыслу. Запись `obj.x = 1` создает обычное изменяемое и перечислимое свойство. А `Object.defineProperty(obj, 'x', { value: 1 })` создаст свойство, которое нельзя перезаписать обычным присваиванием, нельзя увидеть в `Object.keys` и нельзя удалить или перенастроить.\n\nВажно: `Object.defineProperty` может не только создать свойство, но и изменить дескриптор уже существующего свойства, если это разрешено текущими флагами.\n\nХороший кандидат должен уметь объяснить не только что такое дескриптор, но и почему забытый флаг в `defineProperty` меняет поведение свойства.",[2530,2533,2536],{"question":2531,"expected":2532},"Что вернет `Object.getOwnPropertyDescriptor`?","кандидат говорит, что метод вернет объект-дескриптор собственного свойства. Это не само значение свойства, а описание того, как это свойство устроено.\n\nЕсли это свойство данных, в дескрипторе будут `value`, `writable`, `enumerable` и `configurable`. Если это свойство-аксессор, в дескрипторе будут `get`, `set`, `enumerable` и `configurable`.\n\nЕсли такого собственного свойства на объекте нет, метод вернет `undefined`. Важно, что `Object.getOwnPropertyDescriptor` смотрит именно собственные свойства объекта и не ищет свойство по цепочке прототипов.",{"question":2534,"expected":2535},"Есть `const obj = {}`. Почему после `Object.defineProperty(obj, 'x', { value: 1 })` и `obj.x = 2` значение `obj.x` остается `1`, `Object.keys(obj)` не содержит `x`, а `delete obj.x` не удаляет свойство?","кандидат объясняет, что через `Object.defineProperty` мы создали новое собственное свойство данных и явно описали только `value`. Неуказанные флаги нового свойства получают значения по умолчанию: `writable: false`, `enumerable: false`, `configurable: false`.\n\nИз-за `writable: false` свойство нельзя изменить обычным присваиванием. В строгом режиме такая запись выбросит ошибку. Из-за `enumerable: false` свойство не будет видно через `Object.keys` и не попадет в `for..in`. Из-за `configurable: false` его нельзя удалить или свободно перенастроить.\n\nХороший ответ добавляет сравнение с обычным присваиванием: если бы мы создали новое свойство через `obj.x = 1`, оно получило бы более привычные флаги `writable: true`, `enumerable: true`, `configurable: true`.\n\nВажно: эта ловушка касается создания нового свойства через неполный дескриптор. Если свойство уже существует, `defineProperty` меняет только переданные части дескриптора, насколько это разрешено текущими флагами, а пропущенные поля не нужно объяснять как автоматический сброс в `false`.",{"question":2537,"expected":2538},"Когда стоит использовать `defineProperty`, а не обычное присваивание?","кандидат говорит, что обычное присваивание нужно для простого случая: мы хотим положить значение в свойство и получить обычное свойство данных. Если свойства еще не было, `obj.x = 1` создаст собственное свойство с привычными флагами: его можно менять, перечислять и конфигурировать.\n\n`Object.defineProperty` стоит использовать тогда, когда нам важно не только значение, но и поведение свойства. Например, мы хотим создать или изменить свойство так, чтобы оно не попадало в перечисление, не перезаписывалось обычным присваиванием, не удалялось или не перенастраивалось. То есть мы явно управляем `writable`, `enumerable` и `configurable`.\n\nЕще один важный случай - accessor property. Через `defineProperty` можно описать свойство через `get` и `set`, чтобы внешне оно выглядело как обычное свойство, но при чтении или записи запускалась функция. При этом кандидат должен помнить, что свойство не может одновременно быть свойством данных и аксессором: в одном дескрипторе нельзя смешивать `value` или `writable` с `get` или `set`.\n\nХороший практический ответ: `defineProperty` выбираем для точной настройки контракта свойства, а обычное присваивание - когда нужен простой и читаемый способ записать значение без специальных ограничений.",[2540,2544,2546,2550],{"title":2541,"url":2542,"note":2543},"Learn JS: Флаги и дескрипторы свойств","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md","`Object.getOwnPropertyDescriptor`, `Object.defineProperty` и значения флагов по умолчанию.",{"title":1929,"url":1930,"note":2545},"настройка свойства через дескриптор.",{"title":2547,"url":2548,"note":2549},"MDN: Object.getOwnPropertyDescriptor","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fgetownpropertydescriptor\u002Findex.md","получение дескриптора собственного свойства.",{"title":2551,"url":1930,"note":2552},"MDN: Object.defineProperty examples","ограничения и ошибки при применении дескрипторов.","# Q3. Что такое дескриптор свойства?\n\n## Базовый вопрос\n\nЧто такое дескриптор свойства?\n\n## Хороший ответ\n\nДескриптор свойства - это объектное описание внутреннего устройства свойства. Для свойства данных дескриптор может содержать `value`, `writable`, `enumerable` и `configurable`. Для свойства-аксессора вместо `value` и `writable` используются `get` и `set`.\n\nЕсли мы создаем свойство обычным присваиванием или в литерале объекта, для свойства данных обычно получаются флаги:\n\n- `writable: true`;\n- `enumerable: true`;\n- `configurable: true`.\n\nЕсли мы создаем новое свойство через `Object.defineProperty` и не указываем флаги явно, неуказанные флаги получают значения по умолчанию. Для `writable`, `enumerable` и `configurable` это `false`.\n\nПоэтому эти два способа не равны по смыслу. Запись `obj.x = 1` создает обычное изменяемое и перечислимое свойство. А `Object.defineProperty(obj, 'x', { value: 1 })` создаст свойство, которое нельзя перезаписать обычным присваиванием, нельзя увидеть в `Object.keys` и нельзя удалить или перенастроить.\n\nВажно: `Object.defineProperty` может не только создать свойство, но и изменить дескриптор уже существующего свойства, если это разрешено текущими флагами.\n\nХороший кандидат должен уметь объяснить не только что такое дескриптор, но и почему забытый флаг в `defineProperty` меняет поведение свойства.\n\n## Уточняющие вопросы\n\n### 1. Что вернет `Object.getOwnPropertyDescriptor`?\n\nОжидаем: кандидат говорит, что метод вернет объект-дескриптор собственного свойства. Это не само значение свойства, а описание того, как это свойство устроено.\n\nЕсли это свойство данных, в дескрипторе будут `value`, `writable`, `enumerable` и `configurable`. Если это свойство-аксессор, в дескрипторе будут `get`, `set`, `enumerable` и `configurable`.\n\nЕсли такого собственного свойства на объекте нет, метод вернет `undefined`. Важно, что `Object.getOwnPropertyDescriptor` смотрит именно собственные свойства объекта и не ищет свойство по цепочке прототипов.\n\n### 2. Есть `const obj = {}`. Почему после `Object.defineProperty(obj, 'x', { value: 1 })` и `obj.x = 2` значение `obj.x` остается `1`, `Object.keys(obj)` не содержит `x`, а `delete obj.x` не удаляет свойство?\n\nОжидаем: кандидат объясняет, что через `Object.defineProperty` мы создали новое собственное свойство данных и явно описали только `value`. Неуказанные флаги нового свойства получают значения по умолчанию: `writable: false`, `enumerable: false`, `configurable: false`.\n\nИз-за `writable: false` свойство нельзя изменить обычным присваиванием. В строгом режиме такая запись выбросит ошибку. Из-за `enumerable: false` свойство не будет видно через `Object.keys` и не попадет в `for..in`. Из-за `configurable: false` его нельзя удалить или свободно перенастроить.\n\nХороший ответ добавляет сравнение с обычным присваиванием: если бы мы создали новое свойство через `obj.x = 1`, оно получило бы более привычные флаги `writable: true`, `enumerable: true`, `configurable: true`.\n\nВажно: эта ловушка касается создания нового свойства через неполный дескриптор. Если свойство уже существует, `defineProperty` меняет только переданные части дескриптора, насколько это разрешено текущими флагами, а пропущенные поля не нужно объяснять как автоматический сброс в `false`.\n\n### 3. Когда стоит использовать `defineProperty`, а не обычное присваивание?\n\nОжидаем: кандидат говорит, что обычное присваивание нужно для простого случая: мы хотим положить значение в свойство и получить обычное свойство данных. Если свойства еще не было, `obj.x = 1` создаст собственное свойство с привычными флагами: его можно менять, перечислять и конфигурировать.\n\n`Object.defineProperty` стоит использовать тогда, когда нам важно не только значение, но и поведение свойства. Например, мы хотим создать или изменить свойство так, чтобы оно не попадало в перечисление, не перезаписывалось обычным присваиванием, не удалялось или не перенастраивалось. То есть мы явно управляем `writable`, `enumerable` и `configurable`.\n\nЕще один важный случай - accessor property. Через `defineProperty` можно описать свойство через `get` и `set`, чтобы внешне оно выглядело как обычное свойство, но при чтении или записи запускалась функция. При этом кандидат должен помнить, что свойство не может одновременно быть свойством данных и аксессором: в одном дескрипторе нельзя смешивать `value` или `writable` с `get` или `set`.\n\nХороший практический ответ: `defineProperty` выбираем для точной настройки контракта свойства, а обычное присваивание - когда нужен простой и читаемый способ записать значение без специальных ограничений.\n\n## Референсы\n\n- [Learn JS: Флаги и дескрипторы свойств](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md) - `Object.getOwnPropertyDescriptor`, `Object.defineProperty` и значения флагов по умолчанию.\n- [MDN: Object.defineProperty](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fdefineproperty\u002Findex.md) - настройка свойства через дескриптор.\n- [MDN: Object.getOwnPropertyDescriptor](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fgetownpropertydescriptor\u002Findex.md) - получение дескриптора собственного свойства.\n- [MDN: Object.defineProperty examples](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fdefineproperty\u002Findex.md) - ограничения и ошибки при применении дескрипторов.",{"slug":2555,"title":2556,"baseQuestion":2556,"goodAnswer":2557,"followUps":2558,"references":2568,"programSlug":50,"lessonSlug":50,"order":36,"status":13,"rawBody":2573},"recursion-q3-chem-rekursiya-otlichaetsya-ot-cikla","Чем рекурсия отличается от цикла?","Сначала можно сказать так: цикл повторяет один и тот же блок кода в одном текущем месте выполнения, а рекурсия повторяет действие через новые вызовы функции.\n\nВ цикле мы обычно явно храним состояние в переменных: счетчик, индекс, аккумулятор. В рекурсии состояние часто передается через параметры функции или хранится в результате каждого вызова. Поэтому рекурсивное решение может выглядеть ближе к описанию задачи: \"глубина дерева это один плюс максимальная глубина поддеревьев\".\n\nНо рекурсия не бесплатна. Каждый вызов занимает место в стеке. Обычный цикл в JavaScript чаще безопаснее для очень длинных линейных последовательностей, потому что он не создает новую цепочку вызовов.\n\nХороший ответ не должен говорить, что рекурсия всегда лучше или всегда хуже. Выбор зависит от формы задачи: для вложенных деревьев рекурсия часто читается проще, для большого массива без вложенности цикл часто практичнее.",[2559,2562,2565],{"question":2560,"expected":2561},"Почему для большого плоского массива часто выбирают цикл?","кандидат объясняет, что цикл не углубляет стек вызовов на каждый элемент и обычно предсказуемее для длинных последовательностей.",{"question":2563,"expected":2564},"Почему дерево удобно описывать рекурсивно?","кандидат говорит, что каждый узел дерева содержит меньшие деревья или потомков, поэтому одна и та же функция может применяться к текущему узлу и его дочерним частям.",{"question":2566,"expected":2567},"Можно ли любую рекурсию заменить циклом?","кандидат говорит, что обычно можно, если явно хранить состояние, которое раньше лежало в стеке вызовов. Но такой код может стать длиннее и менее наглядным.",[2569,2571],{"title":1954,"url":1955,"note":2570},"рекурсия как решение через меньшие подзадачи.",{"title":2284,"url":2285,"note":2572},"сравнение рекурсии, хвостовых вызовов и разворачивания в цикл.","# Q3. Чем рекурсия отличается от цикла?\n\n## Базовый вопрос\n\nЧем рекурсия отличается от цикла?\n\n## Хороший ответ\n\nСначала можно сказать так: цикл повторяет один и тот же блок кода в одном текущем месте выполнения, а рекурсия повторяет действие через новые вызовы функции.\n\nВ цикле мы обычно явно храним состояние в переменных: счетчик, индекс, аккумулятор. В рекурсии состояние часто передается через параметры функции или хранится в результате каждого вызова. Поэтому рекурсивное решение может выглядеть ближе к описанию задачи: \"глубина дерева это один плюс максимальная глубина поддеревьев\".\n\nНо рекурсия не бесплатна. Каждый вызов занимает место в стеке. Обычный цикл в JavaScript чаще безопаснее для очень длинных линейных последовательностей, потому что он не создает новую цепочку вызовов.\n\nХороший ответ не должен говорить, что рекурсия всегда лучше или всегда хуже. Выбор зависит от формы задачи: для вложенных деревьев рекурсия часто читается проще, для большого массива без вложенности цикл часто практичнее.\n\n## Уточняющие вопросы\n\n### 1. Почему для большого плоского массива часто выбирают цикл?\n\nОжидаем: кандидат объясняет, что цикл не углубляет стек вызовов на каждый элемент и обычно предсказуемее для длинных последовательностей.\n\n### 2. Почему дерево удобно описывать рекурсивно?\n\nОжидаем: кандидат говорит, что каждый узел дерева содержит меньшие деревья или потомков, поэтому одна и та же функция может применяться к текущему узлу и его дочерним частям.\n\n### 3. Можно ли любую рекурсию заменить циклом?\n\nОжидаем: кандидат говорит, что обычно можно, если явно хранить состояние, которое раньше лежало в стеке вызовов. Но такой код может стать длиннее и менее наглядным.\n\n## Референсы\n\n- [MDN: Recursion](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md) - рекурсия как решение через меньшие подзадачи.\n- [Вы не знаете JS: ES6 и дальше — глава 7 Meta Programming](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fes6%20%26%20beyond\u002Fch7.md) - сравнение рекурсии, хвостовых вызовов и разворачивания в цикл.",{"slug":2575,"title":2576,"baseQuestion":2577,"goodAnswer":2578,"followUps":2579,"references":2589,"programSlug":41,"lessonSlug":41,"order":36,"status":13,"rawBody":2598},"rendering-dom-events-forms-q3-chto-takoe-repaint","Что такое repaint?","Что такое repaint в браузере?","Repaint - это повторное рисование внешнего вида элемента или части страницы. Простыми словами: размеры и позиции уже понятны, но браузеру нужно обновить пиксели, потому что изменилось то, как элемент выглядит.\n\nНапример, repaint может понадобиться после изменения цвета текста, фона, тени, изображения или другого визуального свойства. Если геометрия не изменилась, layout может не понадобиться. Но paint все равно не бесплатный: браузеру нужно нарисовать обновленную область.\n\nВажно не говорить, что repaint всегда перерисовывает всю страницу. Браузеры стараются обновлять только нужные области, но большая область, сложные тени, фильтры или много одновременно изменяемых элементов могут сделать paint заметным.\n\nХороший ответ: layout считает место, repaint обновляет внешний вид. Если мы поменяли только цвет, обычно нужен repaint. Если мы поменяли размер, сначала может понадобиться layout, а потом уже paint.",[2580,2583,2586],{"question":2581,"expected":2582},"Чем изменение `background-color` отличается от изменения `width`?","кандидат говорит, что цвет фона меняет внешний вид, но обычно не меняет размеры и положение. `width` меняет геометрию, поэтому может потребовать layout.",{"question":2584,"expected":2585},"Почему repaint тоже может тормозить, если layout не было?","кандидат объясняет, что браузеру все равно нужно обновить пиксели. Если область большая или эффект сложный, эта работа может занять заметное время.",{"question":2587,"expected":2588},"Почему для анимаций часто выбирают `opacity` или `transform`?","кандидат говорит, что эти свойства обычно не требуют пересчета layout. Браузер часто может обработать такие изменения дешевле, особенно если не нужно заново раскладывать соседние элементы.",[2590,2592,2594],{"title":1979,"url":1980,"note":2591},"paint как часть пути рендеринга.",{"title":2307,"url":2308,"note":2593},"связь CSS-свойств с reflow и repaint.",{"title":2595,"url":2596,"note":2597},"MDN: CSS and JavaScript animation performance","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fperformance\u002Fguides\u002Fcss_javascript_animation_performance\u002Findex.md","анимации и выбор свойств для обновления кадров.","# Q3. Что такое repaint?\n\n## Базовый вопрос\n\nЧто такое repaint в браузере?\n\n## Хороший ответ\n\nRepaint - это повторное рисование внешнего вида элемента или части страницы. Простыми словами: размеры и позиции уже понятны, но браузеру нужно обновить пиксели, потому что изменилось то, как элемент выглядит.\n\nНапример, repaint может понадобиться после изменения цвета текста, фона, тени, изображения или другого визуального свойства. Если геометрия не изменилась, layout может не понадобиться. Но paint все равно не бесплатный: браузеру нужно нарисовать обновленную область.\n\nВажно не говорить, что repaint всегда перерисовывает всю страницу. Браузеры стараются обновлять только нужные области, но большая область, сложные тени, фильтры или много одновременно изменяемых элементов могут сделать paint заметным.\n\nХороший ответ: layout считает место, repaint обновляет внешний вид. Если мы поменяли только цвет, обычно нужен repaint. Если мы поменяли размер, сначала может понадобиться layout, а потом уже paint.\n\n## Уточняющие вопросы\n\n### 1. Чем изменение `background-color` отличается от изменения `width`?\n\nОжидаем: кандидат говорит, что цвет фона меняет внешний вид, но обычно не меняет размеры и положение. `width` меняет геометрию, поэтому может потребовать layout.\n\n### 2. Почему repaint тоже может тормозить, если layout не было?\n\nОжидаем: кандидат объясняет, что браузеру все равно нужно обновить пиксели. Если область большая или эффект сложный, эта работа может занять заметное время.\n\n### 3. Почему для анимаций часто выбирают `opacity` или `transform`?\n\nОжидаем: кандидат говорит, что эти свойства обычно не требуют пересчета layout. Браузер часто может обработать такие изменения дешевле, особенно если не нужно заново раскладывать соседние элементы.\n\n## Референсы\n\n- [MDN: Critical rendering path](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fperformance\u002Fguides\u002Fcritical_rendering_path\u002Findex.md) - paint как часть пути рендеринга.\n- [MDN: CSS performance optimization](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Flearn_web_development\u002Fextensions\u002Fperformance\u002Fcss\u002Findex.md) - связь CSS-свойств с reflow и repaint.\n- [MDN: CSS and JavaScript animation performance](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fperformance\u002Fguides\u002Fcss_javascript_animation_performance\u002Findex.md) - анимации и выбор свойств для обновления кадров.",{"slug":2600,"title":2601,"baseQuestion":2602,"goodAnswer":2603,"followUps":2604,"references":2614,"programSlug":19,"lessonSlug":19,"order":36,"status":13,"rawBody":2625},"scope-closures-deep-dive-q3-kak-eval-i-with-menyayut-poisk-imen","Как eval и with меняют поиск имен?","Как `eval` и `with` влияют на поиск имен в JavaScript?","`eval` и `with` считаются механизмами, которые мешают нормальной лексической области видимости. Обычно JavaScript может понять структуру областей по тексту программы. С `eval` и `with` часть этой картины может измениться во время выполнения.\n\nПрямой `eval` в sloppy mode может выполнить строку так, будто этот код написан прямо в текущем месте. Если строка содержит `var`, она может добавить локальную привязку в текущую функцию и затенить внешнее имя. В strict mode объявления внутри `eval` не выходят в окружающую область.\n\n`with` берет объект и временно рассматривает его свойства как имена в отдельной области. Если внутри `with` мы присваиваем в имя, которое есть как свойство объекта, меняется свойство. Если такого свойства нет, поиск идет дальше по обычным правилам. В sloppy mode неразрешенное присваивание может создать неявную глобальную переменную.\n\nОба механизма считаются плохой практикой: они ухудшают читаемость, мешают оптимизациям и создают неожиданные связи. `with` запрещен в strict mode.",[2605,2608,2611],{"question":2606,"expected":2607},"Почему после прямого `eval` с объявлением `var b` функция может начать читать локальную `b`, а не внешнюю?","кандидат объясняет, что прямой `eval` в sloppy mode выполняет строку в текущей области. Объявление `var b` добавляет привязку в область функции, и ближайшее имя `b` начинает находиться там.",{"question":2609,"expected":2610},"У объекта есть свойство `a`. Почему внутри `with (x)` присваивание в `a` меняет `x.a`?","кандидат говорит, что `with` помещает объект в цепочку поиска имен как временную область. Если свойство с таким именем есть, присваивание попадает в это свойство.",{"question":2612,"expected":2613},"У объекта нет свойства `a`. Почему после присваивания в `a` внутри `with (x)` значение `x.a` остается `undefined`, а глобальная `a` появляется?","кандидат объясняет, что `with` не создает отсутствующее свойство при обычном поиске имени. Поиск идет дальше, имя не находится, и в sloppy mode неразрешенный LHS поиск создает неявную глобальную переменную.",[2615,2617,2621],{"title":1877,"url":1878,"note":2616},"разделы про `eval`, `with` и влияние на оптимизации.",{"title":2618,"url":2619,"note":2620},"MDN: eval","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Feval\u002Findex.md","поведение `eval` и ограничения.",{"title":2622,"url":2623,"note":2624},"MDN: with","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fstatements\u002Fwith\u002Findex.md","объект как временная область и запрет в strict mode.","# Q3. Как eval и with меняют поиск имен?\n\n## Базовый вопрос\n\nКак `eval` и `with` влияют на поиск имен в JavaScript?\n\n## Хороший ответ\n\n`eval` и `with` считаются механизмами, которые мешают нормальной лексической области видимости. Обычно JavaScript может понять структуру областей по тексту программы. С `eval` и `with` часть этой картины может измениться во время выполнения.\n\nПрямой `eval` в sloppy mode может выполнить строку так, будто этот код написан прямо в текущем месте. Если строка содержит `var`, она может добавить локальную привязку в текущую функцию и затенить внешнее имя. В strict mode объявления внутри `eval` не выходят в окружающую область.\n\n`with` берет объект и временно рассматривает его свойства как имена в отдельной области. Если внутри `with` мы присваиваем в имя, которое есть как свойство объекта, меняется свойство. Если такого свойства нет, поиск идет дальше по обычным правилам. В sloppy mode неразрешенное присваивание может создать неявную глобальную переменную.\n\nОба механизма считаются плохой практикой: они ухудшают читаемость, мешают оптимизациям и создают неожиданные связи. `with` запрещен в strict mode.\n\n## Уточняющие вопросы\n\n### 1. Почему после прямого `eval` с объявлением `var b` функция может начать читать локальную `b`, а не внешнюю?\n\nОжидаем: кандидат объясняет, что прямой `eval` в sloppy mode выполняет строку в текущей области. Объявление `var b` добавляет привязку в область функции, и ближайшее имя `b` начинает находиться там.\n\n### 2. У объекта есть свойство `a`. Почему внутри `with (x)` присваивание в `a` меняет `x.a`?\n\nОжидаем: кандидат говорит, что `with` помещает объект в цепочку поиска имен как временную область. Если свойство с таким именем есть, присваивание попадает в это свойство.\n\n### 3. У объекта нет свойства `a`. Почему после присваивания в `a` внутри `with (x)` значение `x.a` остается `undefined`, а глобальная `a` появляется?\n\nОжидаем: кандидат объясняет, что `with` не создает отсутствующее свойство при обычном поиске имени. Поиск идет дальше, имя не находится, и в sloppy mode неразрешенный LHS поиск создает неявную глобальную переменную.\n\n## Референсы\n\n- [YDKJS: Глава 2. Лексическая область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch2.md) - разделы про `eval`, `with` и влияние на оптимизации.\n- [MDN: eval](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Feval\u002Findex.md) - поведение `eval` и ограничения.\n- [MDN: with](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fstatements\u002Fwith\u002Findex.md) - объект как временная область и запрет в strict mode.",{"slug":2627,"title":2498,"baseQuestion":2499,"goodAnswer":2500,"followUps":2628,"references":2632,"programSlug":20,"lessonSlug":20,"order":36,"status":13,"rawBody":2524},"scope-hoisting-closures-this-q3-closure",[2629,2630,2631],{"question":2503,"expected":2504},{"question":2506,"expected":2507},{"question":2509,"expected":2510},[2633,2634,2635,2636],{"title":1861,"url":1862,"note":2513},{"title":2515,"url":2516,"note":2517},{"title":2519,"url":2520,"note":2521},{"title":1885,"url":1886,"note":2523},{"slug":2638,"title":2639,"baseQuestion":2639,"goodAnswer":2640,"followUps":2641,"references":2651,"programSlug":21,"lessonSlug":21,"order":36,"status":13,"rawBody":2666},"types-coercion-symbol-json-q3-kak-rabotaet-privedenie-k-boolean","Как работает приведение к boolean?","Логическое приведение отвечает на вопрос: как значение ведет себя в boolean-контексте, например внутри `if`, `!value`, `Boolean(value)` или логических операторов.\n\nВ JavaScript проще запомнить короткий список falsy значений. В текущем языке к ним относятся:\n\n- `undefined`;\n- `null`;\n- `false`;\n- `+0` и `-0`;\n- `NaN`;\n- `0n`;\n- пустая строка `\"\"`.\n\nВсе остальные обычные значения являются truthy. Непустая строка truthy, даже если внутри написано `\"0\"`. Пустой массив truthy, потому что массив - это объект. Пустой объект truthy. Функция truthy. Объектная оболочка `new Boolean(false)` тоже truthy, потому что само значение является объектом.\n\nГлавная ловушка урока: логическое приведение объекта не заглядывает внутрь объекта и не вызывает `valueOf`, `toString` или `Symbol.toPrimitive`. Поэтому объект-оболочка с `false` внутри остается truthy, пока мы явно не достали примитив через `valueOf()`.\n\nНа собеседовании хорошо рассуждать от falsy-списка. Если значения нет в этом коротком списке, значит оно truthy. Не нужно придумывать правило вроде \"пустые контейнеры ложные\": в JavaScript пустой массив и пустой объект истинны.",[2642,2645,2648],{"question":2643,"expected":2644},"Почему `Boolean('0')` дает `true`, а `Boolean(0)` дает `false`?","кандидат говорит, что число `0` находится в falsy-списке, а строка `\"0\"` не пустая. Для строк важна не похожесть содержимого на число, а пустая строка это или нет.\n\nХороший ответ может добавить, что строка из пробелов тоже truthy, потому что она не пустая.",{"question":2646,"expected":2647},"Почему пустой массив и пустой объект являются truthy?","кандидат объясняет, что массив и объект - это объектные значения. Обычные объекты не входят в falsy-список, даже если внутри нет элементов или свойств.\n\nСлабый ответ: \"массив пустой, значит false\". Хороший ответ проверяет именно правило языка, а не интуицию из других языков.",{"question":2649,"expected":2650},"Вызывает ли `Boolean(obj)` методы `valueOf` или `toString` у объекта?","кандидат говорит, что нет. Логическое приведение обычного объекта сразу дает `true` и не пытается приводить объект к примитиву.\n\nЭто важно для понимания `new Boolean(false)`: внутри оболочки лежит `false`, но сама оболочка является объектом и поэтому truthy.",[2652,2656,2658,2662],{"title":2653,"url":2654,"note":2655},"Learn JS: Преобразование типов","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F07-type-conversions\u002Farticle.md","логическое преобразование, falsy\u002Ftruthy и примеры со строкой `\"0\"`.",{"title":2370,"url":2371,"note":2657},"почему `new Boolean(false)` является объектом и ведет себя как truthy.",{"title":2659,"url":2660,"note":2661},"YDKJS: Типы и грамматика, глава 4","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md","falsy-список, truthy-значения и ловушки объектных оболочек.",{"title":2663,"url":2664,"note":2665},"MDN: Boolean","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fboolean\u002Findex.md","логическое приведение и truthy\u002Ffalsy значения.","# Q3. Как работает приведение к boolean?\n\n## Базовый вопрос\n\nКак работает приведение к boolean?\n\n## Хороший ответ\n\nЛогическое приведение отвечает на вопрос: как значение ведет себя в boolean-контексте, например внутри `if`, `!value`, `Boolean(value)` или логических операторов.\n\nВ JavaScript проще запомнить короткий список falsy значений. В текущем языке к ним относятся:\n\n- `undefined`;\n- `null`;\n- `false`;\n- `+0` и `-0`;\n- `NaN`;\n- `0n`;\n- пустая строка `\"\"`.\n\nВсе остальные обычные значения являются truthy. Непустая строка truthy, даже если внутри написано `\"0\"`. Пустой массив truthy, потому что массив - это объект. Пустой объект truthy. Функция truthy. Объектная оболочка `new Boolean(false)` тоже truthy, потому что само значение является объектом.\n\nГлавная ловушка урока: логическое приведение объекта не заглядывает внутрь объекта и не вызывает `valueOf`, `toString` или `Symbol.toPrimitive`. Поэтому объект-оболочка с `false` внутри остается truthy, пока мы явно не достали примитив через `valueOf()`.\n\nНа собеседовании хорошо рассуждать от falsy-списка. Если значения нет в этом коротком списке, значит оно truthy. Не нужно придумывать правило вроде \"пустые контейнеры ложные\": в JavaScript пустой массив и пустой объект истинны.\n\n## Уточняющие вопросы\n\n### 1. Почему `Boolean('0')` дает `true`, а `Boolean(0)` дает `false`?\n\nОжидаем: кандидат говорит, что число `0` находится в falsy-списке, а строка `\"0\"` не пустая. Для строк важна не похожесть содержимого на число, а пустая строка это или нет.\n\nХороший ответ может добавить, что строка из пробелов тоже truthy, потому что она не пустая.\n\n### 2. Почему пустой массив и пустой объект являются truthy?\n\nОжидаем: кандидат объясняет, что массив и объект - это объектные значения. Обычные объекты не входят в falsy-список, даже если внутри нет элементов или свойств.\n\nСлабый ответ: \"массив пустой, значит false\". Хороший ответ проверяет именно правило языка, а не интуицию из других языков.\n\n### 3. Вызывает ли `Boolean(obj)` методы `valueOf` или `toString` у объекта?\n\nОжидаем: кандидат говорит, что нет. Логическое приведение обычного объекта сразу дает `true` и не пытается приводить объект к примитиву.\n\nЭто важно для понимания `new Boolean(false)`: внутри оболочки лежит `false`, но сама оболочка является объектом и поэтому truthy.\n\n## Референсы\n\n- [Learn JS: Преобразование типов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F07-type-conversions\u002Farticle.md) - логическое преобразование, falsy\u002Ftruthy и примеры со строкой `\"0\"`.\n- [Learn JS: Методы примитивов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F01-primitives-methods\u002Farticle.md) - почему `new Boolean(false)` является объектом и ведет себя как truthy.\n- [YDKJS: Типы и грамматика, глава 4](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md) - falsy-список, truthy-значения и ловушки объектных оболочек.\n- [MDN: Boolean](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fboolean\u002Findex.md) - логическое приведение и truthy\u002Ffalsy значения.",{"slug":2668,"title":2669,"baseQuestion":2670,"goodAnswer":2671,"followUps":2672,"references":2682,"programSlug":40,"lessonSlug":40,"order":46,"status":13,"rawBody":2689},"browser-network-q4-chto-takoe-cors","Что такое CORS?","Что такое CORS и зачем он нужен браузеру?","Простыми словами: CORS это механизм, который решает, может ли страница с одного origin читать ответ от другого origin. Сервер может быть доступен в интернете, но браузер не обязан отдавать его ответ JavaScript-коду чужой страницы.\n\nВажно сказать именно про браузерное ограничение. Сервер может получить запрос и даже вернуть ответ, но браузер может не дать JavaScript прочитать этот ответ, если сервер не отправил подходящие CORS-заголовки.\n\nДля простых cross-origin запросов браузер проверяет ответные заголовки вроде `Access-Control-Allow-Origin`. Для более чувствительных запросов браузер сначала отправляет preflight `OPTIONS`, где спрашивает сервер, разрешены ли method, headers и origin будущего запроса.\n\nХороший ответ должен отдельно проговорить: CORS не защищает сервер от всех чужих запросов. Он защищает пользователя и страницу в браузере от чтения ответа там, где сервер явно не разрешил такой доступ.",[2673,2676,2679],{"question":2674,"expected":2675},"Почему запрос мог быть виден на сервере, но в JavaScript мы получили CORS-ошибку?","кандидат говорит, что CORS проверяет доступ JavaScript к ответу. Сам HTTP-запрос мог дойти до сервера, но браузер заблокировал чтение ответа.",{"question":2677,"expected":2678},"Что такое origin простыми словами?","кандидат объясняет связку scheme, host и port. Разница хотя бы в одной части означает другой origin.",{"question":2680,"expected":2681},"Почему добавление своего заголовка может вызвать preflight?","кандидат говорит, что браузер считает такой cross-origin запрос не простым и сначала проверяет разрешение сервера через `OPTIONS`.",[2683,2685],{"title":2099,"url":2100,"note":2684},"модель CORS и preflight.",{"title":2686,"url":2687,"note":2688},"MDN: CORS errors","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Fguides\u002Fcors\u002Ferrors\u002Findex.md","типичные сообщения об ошибках CORS.","# Q4. Что такое CORS?\n\n## Базовый вопрос\n\nЧто такое CORS и зачем он нужен браузеру?\n\n## Хороший ответ\n\nПростыми словами: CORS это механизм, который решает, может ли страница с одного origin читать ответ от другого origin. Сервер может быть доступен в интернете, но браузер не обязан отдавать его ответ JavaScript-коду чужой страницы.\n\nВажно сказать именно про браузерное ограничение. Сервер может получить запрос и даже вернуть ответ, но браузер может не дать JavaScript прочитать этот ответ, если сервер не отправил подходящие CORS-заголовки.\n\nДля простых cross-origin запросов браузер проверяет ответные заголовки вроде `Access-Control-Allow-Origin`. Для более чувствительных запросов браузер сначала отправляет preflight `OPTIONS`, где спрашивает сервер, разрешены ли method, headers и origin будущего запроса.\n\nХороший ответ должен отдельно проговорить: CORS не защищает сервер от всех чужих запросов. Он защищает пользователя и страницу в браузере от чтения ответа там, где сервер явно не разрешил такой доступ.\n\n## Уточняющие вопросы\n\n### 1. Почему запрос мог быть виден на сервере, но в JavaScript мы получили CORS-ошибку?\n\nОжидаем: кандидат говорит, что CORS проверяет доступ JavaScript к ответу. Сам HTTP-запрос мог дойти до сервера, но браузер заблокировал чтение ответа.\n\n### 2. Что такое origin простыми словами?\n\nОжидаем: кандидат объясняет связку scheme, host и port. Разница хотя бы в одной части означает другой origin.\n\n### 3. Почему добавление своего заголовка может вызвать preflight?\n\nОжидаем: кандидат говорит, что браузер считает такой cross-origin запрос не простым и сначала проверяет разрешение сервера через `OPTIONS`.\n\n## Референсы\n\n- [MDN: CORS](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Fguides\u002Fcors\u002Findex.md) - модель CORS и preflight.\n- [MDN: CORS errors](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Fguides\u002Fcors\u002Ferrors\u002Findex.md) - типичные сообщения об ошибках CORS.",{"slug":2691,"title":2692,"baseQuestion":2693,"goodAnswer":2694,"followUps":2695,"references":2705,"programSlug":17,"lessonSlug":17,"order":46,"status":13,"rawBody":2720},"collections-iteration-arrays-q4-zachem-nuzhny-weak-kollekcii","Зачем нужны weak-коллекции?","Зачем в JavaScript нужны weak-коллекции?","`WeakMap` и `WeakSet` нужны, когда мы хотим связать данные с объектом, но не хотим, чтобы сама коллекция удерживала этот объект в памяти.\n\nВ обычном `Map` объект-ключ остается достижимым, пока он лежит в `Map`. Значит, если забыть удалить запись, можно удерживать ненужные объекты. В `WeakMap` ключи удерживаются слабо: если объект больше нигде не достижим, запись может исчезнуть вместе с ним. В `WeakSet` слабо удерживаются сами значения, и они тоже должны быть объектами.\n\nИз-за этого у weak-коллекций нет `size`, обхода, `keys`, `values`, `entries`. Момент сборки мусора не должен быть наблюдаемым из кода, поэтому язык не дает способ спросить \"сколько там сейчас элементов\".\n\nТипичные сценарии: дополнительная информация для DOM-узлов или объектов из чужого кода, кеш по объектам, приватные данные, отметка \"этот объект уже обработан\". Для обычной перечисляемой коллекции weak-структуры не подходят.",[2696,2699,2702],{"question":2697,"expected":2698},"Почему `weakMap.set('x', 1)` бросает ошибку?","кандидат говорит, что ключи `WeakMap` должны быть объектами. Примитивы не могут быть слабо удерживаемыми ключами.",{"question":2700,"expected":2701},"Почему у `WeakMap` нет `size` и обхода по ключам?","кандидат объясняет, что сборка мусора не имеет точного наблюдаемого момента. Если бы можно было увидеть размер или список ключей, код начал бы наблюдать работу GC.",{"question":2703,"expected":2704},"Когда обычный `Map` лучше, чем `WeakMap`?","кандидат говорит, что `Map` нужен, если коллекцию надо обходить, считать размер, хранить примитивные ключи или явно управлять жизненным циклом записей.",[2706,2710,2714,2718],{"title":2707,"url":2708,"note":2709},"ru.javascript.info: WeakMap и WeakSet","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F08-weakmap-weakset\u002Farticle.md","учебное объяснение weak-коллекций и связи со сборкой мусора.",{"title":2711,"url":2712,"note":2713},"MDN: WeakMap","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fweakmap\u002Findex.md","справочник по `WeakMap`.",{"title":2715,"url":2716,"note":2717},"MDN: WeakSet","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fweakset\u002Findex.md","справочник по `WeakSet`.",{"title":1782,"url":1783,"note":2719},"дополнительные объяснения про `WeakMap` и `WeakSet`.","# Q4. Зачем нужны weak-коллекции?\n\n## Базовый вопрос\n\nЗачем в JavaScript нужны weak-коллекции?\n\n## Хороший ответ\n\n`WeakMap` и `WeakSet` нужны, когда мы хотим связать данные с объектом, но не хотим, чтобы сама коллекция удерживала этот объект в памяти.\n\nВ обычном `Map` объект-ключ остается достижимым, пока он лежит в `Map`. Значит, если забыть удалить запись, можно удерживать ненужные объекты. В `WeakMap` ключи удерживаются слабо: если объект больше нигде не достижим, запись может исчезнуть вместе с ним. В `WeakSet` слабо удерживаются сами значения, и они тоже должны быть объектами.\n\nИз-за этого у weak-коллекций нет `size`, обхода, `keys`, `values`, `entries`. Момент сборки мусора не должен быть наблюдаемым из кода, поэтому язык не дает способ спросить \"сколько там сейчас элементов\".\n\nТипичные сценарии: дополнительная информация для DOM-узлов или объектов из чужого кода, кеш по объектам, приватные данные, отметка \"этот объект уже обработан\". Для обычной перечисляемой коллекции weak-структуры не подходят.\n\n## Уточняющие вопросы\n\n### 1. Почему `weakMap.set('x', 1)` бросает ошибку?\n\nОжидаем: кандидат говорит, что ключи `WeakMap` должны быть объектами. Примитивы не могут быть слабо удерживаемыми ключами.\n\n### 2. Почему у `WeakMap` нет `size` и обхода по ключам?\n\nОжидаем: кандидат объясняет, что сборка мусора не имеет точного наблюдаемого момента. Если бы можно было увидеть размер или список ключей, код начал бы наблюдать работу GC.\n\n### 3. Когда обычный `Map` лучше, чем `WeakMap`?\n\nОжидаем: кандидат говорит, что `Map` нужен, если коллекцию надо обходить, считать размер, хранить примитивные ключи или явно управлять жизненным циклом записей.\n\n## Референсы\n\n- [ru.javascript.info: WeakMap и WeakSet](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F08-weakmap-weakset\u002Farticle.md) - учебное объяснение weak-коллекций и связи со сборкой мусора.\n- [MDN: WeakMap](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fweakmap\u002Findex.md) - справочник по `WeakMap`.\n- [MDN: WeakSet](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fweakset\u002Findex.md) - справочник по `WeakSet`.\n- [Вы не знаете JS: ES6 и не только — глава 5 Collections](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fes6%20%26%20beyond\u002Fch5.md) - дополнительные объяснения про `WeakMap` и `WeakSet`.",{"slug":2722,"title":2723,"baseQuestion":2723,"goodAnswer":2724,"followUps":2725,"references":2735,"programSlug":30,"lessonSlug":30,"order":46,"status":13,"rawBody":2742},"event-loop-promises-async-await-q4-kak-promise-poluchaet-itogovyy-rezultat","Как Promise получает итоговый результат?","Сначала можно объяснить просто: `Promise` это объект, который представляет результат работы, который может появиться сейчас или позже. Он связывает код, который производит результат, и код, который хочет получить этот результат.\n\nПри создании через `new Promise` мы передаем executor. JavaScript вызывает executor сразу и синхронно, прямо во время выполнения конструктора. В executor попадают две функции, которые предоставляет сам JavaScript: `resolve` для успешного результата и `reject` для ошибки. Мы не создаем эти функции сами, мы только решаем, когда их вызвать.\n\n`resolve(value)` сообщает успешный результат, `reject(reason)` сообщает ошибку. Сначала Promise находится в состоянии `pending`, потом переходит в `fulfilled` или `rejected`.\n\nПромис завершается только один раз. Первый вызов `resolve` или `reject` фиксирует итог, а следующие попытки изменить результат игнорируются. Поэтому у промиса не бывает \"сначала успех, потом ошибка\" как двух равноправных итогов. Итог один: либо успешное значение, либо причина ошибки.\n\nЕсли executor выбросит ошибку до завершения промиса, промис станет rejected. Это похоже на неявный `try\u002Fcatch` вокруг executor: ошибка не вылетает наружу как обычная синхронная ошибка, а превращается в отклоненный Promise. Но если промис уже был завершен через `resolve` или `reject`, более поздняя ошибка в executor уже не изменит его итог.\n\nВозвращаемое значение executor не становится результатом промиса. Поэтому `return 'a'` внутри executor ничего не завершает. Чтобы передать результат, нужен именно `resolve('a')`.\n\nСостояние и результат промиса - внутренние данные. Мы не читаем их через `promise.state` или `promise.result`. Снаружи мы подписываемся на итог через `.then`, `.catch`, `.finally` или используем `await`.\n\nНа собеседовании важно проговорить две вещи: executor запускается синхронно, а обработчики результата через `.then`, `.catch` и `.finally` выполняются позже через очередь микрозадач. Поэтому код внутри executor может выполниться прямо сейчас, но реакция на уже resolved Promise все равно будет асинхронной относительно текущего стека.",[2726,2729,2732],{"question":2727,"expected":2728},"Почему код внутри executor выполняется раньше кода после `new Promise(...)`?","кандидат говорит, что конструктор `Promise` вызывает executor сразу и синхронно при создании промиса. Поэтому `console.log` внутри executor сработает до `console.log`, который стоит после `new Promise(...)` в той же задаче.",{"question":2730,"expected":2731},"Почему после `resolve('a')`, `reject('b')`, `resolve('c')` обработчик успеха получает именно `'a'`?","кандидат объясняет, что первый вызов завершения промиса выигрывает. После первого `resolve` или `reject` промис уже связан со своим итогом, а все следующие попытки изменить результат игнорируются.",{"question":2733,"expected":2734},"Почему `return 'a'` внутри executor не делает промис выполненным со значением `'a'`?","кандидат объясняет, что результат executor игнорируется. `return` внутри executor влияет только на выполнение самой функции executor, но не на состояние промиса. На состояние промиса влияют `resolve`, `reject` или ошибка, выброшенная внутри executor до завершения промиса.",[2736,2738],{"title":2461,"url":2462,"note":2737},"базовая модель executor, состояний Promise, `resolve` и `reject`.",{"title":2739,"url":2740,"note":2741},"MDN: Promise constructor","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fpromise\u002Findex.md","детали конструктора, синхронный запуск executor и игнорирование return.","# Q4. Как Promise получает итоговый результат?\n\n## Базовый вопрос\n\nКак Promise получает итоговый результат?\n\n## Хороший ответ\n\nСначала можно объяснить просто: `Promise` это объект, который представляет результат работы, который может появиться сейчас или позже. Он связывает код, который производит результат, и код, который хочет получить этот результат.\n\nПри создании через `new Promise` мы передаем executor. JavaScript вызывает executor сразу и синхронно, прямо во время выполнения конструктора. В executor попадают две функции, которые предоставляет сам JavaScript: `resolve` для успешного результата и `reject` для ошибки. Мы не создаем эти функции сами, мы только решаем, когда их вызвать.\n\n`resolve(value)` сообщает успешный результат, `reject(reason)` сообщает ошибку. Сначала Promise находится в состоянии `pending`, потом переходит в `fulfilled` или `rejected`.\n\nПромис завершается только один раз. Первый вызов `resolve` или `reject` фиксирует итог, а следующие попытки изменить результат игнорируются. Поэтому у промиса не бывает \"сначала успех, потом ошибка\" как двух равноправных итогов. Итог один: либо успешное значение, либо причина ошибки.\n\nЕсли executor выбросит ошибку до завершения промиса, промис станет rejected. Это похоже на неявный `try\u002Fcatch` вокруг executor: ошибка не вылетает наружу как обычная синхронная ошибка, а превращается в отклоненный Promise. Но если промис уже был завершен через `resolve` или `reject`, более поздняя ошибка в executor уже не изменит его итог.\n\nВозвращаемое значение executor не становится результатом промиса. Поэтому `return 'a'` внутри executor ничего не завершает. Чтобы передать результат, нужен именно `resolve('a')`.\n\nСостояние и результат промиса - внутренние данные. Мы не читаем их через `promise.state` или `promise.result`. Снаружи мы подписываемся на итог через `.then`, `.catch`, `.finally` или используем `await`.\n\nНа собеседовании важно проговорить две вещи: executor запускается синхронно, а обработчики результата через `.then`, `.catch` и `.finally` выполняются позже через очередь микрозадач. Поэтому код внутри executor может выполниться прямо сейчас, но реакция на уже resolved Promise все равно будет асинхронной относительно текущего стека.\n\n## Уточняющие вопросы\n\n### 1. Почему код внутри executor выполняется раньше кода после `new Promise(...)`?\n\nОжидаем: кандидат говорит, что конструктор `Promise` вызывает executor сразу и синхронно при создании промиса. Поэтому `console.log` внутри executor сработает до `console.log`, который стоит после `new Promise(...)` в той же задаче.\n\n### 2. Почему после `resolve('a')`, `reject('b')`, `resolve('c')` обработчик успеха получает именно `'a'`?\n\nОжидаем: кандидат объясняет, что первый вызов завершения промиса выигрывает. После первого `resolve` или `reject` промис уже связан со своим итогом, а все следующие попытки изменить результат игнорируются.\n\n### 3. Почему `return 'a'` внутри executor не делает промис выполненным со значением `'a'`?\n\nОжидаем: кандидат объясняет, что результат executor игнорируется. `return` внутри executor влияет только на выполнение самой функции executor, но не на состояние промиса. На состояние промиса влияют `resolve`, `reject` или ошибка, выброшенная внутри executor до завершения промиса.\n\n## Референсы\n\n- [ru.javascript.info: Промисы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F02-promise-basics\u002Farticle.md) - базовая модель executor, состояний Promise, `resolve` и `reject`.\n- [MDN: Promise constructor](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fpromise\u002Findex.md) - детали конструктора, синхронный запуск executor и игнорирование return.",{"slug":2744,"title":2745,"baseQuestion":2746,"goodAnswer":2747,"followUps":2748,"references":2758,"programSlug":31,"lessonSlug":31,"order":46,"status":13,"rawBody":2774},"event-loop-promises-deep-dive-q4-pochemu-finally-ne-zamenyaet-uspeshnoe-znachenie","Почему finally не заменяет успешное значение?","Есть цепочка:\n\n```js\nPromise.resolve('a')\n  .finally(() => 'b')\n  .then((a) => console.log(a));\n```\n\nПочему `console.log` выведет `'a'`, а не `'b'`?","`finally` нужен для действия, которое мы хотим выполнить после любого исхода: успеха или ошибки. Например, убрать loader, снять блокировку кнопки, закрыть временный ресурс.\n\nВ отличие от `.then` и `.catch`, `finally` обычно не нужен для преобразования значения. Он не получает успешное значение как обычный аргумент и не должен зависеть от того, успешно завершился Promise или отклонился.\n\nЕсли `finally` завершился нормально, прежний результат проходит дальше. Успешное значение остается успешным значением, прежняя ошибка остается ошибкой. Поэтому после `Promise.resolve('a').finally(() => {})` следующий `.then` получит `'a'`, а после `Promise.reject('a').finally(() => {})` следующий `.catch` получит `'a'`.\n\nНо `finally` может заменить исход. Если внутри `finally` мы бросили ошибку или вернули отклоненный Promise, цепочка дальше пойдет с новой ошибкой из `finally`. Это логично: очистка сама сломалась, и теперь именно эта новая ошибка стала актуальным исходом.\n\nЕсли `finally` вернул успешно завершенный Promise или обычное значение, это значение не становится новым результатом цепочки. Оно только может задержать дальнейшее прохождение цепочки до завершения очистки.",[2749,2752,2755],{"question":2750,"expected":2751},"Почему после `.finally(() => 'b')` следующий `.then` не получает `'b'` вместо старого значения?","кандидат объясняет, что `finally` работает как прозрачный завершающий шаг. Мы используем его не для вычисления нового значения, а для действия после завершения цепочки. Поэтому обычный `return 'b'` из callback не становится новым успешным результатом. Старое значение `'a'` проходит дальше в следующий `.then`, как будто `finally` только выполнил побочное действие между шагами. Если `finally` вернет успешно завершенный Promise, цепочка дождется его завершения, но все равно передаст дальше прежнее значение. Заменить результат обычным значением должен `.then`, а не `.finally`.",{"question":2753,"expected":2754},"Почему после `.finally(() => { throw 'b' })` цепочка идет в `.catch` с ошибкой `'b'`?","кандидат говорит, что прозрачность `finally` сохраняется только если сам `finally` завершился нормально. Если внутри callback произошел `throw` или callback вернул отклоненный Promise, это уже новая ошибка в завершающем действии. Promise, который вернул `.finally`, становится rejected с этой новой причиной. Поэтому дальше цепочка не продолжает старый успешный путь, а идет в ближайший `.catch` с `'b'`. Важно, что эта ошибка заменяет прежний исход: даже если до `finally` был успех с `'a'`, сломавшаяся очистка делает итог цепочки ошибочным.",{"question":2756,"expected":2757},"Нам нужно убрать loader и после успеха запроса, и после ошибки. Почему для этого подходит `.finally()`?","кандидат объясняет практический смысл: loader нужно убрать независимо от того, получили мы данные или ошибку. Если писать это отдельно в `.then` и `.catch`, появляется дублирование и легко забыть один из сценариев. `.finally()` явно показывает, что код не обрабатывает результат запроса и не решает, что показать пользователю, а выполняет общее завершающее действие. После этого успех по-прежнему попадет в следующий успешный обработчик, а ошибка по-прежнему попадет в обработчик ошибок, если `finally` сам не упал.",[2759,2762,2766,2770],{"title":2760,"url":2462,"note":2761},"ru.javascript.info: Промисы основы","очистка через `.finally`, пропуск результата и замена исхода ошибкой.",{"title":2763,"url":2764,"note":2765},"ru.javascript.info: Цепочка промисов","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F03-promise-chaining\u002Farticle.md","ожидание Promise, возвращенного из обработчика цепочки.",{"title":2767,"url":2768,"note":2769},"MDN: Promise.prototype.finally","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Ffinally\u002Findex.md","справочник по `finally`.",{"title":2771,"url":2772,"note":2773},"ECMA-262: Promise.prototype.finally","https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-promise.prototype.finally","формальная механика возврата результата из `finally`.","# Q4. Почему finally не заменяет успешное значение?\n\n## Базовый вопрос\n\nЕсть цепочка:\n\n```js\nPromise.resolve('a')\n  .finally(() => 'b')\n  .then((a) => console.log(a));\n```\n\nПочему `console.log` выведет `'a'`, а не `'b'`?\n\n## Хороший ответ\n\n`finally` нужен для действия, которое мы хотим выполнить после любого исхода: успеха или ошибки. Например, убрать loader, снять блокировку кнопки, закрыть временный ресурс.\n\nВ отличие от `.then` и `.catch`, `finally` обычно не нужен для преобразования значения. Он не получает успешное значение как обычный аргумент и не должен зависеть от того, успешно завершился Promise или отклонился.\n\nЕсли `finally` завершился нормально, прежний результат проходит дальше. Успешное значение остается успешным значением, прежняя ошибка остается ошибкой. Поэтому после `Promise.resolve('a').finally(() => {})` следующий `.then` получит `'a'`, а после `Promise.reject('a').finally(() => {})` следующий `.catch` получит `'a'`.\n\nНо `finally` может заменить исход. Если внутри `finally` мы бросили ошибку или вернули отклоненный Promise, цепочка дальше пойдет с новой ошибкой из `finally`. Это логично: очистка сама сломалась, и теперь именно эта новая ошибка стала актуальным исходом.\n\nЕсли `finally` вернул успешно завершенный Promise или обычное значение, это значение не становится новым результатом цепочки. Оно только может задержать дальнейшее прохождение цепочки до завершения очистки.\n\n## Уточняющие вопросы\n\n### 1. Почему после `.finally(() => 'b')` следующий `.then` не получает `'b'` вместо старого значения?\n\nОжидаем: кандидат объясняет, что `finally` работает как прозрачный завершающий шаг. Мы используем его не для вычисления нового значения, а для действия после завершения цепочки. Поэтому обычный `return 'b'` из callback не становится новым успешным результатом. Старое значение `'a'` проходит дальше в следующий `.then`, как будто `finally` только выполнил побочное действие между шагами. Если `finally` вернет успешно завершенный Promise, цепочка дождется его завершения, но все равно передаст дальше прежнее значение. Заменить результат обычным значением должен `.then`, а не `.finally`.\n\n### 2. Почему после `.finally(() => { throw 'b' })` цепочка идет в `.catch` с ошибкой `'b'`?\n\nОжидаем: кандидат говорит, что прозрачность `finally` сохраняется только если сам `finally` завершился нормально. Если внутри callback произошел `throw` или callback вернул отклоненный Promise, это уже новая ошибка в завершающем действии. Promise, который вернул `.finally`, становится rejected с этой новой причиной. Поэтому дальше цепочка не продолжает старый успешный путь, а идет в ближайший `.catch` с `'b'`. Важно, что эта ошибка заменяет прежний исход: даже если до `finally` был успех с `'a'`, сломавшаяся очистка делает итог цепочки ошибочным.\n\n### 3. Нам нужно убрать loader и после успеха запроса, и после ошибки. Почему для этого подходит `.finally()`?\n\nОжидаем: кандидат объясняет практический смысл: loader нужно убрать независимо от того, получили мы данные или ошибку. Если писать это отдельно в `.then` и `.catch`, появляется дублирование и легко забыть один из сценариев. `.finally()` явно показывает, что код не обрабатывает результат запроса и не решает, что показать пользователю, а выполняет общее завершающее действие. После этого успех по-прежнему попадет в следующий успешный обработчик, а ошибка по-прежнему попадет в обработчик ошибок, если `finally` сам не упал.\n\n## Референсы\n\n- [ru.javascript.info: Промисы основы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F02-promise-basics\u002Farticle.md) - очистка через `.finally`, пропуск результата и замена исхода ошибкой.\n- [ru.javascript.info: Цепочка промисов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F03-promise-chaining\u002Farticle.md) - ожидание Promise, возвращенного из обработчика цепочки.\n- [MDN: Promise.prototype.finally](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Ffinally\u002Findex.md) - справочник по `finally`.\n- [ECMA-262: Promise.prototype.finally](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-promise.prototype.finally) - формальная механика возврата результата из `finally`.",{"slug":2776,"title":2777,"baseQuestion":2778,"goodAnswer":2779,"followUps":2780,"references":2790,"programSlug":59,"lessonSlug":59,"order":46,"status":13,"rawBody":2823},"mock-interview-javascript-core-q4-zachem-nuzhno-klyuchevoe-slovo-this","Зачем нужно ключевое слово this?","Зачем в JavaScript нужно ключевое слово `this`?","`this` нужен, чтобы функция могла работать с текущим объектом вызова, не привязываясь к конкретному имени переменной и не требуя каждый раз передавать этот объект отдельным аргументом.\n\nГлавная идея: метод описывает поведение, а `this` показывает, относительно какого объекта это поведение выполняется в конкретном вызове.\n\nНапример, одна и та же функция может быть методом разных объектов. Если внутри нее используется `this`, функция не зависит от имени внешней переменной. Она смотрит на то, как ее вызвали, и работает с объектом или значением, которое стало `this` именно в этом вызове.\n\nКлючевые мысли:\n\n- `this` - это механизм неявной передачи контекста вызова функции.\n- `this` позволяет методу обращаться к данным объекта, через который метод вызвали.\n- Одна и та же функция может быть переиспользована с разными объектами, потому что `this` определяется при вызове.\n- Без `this` метод часто пришлось бы привязывать к конкретной внешней переменной или явно передавать объект аргументом.\n- В обычных функциях значение `this` выбирается по форме вызова: обычный вызов, вызов как метод, явная привязка через `call`, `apply`, `bind`, вызов через `new`.\n- В strict mode обычный вызов функции без объекта дает `this` равный `undefined`. В нестрогом браузерном script исторически может появиться `window`.\n- У стрелочных функций нет собственного `this`. Они берут `this` из внешнего окружения, поэтому не подходят для методов, чей `this` должен определяться объектом вызова.\n\nХороший ответ должен отделять `this` от области видимости. Scope отвечает на вопрос, где искать имя переменной. `this` отвечает на вопрос, с каким значением вызвана функция.",[2781,2784,2787],{"question":2782,"expected":2783},"Что такое контекст в JavaScript и какой он бывает?","кандидат сначала уточняет, о каком контексте мы говорим. В JavaScript слово \"контекст\" часто используют для двух разных вещей, и хороший ответ не смешивает их в одну кашу.\n\nПервый смысл - контекст выполнения. Это не объект из кода, а служебная запись движка для текущего выполняемого куска JavaScript. Такой контекст хранит состояние выполнения: какой код сейчас выполняется, какая функция активна, из какого script или module пришел код, какие лексические окружения используются для поиска имен. Контексты выполнения лежат в стеке: когда мы вызываем функцию, создается новый контекст выполнения; когда функция заканчивается, он снимается со стека.\n\nНа базовом уровне кандидат может назвать глобальный контекст выполнения обычного script, контекст выполнения ES-модуля и контекст выполнения функции. Не нужно требовать от него спецификационный пересказ, но важно, чтобы он понимал: это про выполнение кода и стек, а не просто про объект перед точкой.\n\nВторой смысл - контекст вызова функции. На собеседованиях под ним часто имеют в виду значение `this`: значение, с которым функция была вызвана. В простом вызове метода это обычно объект перед точкой. При `call`, `apply` и `bind` мы задаем `this` явно. При `new` `this` становится новым объектом. У стрелочной функции своего `this` нет, она использует внешний.\n\nХороший ответ должен прямо развести три вещи:\n\n- контекст выполнения - где и в каком состоянии движок сейчас выполняет код;\n- scope - где JavaScript ищет имена переменных по лексическим окружениям;\n- `this` - с каким значением вызвана функция.\n\nГлавный признак понимания: кандидат не говорит \"контекст это this\" и не говорит \"scope это контекст\". Он объясняет, что `this` связан с вызовом функции, а область видимости связана с местом объявления и поиском имен.",{"question":2785,"expected":2786},"Когда обычная функция использует `this`, как понять, какой объект или значение окажется на месте `this`?","кандидат говорит, что сначала мы ищем место, где эту функцию реально запускают. Сама строка с `this` внутри функции еще не говорит, что именно будет на месте `this`. Для обычной функции `this` появляется не при объявлении функции, а в момент ее вызова.\n\nДальше мы разбираем сам запуск функции. Если функцию запустили как метод объекта, то обычно `this` будет объектом перед точкой. Если функцию запустили просто как отдельную функцию, объекта перед точкой нет: в strict mode `this` будет `undefined`, а в нестрогом браузерном script может стать `window`. Если функцию запустили через `call` или `apply`, то `this` передали явно. Если использовали `bind`, то перед нами уже новая функция с заранее зафиксированным `this`. Если запустили через `new`, то `this` будет новым объектом, который создается этим вызовом.\n\nКандидат должен проговорить простую механику: функция в JavaScript - это значение. Мы можем положить ее в объект, скопировать в другое место, передать в callback или вызвать через другой объект. Поэтому `this` не запоминает объект, где функция когда-то лежала. Важен не \"адрес хранения\" функции, а конкретный вызов.\n\nПолезная проверка для ответа: если мы взяли метод из объекта и передали его как callback, объект перед точкой исчез из вызова. Значит, старый объект не сохранится как `this`, если мы явно не сохранили привязку через `bind`, wrapper или другой механизм.",{"question":2788,"expected":2789},"У `obj` метод `f` записан стрелочной функцией. Почему при вызове `obj.f()` значение `this` внутри `f` не становится `obj`?","кандидат говорит, что мы выбрали не тот тип функции для этой задачи. Если функция должна быть методом объекта и брать `this` от объекта вызова, нужна обычная функция или синтаксис метода.\n\nСтрелочная функция не получает собственный `this` при вызове. Поэтому сам факт, что мы вызвали ее через объект, не делает этот объект значением `this` внутри стрелки. Стрелка берет `this` из внешнего места, где была создана.\n\nХороший ответ должен привести выбор к простой причине: для метода, который должен работать с объектом вызова, стрелка не подходит. Она не умеет получить `this` от этого вызова. В такой ситуации нужно писать обычную функцию или метод.\n\nПри этом стрелочная функция не плохая сама по себе. Она подходит в другой ситуации: когда мы уже внутри обычного метода, там `this` уже правильный, и внутренняя маленькая функция должна использовать тот же самый `this`, а не создавать новый.\n\nИтоговая мысль:\n\n- метод объекта, которому нужен объект вызова, - обычная функция или метод;\n- внутренняя функция, которой нужен уже существующий внешний `this`, - стрелочная функция может быть удобна.\n\nВажно не путать стрелку с `bind`: `bind` создает новую функцию с заранее заданным `this`, а стрелка ничего отдельно не привязывает. Она просто не имеет своего `this` и использует внешний.",[2791,2795,2797,2799,2803,2805,2807,2811,2813,2817,2819],{"title":2792,"url":2793,"note":2794},"Learn JS: Методы объекта, this","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F04-object-methods\u002Farticle.md","зачем методам нужен доступ к текущему объекту, почему `this` определяется при вызове и чем отличаются стрелочные функции.",{"title":2214,"url":2215,"note":2796},"потеря `this`, `bind` и фиксирование контекста для callbacks.",{"title":2206,"url":2207,"note":2798},"почему у стрелочных функций нет собственного `this`.",{"title":2800,"url":2801,"note":2802},"YDKJS: Глава 1. this или That?","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fthis%20%26%20object%20prototypes\u002Fch1.md","мотивация `this` как способа переиспользовать функции с разными объектами контекста.",{"title":2218,"url":2219,"note":2804},"правила привязки `this` через точку вызова.",{"title":2334,"url":2335,"note":2806},"отличие лексической области видимости от механизма `this`, который определяется во время выполнения.",{"title":2808,"url":2809,"note":2810},"YDKJS: Приложение C. Лексический this","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002FapC.md","почему стрелочные функции используют лексический `this` и чем это отличается от обычных правил привязки.",{"title":1836,"url":1837,"note":2812},"стек вызовов, очередь задач и модель выполнения.",{"title":2814,"url":2815,"note":2816},"MDN: this","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fthis\u002Findex.md","правила значения `this` при разных способах вызова.",{"title":2222,"url":2223,"note":2818},"почему стрелочные функции не создают собственный `this`.",{"title":2820,"url":2821,"note":2822},"MDN: Function.prototype.bind","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Ffunction\u002Fbind\u002Findex.md","явная привязка `this` через `bind`.","# Q4. Зачем нужно ключевое слово this?\n\n## Базовый вопрос\n\nЗачем в JavaScript нужно ключевое слово `this`?\n\n## Хороший ответ\n\n`this` нужен, чтобы функция могла работать с текущим объектом вызова, не привязываясь к конкретному имени переменной и не требуя каждый раз передавать этот объект отдельным аргументом.\n\nГлавная идея: метод описывает поведение, а `this` показывает, относительно какого объекта это поведение выполняется в конкретном вызове.\n\nНапример, одна и та же функция может быть методом разных объектов. Если внутри нее используется `this`, функция не зависит от имени внешней переменной. Она смотрит на то, как ее вызвали, и работает с объектом или значением, которое стало `this` именно в этом вызове.\n\nКлючевые мысли:\n\n- `this` - это механизм неявной передачи контекста вызова функции.\n- `this` позволяет методу обращаться к данным объекта, через который метод вызвали.\n- Одна и та же функция может быть переиспользована с разными объектами, потому что `this` определяется при вызове.\n- Без `this` метод часто пришлось бы привязывать к конкретной внешней переменной или явно передавать объект аргументом.\n- В обычных функциях значение `this` выбирается по форме вызова: обычный вызов, вызов как метод, явная привязка через `call`, `apply`, `bind`, вызов через `new`.\n- В strict mode обычный вызов функции без объекта дает `this` равный `undefined`. В нестрогом браузерном script исторически может появиться `window`.\n- У стрелочных функций нет собственного `this`. Они берут `this` из внешнего окружения, поэтому не подходят для методов, чей `this` должен определяться объектом вызова.\n\nХороший ответ должен отделять `this` от области видимости. Scope отвечает на вопрос, где искать имя переменной. `this` отвечает на вопрос, с каким значением вызвана функция.\n\n## Уточняющие вопросы\n\n### 1. Что такое контекст в JavaScript и какой он бывает?\n\nОжидаем: кандидат сначала уточняет, о каком контексте мы говорим. В JavaScript слово \"контекст\" часто используют для двух разных вещей, и хороший ответ не смешивает их в одну кашу.\n\nПервый смысл - контекст выполнения. Это не объект из кода, а служебная запись движка для текущего выполняемого куска JavaScript. Такой контекст хранит состояние выполнения: какой код сейчас выполняется, какая функция активна, из какого script или module пришел код, какие лексические окружения используются для поиска имен. Контексты выполнения лежат в стеке: когда мы вызываем функцию, создается новый контекст выполнения; когда функция заканчивается, он снимается со стека.\n\nНа базовом уровне кандидат может назвать глобальный контекст выполнения обычного script, контекст выполнения ES-модуля и контекст выполнения функции. Не нужно требовать от него спецификационный пересказ, но важно, чтобы он понимал: это про выполнение кода и стек, а не просто про объект перед точкой.\n\nВторой смысл - контекст вызова функции. На собеседованиях под ним часто имеют в виду значение `this`: значение, с которым функция была вызвана. В простом вызове метода это обычно объект перед точкой. При `call`, `apply` и `bind` мы задаем `this` явно. При `new` `this` становится новым объектом. У стрелочной функции своего `this` нет, она использует внешний.\n\nХороший ответ должен прямо развести три вещи:\n\n- контекст выполнения - где и в каком состоянии движок сейчас выполняет код;\n- scope - где JavaScript ищет имена переменных по лексическим окружениям;\n- `this` - с каким значением вызвана функция.\n\nГлавный признак понимания: кандидат не говорит \"контекст это this\" и не говорит \"scope это контекст\". Он объясняет, что `this` связан с вызовом функции, а область видимости связана с местом объявления и поиском имен.\n\n### 2. Когда обычная функция использует `this`, как понять, какой объект или значение окажется на месте `this`?\n\nОжидаем: кандидат говорит, что сначала мы ищем место, где эту функцию реально запускают. Сама строка с `this` внутри функции еще не говорит, что именно будет на месте `this`. Для обычной функции `this` появляется не при объявлении функции, а в момент ее вызова.\n\nДальше мы разбираем сам запуск функции. Если функцию запустили как метод объекта, то обычно `this` будет объектом перед точкой. Если функцию запустили просто как отдельную функцию, объекта перед точкой нет: в strict mode `this` будет `undefined`, а в нестрогом браузерном script может стать `window`. Если функцию запустили через `call` или `apply`, то `this` передали явно. Если использовали `bind`, то перед нами уже новая функция с заранее зафиксированным `this`. Если запустили через `new`, то `this` будет новым объектом, который создается этим вызовом.\n\nКандидат должен проговорить простую механику: функция в JavaScript - это значение. Мы можем положить ее в объект, скопировать в другое место, передать в callback или вызвать через другой объект. Поэтому `this` не запоминает объект, где функция когда-то лежала. Важен не \"адрес хранения\" функции, а конкретный вызов.\n\nПолезная проверка для ответа: если мы взяли метод из объекта и передали его как callback, объект перед точкой исчез из вызова. Значит, старый объект не сохранится как `this`, если мы явно не сохранили привязку через `bind`, wrapper или другой механизм.\n\n### 3. У `obj` метод `f` записан стрелочной функцией. Почему при вызове `obj.f()` значение `this` внутри `f` не становится `obj`?\n\nОжидаем: кандидат говорит, что мы выбрали не тот тип функции для этой задачи. Если функция должна быть методом объекта и брать `this` от объекта вызова, нужна обычная функция или синтаксис метода.\n\nСтрелочная функция не получает собственный `this` при вызове. Поэтому сам факт, что мы вызвали ее через объект, не делает этот объект значением `this` внутри стрелки. Стрелка берет `this` из внешнего места, где была создана.\n\nХороший ответ должен привести выбор к простой причине: для метода, который должен работать с объектом вызова, стрелка не подходит. Она не умеет получить `this` от этого вызова. В такой ситуации нужно писать обычную функцию или метод.\n\nПри этом стрелочная функция не плохая сама по себе. Она подходит в другой ситуации: когда мы уже внутри обычного метода, там `this` уже правильный, и внутренняя маленькая функция должна использовать тот же самый `this`, а не создавать новый.\n\nИтоговая мысль:\n\n- метод объекта, которому нужен объект вызова, - обычная функция или метод;\n- внутренняя функция, которой нужен уже существующий внешний `this`, - стрелочная функция может быть удобна.\n\nВажно не путать стрелку с `bind`: `bind` создает новую функцию с заранее заданным `this`, а стрелка ничего отдельно не привязывает. Она просто не имеет своего `this` и использует внешний.\n\n## Референсы\n\n- [Learn JS: Методы объекта, this](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F04-object-methods\u002Farticle.md) - зачем методам нужен доступ к текущему объекту, почему `this` определяется при вызове и чем отличаются стрелочные функции.\n- [Learn JS: Привязка контекста к функции](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F10-bind\u002Farticle.md) - потеря `this`, `bind` и фиксирование контекста для callbacks.\n- [Learn JS: Повторяем стрелочные функции](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F12-arrow-functions\u002Farticle.md) - почему у стрелочных функций нет собственного `this`.\n- [YDKJS: Глава 1. this или That?](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fthis%20%26%20object%20prototypes\u002Fch1.md) - мотивация `this` как способа переиспользовать функции с разными объектами контекста.\n- [YDKJS: Глава 2. Весь this теперь приобретает смысл](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fthis%20%26%20object%20prototypes\u002Fch2.md) - правила привязки `this` через точку вызова.\n- [YDKJS: Приложение A. Динамическая область видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002FapA.md) - отличие лексической области видимости от механизма `this`, который определяется во время выполнения.\n- [YDKJS: Приложение C. Лексический this](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002FapC.md) - почему стрелочные функции используют лексический `this` и чем это отличается от обычных правил привязки.\n- [MDN: JavaScript execution model](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fexecution_model\u002Findex.md) - стек вызовов, очередь задач и модель выполнения.\n- [MDN: this](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fthis\u002Findex.md) - правила значения `this` при разных способах вызова.\n- [MDN: Arrow functions](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Ffunctions\u002Farrow_functions\u002Findex.md) - почему стрелочные функции не создают собственный `this`.\n- [MDN: Function.prototype.bind](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Ffunction\u002Fbind\u002Findex.md) - явная привязка `this` через `bind`.",{"slug":2825,"title":2826,"baseQuestion":2827,"goodAnswer":2828,"followUps":2829,"references":2839,"programSlug":18,"lessonSlug":18,"order":46,"status":13,"rawBody":2852},"objects-prototypes-classes-q4-zachem-nuzhny-gettery-i-settery-v-javascript","Зачем нужны геттеры и сеттеры в JavaScript?","Зачем в JavaScript нужны геттеры и сеттеры?","Геттеры и сеттеры нужны, чтобы снаружи работать с полем как с обычным свойством, а внутри добавить логику чтения или записи.\n\nТак мы можем сделать вычисляемое свойство, проверять значение перед сохранением, нормализовать данные или сохранить старый внешний API объекта, даже если внутреннее хранение поменялось.\n\nГеттер и сеттер - это функции, которые стоят за свойством-аксессором.\n\nГеттер вызывается при чтении свойства. Если мы читаем `obj.x`, а `x` является свойством-аксессором с геттером, JavaScript вызывает геттер и возвращает его результат. Снаружи это выглядит как обычное свойство, а не как вызов функции.\n\nСеттер вызывается при записи свойства. Если мы выполняем `obj.x = value`, а `x` является свойством-аксессором с сеттером, JavaScript вызывает сеттер и передает ему записываемое значение.\n\nВажно понимать роль `this`. Когда геттер или сеттер вызывается как свойство объекта, `this` внутри обычно указывает на объект, через который мы работаем со свойством. Поэтому геттер может читать другие свойства этого объекта, а сеттер может менять внутреннее поле.\n\nЕсли у свойства-аксессора есть только геттер и нет сеттера, чтение работает, а запись не меняет значение. В strict mode запись в свойство-аксессор без сеттера приводит к `TypeError`, в нестрогом режиме обычно молча не выполняется.\n\nХороший кандидат объясняет геттеры и сеттеры как часть механики свойства, а не как обычные методы, которые нужно явно вызывать.",[2830,2833,2836],{"question":2831,"expected":2832},"Чем геттер отличается от обычного метода?","кандидат говорит, что обычный метод мы вызываем скобками, а геттер запускается при чтении свойства. Для внешнего кода геттер выглядит как свойство, хотя внутри выполняется функция.\n\nХороший ответ может добавить, что геттер должен быть без параметров.",{"question":2834,"expected":2835},"Зачем использовать сеттер, если можно просто присвоить значение обычному свойству?","кандидат объясняет, что сеттер нужен, когда запись должна иметь логику: проверку, нормализацию, обновление другого поля или сохранение обратной совместимости.\n\nПри этом хороший ответ не должен предлагать сеттер для каждого свойства без причины.",{"question":2837,"expected":2838},"У `obj` есть свойство `x` с геттером, который возвращает `1`, но без сеттера. Почему после `obj.x = 2` выражение `obj.x` все равно возвращает `1`?","кандидат говорит, что записывать некуда: сеттер отсутствует. В strict mode будет `TypeError`, в нестрогом режиме операция обычно не изменит значение и пройдет молча.\n\nЭто проверяет связь свойства-аксессора с поведением присваивания.",[2840,2844,2848],{"title":2841,"url":2842,"note":2843},"Learn JS: Свойства - геттеры и сеттеры","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F02-property-accessors\u002Farticle.md","геттер, сеттер, виртуальное свойство и примеры с чтением и записью.",{"title":2845,"url":2846,"note":2847},"MDN: getter","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Ffunctions\u002Fget\u002Findex.md","свойства-аксессоры с функцией чтения.",{"title":2849,"url":2850,"note":2851},"MDN: setter","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Ffunctions\u002Fset\u002Findex.md","как сеттер участвует в записи свойства.","# Q4. Зачем нужны геттеры и сеттеры в JavaScript?\n\n## Базовый вопрос\n\nЗачем в JavaScript нужны геттеры и сеттеры?\n\n## Хороший ответ\n\nГеттеры и сеттеры нужны, чтобы снаружи работать с полем как с обычным свойством, а внутри добавить логику чтения или записи.\n\nТак мы можем сделать вычисляемое свойство, проверять значение перед сохранением, нормализовать данные или сохранить старый внешний API объекта, даже если внутреннее хранение поменялось.\n\nГеттер и сеттер - это функции, которые стоят за свойством-аксессором.\n\nГеттер вызывается при чтении свойства. Если мы читаем `obj.x`, а `x` является свойством-аксессором с геттером, JavaScript вызывает геттер и возвращает его результат. Снаружи это выглядит как обычное свойство, а не как вызов функции.\n\nСеттер вызывается при записи свойства. Если мы выполняем `obj.x = value`, а `x` является свойством-аксессором с сеттером, JavaScript вызывает сеттер и передает ему записываемое значение.\n\nВажно понимать роль `this`. Когда геттер или сеттер вызывается как свойство объекта, `this` внутри обычно указывает на объект, через который мы работаем со свойством. Поэтому геттер может читать другие свойства этого объекта, а сеттер может менять внутреннее поле.\n\nЕсли у свойства-аксессора есть только геттер и нет сеттера, чтение работает, а запись не меняет значение. В strict mode запись в свойство-аксессор без сеттера приводит к `TypeError`, в нестрогом режиме обычно молча не выполняется.\n\nХороший кандидат объясняет геттеры и сеттеры как часть механики свойства, а не как обычные методы, которые нужно явно вызывать.\n\n## Уточняющие вопросы\n\n### 1. Чем геттер отличается от обычного метода?\n\nОжидаем: кандидат говорит, что обычный метод мы вызываем скобками, а геттер запускается при чтении свойства. Для внешнего кода геттер выглядит как свойство, хотя внутри выполняется функция.\n\nХороший ответ может добавить, что геттер должен быть без параметров.\n\n### 2. Зачем использовать сеттер, если можно просто присвоить значение обычному свойству?\n\nОжидаем: кандидат объясняет, что сеттер нужен, когда запись должна иметь логику: проверку, нормализацию, обновление другого поля или сохранение обратной совместимости.\n\nПри этом хороший ответ не должен предлагать сеттер для каждого свойства без причины.\n\n### 3. У `obj` есть свойство `x` с геттером, который возвращает `1`, но без сеттера. Почему после `obj.x = 2` выражение `obj.x` все равно возвращает `1`?\n\nОжидаем: кандидат говорит, что записывать некуда: сеттер отсутствует. В strict mode будет `TypeError`, в нестрогом режиме операция обычно не изменит значение и пройдет молча.\n\nЭто проверяет связь свойства-аксессора с поведением присваивания.\n\n## Референсы\n\n- [Learn JS: Свойства - геттеры и сеттеры](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F02-property-accessors\u002Farticle.md) - геттер, сеттер, виртуальное свойство и примеры с чтением и записью.\n- [MDN: getter](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Ffunctions\u002Fget\u002Findex.md) - свойства-аксессоры с функцией чтения.\n- [MDN: setter](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Ffunctions\u002Fset\u002Findex.md) - как сеттер участвует в записи свойства.",{"slug":2854,"title":2855,"baseQuestion":2856,"goodAnswer":2857,"followUps":2858,"references":2868,"programSlug":50,"lessonSlug":50,"order":46,"status":13,"rawBody":2873},"recursion-q4-chto-proishodit-pri-vozvrate-iz-rekursii","Что происходит при возврате из рекурсии?","Как рекурсивная функция собирает результат после базового случая?","Простыми словами: сначала рекурсия спускается к самому простому случаю, а потом каждый предыдущий вызов получает ответ от следующего и добавляет свою часть работы.\n\nНапример, если мы считаем сумму чисел от `1` до `4`, вызов для `4` ждет сумму до `3`, вызов для `3` ждет сумму до `2`, и так дальше до базового случая. Когда базовый случай вернул готовое значение, вызовы начинают завершаться в обратном порядке.\n\nВажно разделять две фазы:\n\n- спуск, где мы создаем новые вызовы;\n- возврат, где незавершенные вызовы продолжают работу.\n\nНа интервью это помогает объяснять выводы в задачах формата \"что выведется\". Если `console.log` стоит до рекурсивного вызова, он сработает при спуске. Если после рекурсивного вызова, он сработает при возврате назад.",[2859,2862,2865],{"question":2860,"expected":2861},"Почему при `f(3)` вывод до рекурсивного вызова идет как `3 2 1`, а вывод после вызова идет как `1 2 3`?","кандидат объясняет две фазы выполнения: сначала создаются вложенные вызовы, потом они завершаются в обратном порядке.",{"question":2863,"expected":2864},"Почему выражение `n + f(n - 1)` не может сразу вернуть число?","кандидат говорит, что нужно сначала получить результат `f(n - 1)`. Только после возврата внутреннего вызова можно выполнить сложение.",{"question":2866,"expected":2867},"Что хранит внешний вызов, пока ждет результат внутреннего?","кандидат объясняет, что внешний вызов хранит свои параметры, локальные переменные и место, куда нужно продолжить выполнение после возврата.",[2869,2871],{"title":1954,"url":1955,"note":2870},"базовый случай и рекурсивный случай.",{"title":2284,"url":2285,"note":2872},"стек вызовов и стоимость вложенных вызовов.","# Q4. Что происходит при возврате из рекурсии?\n\n## Базовый вопрос\n\nКак рекурсивная функция собирает результат после базового случая?\n\n## Хороший ответ\n\nПростыми словами: сначала рекурсия спускается к самому простому случаю, а потом каждый предыдущий вызов получает ответ от следующего и добавляет свою часть работы.\n\nНапример, если мы считаем сумму чисел от `1` до `4`, вызов для `4` ждет сумму до `3`, вызов для `3` ждет сумму до `2`, и так дальше до базового случая. Когда базовый случай вернул готовое значение, вызовы начинают завершаться в обратном порядке.\n\nВажно разделять две фазы:\n\n- спуск, где мы создаем новые вызовы;\n- возврат, где незавершенные вызовы продолжают работу.\n\nНа интервью это помогает объяснять выводы в задачах формата \"что выведется\". Если `console.log` стоит до рекурсивного вызова, он сработает при спуске. Если после рекурсивного вызова, он сработает при возврате назад.\n\n## Уточняющие вопросы\n\n### 1. Почему при `f(3)` вывод до рекурсивного вызова идет как `3 2 1`, а вывод после вызова идет как `1 2 3`?\n\nОжидаем: кандидат объясняет две фазы выполнения: сначала создаются вложенные вызовы, потом они завершаются в обратном порядке.\n\n### 2. Почему выражение `n + f(n - 1)` не может сразу вернуть число?\n\nОжидаем: кандидат говорит, что нужно сначала получить результат `f(n - 1)`. Только после возврата внутреннего вызова можно выполнить сложение.\n\n### 3. Что хранит внешний вызов, пока ждет результат внутреннего?\n\nОжидаем: кандидат объясняет, что внешний вызов хранит свои параметры, локальные переменные и место, куда нужно продолжить выполнение после возврата.\n\n## Референсы\n\n- [MDN: Recursion](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md) - базовый случай и рекурсивный случай.\n- [Вы не знаете JS: ES6 и дальше — глава 7 Meta Programming](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fes6%20%26%20beyond\u002Fch7.md) - стек вызовов и стоимость вложенных вызовов.",{"slug":2875,"title":2876,"baseQuestion":2876,"goodAnswer":2877,"followUps":2878,"references":2888,"programSlug":41,"lessonSlug":41,"order":46,"status":13,"rawBody":2897},"rendering-dom-events-forms-q4-chto-takoe-prinuditelnyy-layout","Что такое принудительный layout?","Принудительный layout происходит, когда мы изменили DOM или стили, а потом сразу попросили браузер вернуть актуальный размер или положение элемента. Браузер мог бы отложить пересчет до ближайшего кадра, но чтение размера требует точного ответа прямо сейчас.\n\nПример такой ситуации: мы изменили ширину элемента, а потом сразу читаем `offsetWidth`, `scrollHeight` или `getBoundingClientRect()`. Если layout уже устарел, браузер вынужден синхронно пересчитать геометрию перед тем, как вернуть значение.\n\nОдин такой случай не всегда проблема. Проблема начинается, когда мы много раз чередуем запись и чтение: поменяли стиль, прочитали размер, снова поменяли стиль, снова прочитали размер. Такой паттерн часто называют layout thrashing.\n\nПравильная идея простая: сначала читаем нужные размеры, потом отдельно применяем изменения. Так браузеру легче сгруппировать работу.",[2879,2882,2885],{"question":2880,"expected":2881},"Почему после изменения ширины чтение `offsetWidth` должно вернуть уже новое значение?","кандидат говорит, что `offsetWidth` обещает актуальную layout-ширину. Если предыдущая запись сделала расчеты устаревшими, браузеру нужно обновить layout перед возвратом значения.",{"question":2883,"expected":2884},"Почему повторять \"поменяли стиль, прочитали размер\" в цикле обычно хуже, чем сделать два отдельных прохода?","кандидат объясняет, что в первом варианте браузер может пересчитывать layout на каждой итерации. Во втором варианте мы сначала собираем данные, потом применяем изменения, и пересчетов становится меньше.",{"question":2886,"expected":2887},"Как бы мы объяснили это без слова \"оптимизация\"?","кандидат говорит, что мы просто не дергаем браузер туда-сюда. Сначала спрашиваем все, что нужно узнать, потом говорим все, что нужно поменять.",[2889,2891,2893],{"title":2307,"url":2308,"note":2890},"reflow, repaint и выбор свойств для обновления интерфейса.",{"title":2311,"url":2312,"note":2892},"чтение актуальной layout-ширины элемента.",{"title":2894,"url":2895,"note":2896},"MDN: Element.getBoundingClientRect","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Felement\u002Fgetboundingclientrect\u002Findex.md","чтение актуального прямоугольника элемента.","# Q4. Что такое принудительный layout?\n\n## Базовый вопрос\n\nЧто такое принудительный layout?\n\n## Хороший ответ\n\nПринудительный layout происходит, когда мы изменили DOM или стили, а потом сразу попросили браузер вернуть актуальный размер или положение элемента. Браузер мог бы отложить пересчет до ближайшего кадра, но чтение размера требует точного ответа прямо сейчас.\n\nПример такой ситуации: мы изменили ширину элемента, а потом сразу читаем `offsetWidth`, `scrollHeight` или `getBoundingClientRect()`. Если layout уже устарел, браузер вынужден синхронно пересчитать геометрию перед тем, как вернуть значение.\n\nОдин такой случай не всегда проблема. Проблема начинается, когда мы много раз чередуем запись и чтение: поменяли стиль, прочитали размер, снова поменяли стиль, снова прочитали размер. Такой паттерн часто называют layout thrashing.\n\nПравильная идея простая: сначала читаем нужные размеры, потом отдельно применяем изменения. Так браузеру легче сгруппировать работу.\n\n## Уточняющие вопросы\n\n### 1. Почему после изменения ширины чтение `offsetWidth` должно вернуть уже новое значение?\n\nОжидаем: кандидат говорит, что `offsetWidth` обещает актуальную layout-ширину. Если предыдущая запись сделала расчеты устаревшими, браузеру нужно обновить layout перед возвратом значения.\n\n### 2. Почему повторять \"поменяли стиль, прочитали размер\" в цикле обычно хуже, чем сделать два отдельных прохода?\n\nОжидаем: кандидат объясняет, что в первом варианте браузер может пересчитывать layout на каждой итерации. Во втором варианте мы сначала собираем данные, потом применяем изменения, и пересчетов становится меньше.\n\n### 3. Как бы мы объяснили это без слова \"оптимизация\"?\n\nОжидаем: кандидат говорит, что мы просто не дергаем браузер туда-сюда. Сначала спрашиваем все, что нужно узнать, потом говорим все, что нужно поменять.\n\n## Референсы\n\n- [MDN: CSS performance optimization](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Flearn_web_development\u002Fextensions\u002Fperformance\u002Fcss\u002Findex.md) - reflow, repaint и выбор свойств для обновления интерфейса.\n- [MDN: HTMLElement.offsetWidth](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlelement\u002Foffsetwidth\u002Findex.md) - чтение актуальной layout-ширины элемента.\n- [MDN: Element.getBoundingClientRect](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Felement\u002Fgetboundingclientrect\u002Findex.md) - чтение актуального прямоугольника элемента.",{"slug":2899,"title":2900,"baseQuestion":2901,"goodAnswer":2902,"followUps":2903,"references":2913,"programSlug":19,"lessonSlug":19,"order":46,"status":13,"rawBody":2920},"scope-closures-deep-dive-q4-zachem-nuzhna-iife","Зачем нужна IIFE?","Зачем в JavaScript используют IIFE?","IIFE это function expression, которую мы вызываем сразу на месте. Главная польза в старом script-коде: быстро создать отдельную функциональную область и не загрязнять внешнюю область временными именами.\n\nЕсли написать обычное function declaration, имя функции попадет во внешнюю область. Если обернуть функцию в выражение и сразу вызвать, имя можно оставить доступным только внутри самой функции. Так мы получаем изолированное место для временных переменных.\n\nIIFE также используют, чтобы передать значения параметрами и создать отдельные привязки. Это особенно полезно в старых примерах с `var` и замыканиями в циклах: пустая IIFE сама по себе не решает проблему, а IIFE с параметром или локальной переменной создает нужную отдельную привязку.\n\nВ современном коде часть задач IIFE решают блоки с `let` и `const`, ES-модули и обычные функции. Но IIFE остается важной исторической и учебной конструкцией для понимания function expression, области видимости и модульного паттерна.",[2904,2907,2910],{"question":2905,"expected":2906},"Почему `(function f() {})()` не добавляет имя `f` во внешнюю область?","кандидат говорит, что это function expression. Имя named function expression доступно внутри самой функции, но не создает внешнюю привязку как function declaration.",{"question":2908,"expected":2909},"Почему пустая IIFE внутри цикла с `var` не исправляет замыкание на общий счетчик?","кандидат объясняет, что новая область появилась, но в ней нет своей переменной со значением текущей итерации. Callback все равно читает общий `var` из внешнего цикла.",{"question":2911,"expected":2912},"Когда IIFE сейчас может быть лишней?","кандидат говорит, что для простого ограничения временных переменных часто достаточно блока с `let` и `const`, а для изоляции файлового кода лучше подходят ES-модули. IIFE нужна, когда мы сознательно работаем в обычном script или хотим сразу создать замыкание через вызов функции.",[2914,2916,2918],{"title":1881,"url":1882,"note":2915},"function expression, IIFE и скрытие имени функции.",{"title":2519,"url":2520,"note":2917},"IIFE как способ создать отдельную область для замыкания в цикле.",{"title":1865,"url":1866,"note":2919},"IIFE как исторический способ ограничивать область `var`.","# Q4. Зачем нужна IIFE?\n\n## Базовый вопрос\n\nЗачем в JavaScript используют IIFE?\n\n## Хороший ответ\n\nIIFE это function expression, которую мы вызываем сразу на месте. Главная польза в старом script-коде: быстро создать отдельную функциональную область и не загрязнять внешнюю область временными именами.\n\nЕсли написать обычное function declaration, имя функции попадет во внешнюю область. Если обернуть функцию в выражение и сразу вызвать, имя можно оставить доступным только внутри самой функции. Так мы получаем изолированное место для временных переменных.\n\nIIFE также используют, чтобы передать значения параметрами и создать отдельные привязки. Это особенно полезно в старых примерах с `var` и замыканиями в циклах: пустая IIFE сама по себе не решает проблему, а IIFE с параметром или локальной переменной создает нужную отдельную привязку.\n\nВ современном коде часть задач IIFE решают блоки с `let` и `const`, ES-модули и обычные функции. Но IIFE остается важной исторической и учебной конструкцией для понимания function expression, области видимости и модульного паттерна.\n\n## Уточняющие вопросы\n\n### 1. Почему `(function f() {})()` не добавляет имя `f` во внешнюю область?\n\nОжидаем: кандидат говорит, что это function expression. Имя named function expression доступно внутри самой функции, но не создает внешнюю привязку как function declaration.\n\n### 2. Почему пустая IIFE внутри цикла с `var` не исправляет замыкание на общий счетчик?\n\nОжидаем: кандидат объясняет, что новая область появилась, но в ней нет своей переменной со значением текущей итерации. Callback все равно читает общий `var` из внешнего цикла.\n\n### 3. Когда IIFE сейчас может быть лишней?\n\nОжидаем: кандидат говорит, что для простого ограничения временных переменных часто достаточно блока с `let` и `const`, а для изоляции файлового кода лучше подходят ES-модули. IIFE нужна, когда мы сознательно работаем в обычном script или хотим сразу создать замыкание через вызов функции.\n\n## Референсы\n\n- [YDKJS: Глава 3. Область видимости функции против блоков](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch3.md) - function expression, IIFE и скрытие имени функции.\n- [YDKJS: Глава 5. Замыкание области видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md) - IIFE как способ создать отдельную область для замыкания в цикле.\n- [Learn JS: Устаревшее ключевое слово var](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F04-var\u002Farticle.md) - IIFE как исторический способ ограничивать область `var`.",{"slug":2922,"title":2777,"baseQuestion":2778,"goodAnswer":2779,"followUps":2923,"references":2927,"programSlug":20,"lessonSlug":20,"order":46,"status":13,"rawBody":2823},"scope-hoisting-closures-this-q4-this-keyword",[2924,2925,2926],{"question":2782,"expected":2783},{"question":2785,"expected":2786},{"question":2788,"expected":2789},[2928,2929,2930,2931,2932,2933,2934,2935,2936,2937,2938],{"title":2792,"url":2793,"note":2794},{"title":2214,"url":2215,"note":2796},{"title":2206,"url":2207,"note":2798},{"title":2800,"url":2801,"note":2802},{"title":2218,"url":2219,"note":2804},{"title":2334,"url":2335,"note":2806},{"title":2808,"url":2809,"note":2810},{"title":1836,"url":1837,"note":2812},{"title":2814,"url":2815,"note":2816},{"title":2222,"url":2223,"note":2818},{"title":2820,"url":2821,"note":2822},{"slug":2940,"title":2941,"baseQuestion":2941,"goodAnswer":2942,"followUps":2943,"references":2953,"programSlug":21,"lessonSlug":21,"order":46,"status":13,"rawBody":2966},"types-coercion-symbol-json-q4-kak-obekt-privoditsya-k-primitivu","Как объект приводится к примитиву?","Операторы и функции не выполняют математику или строковое сложение прямо над обычным объектом. Если операция ожидает примитив, объект сначала проходит приведение к примитиву. Это называется `ToPrimitive`.\n\nАлгоритм на уровне собеседования такой:\n\n1. Если у объекта есть метод `obj[Symbol.toPrimitive]`, JavaScript вызывает его и передает подсказку `hint`.\n2. Если такого метода нет, используется обычный порядок `toString` и `valueOf`.\n3. Для строкового хинта сначала пробуется `toString`, потом `valueOf`.\n4. Для численного или default-хинта сначала пробуется `valueOf`, потом `toString`.\n5. Метод должен вернуть примитив. Если подходящего примитива получить не удалось, будет ошибка.\n\nНапример, если у обычного объекта есть `valueOf`, который возвращает `2`, то при `obj + 1` объект сначала может стать числом `2`, а потом уже получится `3`. Если мы делаем `String(obj)`, хинт строковый, поэтому обычно первым будет полезен `toString`.\n\nВажно понимать два уровня:\n\n- `ToPrimitive` только получает примитив из объекта.\n- После этого операция может продолжить приведение. Например, умножение может взять полученную строку `\"2\"` и уже ее привести к числу `2`.\n\nПо умолчанию `Object.prototype.valueOf()` возвращает сам объект, поэтому для обычного объекта он не помогает получить примитив. Тогда полезным часто оказывается `toString`, который по умолчанию возвращает `\"[object Object]\"`.",[2944,2947,2950],{"question":2945,"expected":2946},"Почему JavaScript сначала приводит объект к примитиву, а не складывает объекты напрямую?","кандидат говорит, что стандартные операторы вроде `+`, `-`, `*` работают с примитивными значениями или числовыми значениями, а не с произвольной логикой объектов. Для объекта сначала нужен примитивный представитель.\n\nХороший ответ может добавить, что JavaScript не позволяет перегрузить оператор сложения так, чтобы он возвращал новый доменный объект как в некоторых других языках.",{"question":2948,"expected":2949},"У объекта метод `valueOf` вернул `{}`. Почему JavaScript продолжает искать другой способ приведения или бросает ошибку, а не считает это успешным результатом?","кандидат говорит, что для обычного `valueOf` или `toString` такой результат не считается успешным примитивом. JavaScript попробует следующий метод, если он есть. Если ни один метод не вернул примитив, будет ошибка.\n\nХороший ответ может отдельно отметить, что `Symbol.toPrimitive` строже: если он вернул объект, JavaScript сразу бросает `TypeError`.",{"question":2951,"expected":2952},"Почему порядок методов отличается для `String(obj)` и `Number(obj)`?","кандидат говорит, что операция передает подсказку о желаемом направлении приведения. Для строки логично сначала просить `toString`, для числа - `valueOf`. Это подсказка, а не гарантия конкретного типа результата.\n\nТакой ответ показывает, что кандидат понимает роль hint, а не заучивает один порядок на все случаи.",[2954,2958,2960,2964],{"title":2955,"url":2956,"note":2957},"Learn JS: Преобразование объектов в примитивы","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F09-object-toprimitive\u002Farticle.md","хинты, `Symbol.toPrimitive`, `toString`, `valueOf` и порядок вызовов.",{"title":2659,"url":2660,"note":2959},"`ToPrimitive` как часть приведения объектов.",{"title":2961,"url":2962,"note":2963},"MDN: Symbol.toPrimitive","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fsymbol\u002Ftoprimitive\u002Findex.md","приведение объекта к примитиву.",{"title":2382,"url":2383,"note":2965},"роль `valueOf` в приведении обычных объектов.","# Q4. Как объект приводится к примитиву?\n\n## Базовый вопрос\n\nКак объект приводится к примитиву?\n\n## Хороший ответ\n\nОператоры и функции не выполняют математику или строковое сложение прямо над обычным объектом. Если операция ожидает примитив, объект сначала проходит приведение к примитиву. Это называется `ToPrimitive`.\n\nАлгоритм на уровне собеседования такой:\n\n1. Если у объекта есть метод `obj[Symbol.toPrimitive]`, JavaScript вызывает его и передает подсказку `hint`.\n2. Если такого метода нет, используется обычный порядок `toString` и `valueOf`.\n3. Для строкового хинта сначала пробуется `toString`, потом `valueOf`.\n4. Для численного или default-хинта сначала пробуется `valueOf`, потом `toString`.\n5. Метод должен вернуть примитив. Если подходящего примитива получить не удалось, будет ошибка.\n\nНапример, если у обычного объекта есть `valueOf`, который возвращает `2`, то при `obj + 1` объект сначала может стать числом `2`, а потом уже получится `3`. Если мы делаем `String(obj)`, хинт строковый, поэтому обычно первым будет полезен `toString`.\n\nВажно понимать два уровня:\n\n- `ToPrimitive` только получает примитив из объекта.\n- После этого операция может продолжить приведение. Например, умножение может взять полученную строку `\"2\"` и уже ее привести к числу `2`.\n\nПо умолчанию `Object.prototype.valueOf()` возвращает сам объект, поэтому для обычного объекта он не помогает получить примитив. Тогда полезным часто оказывается `toString`, который по умолчанию возвращает `\"[object Object]\"`.\n\n## Уточняющие вопросы\n\n### 1. Почему JavaScript сначала приводит объект к примитиву, а не складывает объекты напрямую?\n\nОжидаем: кандидат говорит, что стандартные операторы вроде `+`, `-`, `*` работают с примитивными значениями или числовыми значениями, а не с произвольной логикой объектов. Для объекта сначала нужен примитивный представитель.\n\nХороший ответ может добавить, что JavaScript не позволяет перегрузить оператор сложения так, чтобы он возвращал новый доменный объект как в некоторых других языках.\n\n### 2. У объекта метод `valueOf` вернул `{}`. Почему JavaScript продолжает искать другой способ приведения или бросает ошибку, а не считает это успешным результатом?\n\nОжидаем: кандидат говорит, что для обычного `valueOf` или `toString` такой результат не считается успешным примитивом. JavaScript попробует следующий метод, если он есть. Если ни один метод не вернул примитив, будет ошибка.\n\nХороший ответ может отдельно отметить, что `Symbol.toPrimitive` строже: если он вернул объект, JavaScript сразу бросает `TypeError`.\n\n### 3. Почему порядок методов отличается для `String(obj)` и `Number(obj)`?\n\nОжидаем: кандидат говорит, что операция передает подсказку о желаемом направлении приведения. Для строки логично сначала просить `toString`, для числа - `valueOf`. Это подсказка, а не гарантия конкретного типа результата.\n\nТакой ответ показывает, что кандидат понимает роль hint, а не заучивает один порядок на все случаи.\n\n## Референсы\n\n- [Learn JS: Преобразование объектов в примитивы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F09-object-toprimitive\u002Farticle.md) - хинты, `Symbol.toPrimitive`, `toString`, `valueOf` и порядок вызовов.\n- [YDKJS: Типы и грамматика, глава 4](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md) - `ToPrimitive` как часть приведения объектов.\n- [MDN: Symbol.toPrimitive](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fsymbol\u002Ftoprimitive\u002Findex.md) - приведение объекта к примитиву.\n- [MDN: Object.prototype.valueOf](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fvalueof\u002Findex.md) - роль `valueOf` в приведении обычных объектов.",{"slug":2968,"title":2969,"baseQuestion":2970,"goodAnswer":2971,"followUps":2972,"references":2982,"programSlug":40,"lessonSlug":40,"order":55,"status":13,"rawBody":2993},"browser-network-q5-chto-takoe-rest-i-restful-api","Что такое REST и RESTful API?","Что такое REST и что обычно называют RESTful API?","Сначала можно объяснить просто: REST это архитектурный стиль для взаимодействия распределенных систем через ресурсы и их представления. В обычной frontend-разработке под RESTful API чаще всего понимают HTTP API, где URL описывает ресурс, HTTP method описывает действие, а ответ возвращает представление ресурса или результат операции.\n\nВажно не сказать слишком примитивно: REST это не просто \"API возвращает JSON\". JSON может быть форматом ответа, но сам REST про принципы взаимодействия. Мы думаем не \"вызвать функцию `getUsers`\", а \"обратиться к ресурсу `\u002Fusers` методом `GET`\". Мы не пишем действие в URL вроде `\u002FdeleteUser`, а обычно используем ресурс `\u002Fusers\u002F1` и method `DELETE`.\n\nВ хорошем ответе должны прозвучать базовые идеи:\n\n- ресурсы имеют адреса;\n- действия выражаются HTTP-методами;\n- клиент и сервер общаются через представления ресурсов;\n- запросы должны быть stateless, то есть каждый запрос несет достаточно контекста для обработки;\n- HTTP-статусы и заголовки являются частью контракта, а не случайной обвязкой.\n\nRESTful API это API, которое следует этим идеям достаточно последовательно. В реальной разработке термин часто используют шире и мягче, поэтому на интервью полезно уточнять: мы говорим про строгий REST как архитектурный стиль или про практичный HTTP JSON API в REST-стиле.",[2973,2976,2979],{"question":2974,"expected":2975},"Почему `\u002Fusers\u002F1` с методом `DELETE` обычно лучше, чем `\u002FdeleteUser?id=1`?","кандидат говорит, что в REST-стиле URL описывает ресурс, а действие задается HTTP-методом. Такой контракт проще читать, тестировать и связывать с HTTP-семантикой.",{"question":2977,"expected":2978},"Почему RESTful API не равен \"любой JSON API\"?","кандидат объясняет, что JSON это только формат данных. RESTful API также требует понятных ресурсов, методов, статусов, stateless-взаимодействия и предсказуемого контракта.",{"question":2980,"expected":2981},"Что значит stateless для REST API?","кандидат говорит, что сервер не должен полагаться на скрытое состояние конкретного диалога с клиентом. Каждый запрос должен содержать данные, которые нужны серверу для понимания операции, например авторизацию, параметры и тело.",[2983,2987,2989],{"title":2984,"url":2985,"note":2986},"Fielding Dissertation: Representational State Transfer REST","https:\u002F\u002Fics.uci.edu\u002F~fielding\u002Fpubs\u002Fdissertation\u002Frest_arch_style.htm","первоисточник про REST как архитектурный стиль.",{"title":2091,"url":2092,"note":2988},"методы HTTP как часть практичного RESTful-контракта.",{"title":2990,"url":2991,"note":2992},"MDN: HTTP response status codes","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Freference\u002Fstatus\u002Findex.md","статусы HTTP как часть ответа API.","# Q5. Что такое REST и RESTful API?\n\n## Базовый вопрос\n\nЧто такое REST и что обычно называют RESTful API?\n\n## Хороший ответ\n\nСначала можно объяснить просто: REST это архитектурный стиль для взаимодействия распределенных систем через ресурсы и их представления. В обычной frontend-разработке под RESTful API чаще всего понимают HTTP API, где URL описывает ресурс, HTTP method описывает действие, а ответ возвращает представление ресурса или результат операции.\n\nВажно не сказать слишком примитивно: REST это не просто \"API возвращает JSON\". JSON может быть форматом ответа, но сам REST про принципы взаимодействия. Мы думаем не \"вызвать функцию `getUsers`\", а \"обратиться к ресурсу `\u002Fusers` методом `GET`\". Мы не пишем действие в URL вроде `\u002FdeleteUser`, а обычно используем ресурс `\u002Fusers\u002F1` и method `DELETE`.\n\nВ хорошем ответе должны прозвучать базовые идеи:\n\n- ресурсы имеют адреса;\n- действия выражаются HTTP-методами;\n- клиент и сервер общаются через представления ресурсов;\n- запросы должны быть stateless, то есть каждый запрос несет достаточно контекста для обработки;\n- HTTP-статусы и заголовки являются частью контракта, а не случайной обвязкой.\n\nRESTful API это API, которое следует этим идеям достаточно последовательно. В реальной разработке термин часто используют шире и мягче, поэтому на интервью полезно уточнять: мы говорим про строгий REST как архитектурный стиль или про практичный HTTP JSON API в REST-стиле.\n\n## Уточняющие вопросы\n\n### 1. Почему `\u002Fusers\u002F1` с методом `DELETE` обычно лучше, чем `\u002FdeleteUser?id=1`?\n\nОжидаем: кандидат говорит, что в REST-стиле URL описывает ресурс, а действие задается HTTP-методом. Такой контракт проще читать, тестировать и связывать с HTTP-семантикой.\n\n### 2. Почему RESTful API не равен \"любой JSON API\"?\n\nОжидаем: кандидат объясняет, что JSON это только формат данных. RESTful API также требует понятных ресурсов, методов, статусов, stateless-взаимодействия и предсказуемого контракта.\n\n### 3. Что значит stateless для REST API?\n\nОжидаем: кандидат говорит, что сервер не должен полагаться на скрытое состояние конкретного диалога с клиентом. Каждый запрос должен содержать данные, которые нужны серверу для понимания операции, например авторизацию, параметры и тело.\n\n## Референсы\n\n- [Fielding Dissertation: Representational State Transfer REST](https:\u002F\u002Fics.uci.edu\u002F~fielding\u002Fpubs\u002Fdissertation\u002Frest_arch_style.htm) - первоисточник про REST как архитектурный стиль.\n- [MDN: HTTP request methods](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Freference\u002Fmethods\u002Findex.md) - методы HTTP как часть практичного RESTful-контракта.\n- [MDN: HTTP response status codes](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Freference\u002Fstatus\u002Findex.md) - статусы HTTP как часть ответа API.",{"slug":2995,"title":2996,"baseQuestion":2997,"goodAnswer":2998,"followUps":2999,"references":3009,"programSlug":17,"lessonSlug":17,"order":55,"status":13,"rawBody":3026},"collections-iteration-arrays-q5-kak-vybirat-metod-massiva-pod-zadachu","Как выбирать метод массива под задачу?","Как выбирать метод массива под задачу обработки данных?","Сначала нужно понять, какой результат мы хотим получить.\n\nЕсли каждому элементу нужен новый вид, берем `map`. Если нужно оставить только часть элементов, берем `filter`. Если нужен один итог, например число, объект, строка или новая структура, часто подходит `reduce`. Если нужен первый подходящий элемент, берем `find`. Если нужен ответ \"есть ли хотя бы один\", берем `some`. Если нужно проверить \"подходят ли все\", берем `every`.\n\nОтдельно важно помнить про мутацию. `slice`, `map`, `filter`, `flat`, `flatMap` возвращают новые массивы. `splice`, `sort`, `reverse`, `push`, `pop`, `shift`, `unshift` меняют исходный массив. Если исходные данные нельзя менять, перед мутирующим методом нужна копия или современный немутирующий аналог там, где он доступен.\n\nНа собеседовании хороший ответ не должен звучать как список названий. Нужно объяснить намерение метода. Так интервьюер видит, что мы выбираем инструмент по смыслу задачи, а не вспоминаем случайный метод.\n\nТакже важно помнить про ловушки: `sort` без compare function сортирует как строки, `map(parseInt)` передает индекс как второй аргумент, sparse arrays могут пропускать callback у некоторых методов, а `reduce` без initialValue падает на пустом массиве.",[3000,3003,3006],{"question":3001,"expected":3002},"Почему для преобразования списка обычно выбираем `map`, а не `forEach`?","кандидат объясняет, что `map` явно возвращает новый массив результатов. `forEach` нужен для побочного действия и не выражает идею преобразования.",{"question":3004,"expected":3005},"Есть `['1', '2', '3']`, мы вызвали `.map(parseInt)` и получили `[1, NaN, NaN]`. Почему так произошло?","кандидат говорит, что `map` передает callback значение и индекс. `parseInt` воспринимает второй аргумент как radix, поэтому индексы меняют смысл разбора строки.",{"question":3007,"expected":3008},"Почему `sort` без функции сравнения может поставить `10` перед `2`?","кандидат объясняет, что обычный `sort` сравнивает строковые представления элементов. Для чисел нужна compare function.",[3010,3014,3018,3022],{"title":3011,"url":3012,"note":3013},"ru.javascript.info: Методы массивов","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F05-array-methods\u002Farticle.md","учебный обзор методов массивов.",{"title":3015,"url":3016,"note":3017},"MDN: Array","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Findex.md","справочник по массивам.",{"title":3019,"url":3020,"note":3021},"MDN: Array.map","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fmap\u002Findex.md","детали поведения `map`.",{"title":3023,"url":3024,"note":3025},"MDN: Array.sort","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fsort\u002Findex.md","детали поведения `sort`.","# Q5. Как выбирать метод массива под задачу?\n\n## Базовый вопрос\n\nКак выбирать метод массива под задачу обработки данных?\n\n## Хороший ответ\n\nСначала нужно понять, какой результат мы хотим получить.\n\nЕсли каждому элементу нужен новый вид, берем `map`. Если нужно оставить только часть элементов, берем `filter`. Если нужен один итог, например число, объект, строка или новая структура, часто подходит `reduce`. Если нужен первый подходящий элемент, берем `find`. Если нужен ответ \"есть ли хотя бы один\", берем `some`. Если нужно проверить \"подходят ли все\", берем `every`.\n\nОтдельно важно помнить про мутацию. `slice`, `map`, `filter`, `flat`, `flatMap` возвращают новые массивы. `splice`, `sort`, `reverse`, `push`, `pop`, `shift`, `unshift` меняют исходный массив. Если исходные данные нельзя менять, перед мутирующим методом нужна копия или современный немутирующий аналог там, где он доступен.\n\nНа собеседовании хороший ответ не должен звучать как список названий. Нужно объяснить намерение метода. Так интервьюер видит, что мы выбираем инструмент по смыслу задачи, а не вспоминаем случайный метод.\n\nТакже важно помнить про ловушки: `sort` без compare function сортирует как строки, `map(parseInt)` передает индекс как второй аргумент, sparse arrays могут пропускать callback у некоторых методов, а `reduce` без initialValue падает на пустом массиве.\n\n## Уточняющие вопросы\n\n### 1. Почему для преобразования списка обычно выбираем `map`, а не `forEach`?\n\nОжидаем: кандидат объясняет, что `map` явно возвращает новый массив результатов. `forEach` нужен для побочного действия и не выражает идею преобразования.\n\n### 2. Есть `['1', '2', '3']`, мы вызвали `.map(parseInt)` и получили `[1, NaN, NaN]`. Почему так произошло?\n\nОжидаем: кандидат говорит, что `map` передает callback значение и индекс. `parseInt` воспринимает второй аргумент как radix, поэтому индексы меняют смысл разбора строки.\n\n### 3. Почему `sort` без функции сравнения может поставить `10` перед `2`?\n\nОжидаем: кандидат объясняет, что обычный `sort` сравнивает строковые представления элементов. Для чисел нужна compare function.\n\n## Референсы\n\n- [ru.javascript.info: Методы массивов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F05-array-methods\u002Farticle.md) - учебный обзор методов массивов.\n- [MDN: Array](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Findex.md) - справочник по массивам.\n- [MDN: Array.map](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fmap\u002Findex.md) - детали поведения `map`.\n- [MDN: Array.sort](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fsort\u002Findex.md) - детали поведения `sort`.",{"slug":3028,"title":3029,"baseQuestion":3030,"goodAnswer":3031,"followUps":3032,"references":3042,"programSlug":30,"lessonSlug":30,"order":55,"status":13,"rawBody":3049},"event-loop-promises-async-await-q5-kak-rabotaet-cepochka-then","Как работает цепочка `.then`?","Как работает цепочка `.then` у Promise?","Сначала можно объяснить так: `.then` это не просто \"подписка на результат\", а шаг преобразования будущего результата. Каждый вызов `.then` возвращает новый Promise. Поэтому мы можем выстроить цепочку, где результат одного обработчика становится входом для следующего.\n\nЕсли обработчик возвращает обычное значение, новый Promise становится fulfilled с этим значением, и следующий `.then` получает его. Если обработчик ничего явно не возвращает, дальше пойдет `undefined`. Если обработчик возвращает промис, следующий шаг цепочки не получит сам объект промиса как обычное значение, а дождется его итогового результата. Если обработчик возвращает thenable, он тоже будет воспринят как промисоподобный объект.\n\nЕсли обработчик выбрасывает ошибку, Promise, который вернул этот `.then`, становится rejected, и управление пойдет к ближайшему обработчику ошибки ниже по цепочке. Поэтому цепочка `.then` одновременно решает две задачи: передает успешные значения дальше и превращает ошибки в управляемую rejected-ветку.\n\nОбработчики `.then` выполняются асинхронно через микрозадачи. Даже если исходный Promise уже fulfilled, обработчик не запускается прямо в момент вызова `.then`. Он будет выполнен после текущего синхронного кода.\n\nВажно отличать цепочку от нескольких подписок на один и тот же промис. Если мы пишем `p.then(...)` несколько раз отдельно, все эти обработчики подписаны на один исходный результат. Они не передают значения друг другу. Настоящая цепочка появляется, когда следующий `.then` вызывается на результате предыдущего `.then`.\n\nНа собеседовании хороший ответ показывает не только порядок вызовов, но и смысл: `.then` это способ преобразовать будущий результат и передать его дальше. Если кандидат говорит только \"then выполнится после промиса\", но не упоминает новый Promise, return значения и ожидание возвращенного промиса, понимание цепочки еще неполное.",[3033,3036,3039],{"question":3034,"expected":3035},"Почему два отдельных `.then` на одном и том же Promise получают одно и то же исходное значение?","кандидат говорит, что это две независимые подписки на один промис. Обе подписки получают исходный результат этого промиса. Возвращаемые значения этих обработчиков уходят в разные новые промисы и не попадают друг к другу.",{"question":3037,"expected":3038},"Что получит следующий `.then`, если предыдущий обработчик вернул обычное число?","кандидат объясняет, что число станет успешным результатом нового промиса, который вернул `.then`, и будет передано дальше по цепочке. Следующий обработчик получит именно это число как аргумент.",{"question":3040,"expected":3041},"Что изменится, если обработчик вернул другой Promise?","кандидат говорит, что следующий шаг цепочки дождется завершения этого промиса и получит его результат или ошибку. Это позволяет строить цепочку асинхронных действий без вложенной пирамиды callback.",[3043,3045],{"title":2763,"url":2764,"note":3044},"передача результата между `.then` и отличие цепочки от независимых подписок.",{"title":3046,"url":3047,"note":3048},"MDN: Promise.prototype.then","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fthen\u002Findex.md","поведение `.then` и возвращаемого промиса.","# Q5. Как работает цепочка `.then`?\n\n## Базовый вопрос\n\nКак работает цепочка `.then` у Promise?\n\n## Хороший ответ\n\nСначала можно объяснить так: `.then` это не просто \"подписка на результат\", а шаг преобразования будущего результата. Каждый вызов `.then` возвращает новый Promise. Поэтому мы можем выстроить цепочку, где результат одного обработчика становится входом для следующего.\n\nЕсли обработчик возвращает обычное значение, новый Promise становится fulfilled с этим значением, и следующий `.then` получает его. Если обработчик ничего явно не возвращает, дальше пойдет `undefined`. Если обработчик возвращает промис, следующий шаг цепочки не получит сам объект промиса как обычное значение, а дождется его итогового результата. Если обработчик возвращает thenable, он тоже будет воспринят как промисоподобный объект.\n\nЕсли обработчик выбрасывает ошибку, Promise, который вернул этот `.then`, становится rejected, и управление пойдет к ближайшему обработчику ошибки ниже по цепочке. Поэтому цепочка `.then` одновременно решает две задачи: передает успешные значения дальше и превращает ошибки в управляемую rejected-ветку.\n\nОбработчики `.then` выполняются асинхронно через микрозадачи. Даже если исходный Promise уже fulfilled, обработчик не запускается прямо в момент вызова `.then`. Он будет выполнен после текущего синхронного кода.\n\nВажно отличать цепочку от нескольких подписок на один и тот же промис. Если мы пишем `p.then(...)` несколько раз отдельно, все эти обработчики подписаны на один исходный результат. Они не передают значения друг другу. Настоящая цепочка появляется, когда следующий `.then` вызывается на результате предыдущего `.then`.\n\nНа собеседовании хороший ответ показывает не только порядок вызовов, но и смысл: `.then` это способ преобразовать будущий результат и передать его дальше. Если кандидат говорит только \"then выполнится после промиса\", но не упоминает новый Promise, return значения и ожидание возвращенного промиса, понимание цепочки еще неполное.\n\n## Уточняющие вопросы\n\n### 1. Почему два отдельных `.then` на одном и том же Promise получают одно и то же исходное значение?\n\nОжидаем: кандидат говорит, что это две независимые подписки на один промис. Обе подписки получают исходный результат этого промиса. Возвращаемые значения этих обработчиков уходят в разные новые промисы и не попадают друг к другу.\n\n### 2. Что получит следующий `.then`, если предыдущий обработчик вернул обычное число?\n\nОжидаем: кандидат объясняет, что число станет успешным результатом нового промиса, который вернул `.then`, и будет передано дальше по цепочке. Следующий обработчик получит именно это число как аргумент.\n\n### 3. Что изменится, если обработчик вернул другой Promise?\n\nОжидаем: кандидат говорит, что следующий шаг цепочки дождется завершения этого промиса и получит его результат или ошибку. Это позволяет строить цепочку асинхронных действий без вложенной пирамиды callback.\n\n## Референсы\n\n- [ru.javascript.info: Цепочка промисов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F03-promise-chaining\u002Farticle.md) - передача результата между `.then` и отличие цепочки от независимых подписок.\n- [MDN: Promise.prototype.then](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fthen\u002Findex.md) - поведение `.then` и возвращаемого промиса.",{"slug":3051,"title":3052,"baseQuestion":3053,"goodAnswer":3054,"followUps":3055,"references":3065,"programSlug":31,"lessonSlug":31,"order":55,"status":13,"rawBody":3086},"event-loop-promises-deep-dive-q5-chem-otlichayutsya-all-allsettled-race-i-any","Чем отличаются all, allSettled, race и any?","Что делают `Promise.all`, `Promise.allSettled`, `Promise.race` и `Promise.any`, и чем они отличаются по поведению при успешных результатах и ошибках?","Эти методы нужны, когда мы координируем несколько асинхронных результатов. Выбор зависит от того, какой общий исход нам нужен.\n\n`Promise.all` выбираем, когда нам нужны все успешные результаты. Он возвращает массив результатов в порядке входного iterable. Если один вход отклонился, итоговый Promise отклоняется. При этом остальные уже запущенные операции не отменяются автоматически.\n\n`Promise.allSettled` выбираем, когда нам важна полная картина по всем операциям: кто успешно завершился, кто упал и с какой причиной. Он не проваливает общий результат из-за одной ошибки, а возвращает массив объектов со статусами.\n\n`Promise.race` выбираем, когда важен первый завершившийся исход, неважно успешный или ошибочный. Это полезно для сценариев \"кто первый ответил\" или для timeout-логики.\n\n`Promise.any` выбираем, когда нам нужен первый успешный результат. Ошибки отдельных входов игнорируются до тех пор, пока есть шанс получить успех. Если все входы отклонились, итоговая ошибка будет `AggregateError`.\n\nНа собеседовании важно добавить, что эти методы координируют уже созданные значения и промисы. Они не \"запускают функции\" сами. Если передать функцию вместо результата ее вызова, это будет просто обычное значение.",[3056,3059,3062],{"question":3057,"expected":3058},"Мы грузим профиль, заказы и рекомендации, и рекомендации упали. Почему `allSettled` лучше `all`, если профиль и заказы все равно нужно показать?","кандидат объясняет, что `Promise.allSettled` выбираем, когда операции независимы друг от друга и нам нужен результат каждой операции, даже если часть из них завершилась ошибкой.\n\n`Promise.all` подходит для сценария \"все или ничего\": если один промис отклонился, общий Promise сразу отклоняется, а успешные результаты остальных операций для этого общего результата уже не важны. Это удобно, когда следующий шаг невозможен без полного набора данных. Например, мы собираем страницу только если загрузились и шаблон, и стили, и основные данные.\n\n`Promise.allSettled` подходит для другого сценария: мы хотим дождаться всех операций и потом отдельно посмотреть, какие завершились успешно, а какие упали. В ответе будет массив объектов со статусами `fulfilled` или `rejected`. У успешных элементов будет `value`, у ошибочных - `reason`.\n\nПрактический пример: мы грузим несколько независимых блоков интерфейса. Если блок рекомендаций не загрузился, это не должно скрывать профиль пользователя и историю заказов. Тогда `allSettled` позволяет показать успешные блоки, а рядом с упавшими блоками отрисовать ошибку или кнопку повтора.\n\nХороший ответ должен отдельно проговорить, что `allSettled` не исправляет ошибки и не отменяет операции. Он просто не превращает первую ошибку в общий провал всей группы, а дает нам полную картину по каждому входному промису.",{"question":3060,"expected":3061},"Первый Promise отклонился, а второй позже успешно вернул данные. Что сделают `race` и `any`?","кандидат объясняет, что `Promise.race` смотрит на первый завершившийся промис. Ему не важно, чем он завершился: успехом или ошибкой. Если первым был успешный Promise, общий результат будет успешным. Если первым был отклоненный Promise, общий результат сразу станет ошибкой.\n\n`Promise.any` устроен иначе: он ищет первый успешный результат. Если какой-то промис отклонился раньше всех, `any` не считает это победой и продолжает ждать другой промис, который завершится успешно. Ошибки отдельных промисов игнорируются до тех пор, пока остается шанс получить хотя бы один успешный результат.\n\nЕсли все входные промисы отклонились, `Promise.any` тоже отклонится, но не с одной первой ошибкой, а с `AggregateError`. Внутри этой ошибки есть массив `errors`, где лежат причины отклонения входных промисов.\n\nПрактически `race` выбираем для сценария \"важно, что случилось первым\". Например, мы соревнуем запрос с timeout-промисом: если таймер отклонился раньше ответа, вся операция должна упасть по timeout.\n\n`any` выбираем для сценария \"нужен любой успешный вариант\". Например, мы пробуем получить данные из нескольких зеркал или загрузить первый доступный ресурс. Ранняя ошибка одного источника не должна ломать результат, если другой источник может успешно ответить позже.\n\nХороший ответ должен не смешивать слова \"первый\" и \"успешный\": `race` - первый завершившийся исход, `any` - первый успешный исход.",{"question":3063,"expected":3064},"У нас есть async-функции `f` и `g`. Почему `Promise.all([f, g])` не запускает их, а `Promise.all([f(), g()])` запускает?","кандидат объясняет, что `Promise.all` не является планировщиком задач и не вызывает элементы массива как функции. Он принимает iterable уже готовых значений: промисов, thenable или обычных значений. Дальше он ждет промисы и собирает их результаты.\n\nЕсли мы передали `[f, g]`, где `f` и `g` - функции, то для `Promise.all` это просто два обычных значения. Он не знает, что их надо вызвать. Поэтому асинхронная работа внутри `f` и `g` не начнется, а итоговый массив будет содержать сами функции как значения.\n\nЧтобы работа стартовала, функции нужно вызвать до передачи в `Promise.all`: `Promise.all([f(), g()])`. В этот момент каждая функция запускается, возвращает Promise, и уже эти Promise попадают в `Promise.all`.\n\nЕсли `f` и `g` независимы, вызовы `f()` и `g()` в массиве создают два промиса сразу, поэтому операции могут идти параллельно. Если написать `await f()` перед вызовом `g()`, второй запуск начнется только после первого результата, и это уже будет последовательное выполнение.\n\nХороший ответ должен отделять две вещи: запуск операции происходит при вызове функции, а `Promise.all` только координирует результаты уже созданных промисов. Это ровно тот нюанс, который референсы подчеркивают для async-функций: в `Promise.all` надо передавать возвращенные промисы, а не сами функции.",[3066,3070,3074,3078,3082],{"title":3067,"url":3068,"note":3069},"ru.javascript.info: Promise API","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F05-promise-api\u002Farticle.md","обзор `Promise.all`, `allSettled`, `race` и `any`.",{"title":3071,"url":3072,"note":3073},"MDN: Promise.all","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fall\u002Findex.md","поведение `Promise.all`.",{"title":3075,"url":3076,"note":3077},"MDN: Promise.allSettled","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fallsettled\u002Findex.md","поведение `Promise.allSettled`.",{"title":3079,"url":3080,"note":3081},"MDN: Promise.race","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Frace\u002Findex.md","поведение `Promise.race`.",{"title":3083,"url":3084,"note":3085},"MDN: Promise.any","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fany\u002Findex.md","поведение `Promise.any` и `AggregateError`.","# Q5. Чем отличаются all, allSettled, race и any?\n\n## Базовый вопрос\n\nЧто делают `Promise.all`, `Promise.allSettled`, `Promise.race` и `Promise.any`, и чем они отличаются по поведению при успешных результатах и ошибках?\n\n## Хороший ответ\n\nЭти методы нужны, когда мы координируем несколько асинхронных результатов. Выбор зависит от того, какой общий исход нам нужен.\n\n`Promise.all` выбираем, когда нам нужны все успешные результаты. Он возвращает массив результатов в порядке входного iterable. Если один вход отклонился, итоговый Promise отклоняется. При этом остальные уже запущенные операции не отменяются автоматически.\n\n`Promise.allSettled` выбираем, когда нам важна полная картина по всем операциям: кто успешно завершился, кто упал и с какой причиной. Он не проваливает общий результат из-за одной ошибки, а возвращает массив объектов со статусами.\n\n`Promise.race` выбираем, когда важен первый завершившийся исход, неважно успешный или ошибочный. Это полезно для сценариев \"кто первый ответил\" или для timeout-логики.\n\n`Promise.any` выбираем, когда нам нужен первый успешный результат. Ошибки отдельных входов игнорируются до тех пор, пока есть шанс получить успех. Если все входы отклонились, итоговая ошибка будет `AggregateError`.\n\nНа собеседовании важно добавить, что эти методы координируют уже созданные значения и промисы. Они не \"запускают функции\" сами. Если передать функцию вместо результата ее вызова, это будет просто обычное значение.\n\n## Уточняющие вопросы\n\n### 1. Мы грузим профиль, заказы и рекомендации, и рекомендации упали. Почему `allSettled` лучше `all`, если профиль и заказы все равно нужно показать?\n\nОжидаем: кандидат объясняет, что `Promise.allSettled` выбираем, когда операции независимы друг от друга и нам нужен результат каждой операции, даже если часть из них завершилась ошибкой.\n\n`Promise.all` подходит для сценария \"все или ничего\": если один промис отклонился, общий Promise сразу отклоняется, а успешные результаты остальных операций для этого общего результата уже не важны. Это удобно, когда следующий шаг невозможен без полного набора данных. Например, мы собираем страницу только если загрузились и шаблон, и стили, и основные данные.\n\n`Promise.allSettled` подходит для другого сценария: мы хотим дождаться всех операций и потом отдельно посмотреть, какие завершились успешно, а какие упали. В ответе будет массив объектов со статусами `fulfilled` или `rejected`. У успешных элементов будет `value`, у ошибочных - `reason`.\n\nПрактический пример: мы грузим несколько независимых блоков интерфейса. Если блок рекомендаций не загрузился, это не должно скрывать профиль пользователя и историю заказов. Тогда `allSettled` позволяет показать успешные блоки, а рядом с упавшими блоками отрисовать ошибку или кнопку повтора.\n\nХороший ответ должен отдельно проговорить, что `allSettled` не исправляет ошибки и не отменяет операции. Он просто не превращает первую ошибку в общий провал всей группы, а дает нам полную картину по каждому входному промису.\n\n### 2. Первый Promise отклонился, а второй позже успешно вернул данные. Что сделают `race` и `any`?\n\nОжидаем: кандидат объясняет, что `Promise.race` смотрит на первый завершившийся промис. Ему не важно, чем он завершился: успехом или ошибкой. Если первым был успешный Promise, общий результат будет успешным. Если первым был отклоненный Promise, общий результат сразу станет ошибкой.\n\n`Promise.any` устроен иначе: он ищет первый успешный результат. Если какой-то промис отклонился раньше всех, `any` не считает это победой и продолжает ждать другой промис, который завершится успешно. Ошибки отдельных промисов игнорируются до тех пор, пока остается шанс получить хотя бы один успешный результат.\n\nЕсли все входные промисы отклонились, `Promise.any` тоже отклонится, но не с одной первой ошибкой, а с `AggregateError`. Внутри этой ошибки есть массив `errors`, где лежат причины отклонения входных промисов.\n\nПрактически `race` выбираем для сценария \"важно, что случилось первым\". Например, мы соревнуем запрос с timeout-промисом: если таймер отклонился раньше ответа, вся операция должна упасть по timeout.\n\n`any` выбираем для сценария \"нужен любой успешный вариант\". Например, мы пробуем получить данные из нескольких зеркал или загрузить первый доступный ресурс. Ранняя ошибка одного источника не должна ломать результат, если другой источник может успешно ответить позже.\n\nХороший ответ должен не смешивать слова \"первый\" и \"успешный\": `race` - первый завершившийся исход, `any` - первый успешный исход.\n\n### 3. У нас есть async-функции `f` и `g`. Почему `Promise.all([f, g])` не запускает их, а `Promise.all([f(), g()])` запускает?\n\nОжидаем: кандидат объясняет, что `Promise.all` не является планировщиком задач и не вызывает элементы массива как функции. Он принимает iterable уже готовых значений: промисов, thenable или обычных значений. Дальше он ждет промисы и собирает их результаты.\n\nЕсли мы передали `[f, g]`, где `f` и `g` - функции, то для `Promise.all` это просто два обычных значения. Он не знает, что их надо вызвать. Поэтому асинхронная работа внутри `f` и `g` не начнется, а итоговый массив будет содержать сами функции как значения.\n\nЧтобы работа стартовала, функции нужно вызвать до передачи в `Promise.all`: `Promise.all([f(), g()])`. В этот момент каждая функция запускается, возвращает Promise, и уже эти Promise попадают в `Promise.all`.\n\nЕсли `f` и `g` независимы, вызовы `f()` и `g()` в массиве создают два промиса сразу, поэтому операции могут идти параллельно. Если написать `await f()` перед вызовом `g()`, второй запуск начнется только после первого результата, и это уже будет последовательное выполнение.\n\nХороший ответ должен отделять две вещи: запуск операции происходит при вызове функции, а `Promise.all` только координирует результаты уже созданных промисов. Это ровно тот нюанс, который референсы подчеркивают для async-функций: в `Promise.all` надо передавать возвращенные промисы, а не сами функции.\n\n## Референсы\n\n- [ru.javascript.info: Promise API](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F05-promise-api\u002Farticle.md) - обзор `Promise.all`, `allSettled`, `race` и `any`.\n- [MDN: Promise.all](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fall\u002Findex.md) - поведение `Promise.all`.\n- [MDN: Promise.allSettled](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fallsettled\u002Findex.md) - поведение `Promise.allSettled`.\n- [MDN: Promise.race](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Frace\u002Findex.md) - поведение `Promise.race`.\n- [MDN: Promise.any](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fany\u002Findex.md) - поведение `Promise.any` и `AggregateError`.",{"slug":3088,"title":2639,"baseQuestion":2639,"goodAnswer":2640,"followUps":3089,"references":3093,"programSlug":59,"lessonSlug":59,"order":55,"status":13,"rawBody":2666},"mock-interview-javascript-core-q5-kak-rabotaet-privedenie-k-boolean",[3090,3091,3092],{"question":2643,"expected":2644},{"question":2646,"expected":2647},{"question":2649,"expected":2650},[3094,3095,3096,3097],{"title":2653,"url":2654,"note":2655},{"title":2370,"url":2371,"note":2657},{"title":2659,"url":2660,"note":2661},{"title":2663,"url":2664,"note":2665},{"slug":3099,"title":3100,"baseQuestion":3100,"goodAnswer":3101,"followUps":3102,"references":3112,"programSlug":18,"lessonSlug":18,"order":55,"status":13,"rawBody":3129},"objects-prototypes-classes-q5-kak-rabotayut-metody-ogranicheniya-obekta","Как работают методы ограничения объекта?","Флаги `writable`, `enumerable` и `configurable` работают на уровне конкретного свойства. Методы `Object.preventExtensions`, `Object.seal` и `Object.freeze` ограничивают объект целиком, но делают это через правила для объекта и его существующих свойств.\n\n`Object.preventExtensions(obj)` запрещает добавлять новые собственные свойства в объект. Уже существующие свойства при этом сами по себе не становятся non-writable или non-configurable.\n\n`Object.seal(obj)` запрещает добавлять и удалять свойства. Он делает объект non-extensible и устанавливает `configurable: false` для существующих собственных свойств. Значения writable-свойств все еще можно менять.\n\n`Object.freeze(obj)` идет дальше: запрещает добавлять и удалять свойства, а для существующих свойств данных делает `configurable: false` и `writable: false`. Поэтому обычные data properties нельзя менять через присваивание.\n\nВажно: эти методы работают поверхностно. Если свойство хранит ссылку на вложенный объект, сам вложенный объект не становится автоматически замороженным, если его отдельно не заморозить.\n\nНа собеседовании удобно мыслить лестницей ограничений: `preventExtensions` запрещает новые свойства, `seal` еще запрещает удаление и перенастройку существующих, `freeze` еще запрещает менять значения data properties.",[3103,3106,3109],{"question":3104,"expected":3105},"После `Object.preventExtensions` можно менять уже существующие свойства?","кандидат говорит, что да, если сами свойства позволяют это. `preventExtensions` запрещает добавлять новые свойства, но не делает автоматически все существующие свойства read-only.\n\nХороший ответ отделяет extensibility объекта от `writable` у конкретного свойства.",{"question":3107,"expected":3108},"Чем `Object.seal` отличается от `Object.freeze`?","кандидат говорит, что оба запрещают добавлять и удалять свойства, но `freeze` дополнительно делает data properties non-writable. После `seal` значение writable-свойства еще можно менять.\n\nЭто ключевое практическое отличие.",{"question":3110,"expected":3111},"Почему `freeze` не всегда означает глубокую неизменяемость данных?","кандидат говорит, что `Object.freeze` работает поверхностно. Если внутри свойства лежит объект, замораживается ссылка на этот объект как значение свойства, но сам вложенный объект остается изменяемым, пока его отдельно не заморозили.\n\nХороший ответ не продает `freeze` как полную защиту всей структуры данных.",[3113,3115,3119,3121,3125],{"title":2541,"url":2542,"note":3114},"глобальное запечатывание объекта, `preventExtensions`, `seal`, `freeze`.",{"title":3116,"url":3117,"note":3118},"MDN: Object.preventExtensions","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fpreventextensions\u002Findex.md","запрет расширения объекта.",{"title":3116,"url":3117,"note":3120},"базовый уровень ограничения расширяемости.",{"title":3122,"url":3123,"note":3124},"MDN: Object.seal","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fseal\u002Findex.md","запечатывание объекта.",{"title":3126,"url":3127,"note":3128},"MDN: Object.freeze","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Ffreeze\u002Findex.md","заморозка объекта.","# Q5. Как работают методы ограничения объекта?\n\n## Базовый вопрос\n\nКак работают методы ограничения объекта?\n\n## Хороший ответ\n\nФлаги `writable`, `enumerable` и `configurable` работают на уровне конкретного свойства. Методы `Object.preventExtensions`, `Object.seal` и `Object.freeze` ограничивают объект целиком, но делают это через правила для объекта и его существующих свойств.\n\n`Object.preventExtensions(obj)` запрещает добавлять новые собственные свойства в объект. Уже существующие свойства при этом сами по себе не становятся non-writable или non-configurable.\n\n`Object.seal(obj)` запрещает добавлять и удалять свойства. Он делает объект non-extensible и устанавливает `configurable: false` для существующих собственных свойств. Значения writable-свойств все еще можно менять.\n\n`Object.freeze(obj)` идет дальше: запрещает добавлять и удалять свойства, а для существующих свойств данных делает `configurable: false` и `writable: false`. Поэтому обычные data properties нельзя менять через присваивание.\n\nВажно: эти методы работают поверхностно. Если свойство хранит ссылку на вложенный объект, сам вложенный объект не становится автоматически замороженным, если его отдельно не заморозить.\n\nНа собеседовании удобно мыслить лестницей ограничений: `preventExtensions` запрещает новые свойства, `seal` еще запрещает удаление и перенастройку существующих, `freeze` еще запрещает менять значения data properties.\n\n## Уточняющие вопросы\n\n### 1. После `Object.preventExtensions` можно менять уже существующие свойства?\n\nОжидаем: кандидат говорит, что да, если сами свойства позволяют это. `preventExtensions` запрещает добавлять новые свойства, но не делает автоматически все существующие свойства read-only.\n\nХороший ответ отделяет extensibility объекта от `writable` у конкретного свойства.\n\n### 2. Чем `Object.seal` отличается от `Object.freeze`?\n\nОжидаем: кандидат говорит, что оба запрещают добавлять и удалять свойства, но `freeze` дополнительно делает data properties non-writable. После `seal` значение writable-свойства еще можно менять.\n\nЭто ключевое практическое отличие.\n\n### 3. Почему `freeze` не всегда означает глубокую неизменяемость данных?\n\nОжидаем: кандидат говорит, что `Object.freeze` работает поверхностно. Если внутри свойства лежит объект, замораживается ссылка на этот объект как значение свойства, но сам вложенный объект остается изменяемым, пока его отдельно не заморозили.\n\nХороший ответ не продает `freeze` как полную защиту всей структуры данных.\n\n## Референсы\n\n- [Learn JS: Флаги и дескрипторы свойств](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F07-object-properties\u002F01-property-descriptors\u002Farticle.md) - глобальное запечатывание объекта, `preventExtensions`, `seal`, `freeze`.\n- [MDN: Object.preventExtensions](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fpreventextensions\u002Findex.md) - запрет расширения объекта.\n- [MDN: Object.preventExtensions](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fpreventextensions\u002Findex.md) - базовый уровень ограничения расширяемости.\n- [MDN: Object.seal](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fseal\u002Findex.md) - запечатывание объекта.\n- [MDN: Object.freeze](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Ffreeze\u002Findex.md) - заморозка объекта.",{"slug":3131,"title":3132,"baseQuestion":3132,"goodAnswer":3133,"followUps":3134,"references":3144,"programSlug":50,"lessonSlug":50,"order":55,"status":13,"rawBody":3151},"recursion-q5-chto-takoe-hvostovaya-rekursiya","Что такое хвостовая рекурсия?","Хвостовая рекурсия это рекурсия, где рекурсивный вызов является последним действием функции. После него текущему вызову уже нечего считать, умножать, складывать или проверять. Он просто возвращает результат внутреннего вызова.\n\nНапример, `return f(n - 1)` находится в хвостовой позиции. А `return n * f(n - 1)` не находится, потому что после возврата `f(n - 1)` текущий вызов еще должен выполнить умножение.\n\nТеоретически хвостовой вызов можно оптимизировать: движок может не хранить старый стековый кадр, если после вызова к нему уже не нужно возвращаться. В спецификационных обсуждениях это называется proper tail calls.\n\nПрактический нюанс для JavaScript: на это нельзя спокойно полагаться во всех популярных браузерах и средах. Поэтому хвостовая форма полезна как способ думать об аккумуляторе и состоянии, но для очень глубокой рекурсии в реальном коде часто выбирают цикл, явный стек или trampoline.",[3135,3138,3141],{"question":3136,"expected":3137},"Чем `return f(n - 1)` отличается от `return n + f(n - 1)`?","кандидат говорит, что в первом случае после внутреннего вызова делать уже нечего, а во втором внешний вызов обязан дождаться результата и выполнить сложение.",{"question":3139,"expected":3140},"Зачем в хвостовой рекурсии часто используют аккумулятор?","кандидат объясняет, что промежуточный результат нужно передавать вперед в параметры, чтобы после рекурсивного вызова не оставалось дополнительной работы.",{"question":3142,"expected":3143},"Почему хвостовая рекурсия не делает любой рекурсивный код автоматически безопасным?","кандидат говорит, что оптимизация хвостовых вызовов зависит от реализации и условий выполнения, поэтому в реальном JavaScript нельзя считать ее универсальной защитой от переполнения стека.",[3145,3147],{"title":2284,"url":2285,"note":3146},"tail calls, TCO, trampoline и ограничения глубины стека.",{"title":3148,"url":3149,"note":3150},"ECMAScript: Tail Position Calls","https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-tail-position-calls","формальная база для хвостовой позиции.","# Q5. Что такое хвостовая рекурсия?\n\n## Базовый вопрос\n\nЧто такое хвостовая рекурсия?\n\n## Хороший ответ\n\nХвостовая рекурсия это рекурсия, где рекурсивный вызов является последним действием функции. После него текущему вызову уже нечего считать, умножать, складывать или проверять. Он просто возвращает результат внутреннего вызова.\n\nНапример, `return f(n - 1)` находится в хвостовой позиции. А `return n * f(n - 1)` не находится, потому что после возврата `f(n - 1)` текущий вызов еще должен выполнить умножение.\n\nТеоретически хвостовой вызов можно оптимизировать: движок может не хранить старый стековый кадр, если после вызова к нему уже не нужно возвращаться. В спецификационных обсуждениях это называется proper tail calls.\n\nПрактический нюанс для JavaScript: на это нельзя спокойно полагаться во всех популярных браузерах и средах. Поэтому хвостовая форма полезна как способ думать об аккумуляторе и состоянии, но для очень глубокой рекурсии в реальном коде часто выбирают цикл, явный стек или trampoline.\n\n## Уточняющие вопросы\n\n### 1. Чем `return f(n - 1)` отличается от `return n + f(n - 1)`?\n\nОжидаем: кандидат говорит, что в первом случае после внутреннего вызова делать уже нечего, а во втором внешний вызов обязан дождаться результата и выполнить сложение.\n\n### 2. Зачем в хвостовой рекурсии часто используют аккумулятор?\n\nОжидаем: кандидат объясняет, что промежуточный результат нужно передавать вперед в параметры, чтобы после рекурсивного вызова не оставалось дополнительной работы.\n\n### 3. Почему хвостовая рекурсия не делает любой рекурсивный код автоматически безопасным?\n\nОжидаем: кандидат говорит, что оптимизация хвостовых вызовов зависит от реализации и условий выполнения, поэтому в реальном JavaScript нельзя считать ее универсальной защитой от переполнения стека.\n\n## Референсы\n\n- [Вы не знаете JS: ES6 и дальше — глава 7 Meta Programming](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fes6%20%26%20beyond\u002Fch7.md) - tail calls, TCO, trampoline и ограничения глубины стека.\n- [ECMAScript: Tail Position Calls](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-tail-position-calls) - формальная база для хвостовой позиции.",{"slug":3153,"title":3154,"baseQuestion":3154,"goodAnswer":3155,"followUps":3156,"references":3166,"programSlug":41,"lessonSlug":41,"order":55,"status":13,"rawBody":3181},"rendering-dom-events-forms-q5-chto-takoe-virtual-dom","Что такое Virtual DOM?","Virtual DOM - это описание интерфейса в памяти, обычно в виде JavaScript-объектов. Это не настоящий DOM-узел браузера. Если сказать проще, фреймворк сначала строит \"черновик\" того, каким должен быть UI, а потом решает, какие реальные DOM-изменения нужны.\n\nГлавная польза Virtual DOM не в том, что он делает DOM бесплатным. Он помогает отделить описание интерфейса от прямых операций с браузерным DOM. Фреймворк может сравнить новое описание со старым и применить к настоящему DOM только нужные изменения.\n\nПосле изменения настоящего DOM браузер все равно делает свою работу: пересчитывает стили, layout, paint и compositing, если это нужно. Поэтому Virtual DOM не отменяет rendering pipeline браузера. Он находится уровнем выше: помогает подготовить и сгруппировать изменения, которые потом попадут в реальный DOM.\n\nНа собеседовании важно не путать три вещи:\n\n- DOM - браузерная модель документа.\n- Virtual DOM - структура данных фреймворка в JavaScript.\n- Render tree - внутренняя браузерная структура видимых элементов после учета CSS.\n\nХороший кандидат должен сказать: Virtual DOM - это не магия и не копия экрана. Это промежуточное описание UI, которое помогает управлять обновлениями настоящего DOM.",[3157,3160,3163],{"question":3158,"expected":3159},"Почему объект с полем `type: 'div'` еще не является DOM-элементом?","кандидат говорит, что это только описание. Настоящий элемент появляется, когда renderer или наш код вызывает браузерный API и вставляет узел в документ.",{"question":3161,"expected":3162},"Почему после Virtual DOM браузер все равно может делать layout и paint?","кандидат объясняет, что layout и paint зависят от настоящего DOM и CSS. Если patch изменил реальный DOM или стили, браузеру все равно нужно обновить видимый результат.",{"question":3164,"expected":3165},"Чем Virtual DOM отличается от Shadow DOM?","кандидат говорит, что Virtual DOM - это структура данных фреймворка для расчета обновлений. Shadow DOM - это браузерный механизм для отдельного DOM-дерева и инкапсуляции стилей внутри компонента.",[3167,3171,3175,3179],{"title":3168,"url":3169,"note":3170},"Vue: Rendering Mechanism","https:\u002F\u002Fvuejs.org\u002Fguide\u002Fextras\u002Frendering-mechanism","официальный разбор Virtual DOM, render pipeline и patch во Vue.",{"title":3172,"url":3173,"note":3174},"React: createElement","https:\u002F\u002Freact.dev\u002Freference\u002Freact\u002FcreateElement","React element как описание UI, которое само не создает DOM-узел.",{"title":3176,"url":3177,"note":3178},"React: Render and Commit","https:\u002F\u002Freact.dev\u002Flearn\u002Frender-and-commit","разделение вычисления UI и применения изменений к DOM.",{"title":1979,"url":1980,"note":3180},"browser render tree, layout и paint как отдельная браузерная цепочка.","# Q5. Что такое Virtual DOM?\n\n## Базовый вопрос\n\nЧто такое Virtual DOM?\n\n## Хороший ответ\n\nVirtual DOM - это описание интерфейса в памяти, обычно в виде JavaScript-объектов. Это не настоящий DOM-узел браузера. Если сказать проще, фреймворк сначала строит \"черновик\" того, каким должен быть UI, а потом решает, какие реальные DOM-изменения нужны.\n\nГлавная польза Virtual DOM не в том, что он делает DOM бесплатным. Он помогает отделить описание интерфейса от прямых операций с браузерным DOM. Фреймворк может сравнить новое описание со старым и применить к настоящему DOM только нужные изменения.\n\nПосле изменения настоящего DOM браузер все равно делает свою работу: пересчитывает стили, layout, paint и compositing, если это нужно. Поэтому Virtual DOM не отменяет rendering pipeline браузера. Он находится уровнем выше: помогает подготовить и сгруппировать изменения, которые потом попадут в реальный DOM.\n\nНа собеседовании важно не путать три вещи:\n\n- DOM - браузерная модель документа.\n- Virtual DOM - структура данных фреймворка в JavaScript.\n- Render tree - внутренняя браузерная структура видимых элементов после учета CSS.\n\nХороший кандидат должен сказать: Virtual DOM - это не магия и не копия экрана. Это промежуточное описание UI, которое помогает управлять обновлениями настоящего DOM.\n\n## Уточняющие вопросы\n\n### 1. Почему объект с полем `type: 'div'` еще не является DOM-элементом?\n\nОжидаем: кандидат говорит, что это только описание. Настоящий элемент появляется, когда renderer или наш код вызывает браузерный API и вставляет узел в документ.\n\n### 2. Почему после Virtual DOM браузер все равно может делать layout и paint?\n\nОжидаем: кандидат объясняет, что layout и paint зависят от настоящего DOM и CSS. Если patch изменил реальный DOM или стили, браузеру все равно нужно обновить видимый результат.\n\n### 3. Чем Virtual DOM отличается от Shadow DOM?\n\nОжидаем: кандидат говорит, что Virtual DOM - это структура данных фреймворка для расчета обновлений. Shadow DOM - это браузерный механизм для отдельного DOM-дерева и инкапсуляции стилей внутри компонента.\n\n## Референсы\n\n- [Vue: Rendering Mechanism](https:\u002F\u002Fvuejs.org\u002Fguide\u002Fextras\u002Frendering-mechanism) - официальный разбор Virtual DOM, render pipeline и patch во Vue.\n- [React: createElement](https:\u002F\u002Freact.dev\u002Freference\u002Freact\u002FcreateElement) - React element как описание UI, которое само не создает DOM-узел.\n- [React: Render and Commit](https:\u002F\u002Freact.dev\u002Flearn\u002Frender-and-commit) - разделение вычисления UI и применения изменений к DOM.\n- [MDN: Critical rendering path](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fperformance\u002Fguides\u002Fcritical_rendering_path\u002Findex.md) - browser render tree, layout и paint как отдельная браузерная цепочка.",{"slug":3183,"title":3184,"baseQuestion":3185,"goodAnswer":3186,"followUps":3187,"references":3197,"programSlug":19,"lessonSlug":19,"order":55,"status":13,"rawBody":3208},"scope-closures-deep-dive-q5-kak-rabotaet-hoisting","Как работает hoisting?","Как работает hoisting в JavaScript?","Hoisting означает, что объявления обрабатываются на этапе подготовки области видимости до выполнения строк кода. Поэтому некоторые имена доступны раньше, чем мы видим их объявление в тексте.\n\nДля `var` поднимается объявление, но не присваивание. Поэтому имя уже существует и имеет значение `undefined`, пока выполнение не дошло до строки присваивания.\n\nДля function declaration поднимается и имя, и тело функции. Поэтому такую функцию обычно можно вызвать до строки объявления.\n\nFunction expression ведет себя иначе. Если функцию кладут в переменную, поднимается только объявление переменной по правилам `var`, `let` или `const`. Само значение функции появляется только когда выполнение дошло до выражения.\n\n`let` и `const` тоже имеют подготовленную привязку, но до строки инициализации находятся в TDZ. Поэтому читать их раньше нельзя, будет `ReferenceError`, а не `undefined`.\n\nГлавная мысль: hoisting не значит, что JavaScript физически переставляет строки. Лучше думать так: сначала создаются привязки, потом код выполняется сверху вниз.",[3188,3191,3194],{"question":3189,"expected":3190},"Почему чтение `var a` до строки `var a = 2` дает `undefined`, а не `2`?","кандидат говорит, что объявление `var a` подготовлено заранее, но присваивание `a = 2` остается на своем месте. До выполнения этой строки значение еще не записано.",{"question":3192,"expected":3193},"Почему function declaration можно вызвать до объявления, а function expression в переменной обычно нельзя?","кандидат разделяет объявление функции и присваивание функции в переменную. Function declaration создается на этапе подготовки вместе с телом, а Function Expression создает значение функции только во время выполнения строки.",{"question":3195,"expected":3196},"Почему смешивание `var` и function declaration с одним именем часто плохо читается?","кандидат объясняет, что такие объявления обрабатываются в одной области и могут перекрывать ожидания о том, какое значение будет у имени в конкретный момент. Хороший ответ говорит не только \"так можно\", но и что на интервью нужно уметь разложить код на подготовку объявлений и выполнение присваиваний.",[3198,3202,3204],{"title":3199,"url":3200,"note":3201},"YDKJS: Глава 4. Поднятие переменных Hoisting","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch4.md","разделение объявления и присваивания, приоритет function declaration.",{"title":1865,"url":1866,"note":3203},"особенности `var` и hoisting.",{"title":3205,"url":3206,"note":3207},"MDN: Hoisting","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Fhoisting\u002Findex.md","термин hoisting и различия между объявлениями.","# Q5. Как работает hoisting?\n\n## Базовый вопрос\n\nКак работает hoisting в JavaScript?\n\n## Хороший ответ\n\nHoisting означает, что объявления обрабатываются на этапе подготовки области видимости до выполнения строк кода. Поэтому некоторые имена доступны раньше, чем мы видим их объявление в тексте.\n\nДля `var` поднимается объявление, но не присваивание. Поэтому имя уже существует и имеет значение `undefined`, пока выполнение не дошло до строки присваивания.\n\nДля function declaration поднимается и имя, и тело функции. Поэтому такую функцию обычно можно вызвать до строки объявления.\n\nFunction expression ведет себя иначе. Если функцию кладут в переменную, поднимается только объявление переменной по правилам `var`, `let` или `const`. Само значение функции появляется только когда выполнение дошло до выражения.\n\n`let` и `const` тоже имеют подготовленную привязку, но до строки инициализации находятся в TDZ. Поэтому читать их раньше нельзя, будет `ReferenceError`, а не `undefined`.\n\nГлавная мысль: hoisting не значит, что JavaScript физически переставляет строки. Лучше думать так: сначала создаются привязки, потом код выполняется сверху вниз.\n\n## Уточняющие вопросы\n\n### 1. Почему чтение `var a` до строки `var a = 2` дает `undefined`, а не `2`?\n\nОжидаем: кандидат говорит, что объявление `var a` подготовлено заранее, но присваивание `a = 2` остается на своем месте. До выполнения этой строки значение еще не записано.\n\n### 2. Почему function declaration можно вызвать до объявления, а function expression в переменной обычно нельзя?\n\nОжидаем: кандидат разделяет объявление функции и присваивание функции в переменную. Function declaration создается на этапе подготовки вместе с телом, а Function Expression создает значение функции только во время выполнения строки.\n\n### 3. Почему смешивание `var` и function declaration с одним именем часто плохо читается?\n\nОжидаем: кандидат объясняет, что такие объявления обрабатываются в одной области и могут перекрывать ожидания о том, какое значение будет у имени в конкретный момент. Хороший ответ говорит не только \"так можно\", но и что на интервью нужно уметь разложить код на подготовку объявлений и выполнение присваиваний.\n\n## Референсы\n\n- [YDKJS: Глава 4. Поднятие переменных Hoisting](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch4.md) - разделение объявления и присваивания, приоритет function declaration.\n- [Learn JS: Устаревшее ключевое слово var](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F04-var\u002Farticle.md) - особенности `var` и hoisting.\n- [MDN: Hoisting](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Fhoisting\u002Findex.md) - термин hoisting и различия между объявлениями.",{"slug":3210,"title":3211,"baseQuestion":3211,"goodAnswer":3212,"followUps":3213,"references":3223,"programSlug":20,"lessonSlug":20,"order":55,"status":13,"rawBody":3239},"scope-hoisting-closures-this-q5-hoisting","Что такое hoisting в JavaScript?","Hoisting - это разговорное название для поведения, при котором JavaScript заранее обрабатывает объявления в области видимости перед выполнением строк кода.\n\nВажно: движок не берет наши строки и физически не переносит их наверх. Правильнее думать так: перед выполнением кода создается лексическое окружение, и в нем заранее появляются привязки для объявлений. А вот присваивания и обычные выражения выполняются там, где они написаны.\n\nКлючевые мысли:\n\n- `var` создает привязку на уровне функции или script и сразу получает значение `undefined`. Поэтому имя уже доступно до строки объявления, но реального присвоенного значения там еще нет.\n- `let` и `const` тоже известны движку заранее в своей области видимости, но до выполнения строки объявления находятся в TDZ. Поэтому обращаться к ним до объявления нельзя.\n- Function declaration обычно создается и инициализируется как функция на этапе подготовки области видимости. Поэтому такую функцию часто можно вызвать до места объявления.\n- Function expression и стрелочная функция, записанная в переменную, создаются только когда выполнение доходит до выражения. До этого момента работает только поведение самой переменной: `let` и `const` дают TDZ, `var` дает `undefined`.\n- Hoisting всегда связан с конкретной областью видимости. `var` внутри функции не всплывает на уровень всей программы, а function declaration внутри блока в strict mode видна в пределах блока.\n\nГлавная мысль: hoisting объясняет, почему имя может быть известно раньше строки объявления, но это не значит, что значение уже готово.",[3214,3217,3220],{"question":3215,"expected":3216},"Почему мы можем обратиться к `var` до строки объявления, но значение там будет `undefined`?","кандидат говорит, что объявление `var` обрабатывается заранее в рамках своей функции или script, поэтому имя уже существует. Но присваивание значения не выполняется заранее, оно остается на своей строке. До этой строки у переменной значение `undefined`.\n\nХороший ответ отделяет объявление от присваивания. Слабый ответ: \"`var` поднялся вместе со значением\".",{"question":3218,"expected":3219},"Почему с `let` и `const` нельзя работать до строки объявления, хотя движок уже знает про это имя?","кандидат говорит, что `let` и `const` создают привязку заранее, но до выполнения строки объявления она находится в TDZ. В этот период имя уже занято в своей области видимости, но обращаться к нему нельзя.\n\nХороший ответ не говорит \"`let` и `const` не hoist-ятся\". Точнее сказать: они hoist-ятся как привязки, но не инициализируются значением `undefined`, как `var`.",{"question":3221,"expected":3222},"Почему `function declaration` обычно можно вызвать до объявления, а стрелочную функцию, записанную в переменную, нет?","кандидат разделяет declaration и expression. Function declaration создается и инициализируется как функция на этапе подготовки области видимости. Стрелочная функция, записанная в переменную, является expression: сама функция появится только когда выполнение дойдет до этой строки.\n\nДальше все зависит от переменной, куда мы положили стрелку. Если это `let` или `const`, до строки объявления будет TDZ. Если это `var`, имя будет доступно раньше, но там будет `undefined`, а не функция.\n\nХороший ответ не сводит все к фразе \"стрелки не hoist-ятся\". Точнее: hoisting относится к привязке переменной, а не к готовой стрелочной функции как значению.",[3224,3226,3228,3230,3233,3235],{"title":1865,"url":1866,"note":3225},"hoisting для `var`, разница между объявлением и присваиванием.",{"title":2202,"url":2203,"note":3227},"Function Declaration против Function Expression и момент создания функции.",{"title":1861,"url":1862,"note":3229},"лексическое окружение, состояние `Uninitialized` и подготовка объявлений.",{"title":3231,"url":3200,"note":3232},"YDKJS: Глава 4. Поднятие","объявления обрабатываются до выполнения кода, присваивания остаются на месте.",{"title":3205,"url":3206,"note":3234},"как обычно объясняют поднятие объявлений.",{"title":3236,"url":3237,"note":3238},"MDN: let","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fstatements\u002Flet\u002Findex.md","блочная область видимости и временная мертвая зона для `let`.","# Q5. Что такое hoisting в JavaScript?\n\n## Базовый вопрос\n\nЧто такое hoisting в JavaScript?\n\n## Хороший ответ\n\nHoisting - это разговорное название для поведения, при котором JavaScript заранее обрабатывает объявления в области видимости перед выполнением строк кода.\n\nВажно: движок не берет наши строки и физически не переносит их наверх. Правильнее думать так: перед выполнением кода создается лексическое окружение, и в нем заранее появляются привязки для объявлений. А вот присваивания и обычные выражения выполняются там, где они написаны.\n\nКлючевые мысли:\n\n- `var` создает привязку на уровне функции или script и сразу получает значение `undefined`. Поэтому имя уже доступно до строки объявления, но реального присвоенного значения там еще нет.\n- `let` и `const` тоже известны движку заранее в своей области видимости, но до выполнения строки объявления находятся в TDZ. Поэтому обращаться к ним до объявления нельзя.\n- Function declaration обычно создается и инициализируется как функция на этапе подготовки области видимости. Поэтому такую функцию часто можно вызвать до места объявления.\n- Function expression и стрелочная функция, записанная в переменную, создаются только когда выполнение доходит до выражения. До этого момента работает только поведение самой переменной: `let` и `const` дают TDZ, `var` дает `undefined`.\n- Hoisting всегда связан с конкретной областью видимости. `var` внутри функции не всплывает на уровень всей программы, а function declaration внутри блока в strict mode видна в пределах блока.\n\nГлавная мысль: hoisting объясняет, почему имя может быть известно раньше строки объявления, но это не значит, что значение уже готово.\n\n## Уточняющие вопросы\n\n### 1. Почему мы можем обратиться к `var` до строки объявления, но значение там будет `undefined`?\n\nОжидаем: кандидат говорит, что объявление `var` обрабатывается заранее в рамках своей функции или script, поэтому имя уже существует. Но присваивание значения не выполняется заранее, оно остается на своей строке. До этой строки у переменной значение `undefined`.\n\nХороший ответ отделяет объявление от присваивания. Слабый ответ: \"`var` поднялся вместе со значением\".\n\n### 2. Почему с `let` и `const` нельзя работать до строки объявления, хотя движок уже знает про это имя?\n\nОжидаем: кандидат говорит, что `let` и `const` создают привязку заранее, но до выполнения строки объявления она находится в TDZ. В этот период имя уже занято в своей области видимости, но обращаться к нему нельзя.\n\nХороший ответ не говорит \"`let` и `const` не hoist-ятся\". Точнее сказать: они hoist-ятся как привязки, но не инициализируются значением `undefined`, как `var`.\n\n### 3. Почему `function declaration` обычно можно вызвать до объявления, а стрелочную функцию, записанную в переменную, нет?\n\nОжидаем: кандидат разделяет declaration и expression. Function declaration создается и инициализируется как функция на этапе подготовки области видимости. Стрелочная функция, записанная в переменную, является expression: сама функция появится только когда выполнение дойдет до этой строки.\n\nДальше все зависит от переменной, куда мы положили стрелку. Если это `let` или `const`, до строки объявления будет TDZ. Если это `var`, имя будет доступно раньше, но там будет `undefined`, а не функция.\n\nХороший ответ не сводит все к фразе \"стрелки не hoist-ятся\". Точнее: hoisting относится к привязке переменной, а не к готовой стрелочной функции как значению.\n\n## Референсы\n\n- [Learn JS: Устаревшее ключевое слово var](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F04-var\u002Farticle.md) - hoisting для `var`, разница между объявлением и присваиванием.\n- [Learn JS: Function Expression](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F16-function-expressions\u002Farticle.md) - Function Declaration против Function Expression и момент создания функции.\n- [Learn JS: Область видимости переменных, замыкание](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md) - лексическое окружение, состояние `Uninitialized` и подготовка объявлений.\n- [YDKJS: Глава 4. Поднятие](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch4.md) - объявления обрабатываются до выполнения кода, присваивания остаются на месте.\n- [MDN: Hoisting](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Fhoisting\u002Findex.md) - как обычно объясняют поднятие объявлений.\n- [MDN: let](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fstatements\u002Flet\u002Findex.md) - блочная область видимости и временная мертвая зона для `let`.",{"slug":3241,"title":3242,"baseQuestion":3242,"goodAnswer":3243,"followUps":3244,"references":3254,"programSlug":21,"lessonSlug":21,"order":55,"status":13,"rawBody":3271},"types-coercion-symbol-json-q5-chem-binarnyy-otlichaetsya-ot-arifmeticheskih-operatorov-pri-privedenii","Чем бинарный `+` отличается от арифметических операторов при приведении?","Операторы `-`, `*`, `\u002F` и большинство математических операторов работают как численные операции. Если операнды не числа, JavaScript приводит их к числам. Поэтому `'5' - 1` становится `5 - 1`, а `'5' * '2'` становится `5 * 2`.\n\nБинарный `+` особенный. Он умеет делать две разные вещи:\n\n- численное сложение;\n- строковую конкатенацию.\n\nДля `+` JavaScript сначала получает примитивы из операндов. Если хотя бы один из полученных примитивов является строкой, оба операнда приводятся к строкам и выполняется конкатенация. Поэтому `'5' + 1` дает `\"51\"`, а `'5' + true` дает `\"5true\"`.\n\nЕсли после приведения к примитивам строк нет, `+` работает как численное сложение. Поэтому `true + true + true` дает `3`: каждый `true` в численном сложении становится `1`, а операции выполняются слева направо.\n\nПорядок тоже важен. В выражении `2 + 2 + '1'` сначала складываются два числа и получается `4`, потом идет строковый плюс и результат становится `\"41\"`. Если строка стоит в начале, например `'1' + 2 + 2`, то первая операция уже запускает конкатенацию, и дальше мы получаем строку.\n\nХороший кандидат не говорит \"плюс всегда превращает все в строки\" или \"минус просто убирает строку\". Он объясняет выбор операции: `+` смотрит на строки после `ToPrimitive`, а `-` и `*` идут в численное приведение.",[3245,3248,3251],{"question":3246,"expected":3247},"Почему у бинарного `+` две роли, а у `-` и `*` такой роли нет?","кандидат говорит, что `+` в JavaScript исторически используется и для сложения, и для склейки строк. `-` и `*` строковой операции не имеют, поэтому они приводят операнды к числам.\n\nХороший ответ должен связать это с правилами языка, а не с тем, что строка \"похожа\" или \"не похожа\" на число.",{"question":3249,"expected":3250},"Почему `true + true + true` дает `3`?","кандидат объясняет, что строк среди операндов нет, поэтому `+` работает как численное сложение. В численном приведении `true` становится `1`, значит выражение превращается в `1 + 1 + 1`.\n\nТакой ответ проверяет, что кандидат не воспринимает boolean отдельно от общей системы приведения.",{"question":3252,"expected":3253},"Как объект может повлиять на результат бинарного `+`?","кандидат говорит, что объект сначала проходит `ToPrimitive`. Если получился строковый примитив, `+` станет конкатенацией. Если получился числовой примитив и второй операнд тоже не строка, `+` станет численным сложением.\n\nХороший ответ может назвать `valueOf`, `toString` или `Symbol.toPrimitive` как механизм, через который объект дает этот примитив.",[3255,3259,3261,3263,3265,3269],{"title":3256,"url":3257,"note":3258},"Learn JS: Базовые операторы, математика","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F08-operators\u002Farticle.md","строковый плюс, численные операторы и порядок выполнения.",{"title":2653,"url":2654,"note":3260},"численное и строковое приведение.",{"title":2955,"url":2956,"note":3262},"что происходит с объектом до применения оператора.",{"title":2659,"url":2660,"note":3264},"явное и неявное приведение, строки и числа.",{"title":3266,"url":3267,"note":3268},"MDN: Addition","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Faddition\u002Findex.md","поведение бинарного `+`.",{"title":3266,"url":3267,"note":3270},"выбор между конкатенацией и численной операцией.","# Q5. Чем бинарный `+` отличается от арифметических операторов при приведении?\n\n## Базовый вопрос\n\nЧем бинарный `+` отличается от арифметических операторов при приведении?\n\n## Хороший ответ\n\nОператоры `-`, `*`, `\u002F` и большинство математических операторов работают как численные операции. Если операнды не числа, JavaScript приводит их к числам. Поэтому `'5' - 1` становится `5 - 1`, а `'5' * '2'` становится `5 * 2`.\n\nБинарный `+` особенный. Он умеет делать две разные вещи:\n\n- численное сложение;\n- строковую конкатенацию.\n\nДля `+` JavaScript сначала получает примитивы из операндов. Если хотя бы один из полученных примитивов является строкой, оба операнда приводятся к строкам и выполняется конкатенация. Поэтому `'5' + 1` дает `\"51\"`, а `'5' + true` дает `\"5true\"`.\n\nЕсли после приведения к примитивам строк нет, `+` работает как численное сложение. Поэтому `true + true + true` дает `3`: каждый `true` в численном сложении становится `1`, а операции выполняются слева направо.\n\nПорядок тоже важен. В выражении `2 + 2 + '1'` сначала складываются два числа и получается `4`, потом идет строковый плюс и результат становится `\"41\"`. Если строка стоит в начале, например `'1' + 2 + 2`, то первая операция уже запускает конкатенацию, и дальше мы получаем строку.\n\nХороший кандидат не говорит \"плюс всегда превращает все в строки\" или \"минус просто убирает строку\". Он объясняет выбор операции: `+` смотрит на строки после `ToPrimitive`, а `-` и `*` идут в численное приведение.\n\n## Уточняющие вопросы\n\n### 1. Почему у бинарного `+` две роли, а у `-` и `*` такой роли нет?\n\nОжидаем: кандидат говорит, что `+` в JavaScript исторически используется и для сложения, и для склейки строк. `-` и `*` строковой операции не имеют, поэтому они приводят операнды к числам.\n\nХороший ответ должен связать это с правилами языка, а не с тем, что строка \"похожа\" или \"не похожа\" на число.\n\n### 2. Почему `true + true + true` дает `3`?\n\nОжидаем: кандидат объясняет, что строк среди операндов нет, поэтому `+` работает как численное сложение. В численном приведении `true` становится `1`, значит выражение превращается в `1 + 1 + 1`.\n\nТакой ответ проверяет, что кандидат не воспринимает boolean отдельно от общей системы приведения.\n\n### 3. Как объект может повлиять на результат бинарного `+`?\n\nОжидаем: кандидат говорит, что объект сначала проходит `ToPrimitive`. Если получился строковый примитив, `+` станет конкатенацией. Если получился числовой примитив и второй операнд тоже не строка, `+` станет численным сложением.\n\nХороший ответ может назвать `valueOf`, `toString` или `Symbol.toPrimitive` как механизм, через который объект дает этот примитив.\n\n## Референсы\n\n- [Learn JS: Базовые операторы, математика](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F08-operators\u002Farticle.md) - строковый плюс, численные операторы и порядок выполнения.\n- [Learn JS: Преобразование типов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F07-type-conversions\u002Farticle.md) - численное и строковое приведение.\n- [Learn JS: Преобразование объектов в примитивы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F09-object-toprimitive\u002Farticle.md) - что происходит с объектом до применения оператора.\n- [YDKJS: Типы и грамматика, глава 4](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md) - явное и неявное приведение, строки и числа.\n- [MDN: Addition](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Faddition\u002Findex.md) - поведение бинарного `+`.\n- [MDN: Addition](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Faddition\u002Findex.md) - выбор между конкатенацией и численной операцией.",{"slug":3273,"title":3274,"baseQuestion":3275,"goodAnswer":3276,"followUps":3277,"references":3287,"programSlug":40,"lessonSlug":40,"order":650,"status":13,"rawBody":3294},"browser-network-q6-chto-oznachaet-status-http-otveta","Что означает статус HTTP-ответа?","Что показывает HTTP status code в ответе?","Сначала можно сказать так: status code это короткий числовой итог обработки запроса на уровне HTTP. Он помогает понять, что произошло: сервер успешно ответил, перенаправил нас, получил ошибочный запрос, не нашел ресурс или сам сломался.\n\nВажно не путать HTTP-ошибку и сетевую ошибку. Если сервер вернул `404` или `500`, у нас все равно есть HTTP-ответ. В `fetch` Promise обычно выполнится успешно, а `response.ok` будет `false`. Если же соединение не состоялось, запрос отменили или браузер заблокировал доступ, тогда `fetch` может отклонить Promise и `Response` не будет.\n\nНа практике в Chrome Network мы смотрим колонку Status, затем открываем request details и проверяем Headers, Preview или Response. Иногда тело ответа содержит полезное сообщение об ошибке, даже если статус не 2xx.",[3278,3281,3284],{"question":3279,"expected":3280},"Почему `fetch` с ответом `404` обычно не попадает в `catch`?","кандидат говорит, что `404` это валидный HTTP-ответ. Promise отклоняется не из-за любого плохого статуса, а из-за сетевой ошибки, отмены или похожей ситуации без обычного Response.",{"question":3282,"expected":3283},"Чем `response.ok` отличается от `response.status`?","кандидат объясняет, что `status` хранит конкретное число, а `ok` это удобная проверка диапазона 200-299.",{"question":3285,"expected":3286},"Что мы проверяем в Network, если видим статус `500`?","кандидат говорит, что нужно открыть запрос, посмотреть URL, method, payload, response body, response headers и понять, какие данные мы отправили серверу.",[3288,3290],{"title":2990,"url":2991,"note":3289},"группы и значения HTTP-статусов.",{"title":3291,"url":3292,"note":3293},"MDN: Response ok","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fresponse\u002Fok\u002Findex.md","как `ok` связан со статусом ответа.","# Q6. Что означает статус HTTP-ответа?\n\n## Базовый вопрос\n\nЧто показывает HTTP status code в ответе?\n\n## Хороший ответ\n\nСначала можно сказать так: status code это короткий числовой итог обработки запроса на уровне HTTP. Он помогает понять, что произошло: сервер успешно ответил, перенаправил нас, получил ошибочный запрос, не нашел ресурс или сам сломался.\n\nВажно не путать HTTP-ошибку и сетевую ошибку. Если сервер вернул `404` или `500`, у нас все равно есть HTTP-ответ. В `fetch` Promise обычно выполнится успешно, а `response.ok` будет `false`. Если же соединение не состоялось, запрос отменили или браузер заблокировал доступ, тогда `fetch` может отклонить Promise и `Response` не будет.\n\nНа практике в Chrome Network мы смотрим колонку Status, затем открываем request details и проверяем Headers, Preview или Response. Иногда тело ответа содержит полезное сообщение об ошибке, даже если статус не 2xx.\n\n## Уточняющие вопросы\n\n### 1. Почему `fetch` с ответом `404` обычно не попадает в `catch`?\n\nОжидаем: кандидат говорит, что `404` это валидный HTTP-ответ. Promise отклоняется не из-за любого плохого статуса, а из-за сетевой ошибки, отмены или похожей ситуации без обычного Response.\n\n### 2. Чем `response.ok` отличается от `response.status`?\n\nОжидаем: кандидат объясняет, что `status` хранит конкретное число, а `ok` это удобная проверка диапазона 200-299.\n\n### 3. Что мы проверяем в Network, если видим статус `500`?\n\nОжидаем: кандидат говорит, что нужно открыть запрос, посмотреть URL, method, payload, response body, response headers и понять, какие данные мы отправили серверу.\n\n## Референсы\n\n- [MDN: HTTP response status codes](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Freference\u002Fstatus\u002Findex.md) - группы и значения HTTP-статусов.\n- [MDN: Response ok](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fresponse\u002Fok\u002Findex.md) - как `ok` связан со статусом ответа.",{"slug":3296,"title":3297,"baseQuestion":3297,"goodAnswer":3298,"followUps":3299,"references":3309,"programSlug":30,"lessonSlug":30,"order":650,"status":13,"rawBody":3316},"event-loop-promises-async-await-q6-kak-oshibki-prohodyat-po-promise-cepochke","Как ошибки проходят по Promise-цепочке?","Простая модель похожа на обычный `try\u002Fcatch`: если в промисе появилась ошибка, управление пропускает обычные успешные обработчики и идет к ближайшему обработчику ошибки. Поэтому `.catch` часто ставят в конце цепочки, чтобы собрать ошибки из нескольких предыдущих шагов.\n\nОшибка может появиться по-разному: через `reject`, через `throw` внутри executor или через `throw` внутри обработчика `.then`. Вокруг executor и обработчиков промисов есть неявное превращение исключения в rejected Promise. Поэтому `throw new Error(...)` внутри `.then` по поведению дальше похож на `return Promise.reject(...)`.\n\n`.catch` обрабатывает ошибку. Если внутри `.catch` мы вернули обычное значение или просто завершили обработчик, цепочка восстановится и следующий `.then` пойдет по успешной ветке. Это означает: ошибка считается обработанной. Если внутри `.catch` снова бросить ошибку или вернуть rejected Promise, ошибка пойдет дальше к следующему обработчику ошибки.\n\nВторой аргумент `.then(onFulfilled, onRejected)` тоже может обработать ошибку, но важно понимать его границу. Он обрабатывает ошибку, с которой в этот `.then` пришел предыдущий Promise. Если ошибка выброшена внутри `onFulfilled` этого же `.then`, ее поймает уже следующий `.catch` или следующий error handler ниже по цепочке.\n\n`.finally` обычно используют для общей очистки: убрать loader, снять disabled, закрыть временный ресурс. Он не получает значение результата и обычно пропускает прежний успех или прежнюю ошибку дальше. Но если внутри `.finally` выбросить ошибку, она заменит предыдущий исход.\n\nНеобработанная ошибка промиса не появляется как обычный синхронный `throw` в месте создания цепочки. Браузер понимает, что ошибка осталась без обработчика, когда микрозадачи по этой цепочке дошли до конца и обработчика не нашлось. Тогда может сработать глобальное событие `unhandledrejection`.",[3300,3303,3306],{"question":3301,"expected":3302},"Почему `.catch` в конце цепочки может поймать ошибку, выброшенную в одном из предыдущих `.then`?","кандидат объясняет, что `throw` внутри обработчика превращает Promise, возвращенный этим `.then`, в rejected. Дальше цепочка пропускает обычные успешные обработчики и ищет ближайший `.catch` или error handler.",{"question":3304,"expected":3305},"Почему после `.catch(() => 'a')` следующий `.then` получает успешное значение?","кандидат говорит, что обработчик ошибки завершился нормально и вернул значение. Значит ошибка считается обработанной, а возвращенное значение становится успешным результатом следующего шага.",{"question":3307,"expected":3308},"Зачем использовать `.finally`, если есть `.then` и `.catch`?","кандидат говорит про общее действие после любого исхода. `finally` нужен не для обработки результата, а для очистки или завершения UI-состояния. Он обычно пропускает исходный результат или ошибку дальше, но новая ошибка внутри `finally` заменит прежний исход.",[3310,3314],{"title":3311,"url":3312,"note":3313},"ru.javascript.info: Промисы обработка ошибок","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F04-promise-error-handling\u002Farticle.md","распространение ошибок, `.catch` и `.finally`.",{"title":1830,"url":1831,"note":3315},"момент появления необработанных ошибок промисов.","# Q6. Как ошибки проходят по Promise-цепочке?\n\n## Базовый вопрос\n\nКак ошибки проходят по Promise-цепочке?\n\n## Хороший ответ\n\nПростая модель похожа на обычный `try\u002Fcatch`: если в промисе появилась ошибка, управление пропускает обычные успешные обработчики и идет к ближайшему обработчику ошибки. Поэтому `.catch` часто ставят в конце цепочки, чтобы собрать ошибки из нескольких предыдущих шагов.\n\nОшибка может появиться по-разному: через `reject`, через `throw` внутри executor или через `throw` внутри обработчика `.then`. Вокруг executor и обработчиков промисов есть неявное превращение исключения в rejected Promise. Поэтому `throw new Error(...)` внутри `.then` по поведению дальше похож на `return Promise.reject(...)`.\n\n`.catch` обрабатывает ошибку. Если внутри `.catch` мы вернули обычное значение или просто завершили обработчик, цепочка восстановится и следующий `.then` пойдет по успешной ветке. Это означает: ошибка считается обработанной. Если внутри `.catch` снова бросить ошибку или вернуть rejected Promise, ошибка пойдет дальше к следующему обработчику ошибки.\n\nВторой аргумент `.then(onFulfilled, onRejected)` тоже может обработать ошибку, но важно понимать его границу. Он обрабатывает ошибку, с которой в этот `.then` пришел предыдущий Promise. Если ошибка выброшена внутри `onFulfilled` этого же `.then`, ее поймает уже следующий `.catch` или следующий error handler ниже по цепочке.\n\n`.finally` обычно используют для общей очистки: убрать loader, снять disabled, закрыть временный ресурс. Он не получает значение результата и обычно пропускает прежний успех или прежнюю ошибку дальше. Но если внутри `.finally` выбросить ошибку, она заменит предыдущий исход.\n\nНеобработанная ошибка промиса не появляется как обычный синхронный `throw` в месте создания цепочки. Браузер понимает, что ошибка осталась без обработчика, когда микрозадачи по этой цепочке дошли до конца и обработчика не нашлось. Тогда может сработать глобальное событие `unhandledrejection`.\n\n## Уточняющие вопросы\n\n### 1. Почему `.catch` в конце цепочки может поймать ошибку, выброшенную в одном из предыдущих `.then`?\n\nОжидаем: кандидат объясняет, что `throw` внутри обработчика превращает Promise, возвращенный этим `.then`, в rejected. Дальше цепочка пропускает обычные успешные обработчики и ищет ближайший `.catch` или error handler.\n\n### 2. Почему после `.catch(() => 'a')` следующий `.then` получает успешное значение?\n\nОжидаем: кандидат говорит, что обработчик ошибки завершился нормально и вернул значение. Значит ошибка считается обработанной, а возвращенное значение становится успешным результатом следующего шага.\n\n### 3. Зачем использовать `.finally`, если есть `.then` и `.catch`?\n\nОжидаем: кандидат говорит про общее действие после любого исхода. `finally` нужен не для обработки результата, а для очистки или завершения UI-состояния. Он обычно пропускает исходный результат или ошибку дальше, но новая ошибка внутри `finally` заменит прежний исход.\n\n## Референсы\n\n- [ru.javascript.info: Промисы обработка ошибок](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F04-promise-error-handling\u002Farticle.md) - распространение ошибок, `.catch` и `.finally`.\n- [ru.javascript.info: Микрозадачи](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F07-microtask-queue\u002Farticle.md) - момент появления необработанных ошибок промисов.",{"slug":3318,"title":3319,"baseQuestion":3320,"goodAnswer":3321,"followUps":3322,"references":3332,"programSlug":31,"lessonSlug":31,"order":650,"status":13,"rawBody":3351},"event-loop-promises-deep-dive-q6-kogda-dva-await-zapuskayut-operacii-posledovatelno","Когда два await запускают операции последовательно?","Есть функция и два варианта кода внутри async-функции:\n\n```js\nfunction f(a) {\n  return new Promise((resolve) => {\n    console.log('start', a);\n    setTimeout(() => resolve(a), 100);\n  });\n}\n```\n\nПервый вариант:\n\n```js\nconst a = f('a');\nconst b = f('b');\n\nawait a;\nawait b;\n```\n\nВторой вариант:\n\n```js\nawait f('a');\nawait f('b');\n```\n\nЧем эти варианты отличаются по моменту запуска операций?","Главная мысль: `await` не запускает асинхронную операцию. Операция обычно стартует тогда, когда мы вызвали функцию, создали `Promise`, начали `fetch` или поставили таймер. `await` только приостанавливает текущую async-функцию до результата.\n\nПоследовательный запуск получается, когда мы вызываем следующую асинхронную операцию только после `await` предыдущей. Тогда второй запрос или таймер даже не начнет работу, пока первый не завершится.\n\nПараллельный запуск получается, когда мы сначала создаем несколько промисов, а потом ждем их результаты. Например, мы вызвали две функции, сохранили два Promise, и только после этого сделали `await Promise.all(...)` или два `await` для уже запущенных промисов.\n\nДля фронтенда это важная практическая разница. Если операции независимы, параллельный запуск обычно быстрее. Если второй шаг зависит от результата первого, последовательность правильнее и понятнее.\n\nХороший ответ не должен сводиться к фразе \"`Promise.all` делает параллельно\". `Promise.all` не запускает работу сам. Он только ждет группу уже созданных промисов и собирает общий результат.",[3323,3326,3329],{"question":3324,"expected":3325},"Мы создали два промиса до первого `await`, а потом написали два `await` подряд. Почему операции уже идут параллельно?","кандидат начинает с момента запуска, а не с формы ожидания. Когда мы пишем `const a = f('a')`, функция `f` уже вызвана, executor внутри `new Promise` уже выполнился, а таймер, запрос или другая асинхронная операция уже переданы окружению. Затем мы так же вызываем `f('b')`, и вторая операция стартует до того, как первый `await` приостановит async-функцию. Поэтому два `await` подряд не делают работу последовательной с точки зрения запуска: первый `await` ждет результат `a`, а второй потом читает уже созданный `b` или ждет оставшееся время. Важно сказать аккуратно: операции идут конкурентно, то есть одновременно находятся в работе, но это не обязательно значит выполнение JavaScript на двух потоках.",{"question":3327,"expected":3328},"Второму запросу нужен id из результата первого запроса. Почему здесь нельзя заранее запустить оба запроса параллельно?","кандидат объясняет зависимость данных. Если второй запрос должен получить `id`, URL, body или другой параметр из результата первого запроса, до завершения первого шага у нас еще нет корректных входных данных для второго. Значит, заранее мы можем запустить только неправильный запрос, заглушку или лишнюю работу, которую потом придется отменять или игнорировать. В такой ситуации последовательность не является ошибкой производительности: мы сначала ждем первый результат, достаем из него нужные данные и только после этого создаем второй Promise. `Promise.all` подходит для независимых операций, а здесь второй шаг зависит от результата первого.",{"question":3330,"expected":3331},"Мы передали в `Promise.all` уже созданные промисы. Почему `Promise.all` только ждет их, а не запускает операции сам?","кандидат разделяет создание операции и координацию результата. `Promise.all` получает iterable с уже готовыми значениями: промисами, thenable-объектами или обычными значениями. Он не вызывает функции из массива и не знает, как именно были устроены запросы или таймеры. Если мы пишем `Promise.all([f('a'), f('b')])`, сначала вычисляются элементы массива, то есть вызываются `f('a')` и `f('b')`, и только потом их промисы попадают в `Promise.all`. Если передать `[f, g]`, сами функции не запустятся: для `Promise.all` это будут обычные значения. Его задача - вернуть новый Promise, который выполнится, когда выполнятся все входные промисы, или отклонится при первой ошибке.",[3333,3335,3337,3341,3343,3347],{"title":2484,"url":2485,"note":3334},"`await`, `Promise.all` и ожидание нескольких промисов.",{"title":3067,"url":3068,"note":3336},"`Promise.all` как ожидание группы уже созданных промисов.",{"title":3338,"url":3339,"note":3340},"Вы не знаете JS: Асинхронность и производительность - глава 3 Промисы","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fasync%20%26%20performance\u002Fch3.md","Promise как способ координации будущих значений.",{"title":3071,"url":3072,"note":3342},"общий результат группы промисов.",{"title":3344,"url":3345,"note":3346},"ECMA-262: Await","https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#L51298","формальная механика ожидания значения в async-функции.",{"title":3348,"url":3349,"note":3350},"ECMA-262: Promise.all","https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#L49647","формальная механика создания общего Promise по iterable входных значений.","# Q6. Когда два await запускают операции последовательно?\n\n## Базовый вопрос\n\nЕсть функция и два варианта кода внутри async-функции:\n\n```js\nfunction f(a) {\n  return new Promise((resolve) => {\n    console.log('start', a);\n    setTimeout(() => resolve(a), 100);\n  });\n}\n```\n\nПервый вариант:\n\n```js\nconst a = f('a');\nconst b = f('b');\n\nawait a;\nawait b;\n```\n\nВторой вариант:\n\n```js\nawait f('a');\nawait f('b');\n```\n\nЧем эти варианты отличаются по моменту запуска операций?\n\n## Хороший ответ\n\nГлавная мысль: `await` не запускает асинхронную операцию. Операция обычно стартует тогда, когда мы вызвали функцию, создали `Promise`, начали `fetch` или поставили таймер. `await` только приостанавливает текущую async-функцию до результата.\n\nПоследовательный запуск получается, когда мы вызываем следующую асинхронную операцию только после `await` предыдущей. Тогда второй запрос или таймер даже не начнет работу, пока первый не завершится.\n\nПараллельный запуск получается, когда мы сначала создаем несколько промисов, а потом ждем их результаты. Например, мы вызвали две функции, сохранили два Promise, и только после этого сделали `await Promise.all(...)` или два `await` для уже запущенных промисов.\n\nДля фронтенда это важная практическая разница. Если операции независимы, параллельный запуск обычно быстрее. Если второй шаг зависит от результата первого, последовательность правильнее и понятнее.\n\nХороший ответ не должен сводиться к фразе \"`Promise.all` делает параллельно\". `Promise.all` не запускает работу сам. Он только ждет группу уже созданных промисов и собирает общий результат.\n\n## Уточняющие вопросы\n\n### 1. Мы создали два промиса до первого `await`, а потом написали два `await` подряд. Почему операции уже идут параллельно?\n\nОжидаем: кандидат начинает с момента запуска, а не с формы ожидания. Когда мы пишем `const a = f('a')`, функция `f` уже вызвана, executor внутри `new Promise` уже выполнился, а таймер, запрос или другая асинхронная операция уже переданы окружению. Затем мы так же вызываем `f('b')`, и вторая операция стартует до того, как первый `await` приостановит async-функцию. Поэтому два `await` подряд не делают работу последовательной с точки зрения запуска: первый `await` ждет результат `a`, а второй потом читает уже созданный `b` или ждет оставшееся время. Важно сказать аккуратно: операции идут конкурентно, то есть одновременно находятся в работе, но это не обязательно значит выполнение JavaScript на двух потоках.\n\n### 2. Второму запросу нужен id из результата первого запроса. Почему здесь нельзя заранее запустить оба запроса параллельно?\n\nОжидаем: кандидат объясняет зависимость данных. Если второй запрос должен получить `id`, URL, body или другой параметр из результата первого запроса, до завершения первого шага у нас еще нет корректных входных данных для второго. Значит, заранее мы можем запустить только неправильный запрос, заглушку или лишнюю работу, которую потом придется отменять или игнорировать. В такой ситуации последовательность не является ошибкой производительности: мы сначала ждем первый результат, достаем из него нужные данные и только после этого создаем второй Promise. `Promise.all` подходит для независимых операций, а здесь второй шаг зависит от результата первого.\n\n### 3. Мы передали в `Promise.all` уже созданные промисы. Почему `Promise.all` только ждет их, а не запускает операции сам?\n\nОжидаем: кандидат разделяет создание операции и координацию результата. `Promise.all` получает iterable с уже готовыми значениями: промисами, thenable-объектами или обычными значениями. Он не вызывает функции из массива и не знает, как именно были устроены запросы или таймеры. Если мы пишем `Promise.all([f('a'), f('b')])`, сначала вычисляются элементы массива, то есть вызываются `f('a')` и `f('b')`, и только потом их промисы попадают в `Promise.all`. Если передать `[f, g]`, сами функции не запустятся: для `Promise.all` это будут обычные значения. Его задача - вернуть новый Promise, который выполнится, когда выполнятся все входные промисы, или отклонится при первой ошибке.\n\n## Референсы\n\n- [ru.javascript.info: Async await](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md) - `await`, `Promise.all` и ожидание нескольких промисов.\n- [ru.javascript.info: Promise API](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F05-promise-api\u002Farticle.md) - `Promise.all` как ожидание группы уже созданных промисов.\n- [Вы не знаете JS: Асинхронность и производительность - глава 3 Промисы](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fasync%20%26%20performance\u002Fch3.md) - Promise как способ координации будущих значений.\n- [MDN: Promise.all](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fall\u002Findex.md) - общий результат группы промисов.\n- [ECMA-262: Await](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#L51298) - формальная механика ожидания значения в async-функции.\n- [ECMA-262: Promise.all](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#L49647) - формальная механика создания общего Promise по iterable входных значений.",{"slug":3353,"title":3354,"baseQuestion":3354,"goodAnswer":3355,"followUps":3356,"references":3366,"programSlug":59,"lessonSlug":59,"order":650,"status":13,"rawBody":3382},"mock-interview-javascript-core-q6-kak-rabotaet-nestrogoe-ravenstvo","Как работает нестрогое равенство?","Нестрогое равенство `==` сравнивает значения через набор правил с приведением типов. Это не просто \"привести все к boolean\" и не просто \"привести все к строке\". У оператора есть отдельный алгоритм.\n\nЕсли типы одинаковые, сравнение почти похоже на строгое равенство: одинаковые строки равны, одинаковые boolean равны, один и тот же объект равен самому себе. Разные объекты не равны, даже если у них одинаковые свойства.\n\nЕсли типы разные, включаются специальные правила. `null` и `undefined` равны друг другу через `==`, но почти больше никому. Boolean перед сравнением приводится к number: `false` становится `0`, `true` становится `1`. Строка и число сравниваются после численного приведения строки. Если объект сравнивается с примитивом, объект сначала приводится к примитиву через `ToPrimitive`.\n\nНа собеседовании важно уметь объяснить путь, а не просто сказать \"лучше не использовать\". В продакшен-коде действительно обычно выбирают `===`, потому что оно не запускает неожиданное приведение. Но если вопрос про вывод кода, нужно уметь пройти алгоритм `==` по шагам.",[3357,3360,3363],{"question":3358,"expected":3359},"Почему `null == undefined` дает `true`, а `null == 0` дает `false`?","кандидат говорит, что для `null` и `undefined` в `==` есть отдельное правило. Они равны друг другу и не приводятся к числу для сравнения с `0`.",{"question":3361,"expected":3362},"Почему `'0' == false` дает `true`?","кандидат объясняет, что boolean сначала становится числом. `false` превращается в `0`, строка `\"0\"` тоже приводится к числу `0`, поэтому сравнение истинно.",{"question":3364,"expected":3365},"Почему `[] == ![]` дает `true`?","кандидат раскладывает выражение по шагам. Пустой массив truthy, поэтому `![]` дает `false`. Потом сравниваем `[] == false`: `false` становится `0`, массив через приведение к примитиву становится пустой строкой, пустая строка становится `0`.",[3367,3371,3375,3378],{"title":3368,"url":3369,"note":3370},"ru.javascript.info: Операторы сравнения","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F09-comparison\u002Farticle.md","различие `==`, `===`, особое поведение `null` и `undefined`.",{"title":3372,"url":3373,"note":3374},"MDN: Equality operator","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fequality\u002Findex.md","правила loose equality и примеры.",{"title":3376,"url":2660,"note":3377},"Вы не знаете JS: Типы и грамматика — глава 4 Приведение","подробная ментальная модель неявного приведения.",{"title":3379,"url":3380,"note":3381},"ECMA-262: IsLooselyEqual","https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-islooselyequal","формальный алгоритм `==`.","# Q7. Как работает нестрогое равенство?\n\n## Базовый вопрос\n\nКак работает нестрогое равенство?\n\n## Хороший ответ\n\nНестрогое равенство `==` сравнивает значения через набор правил с приведением типов. Это не просто \"привести все к boolean\" и не просто \"привести все к строке\". У оператора есть отдельный алгоритм.\n\nЕсли типы одинаковые, сравнение почти похоже на строгое равенство: одинаковые строки равны, одинаковые boolean равны, один и тот же объект равен самому себе. Разные объекты не равны, даже если у них одинаковые свойства.\n\nЕсли типы разные, включаются специальные правила. `null` и `undefined` равны друг другу через `==`, но почти больше никому. Boolean перед сравнением приводится к number: `false` становится `0`, `true` становится `1`. Строка и число сравниваются после численного приведения строки. Если объект сравнивается с примитивом, объект сначала приводится к примитиву через `ToPrimitive`.\n\nНа собеседовании важно уметь объяснить путь, а не просто сказать \"лучше не использовать\". В продакшен-коде действительно обычно выбирают `===`, потому что оно не запускает неожиданное приведение. Но если вопрос про вывод кода, нужно уметь пройти алгоритм `==` по шагам.\n\n## Уточняющие вопросы\n\n### 1. Почему `null == undefined` дает `true`, а `null == 0` дает `false`?\n\nОжидаем: кандидат говорит, что для `null` и `undefined` в `==` есть отдельное правило. Они равны друг другу и не приводятся к числу для сравнения с `0`.\n\n### 2. Почему `'0' == false` дает `true`?\n\nОжидаем: кандидат объясняет, что boolean сначала становится числом. `false` превращается в `0`, строка `\"0\"` тоже приводится к числу `0`, поэтому сравнение истинно.\n\n### 3. Почему `[] == ![]` дает `true`?\n\nОжидаем: кандидат раскладывает выражение по шагам. Пустой массив truthy, поэтому `![]` дает `false`. Потом сравниваем `[] == false`: `false` становится `0`, массив через приведение к примитиву становится пустой строкой, пустая строка становится `0`.\n\n## Референсы\n\n- [ru.javascript.info: Операторы сравнения](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F09-comparison\u002Farticle.md) - различие `==`, `===`, особое поведение `null` и `undefined`.\n- [MDN: Equality operator](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fequality\u002Findex.md) - правила loose equality и примеры.\n- [Вы не знаете JS: Типы и грамматика — глава 4 Приведение](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md) - подробная ментальная модель неявного приведения.\n- [ECMA-262: IsLooselyEqual](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-islooselyequal) - формальный алгоритм `==`.",{"slug":3384,"title":3385,"baseQuestion":3385,"goodAnswer":3386,"followUps":3387,"references":3397,"programSlug":18,"lessonSlug":18,"order":650,"status":13,"rawBody":3408},"objects-prototypes-classes-q6-chto-takoe-klass-v-javascript","Что такое класс в JavaScript?","Класс в JavaScript - это синтаксис для описания конструктора, прототипных методов и связанных элементов класса в одном месте.\n\nЕсли сказать просто: мы описываем шаблон создания объектов. `constructor` отвечает за начальную настройку экземпляра, методы класса попадают на `ClassName.prototype`, а `new ClassName()` создает объект и связывает его с этим прототипом.\n\nПри этом класс не стоит понимать как полностью отдельный от прототипов механизм. Объявление `class A {}` создает функцию-конструктор `A`, а методы внутри class body становятся свойствами `A.prototype`. Экземпляр получает доступ к этим методам через прототипную цепочку.\n\nНо `class` - не просто косметическая запись старой функции-конструктора. У него есть важные особенности:\n\n- class constructor нельзя вызвать без `new`;\n- методы класса создаются неперечислимыми;\n- код внутри class body всегда выполняется в strict mode;\n- class declaration ведет себя как лексическое объявление и попадает в TDZ;\n- static members лежат на самом классе, а не на экземпляре;\n- метод класса не привязан к экземпляру навсегда и может потерять `this` при свободном вызове.\n\nХороший кандидат должен объяснить класс через уже знакомые прототипы: метод не копируется в каждый объект, а лежит на прототипе. Но также важно назвать отличия, из-за которых `class` нельзя считать только другой формой записи функции-конструктора.",[3388,3391,3394],{"question":3389,"expected":3390},"Почему у экземпляра класса метод доступен, хотя `Object.hasOwn(instance, 'method')` возвращает `false`?","кандидат объясняет, что метод находится не на самом экземпляре, а на `ClassName.prototype`. При чтении JavaScript сначала ищет собственное свойство экземпляра, потом идет в прототип и находит метод там.",{"question":3392,"expected":3393},"Чем class отличается от функции-конструктора, если оба варианта создают объекты через `new`?","кандидат называет не только похожесть через `new` и `prototype`, но и отличия: class constructor нельзя вызвать без `new`, методы класса неперечислимые, class body всегда strict mode, class declaration имеет TDZ.",{"question":3395,"expected":3396},"Почему `const f = instance.method; f()` может потерять `this`?","кандидат объясняет, что метод получает `this` в момент вызова. При `instance.method()` объект слева от точки становится `this`. При свободном вызове `f()` объекта слева от точки уже нет, а код внутри class body работает в strict mode, поэтому `this` будет `undefined`.",[3398,3402,3406],{"title":3399,"url":3400,"note":3401},"Learn JS: Класс базовый синтаксис","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F01-class\u002Farticle.md","базовый синтаксис class, связь с функцией-конструктором и методы на prototype.",{"title":3403,"url":3404,"note":3405},"MDN: Classes","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Findex.md","class declarations, class body, methods, fields, strict mode и поведение `this`.",{"title":2814,"url":2815,"note":3407},"правила определения `this` при разных способах вызова функции.","# Q6. Что такое класс в JavaScript?\n\n## Базовый вопрос\n\nЧто такое класс в JavaScript?\n\n## Хороший ответ\n\nКласс в JavaScript - это синтаксис для описания конструктора, прототипных методов и связанных элементов класса в одном месте.\n\nЕсли сказать просто: мы описываем шаблон создания объектов. `constructor` отвечает за начальную настройку экземпляра, методы класса попадают на `ClassName.prototype`, а `new ClassName()` создает объект и связывает его с этим прототипом.\n\nПри этом класс не стоит понимать как полностью отдельный от прототипов механизм. Объявление `class A {}` создает функцию-конструктор `A`, а методы внутри class body становятся свойствами `A.prototype`. Экземпляр получает доступ к этим методам через прототипную цепочку.\n\nНо `class` - не просто косметическая запись старой функции-конструктора. У него есть важные особенности:\n\n- class constructor нельзя вызвать без `new`;\n- методы класса создаются неперечислимыми;\n- код внутри class body всегда выполняется в strict mode;\n- class declaration ведет себя как лексическое объявление и попадает в TDZ;\n- static members лежат на самом классе, а не на экземпляре;\n- метод класса не привязан к экземпляру навсегда и может потерять `this` при свободном вызове.\n\nХороший кандидат должен объяснить класс через уже знакомые прототипы: метод не копируется в каждый объект, а лежит на прототипе. Но также важно назвать отличия, из-за которых `class` нельзя считать только другой формой записи функции-конструктора.\n\n## Уточняющие вопросы\n\n### 1. Почему у экземпляра класса метод доступен, хотя `Object.hasOwn(instance, 'method')` возвращает `false`?\n\nОжидаем: кандидат объясняет, что метод находится не на самом экземпляре, а на `ClassName.prototype`. При чтении JavaScript сначала ищет собственное свойство экземпляра, потом идет в прототип и находит метод там.\n\n### 2. Чем class отличается от функции-конструктора, если оба варианта создают объекты через `new`?\n\nОжидаем: кандидат называет не только похожесть через `new` и `prototype`, но и отличия: class constructor нельзя вызвать без `new`, методы класса неперечислимые, class body всегда strict mode, class declaration имеет TDZ.\n\n### 3. Почему `const f = instance.method; f()` может потерять `this`?\n\nОжидаем: кандидат объясняет, что метод получает `this` в момент вызова. При `instance.method()` объект слева от точки становится `this`. При свободном вызове `f()` объекта слева от точки уже нет, а код внутри class body работает в strict mode, поэтому `this` будет `undefined`.\n\n## Референсы\n\n- [Learn JS: Класс базовый синтаксис](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F01-class\u002Farticle.md) - базовый синтаксис class, связь с функцией-конструктором и методы на prototype.\n- [MDN: Classes](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Findex.md) - class declarations, class body, methods, fields, strict mode и поведение `this`.\n- [MDN: this](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fthis\u002Findex.md) - правила определения `this` при разных способах вызова функции.",{"slug":3410,"title":3411,"baseQuestion":3412,"goodAnswer":3413,"followUps":3414,"references":3424,"programSlug":50,"lessonSlug":50,"order":650,"status":13,"rawBody":3431},"recursion-q6-kak-rekursiya-pomogaet-obhodit-vlozhennye-dannye","Как рекурсия помогает обходить вложенные данные?","Почему рекурсия удобна для обхода вложенных структур данных?","Простыми словами: вложенная структура часто состоит из таких же структур внутри. Массив может содержать другие массивы. Узел дерева может содержать дочерние узлы. Папка может содержать подпапки. Поэтому одну функцию можно применить к текущему уровню, а потом к каждому вложенному уровню.\n\nХороший рекурсивный обход обычно отвечает на три вопроса:\n\n- что делать с текущим элементом;\n- как понять, что внутри есть вложенные элементы;\n- что вернуть, когда вложенности больше нет.\n\nНапример, чтобы посчитать сумму во вложенном массиве, мы складываем обычные числа, а для вложенного массива вызываем ту же функцию. Чтобы найти значение в дереве, мы проверяем текущий узел, а потом рекурсивно проверяем дочерние узлы.\n\nВажно не терять результат внутренних вызовов. Частая ошибка: вызвать рекурсивную функцию внутри цикла, но не вернуть найденное значение наружу.",[3415,3418,3421],{"question":3416,"expected":3417},"Почему вложенный массив можно обрабатывать той же функцией, что и внешний массив?","кандидат говорит, что вложенный массив имеет такую же форму данных, только меньший размер или меньшую глубину.",{"question":3419,"expected":3420},"Что обычно является базовым случаем при обходе дерева?","кандидат объясняет, что базовым случаем может быть пустой узел, узел без детей или найденное целевое значение.",{"question":3422,"expected":3423},"Почему при поиске в дереве важно возвращать результат рекурсивного вызова?","кандидат говорит, что найденное значение появляется внутри более глубокого вызова, и его нужно передать назад через всю цепочку вызовов.",[3425,3427],{"title":1954,"url":1955,"note":3426},"рекурсия как работа с меньшими подзадачами.",{"title":3428,"url":3429,"note":3430},"MDN: Array.isArray","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fisarray\u002Findex.md","проверка массива при обходе вложенных массивов.","# Q6. Как рекурсия помогает обходить вложенные данные?\n\n## Базовый вопрос\n\nПочему рекурсия удобна для обхода вложенных структур данных?\n\n## Хороший ответ\n\nПростыми словами: вложенная структура часто состоит из таких же структур внутри. Массив может содержать другие массивы. Узел дерева может содержать дочерние узлы. Папка может содержать подпапки. Поэтому одну функцию можно применить к текущему уровню, а потом к каждому вложенному уровню.\n\nХороший рекурсивный обход обычно отвечает на три вопроса:\n\n- что делать с текущим элементом;\n- как понять, что внутри есть вложенные элементы;\n- что вернуть, когда вложенности больше нет.\n\nНапример, чтобы посчитать сумму во вложенном массиве, мы складываем обычные числа, а для вложенного массива вызываем ту же функцию. Чтобы найти значение в дереве, мы проверяем текущий узел, а потом рекурсивно проверяем дочерние узлы.\n\nВажно не терять результат внутренних вызовов. Частая ошибка: вызвать рекурсивную функцию внутри цикла, но не вернуть найденное значение наружу.\n\n## Уточняющие вопросы\n\n### 1. Почему вложенный массив можно обрабатывать той же функцией, что и внешний массив?\n\nОжидаем: кандидат говорит, что вложенный массив имеет такую же форму данных, только меньший размер или меньшую глубину.\n\n### 2. Что обычно является базовым случаем при обходе дерева?\n\nОжидаем: кандидат объясняет, что базовым случаем может быть пустой узел, узел без детей или найденное целевое значение.\n\n### 3. Почему при поиске в дереве важно возвращать результат рекурсивного вызова?\n\nОжидаем: кандидат говорит, что найденное значение появляется внутри более глубокого вызова, и его нужно передать назад через всю цепочку вызовов.\n\n## Референсы\n\n- [MDN: Recursion](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fglossary\u002Frecursion\u002Findex.md) - рекурсия как работа с меньшими подзадачами.\n- [MDN: Array.isArray](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fisarray\u002Findex.md) - проверка массива при обходе вложенных массивов.",{"slug":3433,"title":3434,"baseQuestion":3434,"goodAnswer":3435,"followUps":3436,"references":3446,"programSlug":41,"lessonSlug":41,"order":650,"status":13,"rawBody":3455},"rendering-dom-events-forms-q6-kak-sobytie-prohodit-po-dom-derevu","Как событие проходит по DOM-дереву?","Сначала можно сказать просто: событие не живет только на одном элементе. Если мы кликнули по вложенному элементу, браузер строит путь события через DOM-дерево и вызывает подходящие обработчики по этому пути.\n\nОбычно у события есть три части пути:\n\n- погружение от верхних узлов к целевому элементу;\n- целевой элемент, на котором событие началось;\n- всплытие от целевого элемента обратно вверх.\n\nОбычные обработчики `addEventListener('click', handler)` чаще всего срабатывают на фазе всплытия. Если передать `{ capture: true }`, обработчик сработает на фазе погружения. Поэтому порядок обработчиков зависит не только от вложенности элементов, но и от того, на какой фазе мы подписались.\n\nНа собеседовании важно объяснить не только слова \"capturing\" и \"bubbling\", а путь мысли: событие начинается в конкретной точке интерфейса, проходит по цепочке предков, и каждый предок может получить шанс обработать это событие.",[3437,3440,3443],{"question":3438,"expected":3439},"Почему обработчик на родителе может увидеть клик по дочернему элементу?","кандидат говорит, что многие события всплывают. После целевого элемента событие поднимается по предкам, поэтому обработчик родителя тоже может сработать.",{"question":3441,"expected":3442},"Зачем нужна фаза погружения, если обычно хватает всплытия?","кандидат объясняет, что иногда нужно перехватить событие раньше, чем оно дойдет до целевого элемента или обработчиков на пути всплытия.",{"question":3444,"expected":3445},"Почему не любое событие удобно ловить на родителе?","кандидат говорит, что не все события всплывают одинаково. Для части событий нужны другие события или отдельная подписка, например у фокуса часто используют `focusin` вместо `focus`.",[3447,3451],{"title":3448,"url":3449,"note":3450},"ru.javascript.info: Всплытие и погружение","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F02-bubbling-and-capturing\u002Farticle.md","объясняет путь события, фазы и порядок обработчиков.",{"title":3452,"url":3453,"note":3454},"MDN: EventTarget addEventListener","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Feventtarget\u002Faddeventlistener\u002Findex.md","описывает опцию `capture` и работу подписки.","# Q6. Как событие проходит по DOM-дереву?\n\n## Базовый вопрос\n\nКак событие проходит по DOM-дереву?\n\n## Хороший ответ\n\nСначала можно сказать просто: событие не живет только на одном элементе. Если мы кликнули по вложенному элементу, браузер строит путь события через DOM-дерево и вызывает подходящие обработчики по этому пути.\n\nОбычно у события есть три части пути:\n\n- погружение от верхних узлов к целевому элементу;\n- целевой элемент, на котором событие началось;\n- всплытие от целевого элемента обратно вверх.\n\nОбычные обработчики `addEventListener('click', handler)` чаще всего срабатывают на фазе всплытия. Если передать `{ capture: true }`, обработчик сработает на фазе погружения. Поэтому порядок обработчиков зависит не только от вложенности элементов, но и от того, на какой фазе мы подписались.\n\nНа собеседовании важно объяснить не только слова \"capturing\" и \"bubbling\", а путь мысли: событие начинается в конкретной точке интерфейса, проходит по цепочке предков, и каждый предок может получить шанс обработать это событие.\n\n## Уточняющие вопросы\n\n### 1. Почему обработчик на родителе может увидеть клик по дочернему элементу?\n\nОжидаем: кандидат говорит, что многие события всплывают. После целевого элемента событие поднимается по предкам, поэтому обработчик родителя тоже может сработать.\n\n### 2. Зачем нужна фаза погружения, если обычно хватает всплытия?\n\nОжидаем: кандидат объясняет, что иногда нужно перехватить событие раньше, чем оно дойдет до целевого элемента или обработчиков на пути всплытия.\n\n### 3. Почему не любое событие удобно ловить на родителе?\n\nОжидаем: кандидат говорит, что не все события всплывают одинаково. Для части событий нужны другие события или отдельная подписка, например у фокуса часто используют `focusin` вместо `focus`.\n\n## Референсы\n\n- [ru.javascript.info: Всплытие и погружение](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F02-bubbling-and-capturing\u002Farticle.md) - объясняет путь события, фазы и порядок обработчиков.\n- [MDN: EventTarget addEventListener](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Feventtarget\u002Faddeventlistener\u002Findex.md) - описывает опцию `capture` и работу подписки.",{"slug":3457,"title":3458,"baseQuestion":3459,"goodAnswer":3460,"followUps":3461,"references":3471,"programSlug":19,"lessonSlug":19,"order":650,"status":13,"rawBody":3478},"scope-closures-deep-dive-q6-pochemu-zamykanie-v-cikle-s-var-chasto-daet-odno-znachenie","Почему замыкание в цикле с var часто дает одно значение?","Почему замыкание в цикле с `var` часто дает одно и то же значение?","`var` не создает новую привязку на каждую итерацию цикла. В обычном `for` с `var` есть одна общая переменная счетчика для всего цикла в ближайшей функции или script.\n\nЕсли внутри каждой итерации мы создаем функцию, эта функция замыкается не на копию числа, а на одну и ту же переменную. Когда цикл закончился, общая переменная уже имеет финальное значение. Поэтому все сохраненные callbacks читают это финальное значение.\n\nЧтобы получить отдельное значение для каждой функции, нужна отдельная привязка на каждую итерацию. В старом коде это делали через IIFE с параметром или локальной переменной. В современном коде часто используют `let` в заголовке цикла, потому что `let` создает отдельную привязку для каждой итерации.\n\nВажно: проблема не в том, что функция \"не умеет запоминать\". Наоборот, она запоминает доступ к переменной слишком точно. Просто переменная одна общая.",[3462,3465,3468],{"question":3463,"expected":3464},"Почему функции из цикла с `var` не хранят снимок значения на момент создания?","кандидат говорит, что замыкание сохраняет доступ к привязке, а не обязательно копирует значение. Все функции смотрят на одну общую переменную счетчика.",{"question":3466,"expected":3467},"Почему IIFE с параметром исправляет ситуацию?","кандидат объясняет, что при каждом вызове IIFE создается новый параметр. Callback внутри IIFE замыкается уже на этот параметр, а не на общий счетчик цикла.",{"question":3469,"expected":3470},"Почему `for (let i = 0; ...)` ведет себя иначе?","кандидат говорит, что `let` в заголовке `for` создает отдельную привязку для каждой итерации. Поэтому каждая функция получает доступ к своей итерационной переменной.",[3472,3474,3476],{"title":2519,"url":2520,"note":3473},"раздел \"Циклы + замыкание\" с `setTimeout`, IIFE и `let`.",{"title":1865,"url":1866,"note":3475},"область видимости `var` и историческое решение через IIFE.",{"title":1885,"url":1886,"note":3477},"классическая ошибка с замыканиями в цикле.","# Q6. Почему замыкание в цикле с var часто дает одно значение?\n\n## Базовый вопрос\n\nПочему замыкание в цикле с `var` часто дает одно и то же значение?\n\n## Хороший ответ\n\n`var` не создает новую привязку на каждую итерацию цикла. В обычном `for` с `var` есть одна общая переменная счетчика для всего цикла в ближайшей функции или script.\n\nЕсли внутри каждой итерации мы создаем функцию, эта функция замыкается не на копию числа, а на одну и ту же переменную. Когда цикл закончился, общая переменная уже имеет финальное значение. Поэтому все сохраненные callbacks читают это финальное значение.\n\nЧтобы получить отдельное значение для каждой функции, нужна отдельная привязка на каждую итерацию. В старом коде это делали через IIFE с параметром или локальной переменной. В современном коде часто используют `let` в заголовке цикла, потому что `let` создает отдельную привязку для каждой итерации.\n\nВажно: проблема не в том, что функция \"не умеет запоминать\". Наоборот, она запоминает доступ к переменной слишком точно. Просто переменная одна общая.\n\n## Уточняющие вопросы\n\n### 1. Почему функции из цикла с `var` не хранят снимок значения на момент создания?\n\nОжидаем: кандидат говорит, что замыкание сохраняет доступ к привязке, а не обязательно копирует значение. Все функции смотрят на одну общую переменную счетчика.\n\n### 2. Почему IIFE с параметром исправляет ситуацию?\n\nОжидаем: кандидат объясняет, что при каждом вызове IIFE создается новый параметр. Callback внутри IIFE замыкается уже на этот параметр, а не на общий счетчик цикла.\n\n### 3. Почему `for (let i = 0; ...)` ведет себя иначе?\n\nОжидаем: кандидат говорит, что `let` в заголовке `for` создает отдельную привязку для каждой итерации. Поэтому каждая функция получает доступ к своей итерационной переменной.\n\n## Референсы\n\n- [YDKJS: Глава 5. Замыкание области видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md) - раздел \"Циклы + замыкание\" с `setTimeout`, IIFE и `let`.\n- [Learn JS: Устаревшее ключевое слово var](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F04-var\u002Farticle.md) - область видимости `var` и историческое решение через IIFE.\n- [MDN: Closures](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Fclosures\u002Findex.md) - классическая ошибка с замыканиями в цикле.",{"slug":3480,"title":3481,"baseQuestion":3481,"goodAnswer":3482,"followUps":3483,"references":3493,"programSlug":21,"lessonSlug":21,"order":650,"status":13,"rawBody":3510},"types-coercion-symbol-json-q6-kakimi-znacheniyami-mogut-byt-klyuchi-svoystv-obychnogo-obekta","Какими значениями могут быть ключи свойств обычного объекта?","У обычного объекта ключ свойства в итоге может быть только строкой или `Symbol`. Это важная мысль для собеседования: когда мы пишем ключ через квадратные скобки, JavaScript не хранит там произвольное значение как ключ обычного объекта.\n\nЕсли ключ не является `Symbol`, он приводится к строке. Число `3` становится строкой `\"3\"`, `true` становится строкой `\"true\"`, обычный объект часто становится строкой `\"[object Object]\"`. Поэтому два разных объекта, использованные как ключи обычного объекта, могут попасть в один и тот же строковый ключ.\n\n`Symbol` ведет себя иначе. Он может быть ключом свойства без строкового приведения. Даже если два символа имеют одинаковое описание, это разные ключи, если они созданы разными вызовами `Symbol()`.\n\nВажно не путать `Symbol(\"a\")` и строку `\"Symbol(a)\"`. Это разные ключи. Строка просто выглядит похоже на текстовое представление символа, но она не становится тем же самым ключом.\n\nСимвольные ключи не попадают в `Object.keys()` и обычно пропускаются при JSON-сериализации. Но они не являются магически приватными: их можно получить через `Object.getOwnPropertySymbols()` или `Reflect.ownKeys()`.",[3484,3487,3490],{"question":3485,"expected":3486},"Почему после записи `obj[true] = 1` значение можно прочитать как `obj.true`?","кандидат говорит, что `true` перед записью ключа приводится к строке `\"true\"`. Точечная запись `obj.true` тоже обращается к строковому ключу `\"true\"`, поэтому мы читаем то же свойство.",{"question":3488,"expected":3489},"Почему два разных объекта как ключи обычного объекта могут перезаписать друг друга?","кандидат объясняет, что обычный объект не хранит объектные значения как ключи напрямую. Оба объекта проходят строковое приведение и по умолчанию могут дать одинаковую строку `\"[object Object]\"`.",{"question":3491,"expected":3492},"Почему `Object.keys(obj)` не показывает символьный ключ?","кандидат говорит, что `Object.keys()` возвращает перечислимые строковые ключи. Символьные ключи лежат отдельно и читаются через специальные API вроде `Object.getOwnPropertySymbols()`.",[3494,3498,3502,3506],{"title":3495,"url":3496,"note":3497},"ru.javascript.info: Объекты","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F01-object\u002Farticle.md","ключи свойств, квадратные скобки и строковые имена свойств.",{"title":3499,"url":3500,"note":3501},"ru.javascript.info: Тип данных Symbol","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F08-symbol\u002Farticle.md","`Symbol` как ключ свойства и поведение при переборе.",{"title":3503,"url":3504,"note":3505},"MDN: JSON.stringify","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fjson\u002Fstringify\u002Findex.md","пропуск символьных ключей и специальных значений при сериализации.",{"title":3507,"url":3508,"note":3509},"ECMA-262: ToPropertyKey","https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-topropertykey","формальное приведение значения к ключу свойства.","# Q6. Какими значениями могут быть ключи свойств обычного объекта?\n\n## Базовый вопрос\n\nКакими значениями могут быть ключи свойств обычного объекта?\n\n## Хороший ответ\n\nУ обычного объекта ключ свойства в итоге может быть только строкой или `Symbol`. Это важная мысль для собеседования: когда мы пишем ключ через квадратные скобки, JavaScript не хранит там произвольное значение как ключ обычного объекта.\n\nЕсли ключ не является `Symbol`, он приводится к строке. Число `3` становится строкой `\"3\"`, `true` становится строкой `\"true\"`, обычный объект часто становится строкой `\"[object Object]\"`. Поэтому два разных объекта, использованные как ключи обычного объекта, могут попасть в один и тот же строковый ключ.\n\n`Symbol` ведет себя иначе. Он может быть ключом свойства без строкового приведения. Даже если два символа имеют одинаковое описание, это разные ключи, если они созданы разными вызовами `Symbol()`.\n\nВажно не путать `Symbol(\"a\")` и строку `\"Symbol(a)\"`. Это разные ключи. Строка просто выглядит похоже на текстовое представление символа, но она не становится тем же самым ключом.\n\nСимвольные ключи не попадают в `Object.keys()` и обычно пропускаются при JSON-сериализации. Но они не являются магически приватными: их можно получить через `Object.getOwnPropertySymbols()` или `Reflect.ownKeys()`.\n\n## Уточняющие вопросы\n\n### 1. Почему после записи `obj[true] = 1` значение можно прочитать как `obj.true`?\n\nОжидаем: кандидат говорит, что `true` перед записью ключа приводится к строке `\"true\"`. Точечная запись `obj.true` тоже обращается к строковому ключу `\"true\"`, поэтому мы читаем то же свойство.\n\n### 2. Почему два разных объекта как ключи обычного объекта могут перезаписать друг друга?\n\nОжидаем: кандидат объясняет, что обычный объект не хранит объектные значения как ключи напрямую. Оба объекта проходят строковое приведение и по умолчанию могут дать одинаковую строку `\"[object Object]\"`.\n\n### 3. Почему `Object.keys(obj)` не показывает символьный ключ?\n\nОжидаем: кандидат говорит, что `Object.keys()` возвращает перечислимые строковые ключи. Символьные ключи лежат отдельно и читаются через специальные API вроде `Object.getOwnPropertySymbols()`.\n\n## Референсы\n\n- [ru.javascript.info: Объекты](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F01-object\u002Farticle.md) - ключи свойств, квадратные скобки и строковые имена свойств.\n- [ru.javascript.info: Тип данных Symbol](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F04-object-basics\u002F08-symbol\u002Farticle.md) - `Symbol` как ключ свойства и поведение при переборе.\n- [MDN: JSON.stringify](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fjson\u002Fstringify\u002Findex.md) - пропуск символьных ключей и специальных значений при сериализации.\n- [ECMA-262: ToPropertyKey](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-topropertykey) - формальное приведение значения к ключу свойства.",{"slug":3512,"title":3513,"baseQuestion":3514,"goodAnswer":3515,"followUps":3516,"references":3526,"programSlug":40,"lessonSlug":40,"order":725,"status":13,"rawBody":3535},"browser-network-q7-kak-rabotaet-fetch-api","Как работает Fetch API?","Что возвращает `fetch` и в каком порядке мы получаем данные?","Простой ответ: `fetch` возвращает Promise, который после получения ответа дает объект `Response`. Но сам `Response` еще не является готовым JSON или текстом. Чтобы прочитать тело, мы вызываем `response.json()`, `response.text()`, `response.blob()` или другой метод чтения, и это тоже асинхронный шаг.\n\nНа интервью важно проговорить две стадии:\n\n- сначала мы ждем сетевой ответ и получаем `Response`;\n- потом отдельно читаем тело ответа.\n\nЕще важно помнить, что тело читается как поток. После чтения `bodyUsed` становится `true`, и тот же body нельзя просто прочитать второй раз. Если нужно прочитать ответ двумя способами, используем `response.clone()` до первого чтения.",[3517,3520,3523],{"question":3518,"expected":3519},"Почему после `await fetch(...)` у нас еще нет обычного объекта с данными?","кандидат говорит, что `fetch` возвращает HTTP-ответ с метаданными и потоковым телом. JSON надо прочитать и распарсить отдельным вызовом.",{"question":3521,"expected":3522},"Почему тело ответа нельзя читать сколько угодно раз?","кандидат объясняет идею потока: чтение потребляет body. После этого `bodyUsed` становится `true`, и повторное чтение того же тела не работает.",{"question":3524,"expected":3525},"Когда нам может понадобиться `response.clone()`?","кандидат говорит про сценарий, где один и тот же ответ нужно отдать дальше и одновременно прочитать, например при кешировании в Service Worker или при отладочном логировании.",[3527,3531],{"title":3528,"url":3529,"note":3530},"MDN: Window fetch","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fwindow\u002Ffetch\u002Findex.md","базовое поведение `fetch`.",{"title":3532,"url":3533,"note":3534},"MDN: Response","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fresponse\u002Findex.md","чтение тела ответа и свойства ответа.","# Q7. Как работает Fetch API?\n\n## Базовый вопрос\n\nЧто возвращает `fetch` и в каком порядке мы получаем данные?\n\n## Хороший ответ\n\nПростой ответ: `fetch` возвращает Promise, который после получения ответа дает объект `Response`. Но сам `Response` еще не является готовым JSON или текстом. Чтобы прочитать тело, мы вызываем `response.json()`, `response.text()`, `response.blob()` или другой метод чтения, и это тоже асинхронный шаг.\n\nНа интервью важно проговорить две стадии:\n\n- сначала мы ждем сетевой ответ и получаем `Response`;\n- потом отдельно читаем тело ответа.\n\nЕще важно помнить, что тело читается как поток. После чтения `bodyUsed` становится `true`, и тот же body нельзя просто прочитать второй раз. Если нужно прочитать ответ двумя способами, используем `response.clone()` до первого чтения.\n\n## Уточняющие вопросы\n\n### 1. Почему после `await fetch(...)` у нас еще нет обычного объекта с данными?\n\nОжидаем: кандидат говорит, что `fetch` возвращает HTTP-ответ с метаданными и потоковым телом. JSON надо прочитать и распарсить отдельным вызовом.\n\n### 2. Почему тело ответа нельзя читать сколько угодно раз?\n\nОжидаем: кандидат объясняет идею потока: чтение потребляет body. После этого `bodyUsed` становится `true`, и повторное чтение того же тела не работает.\n\n### 3. Когда нам может понадобиться `response.clone()`?\n\nОжидаем: кандидат говорит про сценарий, где один и тот же ответ нужно отдать дальше и одновременно прочитать, например при кешировании в Service Worker или при отладочном логировании.\n\n## Референсы\n\n- [MDN: Window fetch](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fwindow\u002Ffetch\u002Findex.md) - базовое поведение `fetch`.\n- [MDN: Response](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fresponse\u002Findex.md) - чтение тела ответа и свойства ответа.",{"slug":3537,"title":3538,"baseQuestion":3539,"goodAnswer":3540,"followUps":3541,"references":3551,"programSlug":30,"lessonSlug":30,"order":725,"status":13,"rawBody":3562},"event-loop-promises-async-await-q7-kak-rabotaet-async-await","Как работает async\u002Fawait?","Как работает `async\u002Fawait`?","Сначала можно объяснить просто: `async\u002Fawait` это более удобный синтаксис для работы с промисами. Он не делает асинхронный код синхронным по-настоящему, а позволяет писать ожидание результата в линейном стиле.\n\n`async` перед функцией означает, что функция всегда возвращает Promise. Если внутри вернуть обычное значение, итоговый Promise выполнится с этим значением. Если внутри выбросить ошибку, итоговый Promise станет rejected.\n\nКод внутри async-функции до первого `await` выполняется сразу, синхронно, как в обычной функции. Когда выполнение доходит до `await`, текущая async-функция приостанавливается и возвращает управление наружу. При этом основной поток JavaScript не блокируется: браузер может выполнять другие задачи, события, таймеры и микрозадачи.\n\n`await` можно использовать внутри async-функции. Он ожидает результат промиса или thenable. Когда значение справа от `await` успешно завершается, `await` возвращает это значение внутрь функции. Когда оно завершается с ошибкой, `await` выбрасывает исключение в месте ожидания, и его можно поймать через `try\u002Fcatch`.\n\nПродолжение после `await` по смыслу похоже на код внутри `.then`: оно выполняется позже, а не в текущем синхронном стеке. Поэтому `async\u002Fawait` меняет форму записи, но не отменяет event loop, Promise и микрозадачи.\n\nВажно не путать `await` с задержкой времени. `await setTimeout(...)` не ждет таймер, потому что `setTimeout` возвращает id таймера, а не Promise.\n\nЕсли нам нужно ждать несколько независимых операций, `await` сам по себе не делает их параллельными. Параллельность зависит от того, когда мы запустили операции. Если сначала создать несколько промисов, а потом ждать их через `Promise.all`, операции идут одновременно. Если запускать следующий запрос только после `await` предыдущего, получится последовательное выполнение.",[3542,3545,3548],{"question":3543,"expected":3544},"Почему async-функция, которая возвращает `1`, снаружи дает Promise, а не число `1`?","кандидат объясняет, что `async` задает контракт функции: она всегда возвращает Promise. Обычное значение становится fulfilled-результатом этого Promise, а выброшенная ошибка становится rejected-результатом.",{"question":3546,"expected":3547},"Почему код после `await` выполняется позже синхронного кода снаружи функции?","кандидат говорит, что `await` отдает управление наружу, а продолжение async-функции попадает в асинхронное выполнение через промисы и микрозадачи. Поэтому внешний синхронный код получает шанс выполниться раньше продолжения после `await`.",{"question":3549,"expected":3550},"Почему `await setTimeout(fn, 1000)` не означает \"подождать одну секунду\"?","кандидат говорит, что `setTimeout` возвращает id таймера, а не Promise. `await` дождется только этого обычного значения, а сам callback таймера выполнится отдельно. Чтобы действительно ждать таймер, нужно обернуть его в Promise и вызвать `resolve` внутри callback.",[3552,3554,3558],{"title":2484,"url":2485,"note":3553},"базовое поведение `async`, `await` и `try\u002Fcatch`.",{"title":3555,"url":3556,"note":3557},"MDN: async function","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fstatements\u002Fasync_function\u002Findex.md","детали возврата Promise из async-функции.",{"title":3559,"url":3560,"note":3561},"MDN: await","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fawait\u002Findex.md","справочник по оператору `await`.","# Q7. Как работает async\u002Fawait?\n\n## Базовый вопрос\n\nКак работает `async\u002Fawait`?\n\n## Хороший ответ\n\nСначала можно объяснить просто: `async\u002Fawait` это более удобный синтаксис для работы с промисами. Он не делает асинхронный код синхронным по-настоящему, а позволяет писать ожидание результата в линейном стиле.\n\n`async` перед функцией означает, что функция всегда возвращает Promise. Если внутри вернуть обычное значение, итоговый Promise выполнится с этим значением. Если внутри выбросить ошибку, итоговый Promise станет rejected.\n\nКод внутри async-функции до первого `await` выполняется сразу, синхронно, как в обычной функции. Когда выполнение доходит до `await`, текущая async-функция приостанавливается и возвращает управление наружу. При этом основной поток JavaScript не блокируется: браузер может выполнять другие задачи, события, таймеры и микрозадачи.\n\n`await` можно использовать внутри async-функции. Он ожидает результат промиса или thenable. Когда значение справа от `await` успешно завершается, `await` возвращает это значение внутрь функции. Когда оно завершается с ошибкой, `await` выбрасывает исключение в месте ожидания, и его можно поймать через `try\u002Fcatch`.\n\nПродолжение после `await` по смыслу похоже на код внутри `.then`: оно выполняется позже, а не в текущем синхронном стеке. Поэтому `async\u002Fawait` меняет форму записи, но не отменяет event loop, Promise и микрозадачи.\n\nВажно не путать `await` с задержкой времени. `await setTimeout(...)` не ждет таймер, потому что `setTimeout` возвращает id таймера, а не Promise.\n\nЕсли нам нужно ждать несколько независимых операций, `await` сам по себе не делает их параллельными. Параллельность зависит от того, когда мы запустили операции. Если сначала создать несколько промисов, а потом ждать их через `Promise.all`, операции идут одновременно. Если запускать следующий запрос только после `await` предыдущего, получится последовательное выполнение.\n\n## Уточняющие вопросы\n\n### 1. Почему async-функция, которая возвращает `1`, снаружи дает Promise, а не число `1`?\n\nОжидаем: кандидат объясняет, что `async` задает контракт функции: она всегда возвращает Promise. Обычное значение становится fulfilled-результатом этого Promise, а выброшенная ошибка становится rejected-результатом.\n\n### 2. Почему код после `await` выполняется позже синхронного кода снаружи функции?\n\nОжидаем: кандидат говорит, что `await` отдает управление наружу, а продолжение async-функции попадает в асинхронное выполнение через промисы и микрозадачи. Поэтому внешний синхронный код получает шанс выполниться раньше продолжения после `await`.\n\n### 3. Почему `await setTimeout(fn, 1000)` не означает \"подождать одну секунду\"?\n\nОжидаем: кандидат говорит, что `setTimeout` возвращает id таймера, а не Promise. `await` дождется только этого обычного значения, а сам callback таймера выполнится отдельно. Чтобы действительно ждать таймер, нужно обернуть его в Promise и вызвать `resolve` внутри callback.\n\n## Референсы\n\n- [ru.javascript.info: Async await](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F08-async-await\u002Farticle.md) - базовое поведение `async`, `await` и `try\u002Fcatch`.\n- [MDN: async function](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fstatements\u002Fasync_function\u002Findex.md) - детали возврата Promise из async-функции.\n- [MDN: await](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fawait\u002Findex.md) - справочник по оператору `await`.",{"slug":3564,"title":3565,"baseQuestion":3566,"goodAnswer":3567,"followUps":3568,"references":3578,"programSlug":31,"lessonSlug":31,"order":725,"status":13,"rawBody":3611},"event-loop-promises-deep-dive-q7-chto-proizoydet-posle-abort-u-zaprosa-s-signal","Что произойдет после abort у запроса с signal?","Есть код:\n\n```js\nconst a = new AbortController();\n\nconst b = fetch('\u002Fapi', {\n  signal: a.signal,\n});\n\na.abort('c');\n```\n\nЧто произойдет с `a.signal`, запросом и Promise `b` после вызова `abort`?","`AbortController` нужен, чтобы передать асинхронной операции сигнал отмены. Сам по себе `Promise` умеет завершиться успехом или ошибкой, но он не умеет остановить работу, которая уже началась.\n\nНапример, если мы начали `fetch`, Promise от `fetch` может позже завершиться с результатом или ошибкой. Но вызов `.catch` или `Promise.race` не отменяет сетевой запрос сам по себе. Для отмены нужен отдельный механизм на уровне операции. В браузере таким стандартным механизмом является `AbortController` и его `signal`.\n\nМы создаем controller, передаем `controller.signal` в операцию, а затем вызываем `controller.abort(reason)`. Сигнал переходит в состояние aborted, получает `reason` и уведомляет подписчиков событием `abort`. Если API поддерживает этот сигнал, оно может остановить свою работу и завершиться ошибкой отмены.\n\nВажно понимать границу ответственности. `AbortController` не является заменой Promise и не превращает асинхронность в синхронный код. Он просто дает общий способ сказать \"эту работу больше не надо продолжать\".\n\nЕще одна важная деталь: сигнал отменяется один раз. После первого `abort` состояние `aborted` остается `true`, а причина отмены уже зафиксирована. Повторный `abort` не создает новую отмену с новой причиной.",[3569,3572,3575],{"question":3570,"expected":3571},"Мы сделали timeout через `Promise.race`, но не передали `signal` в `fetch`. Почему отклоненный Promise не остановит сам запрос?","кандидат разделяет итог Promise и реальную работу под ним. `Promise.race` создает новый Promise, который завершится по первому завершившемуся участнику: например, timeout отклонился раньше, и общий Promise тоже отклонился. Но это не отправляет команду в `fetch` и не освобождает сетевой ресурс. Сам запрос уже стартовал в браузерном окружении и может продолжать идти, пока сервер не ответит, соединение не оборвется или его явно не отменят. Чтобы timeout действительно отменял `fetch`, нужно связать запрос с `AbortSignal` и при таймауте вызвать `controller.abort()` или использовать готовый timeout-signal.",{"question":3573,"expected":3574},"После `controller.abort('a')` получили `signal.aborted === true` и `signal.reason === 'a'`. Почему повторный `abort('b')` не меняет reason?","кандидат объясняет одноразовость сигнала. До отмены `signal.aborted` равен `false`, а причина еще не зафиксирована. Первый `controller.abort('a')` переводит signal в состояние отмены, выставляет `aborted === true`, сохраняет `reason === 'a'` и уведомляет слушателей событием `abort`. После этого signal уже считается отмененным навсегда. Повторный `abort('b')` не запускает новую отмену и не переписывает причину, потому что стандартный алгоритм сначала проверяет, отменен ли signal, и если да, просто завершает работу.",{"question":3576,"expected":3577},"Три `fetch` получили один и тот же `signal`. Почему один вызов `abort()` может отменить все три операции?","кандидат говорит, что `signal` это общий объект-сигнал, который можно передать в несколько операций. Каждый `fetch`, получивший этот signal, подписывается на его отмену или добавляет свою abort-логику. Когда мы вызываем `controller.abort()`, меняется состояние одного общего `signal`: он становится aborted, получает reason и отправляет событие `abort`. Все операции, которые слушают этот signal и еще не завершились, видят один и тот же сигнал отмены и могут остановиться. Поэтому один controller удобен для группы связанных запросов, например для отмены всех загрузок при уходе со страницы.",[3579,3583,3585,3589,3593,3597,3601,3603,3607],{"title":3580,"url":3581,"note":3582},"ru.javascript.info: Fetch прерывание запроса","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F5-network\u002F04-fetch-abort\u002Farticle.md","отмена `fetch` и собственных асинхронных задач через `AbortController`.",{"title":3067,"url":3068,"note":3584},"`Promise.race` и отсутствие встроенной отмены у Promise.",{"title":3586,"url":3587,"note":3588},"MDN: AbortController","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fabortcontroller\u002Findex.md","справочник по controller и signal.",{"title":3590,"url":3591,"note":3592},"MDN: AbortController abort","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fabortcontroller\u002Fabort\u002Findex.md","параметр `reason` у `abort`.",{"title":3594,"url":3595,"note":3596},"MDN: AbortSignal","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fabortsignal\u002Findex.md","`aborted`, `reason` и событие `abort`.",{"title":3598,"url":3599,"note":3600},"MDN: Promise cancellation","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Fusing_promises\u002Findex.md#cancellation","Promise не имеет собственного протокола отмены.",{"title":3079,"url":3080,"note":3602},"`race` возвращает Promise с результатом первого завершившегося участника.",{"title":3604,"url":3605,"note":3606},"MDN: Fetch API using fetch","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Ffetch_api\u002Fusing_fetch\u002Findex.md#canceling_a_request","отмена `fetch` через `AbortController` и `signal`.",{"title":3608,"url":3609,"note":3610},"DOM Standard: AbortController and AbortSignal","https:\u002F\u002Fdom.spec.whatwg.org\u002F#abortcontroller","одноразовое состояние abort, `reason` и алгоритмы уведомления слушателей.","# Q7. Что произойдет после abort у запроса с signal?\n\n## Базовый вопрос\n\nЕсть код:\n\n```js\nconst a = new AbortController();\n\nconst b = fetch('\u002Fapi', {\n  signal: a.signal,\n});\n\na.abort('c');\n```\n\nЧто произойдет с `a.signal`, запросом и Promise `b` после вызова `abort`?\n\n## Хороший ответ\n\n`AbortController` нужен, чтобы передать асинхронной операции сигнал отмены. Сам по себе `Promise` умеет завершиться успехом или ошибкой, но он не умеет остановить работу, которая уже началась.\n\nНапример, если мы начали `fetch`, Promise от `fetch` может позже завершиться с результатом или ошибкой. Но вызов `.catch` или `Promise.race` не отменяет сетевой запрос сам по себе. Для отмены нужен отдельный механизм на уровне операции. В браузере таким стандартным механизмом является `AbortController` и его `signal`.\n\nМы создаем controller, передаем `controller.signal` в операцию, а затем вызываем `controller.abort(reason)`. Сигнал переходит в состояние aborted, получает `reason` и уведомляет подписчиков событием `abort`. Если API поддерживает этот сигнал, оно может остановить свою работу и завершиться ошибкой отмены.\n\nВажно понимать границу ответственности. `AbortController` не является заменой Promise и не превращает асинхронность в синхронный код. Он просто дает общий способ сказать \"эту работу больше не надо продолжать\".\n\nЕще одна важная деталь: сигнал отменяется один раз. После первого `abort` состояние `aborted` остается `true`, а причина отмены уже зафиксирована. Повторный `abort` не создает новую отмену с новой причиной.\n\n## Уточняющие вопросы\n\n### 1. Мы сделали timeout через `Promise.race`, но не передали `signal` в `fetch`. Почему отклоненный Promise не остановит сам запрос?\n\nОжидаем: кандидат разделяет итог Promise и реальную работу под ним. `Promise.race` создает новый Promise, который завершится по первому завершившемуся участнику: например, timeout отклонился раньше, и общий Promise тоже отклонился. Но это не отправляет команду в `fetch` и не освобождает сетевой ресурс. Сам запрос уже стартовал в браузерном окружении и может продолжать идти, пока сервер не ответит, соединение не оборвется или его явно не отменят. Чтобы timeout действительно отменял `fetch`, нужно связать запрос с `AbortSignal` и при таймауте вызвать `controller.abort()` или использовать готовый timeout-signal.\n\n### 2. После `controller.abort('a')` получили `signal.aborted === true` и `signal.reason === 'a'`. Почему повторный `abort('b')` не меняет reason?\n\nОжидаем: кандидат объясняет одноразовость сигнала. До отмены `signal.aborted` равен `false`, а причина еще не зафиксирована. Первый `controller.abort('a')` переводит signal в состояние отмены, выставляет `aborted === true`, сохраняет `reason === 'a'` и уведомляет слушателей событием `abort`. После этого signal уже считается отмененным навсегда. Повторный `abort('b')` не запускает новую отмену и не переписывает причину, потому что стандартный алгоритм сначала проверяет, отменен ли signal, и если да, просто завершает работу.\n\n### 3. Три `fetch` получили один и тот же `signal`. Почему один вызов `abort()` может отменить все три операции?\n\nОжидаем: кандидат говорит, что `signal` это общий объект-сигнал, который можно передать в несколько операций. Каждый `fetch`, получивший этот signal, подписывается на его отмену или добавляет свою abort-логику. Когда мы вызываем `controller.abort()`, меняется состояние одного общего `signal`: он становится aborted, получает reason и отправляет событие `abort`. Все операции, которые слушают этот signal и еще не завершились, видят один и тот же сигнал отмены и могут остановиться. Поэтому один controller удобен для группы связанных запросов, например для отмены всех загрузок при уходе со страницы.\n\n## Референсы\n\n- [ru.javascript.info: Fetch прерывание запроса](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F5-network\u002F04-fetch-abort\u002Farticle.md) - отмена `fetch` и собственных асинхронных задач через `AbortController`.\n- [ru.javascript.info: Promise API](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F05-promise-api\u002Farticle.md) - `Promise.race` и отсутствие встроенной отмены у Promise.\n- [MDN: AbortController](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fabortcontroller\u002Findex.md) - справочник по controller и signal.\n- [MDN: AbortController abort](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fabortcontroller\u002Fabort\u002Findex.md) - параметр `reason` у `abort`.\n- [MDN: AbortSignal](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fabortsignal\u002Findex.md) - `aborted`, `reason` и событие `abort`.\n- [MDN: Promise cancellation](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Fusing_promises\u002Findex.md#cancellation) - Promise не имеет собственного протокола отмены.\n- [MDN: Promise.race](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Frace\u002Findex.md) - `race` возвращает Promise с результатом первого завершившегося участника.\n- [MDN: Fetch API using fetch](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Ffetch_api\u002Fusing_fetch\u002Findex.md#canceling_a_request) - отмена `fetch` через `AbortController` и `signal`.\n- [DOM Standard: AbortController and AbortSignal](https:\u002F\u002Fdom.spec.whatwg.org\u002F#abortcontroller) - одноразовое состояние abort, `reason` и алгоритмы уведомления слушателей.",{"slug":3613,"title":1759,"baseQuestion":1760,"goodAnswer":1761,"followUps":3614,"references":3618,"programSlug":59,"lessonSlug":59,"order":725,"status":13,"rawBody":1785},"mock-interview-javascript-core-q7-chem-map-otlichaetsya-ot-obychnogo-obekta",[3615,3616,3617],{"question":1764,"expected":1765},{"question":1767,"expected":1768},{"question":1770,"expected":1771},[3619,3620,3621],{"title":1774,"url":1775,"note":1776},{"title":1778,"url":1779,"note":1780},{"title":1782,"url":1783,"note":1784},{"slug":3623,"title":3624,"baseQuestion":3624,"goodAnswer":3625,"followUps":3626,"references":3636,"programSlug":18,"lessonSlug":18,"order":725,"status":13,"rawBody":3649},"objects-prototypes-classes-q7-kak-rabotaet-nasledovanie-klassov","Как работает наследование классов?","Наследование классов через `extends` настраивает прототипные связи между классом-наследником и родительским классом.\n\nЕсли мы пишем `class B extends A`, JavaScript создает две важные связи:\n\n- `B.prototype` наследует от `A.prototype`, поэтому экземпляры `B` могут находить методы `A`;\n- сам класс `B` наследует от `A`, поэтому `B` может находить унаследованные static members.\n\nВажно: `extends` не копирует методы родителя в наследника и не копирует свойства в экземпляр. Он настраивает пути поиска. Если метода нет в `B.prototype`, JavaScript может продолжить поиск в `A.prototype`. Если static member не найден на `B`, поиск может продолжиться на `A`.\n\n`super()` используется в constructor наследника, чтобы вызвать родительский constructor. Если наследник объявил свой `constructor`, он обязан вызвать `super()` до первого обращения к `this`, потому что в derived constructor `this` еще не готов.\n\n`super.method()` используется внутри метода наследника, чтобы вызвать родительский метод. При этом `this` не становится родительским прототипом. Родительский метод вызывается с текущим экземпляром как `this`.\n\nХороший кандидат должен уметь сказать: `extends` - это настройка прототипных связей, `super()` - вызов родительского constructor, а `super.method()` - вызов родительского метода с текущим `this`.",[3627,3630,3633],{"question":3628,"expected":3629},"Почему после `class B extends A` выражение `Object.getPrototypeOf(B.prototype) === A.prototype` возвращает `true`?","кандидат объясняет, что `extends` связывает прототип наследника с прототипом родителя. Поэтому если метод не найден в `B.prototype`, поиск может продолжиться в `A.prototype`.",{"question":3631,"expected":3632},"Почему в constructor наследника нужно вызвать `super()` до обращения к `this`?","кандидат объясняет, что в derived constructor `this` еще не инициализирован. Родительский constructor должен выполнить свою часть создания объекта, и только после этого наследник может записывать свойства в `this`.",{"question":3634,"expected":3635},"Почему `super.f()` внутри метода наследника работает с текущим экземпляром?","кандидат говорит, что `super.f()` берет метод выше по прототипной цепочке, но вызывает его с текущим `this`. Поэтому родительский метод видит тот же объект, на котором был вызван метод наследника.",[3637,3641,3645],{"title":3638,"url":3639,"note":3640},"Learn JS: Наследование классов","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F02-class-inheritance\u002Farticle.md","`extends`, `super()`, `super.method()` и прототипные связи классов.",{"title":3642,"url":3643,"note":3644},"MDN: extends","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fextends\u002Findex.md","прототипные связи при `extends`.",{"title":3646,"url":3647,"note":3648},"MDN: constructor","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fconstructor\u002Findex.md","правило вызова `super()` в derived constructor.","# Q7. Как работает наследование классов?\n\n## Базовый вопрос\n\nКак работает наследование классов?\n\n## Хороший ответ\n\nНаследование классов через `extends` настраивает прототипные связи между классом-наследником и родительским классом.\n\nЕсли мы пишем `class B extends A`, JavaScript создает две важные связи:\n\n- `B.prototype` наследует от `A.prototype`, поэтому экземпляры `B` могут находить методы `A`;\n- сам класс `B` наследует от `A`, поэтому `B` может находить унаследованные static members.\n\nВажно: `extends` не копирует методы родителя в наследника и не копирует свойства в экземпляр. Он настраивает пути поиска. Если метода нет в `B.prototype`, JavaScript может продолжить поиск в `A.prototype`. Если static member не найден на `B`, поиск может продолжиться на `A`.\n\n`super()` используется в constructor наследника, чтобы вызвать родительский constructor. Если наследник объявил свой `constructor`, он обязан вызвать `super()` до первого обращения к `this`, потому что в derived constructor `this` еще не готов.\n\n`super.method()` используется внутри метода наследника, чтобы вызвать родительский метод. При этом `this` не становится родительским прототипом. Родительский метод вызывается с текущим экземпляром как `this`.\n\nХороший кандидат должен уметь сказать: `extends` - это настройка прототипных связей, `super()` - вызов родительского constructor, а `super.method()` - вызов родительского метода с текущим `this`.\n\n## Уточняющие вопросы\n\n### 1. Почему после `class B extends A` выражение `Object.getPrototypeOf(B.prototype) === A.prototype` возвращает `true`?\n\nОжидаем: кандидат объясняет, что `extends` связывает прототип наследника с прототипом родителя. Поэтому если метод не найден в `B.prototype`, поиск может продолжиться в `A.prototype`.\n\n### 2. Почему в constructor наследника нужно вызвать `super()` до обращения к `this`?\n\nОжидаем: кандидат объясняет, что в derived constructor `this` еще не инициализирован. Родительский constructor должен выполнить свою часть создания объекта, и только после этого наследник может записывать свойства в `this`.\n\n### 3. Почему `super.f()` внутри метода наследника работает с текущим экземпляром?\n\nОжидаем: кандидат говорит, что `super.f()` берет метод выше по прототипной цепочке, но вызывает его с текущим `this`. Поэтому родительский метод видит тот же объект, на котором был вызван метод наследника.\n\n## Референсы\n\n- [Learn JS: Наследование классов](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F02-class-inheritance\u002Farticle.md) - `extends`, `super()`, `super.method()` и прототипные связи классов.\n- [MDN: extends](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fextends\u002Findex.md) - прототипные связи при `extends`.\n- [MDN: constructor](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fconstructor\u002Findex.md) - правило вызова `super()` в derived constructor.",{"slug":3651,"title":3652,"baseQuestion":3653,"goodAnswer":3654,"followUps":3655,"references":3665,"programSlug":50,"lessonSlug":50,"order":725,"status":13,"rawBody":3674},"recursion-q7-kak-funkciya-mozhet-ssylatsya-na-sebya","Как функция может ссылаться на себя?","Как рекурсивная функция находит саму себя при повторном вызове?","Обычно функция вызывает себя по имени. У function declaration это имя создается в окружающей области видимости, поэтому внутри тела функции оно доступно.\n\nС function expression есть важная деталь: выражение может быть именованным. В записи `const a = function f() { return f(); }` имя `f` доступно внутри самой функции и указывает на эту функцию. При этом снаружи имя `f` не появляется как отдельная переменная.\n\nЭто полезно для рекурсии, потому что ссылка на функцию не зависит от внешней переменной. Если внешнюю переменную потом переназначить, внутреннее имя function expression все равно продолжит указывать на исходную функцию.\n\nДля стрелочных функций отдельного внутреннего имени нет. Они могут вызывать себя через внешнюю переменную, но это слабее: если переменную переназначили, рекурсивная ссылка может сломаться.",[3656,3659,3662],{"question":3657,"expected":3658},"Зачем именовать function expression, если функция уже лежит в переменной?","кандидат объясняет, что внутреннее имя дает стабильную ссылку на саму функцию для рекурсии и отладки.",{"question":3660,"expected":3661},"Почему после `a = null` именованная function expression все еще может вызвать себя через внутреннее имя?","кандидат говорит, что внутреннее имя привязано к самой функции, а не к внешней переменной `a`.",{"question":3663,"expected":3664},"Почему стрелочная функция хуже подходит для саморекурсии через собственное имя?","кандидат объясняет, что у стрелочной функции нет своего внутреннего имени function expression, поэтому она обычно зависит от внешней привязки.",[3666,3670],{"title":3667,"url":3668,"note":3669},"ECMAScript: Function Definitions","https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-function-definitions","внутреннее имя FunctionExpression доступно в теле функции.",{"title":3671,"url":3672,"note":3673},"Вы не знаете JS: ES6 и дальше — глава 2 Syntax","https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fes6%20%26%20beyond\u002Fch2.md","зачем function expression нужно имя для рекурсии и self-reference.","# Q7. Как функция может ссылаться на себя?\n\n## Базовый вопрос\n\nКак рекурсивная функция находит саму себя при повторном вызове?\n\n## Хороший ответ\n\nОбычно функция вызывает себя по имени. У function declaration это имя создается в окружающей области видимости, поэтому внутри тела функции оно доступно.\n\nС function expression есть важная деталь: выражение может быть именованным. В записи `const a = function f() { return f(); }` имя `f` доступно внутри самой функции и указывает на эту функцию. При этом снаружи имя `f` не появляется как отдельная переменная.\n\nЭто полезно для рекурсии, потому что ссылка на функцию не зависит от внешней переменной. Если внешнюю переменную потом переназначить, внутреннее имя function expression все равно продолжит указывать на исходную функцию.\n\nДля стрелочных функций отдельного внутреннего имени нет. Они могут вызывать себя через внешнюю переменную, но это слабее: если переменную переназначили, рекурсивная ссылка может сломаться.\n\n## Уточняющие вопросы\n\n### 1. Зачем именовать function expression, если функция уже лежит в переменной?\n\nОжидаем: кандидат объясняет, что внутреннее имя дает стабильную ссылку на саму функцию для рекурсии и отладки.\n\n### 2. Почему после `a = null` именованная function expression все еще может вызвать себя через внутреннее имя?\n\nОжидаем: кандидат говорит, что внутреннее имя привязано к самой функции, а не к внешней переменной `a`.\n\n### 3. Почему стрелочная функция хуже подходит для саморекурсии через собственное имя?\n\nОжидаем: кандидат объясняет, что у стрелочной функции нет своего внутреннего имени function expression, поэтому она обычно зависит от внешней привязки.\n\n## Референсы\n\n- [ECMAScript: Function Definitions](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-function-definitions) - внутреннее имя FunctionExpression доступно в теле функции.\n- [Вы не знаете JS: ES6 и дальше — глава 2 Syntax](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fes6%20%26%20beyond\u002Fch2.md) - зачем function expression нужно имя для рекурсии и self-reference.",{"slug":3676,"title":3677,"baseQuestion":3677,"goodAnswer":3678,"followUps":3679,"references":3689,"programSlug":41,"lessonSlug":41,"order":725,"status":13,"rawBody":3700},"rendering-dom-events-forms-q7-chem-event-target-otlichaetsya-ot-event-currenttarget","Чем `event.target` отличается от `event.currentTarget`?","Если объяснять простыми словами, `event.target` отвечает на вопрос \"где событие началось\", а `event.currentTarget` отвечает на вопрос \"чей обработчик выполняется прямо сейчас\".\n\nНапример, мы кликнули по вложенному `span`, а обработчик висит на родительском `button`. Тогда `target` будет указывать на `span`, потому что событие началось там. `currentTarget` будет указывать на `button`, потому что сейчас выполняется обработчик кнопки.\n\nЭта разница особенно важна при всплытии и делегировании. Один и тот же объект события проходит через разные элементы. `target` остается исходной целью события, а `currentTarget` меняется от обработчика к обработчику.\n\nХороший ответ должен показать, что кандидат не путает \"элемент, по которому кликнули\" и \"элемент, на котором висит текущий listener\".",[3680,3683,3686],{"question":3681,"expected":3682},"Мы кликнули по `span` внутри `button`, а обработчик стоит на `button`. Что будет в `target`?","кандидат говорит, что `target` будет ссылаться на `span`, если именно он стал исходной целью события.",{"question":3684,"expected":3685},"Почему `currentTarget` полезен, когда один обработчик стоит на родителе?","кандидат объясняет, что `currentTarget` стабильно указывает на элемент с текущим обработчиком. Это помогает не потерять контейнер, через который мы обрабатываем событие.",{"question":3687,"expected":3688},"Почему в обработчике на родителе нельзя всегда считать `target` самим родителем?","кандидат говорит, что из-за всплытия событие могло начаться глубже. Родитель только получил событие позже по пути.",[3690,3694,3698],{"title":3691,"url":3692,"note":3693},"MDN: Event target","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fevent\u002Ftarget\u002Findex.md","описывает исходную цель события.",{"title":3695,"url":3696,"note":3697},"MDN: Event currentTarget","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fevent\u002Fcurrenttarget\u002Findex.md","описывает элемент, обработчик которого выполняется.",{"title":3448,"url":3449,"note":3699},"показывает разницу на примерах всплытия.","# Q7. Чем `event.target` отличается от `event.currentTarget`?\n\n## Базовый вопрос\n\nЧем `event.target` отличается от `event.currentTarget`?\n\n## Хороший ответ\n\nЕсли объяснять простыми словами, `event.target` отвечает на вопрос \"где событие началось\", а `event.currentTarget` отвечает на вопрос \"чей обработчик выполняется прямо сейчас\".\n\nНапример, мы кликнули по вложенному `span`, а обработчик висит на родительском `button`. Тогда `target` будет указывать на `span`, потому что событие началось там. `currentTarget` будет указывать на `button`, потому что сейчас выполняется обработчик кнопки.\n\nЭта разница особенно важна при всплытии и делегировании. Один и тот же объект события проходит через разные элементы. `target` остается исходной целью события, а `currentTarget` меняется от обработчика к обработчику.\n\nХороший ответ должен показать, что кандидат не путает \"элемент, по которому кликнули\" и \"элемент, на котором висит текущий listener\".\n\n## Уточняющие вопросы\n\n### 1. Мы кликнули по `span` внутри `button`, а обработчик стоит на `button`. Что будет в `target`?\n\nОжидаем: кандидат говорит, что `target` будет ссылаться на `span`, если именно он стал исходной целью события.\n\n### 2. Почему `currentTarget` полезен, когда один обработчик стоит на родителе?\n\nОжидаем: кандидат объясняет, что `currentTarget` стабильно указывает на элемент с текущим обработчиком. Это помогает не потерять контейнер, через который мы обрабатываем событие.\n\n### 3. Почему в обработчике на родителе нельзя всегда считать `target` самим родителем?\n\nОжидаем: кандидат говорит, что из-за всплытия событие могло начаться глубже. Родитель только получил событие позже по пути.\n\n## Референсы\n\n- [MDN: Event target](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fevent\u002Ftarget\u002Findex.md) - описывает исходную цель события.\n- [MDN: Event currentTarget](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fevent\u002Fcurrenttarget\u002Findex.md) - описывает элемент, обработчик которого выполняется.\n- [ru.javascript.info: Всплытие и погружение](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F02-bubbling-and-capturing\u002Farticle.md) - показывает разницу на примерах всплытия.",{"slug":3702,"title":3703,"baseQuestion":3703,"goodAnswer":3704,"followUps":3705,"references":3715,"programSlug":19,"lessonSlug":19,"order":725,"status":13,"rawBody":3722},"scope-closures-deep-dive-q7-chto-delaet-funkciyu-modulem-cherez-zamykanie","Что делает функцию модулем через замыкание?","Модульный паттерн через замыкание появляется, когда мы вызываем внешнюю функцию, создаем внутри нее приватные переменные и возвращаем наружу API с функциями, которые имеют доступ к этим приватным переменным.\n\nНужны две важные части. Первая: внешняя функция должна быть вызвана, чтобы появилась отдельная внутренняя область с состоянием. Вторая: наружу должна выйти хотя бы одна внутренняя функция, которая замыкается на эту область и может читать или менять приватное состояние.\n\nПросто объект со свойствами сам по себе не является модулем в этом смысле. Если нет закрытой области и функций, которые продолжают иметь к ней доступ, то нет и приватного состояния через замыкание.\n\nТакой паттерн помогает не хранить внутренние детали в глобальной области и отдавать наружу только нужные операции. Несколько вызовов фабрики модуля могут создать несколько независимых экземпляров с разным приватным состоянием.",[3706,3709,3712],{"question":3707,"expected":3708},"Почему внешнюю функцию нужно именно вызвать?","кандидат говорит, что без вызова не создастся конкретное лексическое окружение с приватными переменными. Само определение функции еще не создает экземпляр состояния модуля.",{"question":3710,"expected":3711},"Почему возвращенный объект с одними данными не дает тот же модульный эффект?","кандидат объясняет, что данные объекта доступны напрямую как свойства. Для модульного паттерна важны функции в API, которые замыкаются на скрытую область и управляют состоянием без прямого доступа снаружи.",{"question":3713,"expected":3714},"Почему два вызова фабрики модуля могут иметь независимое состояние?","кандидат говорит, что каждый вызов внешней функции создает новое лексическое окружение. Функции из первого возвращенного API замкнуты на первое окружение, функции из второго API на второе.",[3716,3718,3720],{"title":2519,"url":2520,"note":3717},"раздел \"Модули\" и признаки модульного паттерна.",{"title":1861,"url":1862,"note":3719},"сохранение внешнего лексического окружения функцией.",{"title":1873,"url":1874,"note":3721},"современная модульная область как развитие идеи изоляции.","# Q7. Что делает функцию модулем через замыкание?\n\n## Базовый вопрос\n\nЧто делает функцию модулем через замыкание?\n\n## Хороший ответ\n\nМодульный паттерн через замыкание появляется, когда мы вызываем внешнюю функцию, создаем внутри нее приватные переменные и возвращаем наружу API с функциями, которые имеют доступ к этим приватным переменным.\n\nНужны две важные части. Первая: внешняя функция должна быть вызвана, чтобы появилась отдельная внутренняя область с состоянием. Вторая: наружу должна выйти хотя бы одна внутренняя функция, которая замыкается на эту область и может читать или менять приватное состояние.\n\nПросто объект со свойствами сам по себе не является модулем в этом смысле. Если нет закрытой области и функций, которые продолжают иметь к ней доступ, то нет и приватного состояния через замыкание.\n\nТакой паттерн помогает не хранить внутренние детали в глобальной области и отдавать наружу только нужные операции. Несколько вызовов фабрики модуля могут создать несколько независимых экземпляров с разным приватным состоянием.\n\n## Уточняющие вопросы\n\n### 1. Почему внешнюю функцию нужно именно вызвать?\n\nОжидаем: кандидат говорит, что без вызова не создастся конкретное лексическое окружение с приватными переменными. Само определение функции еще не создает экземпляр состояния модуля.\n\n### 2. Почему возвращенный объект с одними данными не дает тот же модульный эффект?\n\nОжидаем: кандидат объясняет, что данные объекта доступны напрямую как свойства. Для модульного паттерна важны функции в API, которые замыкаются на скрытую область и управляют состоянием без прямого доступа снаружи.\n\n### 3. Почему два вызова фабрики модуля могут иметь независимое состояние?\n\nОжидаем: кандидат говорит, что каждый вызов внешней функции создает новое лексическое окружение. Функции из первого возвращенного API замкнуты на первое окружение, функции из второго API на второе.\n\n## Референсы\n\n- [YDKJS: Глава 5. Замыкание области видимости](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002Fch5.md) - раздел \"Модули\" и признаки модульного паттерна.\n- [Learn JS: Область видимости переменных, замыкание](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F06-advanced-functions\u002F03-closure\u002Farticle.md) - сохранение внешнего лексического окружения функцией.\n- [Learn JS: Модули, введение](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F13-modules\u002F01-modules-intro\u002Farticle.md) - современная модульная область как развитие идеи изоляции.",{"slug":3724,"title":3354,"baseQuestion":3354,"goodAnswer":3355,"followUps":3725,"references":3729,"programSlug":21,"lessonSlug":21,"order":725,"status":13,"rawBody":3382},"types-coercion-symbol-json-q7-kak-rabotaet-nestrogoe-ravenstvo",[3726,3727,3728],{"question":3358,"expected":3359},{"question":3361,"expected":3362},{"question":3364,"expected":3365},[3730,3731,3732,3733],{"title":3368,"url":3369,"note":3370},{"title":3372,"url":3373,"note":3374},{"title":3376,"url":2660,"note":3377},{"title":3379,"url":3380,"note":3381},{"slug":3735,"title":3736,"baseQuestion":3737,"goodAnswer":3738,"followUps":3739,"references":3749,"programSlug":40,"lessonSlug":40,"order":796,"status":13,"rawBody":3760},"browser-network-q8-zachem-nuzhny-request-response-i-headers","Зачем нужны Request Response и Headers?","Какую роль играют `Request`, `Response` и `Headers` в Fetch API?","Если объяснять просто, Fetch API не работает только со строкой URL. Он дает отдельные объекты для частей сетевого обмена. `Request` описывает запрос, `Response` описывает ответ, а `Headers` хранит HTTP-заголовки.\n\n`Request` удобен, когда мы хотим заранее собрать метод, URL, заголовки, body, credentials, cache mode и другие настройки. `Response` хранит статус, `ok`, headers, url и body. `Headers` дает единый API для чтения и изменения заголовков с учетом нормализации имен.\n\nТехнически эти объекты особенно важны в Service Worker. Там мы получаем событие fetch с `request`, можем выполнить сетевой запрос, вернуть `Response`, положить копию в Cache Storage или собрать ответ самостоятельно.",[3740,3743,3746],{"question":3741,"expected":3742},"Почему удобнее работать с `Headers`, а не с обычным объектом?","кандидат говорит, что имена заголовков нечувствительны к регистру, значения могут объединяться, а API `Headers` учитывает правила браузера.",{"question":3744,"expected":3745},"Почему `Request` и `Response` умеют `clone()`?","кандидат объясняет, что body является потоком. clone нужен, чтобы заранее сделать вторую копию для чтения или передачи дальше.",{"question":3747,"expected":3748},"Где кроме обычного `fetch` мы встречаем эти объекты?","кандидат называет Service Worker, Cache API, обработку fetch-событий и ручное создание ответов.",[3750,3754,3756],{"title":3751,"url":3752,"note":3753},"MDN: Request","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Frequest\u002Findex.md","объект запроса в Fetch API.",{"title":3532,"url":3533,"note":3755},"объект ответа в Fetch API.",{"title":3757,"url":3758,"note":3759},"MDN: Headers","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fheaders\u002Findex.md","API заголовков.","# Q8. Зачем нужны Request Response и Headers?\n\n## Базовый вопрос\n\nКакую роль играют `Request`, `Response` и `Headers` в Fetch API?\n\n## Хороший ответ\n\nЕсли объяснять просто, Fetch API не работает только со строкой URL. Он дает отдельные объекты для частей сетевого обмена. `Request` описывает запрос, `Response` описывает ответ, а `Headers` хранит HTTP-заголовки.\n\n`Request` удобен, когда мы хотим заранее собрать метод, URL, заголовки, body, credentials, cache mode и другие настройки. `Response` хранит статус, `ok`, headers, url и body. `Headers` дает единый API для чтения и изменения заголовков с учетом нормализации имен.\n\nТехнически эти объекты особенно важны в Service Worker. Там мы получаем событие fetch с `request`, можем выполнить сетевой запрос, вернуть `Response`, положить копию в Cache Storage или собрать ответ самостоятельно.\n\n## Уточняющие вопросы\n\n### 1. Почему удобнее работать с `Headers`, а не с обычным объектом?\n\nОжидаем: кандидат говорит, что имена заголовков нечувствительны к регистру, значения могут объединяться, а API `Headers` учитывает правила браузера.\n\n### 2. Почему `Request` и `Response` умеют `clone()`?\n\nОжидаем: кандидат объясняет, что body является потоком. clone нужен, чтобы заранее сделать вторую копию для чтения или передачи дальше.\n\n### 3. Где кроме обычного `fetch` мы встречаем эти объекты?\n\nОжидаем: кандидат называет Service Worker, Cache API, обработку fetch-событий и ручное создание ответов.\n\n## Референсы\n\n- [MDN: Request](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Frequest\u002Findex.md) - объект запроса в Fetch API.\n- [MDN: Response](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fresponse\u002Findex.md) - объект ответа в Fetch API.\n- [MDN: Headers](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fheaders\u002Findex.md) - API заголовков.",{"slug":3762,"title":3763,"baseQuestion":3764,"goodAnswer":3765,"followUps":3766,"references":3776,"programSlug":30,"lessonSlug":30,"order":796,"status":13,"rawBody":3783},"event-loop-promises-async-await-q8-kak-rabotaet-promise-all","Как работает Promise.all?","Как работает `Promise.all`?","Сначала можно объяснить так: `Promise.all` нужен для сценария \"нужны все успешные результаты\". Мы передаем iterable с промисами или обычными значениями, а на выходе получаем Promise общего результата.\n\n`Promise.all` успешно выполняется, когда все входные значения успешно завершились. Результат приходит массивом в порядке исходного iterable, а не в порядке фактического завершения. Если первый промис завершился последним, его результат все равно будет первым элементом итогового массива.\n\nВ iterable можно передавать не только промисы. Обычные значения считаются уже готовыми успешными результатами и попадают в итоговый массив как значения. Но чаще всего `Promise.all` используют с массивом промисов, например после `map`, где каждый элемент запускает `fetch` или другую асинхронную операцию.\n\nЕсли хотя бы один входной промис отклоняется, итоговый Promise отклоняется с этой причиной. Это поведение называют fail fast: общий результат больше не ждет успешной картины \"все готово\", потому что условие \"все успешно\" уже невозможно.\n\nПри этом `Promise.all` не отменяет остальные операции. Если другие запросы уже запущены, они обычно продолжат выполняться, но их результаты для этого `Promise.all` больше не нужны. Отмена запросов - это отдельная тема, обычно через `AbortController`, а не через сам Promise API.\n\nЕсли нужны не только успешные результаты, а все исходы, используют `Promise.allSettled`. Он ждет завершения всех входных значений и возвращает массив объектов со статусами `fulfilled` или `rejected`.\n\nВажная практическая ловушка: `Promise.all` не запускает функции. Он принимает уже созданные промисы или значения. Если передать `[f, g]`, где `f` и `g` - функции, то он просто увидит две обычные функции как значения. Чтобы стартовала асинхронная работа, нужно вызвать функции: `Promise.all([f(), g()])`.",[3767,3770,3773],{"question":3768,"expected":3769},"Почему результат `Promise.all` сохраняет порядок входного массива, а не порядок завершения операций?","кандидат говорит, что метод собирает результаты по позициям исходного iterable. Время завершения влияет на момент готовности общего результата, но не на порядок элементов. Это удобно, когда мы хотим сопоставить результат с исходным массивом запросов.",{"question":3771,"expected":3772},"Что происходит с остальными запросами, если один промис внутри `Promise.all` отклонился?","кандидат объясняет, что итоговый Promise отклоняется с причиной первого отклонения, которое определило общий провал. Сами уже запущенные операции не отменяются автоматически и могут продолжить выполняться, просто их результаты больше не используются этим `Promise.all`.",{"question":3774,"expected":3775},"Когда `Promise.allSettled` подходит лучше, чем `Promise.all`?","кандидат говорит про частичные результаты: нам важно увидеть и успешные, и ошибочные исходы, например при загрузке независимых блоков данных. `allSettled` подходит, когда ошибка одной операции не должна скрывать информацию о других.",[3777,3779,3781],{"title":3067,"url":3068,"note":3778},"`Promise.all`, `Promise.allSettled` и поведение при ошибках.",{"title":3071,"url":3072,"note":3780},"справочник по `Promise.all`.",{"title":3075,"url":3076,"note":3782},"справочник по `Promise.allSettled`.","# Q8. Как работает Promise.all?\n\n## Базовый вопрос\n\nКак работает `Promise.all`?\n\n## Хороший ответ\n\nСначала можно объяснить так: `Promise.all` нужен для сценария \"нужны все успешные результаты\". Мы передаем iterable с промисами или обычными значениями, а на выходе получаем Promise общего результата.\n\n`Promise.all` успешно выполняется, когда все входные значения успешно завершились. Результат приходит массивом в порядке исходного iterable, а не в порядке фактического завершения. Если первый промис завершился последним, его результат все равно будет первым элементом итогового массива.\n\nВ iterable можно передавать не только промисы. Обычные значения считаются уже готовыми успешными результатами и попадают в итоговый массив как значения. Но чаще всего `Promise.all` используют с массивом промисов, например после `map`, где каждый элемент запускает `fetch` или другую асинхронную операцию.\n\nЕсли хотя бы один входной промис отклоняется, итоговый Promise отклоняется с этой причиной. Это поведение называют fail fast: общий результат больше не ждет успешной картины \"все готово\", потому что условие \"все успешно\" уже невозможно.\n\nПри этом `Promise.all` не отменяет остальные операции. Если другие запросы уже запущены, они обычно продолжат выполняться, но их результаты для этого `Promise.all` больше не нужны. Отмена запросов - это отдельная тема, обычно через `AbortController`, а не через сам Promise API.\n\nЕсли нужны не только успешные результаты, а все исходы, используют `Promise.allSettled`. Он ждет завершения всех входных значений и возвращает массив объектов со статусами `fulfilled` или `rejected`.\n\nВажная практическая ловушка: `Promise.all` не запускает функции. Он принимает уже созданные промисы или значения. Если передать `[f, g]`, где `f` и `g` - функции, то он просто увидит две обычные функции как значения. Чтобы стартовала асинхронная работа, нужно вызвать функции: `Promise.all([f(), g()])`.\n\n## Уточняющие вопросы\n\n### 1. Почему результат `Promise.all` сохраняет порядок входного массива, а не порядок завершения операций?\n\nОжидаем: кандидат говорит, что метод собирает результаты по позициям исходного iterable. Время завершения влияет на момент готовности общего результата, но не на порядок элементов. Это удобно, когда мы хотим сопоставить результат с исходным массивом запросов.\n\n### 2. Что происходит с остальными запросами, если один промис внутри `Promise.all` отклонился?\n\nОжидаем: кандидат объясняет, что итоговый Promise отклоняется с причиной первого отклонения, которое определило общий провал. Сами уже запущенные операции не отменяются автоматически и могут продолжить выполняться, просто их результаты больше не используются этим `Promise.all`.\n\n### 3. Когда `Promise.allSettled` подходит лучше, чем `Promise.all`?\n\nОжидаем: кандидат говорит про частичные результаты: нам важно увидеть и успешные, и ошибочные исходы, например при загрузке независимых блоков данных. `allSettled` подходит, когда ошибка одной операции не должна скрывать информацию о других.\n\n## Референсы\n\n- [ru.javascript.info: Promise API](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F11-async\u002F05-promise-api\u002Farticle.md) - `Promise.all`, `Promise.allSettled` и поведение при ошибках.\n- [MDN: Promise.all](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fall\u002Findex.md) - справочник по `Promise.all`.\n- [MDN: Promise.allSettled](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fpromise\u002Fallsettled\u002Findex.md) - справочник по `Promise.allSettled`.",{"slug":3785,"title":3786,"baseQuestion":3787,"goodAnswer":3788,"followUps":3789,"references":3799,"programSlug":31,"lessonSlug":31,"order":796,"status":13,"rawBody":3824},"event-loop-promises-deep-dive-q8-pochemu-for-await-ne-obrabatyvaet-vse-znacheniya-srazu","Почему for await не обрабатывает все значения сразу?","Есть async generator:\n\n```js\nasync function* f() {\n  yield await Promise.resolve('a');\n  yield await Promise.resolve('b');\n}\n\n(async function g() {\n  for await (const a of f()) {\n    console.log(a);\n  }\n})();\n```\n\nПочему цикл получает и обрабатывает значения по одному, а не запускает обработку всех значений сразу?","`for await...of` нужен для перебора асинхронных источников данных. Обычный `for...of` берет значения из синхронного iterable. `for await...of` умеет ждать значения, которые приходят через async iterable.\n\nAsync iterable - это объект, у которого есть метод `Symbol.asyncIterator`. Этот метод возвращает async iterator. У iterator есть метод `next`, который возвращает Promise с объектом вида `{ value, done }`. Цикл вызывает `next`, ждет Promise, смотрит на `done` и либо передает `value` в тело цикла, либо завершает перебор.\n\nАсинхронный генератор `async function*` удобно создает такой async iterable автоматически. Внутри него можно использовать `await`, а наружу отдавать значения через `yield`.\n\nВажная деталь: `for await...of` обрабатывает значения последовательно. Он не берет следующий элемент, пока не дождался текущего `next` и пока тело текущей итерации не закончило выполнение. Поэтому это хороший инструмент для потоков данных и последовательной обработки, но не способ автоматически распараллелить все элементы.\n\nЕще одна деталь: если async generator делает `return`, это завершает iterator. Возвращенное значение не попадает как обычный элемент в тело цикла.",[3790,3793,3796],{"question":3791,"expected":3792},"У объекта есть `Symbol.asyncIterator`, а `next()` возвращает Promise. Почему обычный `for...of` не подходит, а `for await...of` подходит?","кандидат разделяет два протокола итерации. Обычный `for...of` ищет `Symbol.iterator` и работает с синхронным iterator, у которого `next()` сразу возвращает объект результата вида `{ value, done }`. Если у объекта есть только `Symbol.asyncIterator`, для обычного `for...of` это не тот контракт: он не будет ждать Promise от `next()` и не сможет нормально получить асинхронные значения. `for await...of` как раз берет async iterator через `Symbol.asyncIterator`, вызывает `next()` и ждет Promise с результатом итерации. Поэтому он подходит для данных, которые появляются позже, например после таймера, сетевого чтения или шага async generator.",{"question":3794,"expected":3795},"В теле `for await...of` мы стартовали асинхронную работу, но не сделали `await`. Почему цикл может перейти к следующему элементу раньше завершения этой работы?","кандидат объясняет, что у цикла есть своя обязанность: на каждой итерации он вызывает `next()`, ждет Promise от async iterator, проверяет `done`, передает `value` в тело и после завершения тела переходит к следующему `next()`. Но если внутри тела мы просто вызвали асинхронную функцию и не сделали `await`, то для самого тела это обычное синхронное действие: Promise создан, работа стартовала, а блок кода уже закончился. Цикл не отслеживает все промисы, которые мы могли случайно создать внутри тела. Чтобы обработка одного элемента действительно ждала эту работу, мы пишем `await` внутри тела. Если нужна параллельная обработка, мы осознанно собираем промисы и потом ждем их, например через `Promise.all`.\n\nХороший ответ разделяет две вещи: цикл последовательно получает элементы из async iterator, но он не обязан ждать каждую асинхронную операцию, которую мы запустили внутри тела. Он ждет только то ожидание, которое стало частью выполнения тела цикла.",{"question":3797,"expected":3798},"Async generator сделал `yield 1`, а потом `return 2`. Почему тело `for await...of` получает `1`, но не получает `2`?","кандидат говорит, что `yield` отдает очередное значение наружу как обычный элемент последовательности, поэтому `yield 1` приходит в тело цикла при результате `{ value: 1, done: false }`. `return 2` работает иначе: он завершает async generator и дает результат итератора с `done: true`. Для `for await...of` значение при `done: true` уже не является элементом цикла, поэтому тело не выполняется с `2`. Это значение можно увидеть при ручном вызове `await generator.next()`, но обычный цикл использует `done: true` как сигнал остановиться.",[3800,3804,3808,3812,3816,3820],{"title":3801,"url":3802,"note":3803},"ru.javascript.info: Асинхронные итераторы и генераторы","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F12-generators-iterators\u002F2-async-iterators-generators\u002Farticle.md","async iterable, async generator и `for await...of`.",{"title":3805,"url":3806,"note":3807},"MDN: for await...of","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fstatements\u002Ffor-await...of\u002Findex.md","справочник по синтаксису и поведению цикла.",{"title":3809,"url":3810,"note":3811},"MDN: AsyncIterator","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fasynciterator\u002Findex.md","async iterator protocol и связь с `Symbol.asyncIterator`.",{"title":3813,"url":3814,"note":3815},"MDN: AsyncGenerator","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fasyncgenerator\u002Findex.md","объект, который возвращает `async function*`.",{"title":3817,"url":3818,"note":3819},"ECMA-262: ForInOfStatement","https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#L22364","формальная механика `for await...of`, ожидание `next()` и проверка `done`.",{"title":3821,"url":3822,"note":3823},"ECMA-262: AsyncGenerator Objects","https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#L50743","async generator как async iterator и async iterable.","# Q8. Почему for await не обрабатывает все значения сразу?\n\n## Базовый вопрос\n\nЕсть async generator:\n\n```js\nasync function* f() {\n  yield await Promise.resolve('a');\n  yield await Promise.resolve('b');\n}\n\n(async function g() {\n  for await (const a of f()) {\n    console.log(a);\n  }\n})();\n```\n\nПочему цикл получает и обрабатывает значения по одному, а не запускает обработку всех значений сразу?\n\n## Хороший ответ\n\n`for await...of` нужен для перебора асинхронных источников данных. Обычный `for...of` берет значения из синхронного iterable. `for await...of` умеет ждать значения, которые приходят через async iterable.\n\nAsync iterable - это объект, у которого есть метод `Symbol.asyncIterator`. Этот метод возвращает async iterator. У iterator есть метод `next`, который возвращает Promise с объектом вида `{ value, done }`. Цикл вызывает `next`, ждет Promise, смотрит на `done` и либо передает `value` в тело цикла, либо завершает перебор.\n\nАсинхронный генератор `async function*` удобно создает такой async iterable автоматически. Внутри него можно использовать `await`, а наружу отдавать значения через `yield`.\n\nВажная деталь: `for await...of` обрабатывает значения последовательно. Он не берет следующий элемент, пока не дождался текущего `next` и пока тело текущей итерации не закончило выполнение. Поэтому это хороший инструмент для потоков данных и последовательной обработки, но не способ автоматически распараллелить все элементы.\n\nЕще одна деталь: если async generator делает `return`, это завершает iterator. Возвращенное значение не попадает как обычный элемент в тело цикла.\n\n## Уточняющие вопросы\n\n### 1. У объекта есть `Symbol.asyncIterator`, а `next()` возвращает Promise. Почему обычный `for...of` не подходит, а `for await...of` подходит?\n\nОжидаем: кандидат разделяет два протокола итерации. Обычный `for...of` ищет `Symbol.iterator` и работает с синхронным iterator, у которого `next()` сразу возвращает объект результата вида `{ value, done }`. Если у объекта есть только `Symbol.asyncIterator`, для обычного `for...of` это не тот контракт: он не будет ждать Promise от `next()` и не сможет нормально получить асинхронные значения. `for await...of` как раз берет async iterator через `Symbol.asyncIterator`, вызывает `next()` и ждет Promise с результатом итерации. Поэтому он подходит для данных, которые появляются позже, например после таймера, сетевого чтения или шага async generator.\n\n### 2. В теле `for await...of` мы стартовали асинхронную работу, но не сделали `await`. Почему цикл может перейти к следующему элементу раньше завершения этой работы?\n\nОжидаем: кандидат объясняет, что у цикла есть своя обязанность: на каждой итерации он вызывает `next()`, ждет Promise от async iterator, проверяет `done`, передает `value` в тело и после завершения тела переходит к следующему `next()`. Но если внутри тела мы просто вызвали асинхронную функцию и не сделали `await`, то для самого тела это обычное синхронное действие: Promise создан, работа стартовала, а блок кода уже закончился. Цикл не отслеживает все промисы, которые мы могли случайно создать внутри тела. Чтобы обработка одного элемента действительно ждала эту работу, мы пишем `await` внутри тела. Если нужна параллельная обработка, мы осознанно собираем промисы и потом ждем их, например через `Promise.all`.\n\nХороший ответ разделяет две вещи: цикл последовательно получает элементы из async iterator, но он не обязан ждать каждую асинхронную операцию, которую мы запустили внутри тела. Он ждет только то ожидание, которое стало частью выполнения тела цикла.\n\n### 3. Async generator сделал `yield 1`, а потом `return 2`. Почему тело `for await...of` получает `1`, но не получает `2`?\n\nОжидаем: кандидат говорит, что `yield` отдает очередное значение наружу как обычный элемент последовательности, поэтому `yield 1` приходит в тело цикла при результате `{ value: 1, done: false }`. `return 2` работает иначе: он завершает async generator и дает результат итератора с `done: true`. Для `for await...of` значение при `done: true` уже не является элементом цикла, поэтому тело не выполняется с `2`. Это значение можно увидеть при ручном вызове `await generator.next()`, но обычный цикл использует `done: true` как сигнал остановиться.\n\n## Референсы\n\n- [ru.javascript.info: Асинхронные итераторы и генераторы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F12-generators-iterators\u002F2-async-iterators-generators\u002Farticle.md) - async iterable, async generator и `for await...of`.\n- [MDN: for await...of](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fstatements\u002Ffor-await...of\u002Findex.md) - справочник по синтаксису и поведению цикла.\n- [MDN: AsyncIterator](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fasynciterator\u002Findex.md) - async iterator protocol и связь с `Symbol.asyncIterator`.\n- [MDN: AsyncGenerator](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fasyncgenerator\u002Findex.md) - объект, который возвращает `async function*`.\n- [ECMA-262: ForInOfStatement](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#L22364) - формальная механика `for await...of`, ожидание `next()` и проверка `done`.\n- [ECMA-262: AsyncGenerator Objects](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#L50743) - async generator как async iterator и async iterable.",{"slug":3826,"title":2996,"baseQuestion":2997,"goodAnswer":2998,"followUps":3827,"references":3831,"programSlug":59,"lessonSlug":59,"order":796,"status":13,"rawBody":3026},"mock-interview-javascript-core-q8-kak-vybirat-metod-massiva-pod-zadachu",[3828,3829,3830],{"question":3001,"expected":3002},{"question":3004,"expected":3005},{"question":3007,"expected":3008},[3832,3833,3834,3835],{"title":3011,"url":3012,"note":3013},{"title":3015,"url":3016,"note":3017},{"title":3019,"url":3020,"note":3021},{"title":3023,"url":3024,"note":3025},{"slug":3837,"title":3838,"baseQuestion":3838,"goodAnswer":3839,"followUps":3840,"references":3850,"programSlug":18,"lessonSlug":18,"order":796,"status":13,"rawBody":3867},"objects-prototypes-classes-q8-kak-rabotayut-polya-klassa","Как работают поля класса?","Поля класса описывают свойства, которые JavaScript создаст на экземпляре класса или на самом классе, если поле объявлено как `static`.\n\nОбычное public field, например `x = 1`, создается как собственное свойство каждого нового экземпляра. Это отличается от метода класса: метод лежит на `ClassName.prototype` и общий для экземпляров, а field создается заново для каждого экземпляра.\n\nStatic field, например `static x = 1`, создается на самом классе. Поэтому мы читаем его как `A.x`, а не как `new A().x`, если у экземпляра нет отдельного поля с таким именем.\n\nPrivate field объявляется через имя с `#`, например `#x = 1`. Это не обычное свойство с ключом `\"#x\"`. К нему нельзя обратиться снаружи класса, нельзя прочитать через квадратные скобки, нельзя увидеть через `Object.keys`, нельзя удалить и нельзя создать позже обычным присваиванием.\n\nПорядок инициализации тоже важен:\n\n- в базовом классе instance fields создаются перед выполнением тела `constructor`;\n- в наследнике сначала выполняется `super()`, потом создаются instance fields наследника, потом продолжается constructor наследника;\n- поля внутри одного класса инициализируются сверху вниз.\n\nХороший кандидат должен объяснить поля не как переменные внутри класса, а как свойства, которые создаются на экземпляре или на самом классе в определенный момент создания.",[3841,3844,3847],{"question":3842,"expected":3843},"Почему `x = []` внутри класса дает разный массив для разных экземпляров?","кандидат объясняет, что initializer поля выполняется для каждого нового экземпляра. Поэтому каждый экземпляр получает свое собственное свойство `x` со своим массивом.",{"question":3845,"expected":3846},"Почему `Object.keys(instance)` видит public field, но не видит private field?","кандидат говорит, что public field создается как обычное собственное свойство экземпляра. Private field не является обычным enumerable property, поэтому объектные методы перечисления его не показывают.",{"question":3848,"expected":3849},"Почему constructor родителя не видит public field наследника?","кандидат объясняет, что поля наследника создаются только после `super()`. А `super()` как раз выполняет constructor родителя. Значит на момент родительского constructor поля наследника еще не созданы.",[3851,3855,3859,3863],{"title":3852,"url":3853,"note":3854},"MDN: Public class fields","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fpublic_class_fields\u002Findex.md","public fields как свойства экземпляра и порядок их создания.",{"title":3856,"url":3857,"note":3858},"MDN: Private elements","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fprivate_elements\u002Findex.md","private fields, private methods, ограничения доступа и `#x in obj`.",{"title":3860,"url":3861,"note":3862},"MDN: static","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fstatic\u002Findex.md","static fields и static methods как свойства самого класса.",{"title":3864,"url":3865,"note":3866},"Learn JS: Приватные и защищенные методы и свойства","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F04-private-protected-properties-methods\u002Farticle.md","учебное объяснение публичного, защищенного и приватного интерфейса.","# Q8. Как работают поля класса?\n\n## Базовый вопрос\n\nКак работают поля класса?\n\n## Хороший ответ\n\nПоля класса описывают свойства, которые JavaScript создаст на экземпляре класса или на самом классе, если поле объявлено как `static`.\n\nОбычное public field, например `x = 1`, создается как собственное свойство каждого нового экземпляра. Это отличается от метода класса: метод лежит на `ClassName.prototype` и общий для экземпляров, а field создается заново для каждого экземпляра.\n\nStatic field, например `static x = 1`, создается на самом классе. Поэтому мы читаем его как `A.x`, а не как `new A().x`, если у экземпляра нет отдельного поля с таким именем.\n\nPrivate field объявляется через имя с `#`, например `#x = 1`. Это не обычное свойство с ключом `\"#x\"`. К нему нельзя обратиться снаружи класса, нельзя прочитать через квадратные скобки, нельзя увидеть через `Object.keys`, нельзя удалить и нельзя создать позже обычным присваиванием.\n\nПорядок инициализации тоже важен:\n\n- в базовом классе instance fields создаются перед выполнением тела `constructor`;\n- в наследнике сначала выполняется `super()`, потом создаются instance fields наследника, потом продолжается constructor наследника;\n- поля внутри одного класса инициализируются сверху вниз.\n\nХороший кандидат должен объяснить поля не как переменные внутри класса, а как свойства, которые создаются на экземпляре или на самом классе в определенный момент создания.\n\n## Уточняющие вопросы\n\n### 1. Почему `x = []` внутри класса дает разный массив для разных экземпляров?\n\nОжидаем: кандидат объясняет, что initializer поля выполняется для каждого нового экземпляра. Поэтому каждый экземпляр получает свое собственное свойство `x` со своим массивом.\n\n### 2. Почему `Object.keys(instance)` видит public field, но не видит private field?\n\nОжидаем: кандидат говорит, что public field создается как обычное собственное свойство экземпляра. Private field не является обычным enumerable property, поэтому объектные методы перечисления его не показывают.\n\n### 3. Почему constructor родителя не видит public field наследника?\n\nОжидаем: кандидат объясняет, что поля наследника создаются только после `super()`. А `super()` как раз выполняет constructor родителя. Значит на момент родительского constructor поля наследника еще не созданы.\n\n## Референсы\n\n- [MDN: Public class fields](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fpublic_class_fields\u002Findex.md) - public fields как свойства экземпляра и порядок их создания.\n- [MDN: Private elements](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fprivate_elements\u002Findex.md) - private fields, private methods, ограничения доступа и `#x in obj`.\n- [MDN: static](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fclasses\u002Fstatic\u002Findex.md) - static fields и static methods как свойства самого класса.\n- [Learn JS: Приватные и защищенные методы и свойства](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F09-classes\u002F04-private-protected-properties-methods\u002Farticle.md) - учебное объяснение публичного, защищенного и приватного интерфейса.",{"slug":3869,"title":3870,"baseQuestion":3871,"goodAnswer":3872,"followUps":3873,"references":3883,"programSlug":50,"lessonSlug":50,"order":796,"status":13,"rawBody":3888},"recursion-q8-kakie-oshibki-chasto-delayut-v-rekursii","Какие ошибки часто делают в рекурсии?","Какие типичные ошибки встречаются в рекурсивных функциях?","Самая частая ошибка: нет корректного базового случая. Тогда функция вызывает себя бесконечно или до переполнения стека.\n\nВторая ошибка: рекурсивный случай не приближает данные к базовому случаю. Например, функция каждый раз вызывает себя с тем же значением. Формально базовый случай может быть написан, но программа до него не дойдет.\n\nТретья ошибка: потерян результат рекурсивного вызова. Мы вызвали функцию глубже, она нашла ответ, но внешний вызов не сделал `return` и вернул `undefined`.\n\nЕще одна частая проблема: ожидание, что рекурсия будет безопасна для любой глубины. В JavaScript стек ограничен, поэтому для очень длинных цепочек обычно выбирают цикл, явный стек или другую технику.\n\nХороший ответ на интервью должен звучать практично: перед написанием рекурсии мы проверяем, где остановка, как задача уменьшается, что возвращает каждый вызов и насколько глубокой может быть цепочка.",[3874,3877,3880],{"question":3875,"expected":3876},"Почему базовый случай может быть написан, но рекурсия все равно не остановится?","кандидат говорит, что рекурсивный вызов может не менять данные или менять их не в сторону базового случая.",{"question":3878,"expected":3879},"Почему функция поиска может найти значение внутри дерева, но внешний вызов вернет `undefined`?","кандидат объясняет, что результат внутреннего вызова нужно вернуть из внешнего вызова. Сам факт вызова не передает результат наверх автоматически.",{"question":3881,"expected":3882},"Когда рекурсивное решение лучше заменить на цикл или явный стек?","кандидат говорит про очень большую или непредсказуемую глубину, где стек вызовов может переполниться.",[3884,3886],{"title":1958,"url":1959,"note":3885},"ошибки при бесконечной или слишком глубокой рекурсии.",{"title":2284,"url":2285,"note":3887},"ограничения стека и техники обхода ограничений.","# Q8. Какие ошибки часто делают в рекурсии?\n\n## Базовый вопрос\n\nКакие типичные ошибки встречаются в рекурсивных функциях?\n\n## Хороший ответ\n\nСамая частая ошибка: нет корректного базового случая. Тогда функция вызывает себя бесконечно или до переполнения стека.\n\nВторая ошибка: рекурсивный случай не приближает данные к базовому случаю. Например, функция каждый раз вызывает себя с тем же значением. Формально базовый случай может быть написан, но программа до него не дойдет.\n\nТретья ошибка: потерян результат рекурсивного вызова. Мы вызвали функцию глубже, она нашла ответ, но внешний вызов не сделал `return` и вернул `undefined`.\n\nЕще одна частая проблема: ожидание, что рекурсия будет безопасна для любой глубины. В JavaScript стек ограничен, поэтому для очень длинных цепочек обычно выбирают цикл, явный стек или другую технику.\n\nХороший ответ на интервью должен звучать практично: перед написанием рекурсии мы проверяем, где остановка, как задача уменьшается, что возвращает каждый вызов и насколько глубокой может быть цепочка.\n\n## Уточняющие вопросы\n\n### 1. Почему базовый случай может быть написан, но рекурсия все равно не остановится?\n\nОжидаем: кандидат говорит, что рекурсивный вызов может не менять данные или менять их не в сторону базового случая.\n\n### 2. Почему функция поиска может найти значение внутри дерева, но внешний вызов вернет `undefined`?\n\nОжидаем: кандидат объясняет, что результат внутреннего вызова нужно вернуть из внешнего вызова. Сам факт вызова не передает результат наверх автоматически.\n\n### 3. Когда рекурсивное решение лучше заменить на цикл или явный стек?\n\nОжидаем: кандидат говорит про очень большую или непредсказуемую глубину, где стек вызовов может переполниться.\n\n## Референсы\n\n- [MDN: InternalError too much recursion](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Ferrors\u002Ftoo_much_recursion\u002Findex.md) - ошибки при бесконечной или слишком глубокой рекурсии.\n- [Вы не знаете JS: ES6 и дальше — глава 7 Meta Programming](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fes6%20%26%20beyond\u002Fch7.md) - ограничения стека и техники обхода ограничений.",{"slug":3890,"title":3891,"baseQuestion":3891,"goodAnswer":3892,"followUps":3893,"references":3903,"programSlug":41,"lessonSlug":41,"order":796,"status":13,"rawBody":3910},"rendering-dom-events-forms-q8-chto-takoe-delegirovanie-sobytiy","Что такое делегирование событий?","Делегирование событий - это прием, когда мы ставим один обработчик на общий родительский элемент, а внутри обработчика понимаем, какой дочерний элемент реально вызвал событие.\n\nПростая мысль такая: если клики по дочерним элементам всплывают к родителю, нам не обязательно вешать listener на каждый дочерний элемент. Мы можем обработать событие в одном месте, посмотреть на `event.target`, при необходимости подняться через `closest`, проверить границы контейнера и выполнить нужное действие.\n\nЭто особенно полезно для списков, таблиц, меню и динамических элементов. Если новые элементы добавятся позже, обработчик на родителе уже сможет их увидеть.\n\nНа собеседовании важно не сводить ответ к фразе \"это один обработчик вместо многих\". Нужно еще сказать, что делегирование держится на всплытии и аккуратной проверке цели события.",[3894,3897,3900],{"question":3895,"expected":3896},"Почему делегирование работает для новых элементов, которых не было при первой отрисовке?","кандидат говорит, что обработчик стоит на родителе. Новый дочерний элемент тоже будет отправлять всплывающее событие через этого родителя.",{"question":3898,"expected":3899},"Зачем внутри делегированного обработчика часто используют `closest`?","кандидат объясняет, что клик может начаться на вложенном элементе внутри нужной кнопки или строки. `closest` помогает найти подходящий элемент выше по дереву.",{"question":3901,"expected":3902},"Почему после `closest` нужно проверить, что найденный элемент находится внутри нашего контейнера?","кандидат говорит, что поиск может подняться выше или найти элемент не из той зоны интерфейса. Проверка контейнера защищает обработчик от чужих узлов.",[3904,3908],{"title":3905,"url":3906,"note":3907},"ru.javascript.info: Делегирование событий","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F03-event-delegation\u002Farticle.md","объясняет прием через общий обработчик на контейнере.",{"title":3452,"url":3453,"note":3909},"содержит примеры подписки и обработки всплывающих событий.","# Q8. Что такое делегирование событий?\n\n## Базовый вопрос\n\nЧто такое делегирование событий?\n\n## Хороший ответ\n\nДелегирование событий - это прием, когда мы ставим один обработчик на общий родительский элемент, а внутри обработчика понимаем, какой дочерний элемент реально вызвал событие.\n\nПростая мысль такая: если клики по дочерним элементам всплывают к родителю, нам не обязательно вешать listener на каждый дочерний элемент. Мы можем обработать событие в одном месте, посмотреть на `event.target`, при необходимости подняться через `closest`, проверить границы контейнера и выполнить нужное действие.\n\nЭто особенно полезно для списков, таблиц, меню и динамических элементов. Если новые элементы добавятся позже, обработчик на родителе уже сможет их увидеть.\n\nНа собеседовании важно не сводить ответ к фразе \"это один обработчик вместо многих\". Нужно еще сказать, что делегирование держится на всплытии и аккуратной проверке цели события.\n\n## Уточняющие вопросы\n\n### 1. Почему делегирование работает для новых элементов, которых не было при первой отрисовке?\n\nОжидаем: кандидат говорит, что обработчик стоит на родителе. Новый дочерний элемент тоже будет отправлять всплывающее событие через этого родителя.\n\n### 2. Зачем внутри делегированного обработчика часто используют `closest`?\n\nОжидаем: кандидат объясняет, что клик может начаться на вложенном элементе внутри нужной кнопки или строки. `closest` помогает найти подходящий элемент выше по дереву.\n\n### 3. Почему после `closest` нужно проверить, что найденный элемент находится внутри нашего контейнера?\n\nОжидаем: кандидат говорит, что поиск может подняться выше или найти элемент не из той зоны интерфейса. Проверка контейнера защищает обработчик от чужих узлов.\n\n## Референсы\n\n- [ru.javascript.info: Делегирование событий](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F03-event-delegation\u002Farticle.md) - объясняет прием через общий обработчик на контейнере.\n- [MDN: EventTarget addEventListener](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Feventtarget\u002Faddeventlistener\u002Findex.md) - содержит примеры подписки и обработки всплывающих событий.",{"slug":3912,"title":3913,"baseQuestion":3914,"goodAnswer":3915,"followUps":3916,"references":3926,"programSlug":19,"lessonSlug":19,"order":796,"status":13,"rawBody":3935},"scope-closures-deep-dive-q8-pochemu-settimeout-mozhet-poteryat-this","Почему setTimeout может потерять this?","Почему метод объекта может потерять `this` при передаче в `setTimeout`?","Метод получает `this` от способа вызова. Когда мы вызываем `obj.f()`, функция вызывается как свойство объекта, и `this` внутри обычной функции будет связан с `obj`.\n\nЕсли мы передаем `obj.f` в `setTimeout`, мы передаем значение функции отдельно от объекта. Связь \"вызвать как метод `obj`\" теряется. Позже таймер вызывает callback сам, а не как `obj.f()`. Поэтому `this` уже определяется правилами вызова callback в таймере, а не исходным объектом.\n\nВ браузерном sloppy script обычный callback из `setTimeout` часто получает `this === window`. В strict mode обычная отдельно вызванная функция не получает объект автоматически. В любом случае рассчитывать на исходный объект после передачи метода как значения нельзя.\n\nРешения: заранее привязать функцию через `bind`, вызвать метод внутри обертки, сохранить нужное значение в лексической переменной или использовать стрелку там, где мы осознанно хотим взять внешний `this`.\n\nВажно: дополнительные аргументы `setTimeout` передаются в callback как аргументы функции. Они не задают `this`.",[3917,3920,3923],{"question":3918,"expected":3919},"Почему `obj.f()` и `setTimeout(obj.f, 0)` не эквивалентны?","кандидат говорит, что в первом случае функция вызывается как метод объекта, а во втором из объекта достали значение функции и передали его дальше. Таймер позже вызывает функцию без исходного reference на объект.",{"question":3921,"expected":3922},"Почему дополнительный аргумент `setTimeout` не является контекстом вызова?","кандидат объясняет, что аргументы после задержки передаются в callback как обычные параметры. Они не меняют `this`. Чтобы задать `this`, нужен другой механизм, например `bind`.",{"question":3924,"expected":3925},"Чем `bind` отличается от сохранения `var self = this`?","кандидат говорит, что `bind` создает новую функцию с фиксированным `this`, а `self` это обычная переменная из внешней области. Callback читает `self` через замыкание, поэтому ему уже не нужно полагаться на свой `this`.",[3927,3929,3933],{"title":2808,"url":2809,"note":3928},"потеря `this` в `setTimeout`, `self`, стрелки и `bind`.",{"title":3930,"url":3931,"note":3932},"MDN: setTimeout","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fwindow\u002Fsettimeout\u002Findex.md","дополнительные аргументы callback и особенности вызова.",{"title":2820,"url":2821,"note":3934},"создание функции с привязанным `this`.","# Q8. Почему setTimeout может потерять this?\n\n## Базовый вопрос\n\nПочему метод объекта может потерять `this` при передаче в `setTimeout`?\n\n## Хороший ответ\n\nМетод получает `this` от способа вызова. Когда мы вызываем `obj.f()`, функция вызывается как свойство объекта, и `this` внутри обычной функции будет связан с `obj`.\n\nЕсли мы передаем `obj.f` в `setTimeout`, мы передаем значение функции отдельно от объекта. Связь \"вызвать как метод `obj`\" теряется. Позже таймер вызывает callback сам, а не как `obj.f()`. Поэтому `this` уже определяется правилами вызова callback в таймере, а не исходным объектом.\n\nВ браузерном sloppy script обычный callback из `setTimeout` часто получает `this === window`. В strict mode обычная отдельно вызванная функция не получает объект автоматически. В любом случае рассчитывать на исходный объект после передачи метода как значения нельзя.\n\nРешения: заранее привязать функцию через `bind`, вызвать метод внутри обертки, сохранить нужное значение в лексической переменной или использовать стрелку там, где мы осознанно хотим взять внешний `this`.\n\nВажно: дополнительные аргументы `setTimeout` передаются в callback как аргументы функции. Они не задают `this`.\n\n## Уточняющие вопросы\n\n### 1. Почему `obj.f()` и `setTimeout(obj.f, 0)` не эквивалентны?\n\nОжидаем: кандидат говорит, что в первом случае функция вызывается как метод объекта, а во втором из объекта достали значение функции и передали его дальше. Таймер позже вызывает функцию без исходного reference на объект.\n\n### 2. Почему дополнительный аргумент `setTimeout` не является контекстом вызова?\n\nОжидаем: кандидат объясняет, что аргументы после задержки передаются в callback как обычные параметры. Они не меняют `this`. Чтобы задать `this`, нужен другой механизм, например `bind`.\n\n### 3. Чем `bind` отличается от сохранения `var self = this`?\n\nОжидаем: кандидат говорит, что `bind` создает новую функцию с фиксированным `this`, а `self` это обычная переменная из внешней области. Callback читает `self` через замыкание, поэтому ему уже не нужно полагаться на свой `this`.\n\n## Референсы\n\n- [YDKJS: Приложение C. Лексический this](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Fscope%20%26%20closures\u002FapC.md) - потеря `this` в `setTimeout`, `self`, стрелки и `bind`.\n- [MDN: setTimeout](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fwindow\u002Fsettimeout\u002Findex.md) - дополнительные аргументы callback и особенности вызова.\n- [MDN: Function.prototype.bind](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Ffunction\u002Fbind\u002Findex.md) - создание функции с привязанным `this`.",{"slug":3937,"title":3938,"baseQuestion":3938,"goodAnswer":3939,"followUps":3940,"references":3950,"programSlug":21,"lessonSlug":21,"order":796,"status":13,"rawBody":3966},"types-coercion-symbol-json-q8-chem-otlichayutsya-object-is-i-samevaluezero","Чем отличаются `===`, `Object.is` и SameValueZero?","Все три механизма сравнивают значения без общего приведения типов, но по-разному относятся к двум числовым ловушкам: `NaN` и знаку нуля.\n\n`===` не приводит разные типы. Для большинства значений это привычная проверка \"одно и то же значение\". Но у чисел есть особенности: `NaN === NaN` дает `false`, а `0 === -0` дает `true`.\n\n`Object.is` использует алгоритм SameValue. Он считает `NaN` одинаковым с `NaN`, но отличает `0` от `-0`. Поэтому `Object.is(NaN, NaN)` дает `true`, а `Object.is(0, -0)` дает `false`.\n\nSameValueZero похож на SameValue, но считает `0` и `-0` одинаковыми. При этом `NaN` он тоже считает одинаковым с `NaN`. Этот алгоритм используется там, где такое поведение удобно для поиска и коллекций, например в `Array.prototype.includes`, `Map` и `Set`.\n\nПрактический вывод простой: для обычной бизнес-логики чаще выбирают `===`. Для проверки `NaN` используют `Number.isNaN()` или явно знают про `Object.is`. Для поиска `NaN` в массиве `includes` подходит лучше, чем `indexOf`.",[3941,3944,3947],{"question":3942,"expected":3943},"Почему `NaN === NaN` дает `false`, а `Object.is(NaN, NaN)` дает `true`?","кандидат говорит, что строгое равенство сохраняет числовое правило, по которому `NaN` не равен ничему, включая себя. `Object.is` использует другой алгоритм одинаковости и считает два `NaN` одинаковыми.",{"question":3945,"expected":3946},"Почему `[NaN].indexOf(NaN)` дает `-1`, а `[NaN].includes(NaN)` дает `true`?","кандидат объясняет разницу алгоритмов. `indexOf` ищет через строгое равенство, поэтому не находит `NaN`. `includes` использует SameValueZero, поэтому находит.",{"question":3948,"expected":3949},"Когда нам вообще важно отличать `0` от `-0`?","кандидат говорит, что в большинстве прикладного кода это не важно, поэтому `===` обычно достаточно. Отличие может всплыть в низкоуровневой численной логике, метапрограммировании или при разборе edge cases, например через `1 \u002F -0`.",[3951,3955,3959,3963],{"title":3952,"url":3953,"note":3954},"MDN: Equality comparisons and sameness","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Fequality_comparisons_and_sameness\u002Findex.md","сравнение `==`, `===`, `Object.is` и SameValueZero.",{"title":3956,"url":3957,"note":3958},"MDN: Object.is","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fis\u002Findex.md","поведение SameValue для `NaN` и `-0`.",{"title":3960,"url":3961,"note":3962},"MDN: Array.prototype.includes","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fincludes\u002Findex.md","поиск через SameValueZero.",{"title":2126,"url":3964,"note":3965},"https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-samevaluezero","формальный алгоритм SameValueZero.","# Q8. Чем отличаются `===`, `Object.is` и SameValueZero?\n\n## Базовый вопрос\n\nЧем отличаются `===`, `Object.is` и SameValueZero?\n\n## Хороший ответ\n\nВсе три механизма сравнивают значения без общего приведения типов, но по-разному относятся к двум числовым ловушкам: `NaN` и знаку нуля.\n\n`===` не приводит разные типы. Для большинства значений это привычная проверка \"одно и то же значение\". Но у чисел есть особенности: `NaN === NaN` дает `false`, а `0 === -0` дает `true`.\n\n`Object.is` использует алгоритм SameValue. Он считает `NaN` одинаковым с `NaN`, но отличает `0` от `-0`. Поэтому `Object.is(NaN, NaN)` дает `true`, а `Object.is(0, -0)` дает `false`.\n\nSameValueZero похож на SameValue, но считает `0` и `-0` одинаковыми. При этом `NaN` он тоже считает одинаковым с `NaN`. Этот алгоритм используется там, где такое поведение удобно для поиска и коллекций, например в `Array.prototype.includes`, `Map` и `Set`.\n\nПрактический вывод простой: для обычной бизнес-логики чаще выбирают `===`. Для проверки `NaN` используют `Number.isNaN()` или явно знают про `Object.is`. Для поиска `NaN` в массиве `includes` подходит лучше, чем `indexOf`.\n\n## Уточняющие вопросы\n\n### 1. Почему `NaN === NaN` дает `false`, а `Object.is(NaN, NaN)` дает `true`?\n\nОжидаем: кандидат говорит, что строгое равенство сохраняет числовое правило, по которому `NaN` не равен ничему, включая себя. `Object.is` использует другой алгоритм одинаковости и считает два `NaN` одинаковыми.\n\n### 2. Почему `[NaN].indexOf(NaN)` дает `-1`, а `[NaN].includes(NaN)` дает `true`?\n\nОжидаем: кандидат объясняет разницу алгоритмов. `indexOf` ищет через строгое равенство, поэтому не находит `NaN`. `includes` использует SameValueZero, поэтому находит.\n\n### 3. Когда нам вообще важно отличать `0` от `-0`?\n\nОжидаем: кандидат говорит, что в большинстве прикладного кода это не важно, поэтому `===` обычно достаточно. Отличие может всплыть в низкоуровневой численной логике, метапрограммировании или при разборе edge cases, например через `1 \u002F -0`.\n\n## Референсы\n\n- [MDN: Equality comparisons and sameness](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Fguide\u002Fequality_comparisons_and_sameness\u002Findex.md) - сравнение `==`, `===`, `Object.is` и SameValueZero.\n- [MDN: Object.is](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fobject\u002Fis\u002Findex.md) - поведение SameValue для `NaN` и `-0`.\n- [MDN: Array.prototype.includes](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Farray\u002Fincludes\u002Findex.md) - поиск через SameValueZero.\n- [ECMA-262: SameValueZero](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-samevaluezero) - формальный алгоритм SameValueZero.",{"slug":3968,"title":3969,"baseQuestion":3970,"goodAnswer":3971,"followUps":3972,"references":3982,"programSlug":40,"lessonSlug":40,"order":860,"status":13,"rawBody":3995},"browser-network-q9-kak-rabotaet-keshirovanie-v-brauzere","Как работает кеширование в браузере?","Как браузер решает, можно ли использовать закешированный ответ?","Сначала можно объяснить так: браузер не обязан каждый раз заново скачивать ресурс. Он может сохранить ответ и позже решить, можно ли использовать его снова. Это решение зависит от HTTP-заголовков ответа, возраста записи, режима запроса и иногда от повторной проверки на сервере.\n\nКлючевой заголовок для собеседования — `Cache-Control`. Например `max-age` говорит, сколько времени ответ можно считать свежим, `no-cache` требует проверки перед повторным использованием, а `no-store` запрещает хранить ответ.\n\nВажно не путать HTTP cache, Cache Storage и memory cache. HTTP cache работает как часть загрузки ресурсов. Cache Storage это программируемое хранилище, обычно рядом с Service Worker. В Chrome DevTools HTTP-кеш хорошо виден в Network через Size, Status и заголовки, а Cache Storage смотрят во вкладке Application.",[3973,3976,3979],{"question":3974,"expected":3975},"Чем `no-cache` отличается от `no-store`?","кандидат говорит, что `no-cache` не запрещает хранение, но требует перепроверку перед использованием. `no-store` просит не сохранять ответ.",{"question":3977,"expected":3978},"Почему при включенном Disable cache в Network поведение может отличаться от обычного пользователя?","кандидат объясняет, что DevTools временно отключает браузерный кеш для открытых DevTools, чтобы удобнее проверять первую загрузку и свежие ресурсы.",{"question":3980,"expected":3981},"Где в Chrome смотреть Cache Storage?","кандидат говорит про вкладку Application и раздел Cache Storage. Это отдельная зона от обычной таблицы запросов в Network.",[3983,3987,3991],{"title":3984,"url":3985,"note":3986},"MDN: HTTP caching","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Fguides\u002Fcaching\u002Findex.md","правила кеширования HTTP.",{"title":3988,"url":3989,"note":3990},"MDN: Cache-Control","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Freference\u002Fheaders\u002Fcache-control\u002Findex.md","директивы `Cache-Control`.",{"title":3992,"url":3993,"note":3994},"Chrome DevTools: Network features reference","https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fdevtools\u002Fnetwork\u002Freference\u002F","Disable cache и признаки кеша в Network.","# Q9. Как работает кеширование в браузере?\n\n## Базовый вопрос\n\nКак браузер решает, можно ли использовать закешированный ответ?\n\n## Хороший ответ\n\nСначала можно объяснить так: браузер не обязан каждый раз заново скачивать ресурс. Он может сохранить ответ и позже решить, можно ли использовать его снова. Это решение зависит от HTTP-заголовков ответа, возраста записи, режима запроса и иногда от повторной проверки на сервере.\n\nКлючевой заголовок для собеседования — `Cache-Control`. Например `max-age` говорит, сколько времени ответ можно считать свежим, `no-cache` требует проверки перед повторным использованием, а `no-store` запрещает хранить ответ.\n\nВажно не путать HTTP cache, Cache Storage и memory cache. HTTP cache работает как часть загрузки ресурсов. Cache Storage это программируемое хранилище, обычно рядом с Service Worker. В Chrome DevTools HTTP-кеш хорошо виден в Network через Size, Status и заголовки, а Cache Storage смотрят во вкладке Application.\n\n## Уточняющие вопросы\n\n### 1. Чем `no-cache` отличается от `no-store`?\n\nОжидаем: кандидат говорит, что `no-cache` не запрещает хранение, но требует перепроверку перед использованием. `no-store` просит не сохранять ответ.\n\n### 2. Почему при включенном Disable cache в Network поведение может отличаться от обычного пользователя?\n\nОжидаем: кандидат объясняет, что DevTools временно отключает браузерный кеш для открытых DevTools, чтобы удобнее проверять первую загрузку и свежие ресурсы.\n\n### 3. Где в Chrome смотреть Cache Storage?\n\nОжидаем: кандидат говорит про вкладку Application и раздел Cache Storage. Это отдельная зона от обычной таблицы запросов в Network.\n\n## Референсы\n\n- [MDN: HTTP caching](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Fguides\u002Fcaching\u002Findex.md) - правила кеширования HTTP.\n- [MDN: Cache-Control](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fhttp\u002Freference\u002Fheaders\u002Fcache-control\u002Findex.md) - директивы `Cache-Control`.\n- [Chrome DevTools: Network features reference](https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fdevtools\u002Fnetwork\u002Freference\u002F) - Disable cache и признаки кеша в Network.",{"slug":3997,"title":1788,"baseQuestion":1789,"goodAnswer":1790,"followUps":3998,"references":4002,"programSlug":59,"lessonSlug":59,"order":860,"status":13,"rawBody":1810},"mock-interview-javascript-core-q9-chto-takoe-event-loop",[3999,4000,4001],{"question":1793,"expected":1794},{"question":1796,"expected":1797},{"question":1799,"expected":1800},[4003,4004],{"title":1803,"url":1804,"note":1805},{"title":1807,"url":1808,"note":1809},{"slug":4006,"title":4007,"baseQuestion":4007,"goodAnswer":4008,"followUps":4009,"references":4019,"programSlug":41,"lessonSlug":41,"order":860,"status":13,"rawBody":4028},"rendering-dom-events-forms-q9-chto-delaet-preventdefault","Что делает `preventDefault()`?","`preventDefault()` просит браузер не выполнять действие по умолчанию для события. Он не удаляет событие, не останавливает обработчики и не отменяет сам факт клика или submit. Он влияет именно на стандартное действие браузера.\n\nПримеры простые:\n\n- клик по ссылке обычно ведет по `href`;\n- отправка формы обычно приводит к отправке данных и переходу;\n- некоторые жесты на мобильных устройствах связаны с прокруткой.\n\nЕсли событие можно отменить, `preventDefault()` помечает его как отмененное. Это видно через `event.defaultPrevented`, а `dispatchEvent` для отмененного cancelable события возвращает `false`.\n\nВажная деталь: событие должно быть cancelable. Если событие не отменяемое или обработчик passive, вызов `preventDefault()` не даст ожидаемого эффекта.",[4010,4013,4016],{"question":4011,"expected":4012},"Мы кликнули по ссылке с `href`, в обработчике вызвали `preventDefault()`. Что мы отменили?","кандидат говорит, что мы отменили переход по ссылке как действие браузера по умолчанию, но сам click и обработчики события уже происходят.",{"question":4014,"expected":4015},"Чем `preventDefault()` отличается от остановки всплытия?","кандидат объясняет, что `preventDefault()` влияет на действие браузера, а не на путь события по DOM-дереву.",{"question":4017,"expected":4018},"Почему `preventDefault()` может не сработать?","кандидат называет неотменяемое событие, passive listener или ситуацию, где у события просто нет подходящего действия по умолчанию.",[4020,4024],{"title":4021,"url":4022,"note":4023},"MDN: Event preventDefault","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fevent\u002Fpreventdefault\u002Findex.md","описывает отмену действия по умолчанию.",{"title":4025,"url":4026,"note":4027},"ru.javascript.info: Действия браузера по умолчанию","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F04-default-browser-action\u002Farticle.md","объясняет отмену действий браузера на учебных примерах.","# Q9. Что делает `preventDefault()`?\n\n## Базовый вопрос\n\nЧто делает `preventDefault()`?\n\n## Хороший ответ\n\n`preventDefault()` просит браузер не выполнять действие по умолчанию для события. Он не удаляет событие, не останавливает обработчики и не отменяет сам факт клика или submit. Он влияет именно на стандартное действие браузера.\n\nПримеры простые:\n\n- клик по ссылке обычно ведет по `href`;\n- отправка формы обычно приводит к отправке данных и переходу;\n- некоторые жесты на мобильных устройствах связаны с прокруткой.\n\nЕсли событие можно отменить, `preventDefault()` помечает его как отмененное. Это видно через `event.defaultPrevented`, а `dispatchEvent` для отмененного cancelable события возвращает `false`.\n\nВажная деталь: событие должно быть cancelable. Если событие не отменяемое или обработчик passive, вызов `preventDefault()` не даст ожидаемого эффекта.\n\n## Уточняющие вопросы\n\n### 1. Мы кликнули по ссылке с `href`, в обработчике вызвали `preventDefault()`. Что мы отменили?\n\nОжидаем: кандидат говорит, что мы отменили переход по ссылке как действие браузера по умолчанию, но сам click и обработчики события уже происходят.\n\n### 2. Чем `preventDefault()` отличается от остановки всплытия?\n\nОжидаем: кандидат объясняет, что `preventDefault()` влияет на действие браузера, а не на путь события по DOM-дереву.\n\n### 3. Почему `preventDefault()` может не сработать?\n\nОжидаем: кандидат называет неотменяемое событие, passive listener или ситуацию, где у события просто нет подходящего действия по умолчанию.\n\n## Референсы\n\n- [MDN: Event preventDefault](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fevent\u002Fpreventdefault\u002Findex.md) - описывает отмену действия по умолчанию.\n- [ru.javascript.info: Действия браузера по умолчанию](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F04-default-browser-action\u002Farticle.md) - объясняет отмену действий браузера на учебных примерах.",{"slug":4030,"title":4031,"baseQuestion":4031,"goodAnswer":4032,"followUps":4033,"references":4043,"programSlug":21,"lessonSlug":21,"order":860,"status":13,"rawBody":4056},"types-coercion-symbol-json-q9-kak-rabotayut-sravneniya-otnosheniy","Как работают сравнения отношений?","Сравнения отношений `\u003C`, `>`, `\u003C=`, `>=` отвечают на вопрос порядка, а не равенства. Они работают по своим правилам и не обязаны вести себя так же, как `==`.\n\nОбычно операнды сначала приводятся к примитивам. Если после этого оба значения являются строками, JavaScript сравнивает их как строки, посимвольно. Поэтому `\"42\" \u003C \"043\"` дает `false`: сравнение начинается с первого символа, а символ `\"4\"` больше символа `\"0\"`.\n\nЕсли это не две строки, значения обычно идут в численное сравнение. Boolean становится числом, `null` становится `0`, а `undefined` становится `NaN`. Любое обычное сравнение с `NaN` дает `false`.\n\nЦепочки сравнений в JavaScript не работают как в математике. Выражение `3 > 2 > 1` выполняется слева направо: сначала `3 > 2` дает `true`, потом сравнивается `true > 1`, то есть `1 > 1`, и получается `false`.\n\nОтдельная собеседовательская ловушка: `null >= 0` дает `true`, а `null == 0` дает `false`, потому что сравнения отношений и нестрогое равенство используют разные правила.",[4034,4037,4040],{"question":4035,"expected":4036},"Почему `3 > 2 > 1` дает `false`?","кандидат говорит, что это не математическая цепочка. Сначала `3 > 2` дает `true`, потом `true` приводится к числу `1`, и выражение становится `1 > 1`.",{"question":4038,"expected":4039},"Почему `null >= 0` дает `true`, а `null == 0` дает `false`?","кандидат объясняет, что `>=` запускает численное сравнение, где `null` становится `0`. А в `==` для `null` есть отдельное правило: он равен только `undefined` и самому себе.",{"question":4041,"expected":4042},"Почему массивы в сравнении `\u003C` могут сравниваться как строки?","кандидат говорит, что массив сначала приводится к примитиву. Массив с одним элементом часто дает строку этого элемента, и если с другой стороны тоже строка, дальше идет строковое сравнение.",[4044,4046,4050,4052],{"title":3368,"url":3369,"note":4045},"численное и строковое сравнение, `null` и `undefined`.",{"title":4047,"url":4048,"note":4049},"MDN: Less than operator","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fless_than\u002Findex.md","порядок приведения в сравнении `\u003C`.",{"title":3376,"url":2660,"note":4051},"разбор неявного приведения в операторах.",{"title":4053,"url":4054,"note":4055},"ECMA-262: IsLessThan","https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-islessthan","формальный алгоритм сравнения отношений.","# Q9. Как работают сравнения отношений?\n\n## Базовый вопрос\n\nКак работают сравнения отношений?\n\n## Хороший ответ\n\nСравнения отношений `\u003C`, `>`, `\u003C=`, `>=` отвечают на вопрос порядка, а не равенства. Они работают по своим правилам и не обязаны вести себя так же, как `==`.\n\nОбычно операнды сначала приводятся к примитивам. Если после этого оба значения являются строками, JavaScript сравнивает их как строки, посимвольно. Поэтому `\"42\" \u003C \"043\"` дает `false`: сравнение начинается с первого символа, а символ `\"4\"` больше символа `\"0\"`.\n\nЕсли это не две строки, значения обычно идут в численное сравнение. Boolean становится числом, `null` становится `0`, а `undefined` становится `NaN`. Любое обычное сравнение с `NaN` дает `false`.\n\nЦепочки сравнений в JavaScript не работают как в математике. Выражение `3 > 2 > 1` выполняется слева направо: сначала `3 > 2` дает `true`, потом сравнивается `true > 1`, то есть `1 > 1`, и получается `false`.\n\nОтдельная собеседовательская ловушка: `null >= 0` дает `true`, а `null == 0` дает `false`, потому что сравнения отношений и нестрогое равенство используют разные правила.\n\n## Уточняющие вопросы\n\n### 1. Почему `3 > 2 > 1` дает `false`?\n\nОжидаем: кандидат говорит, что это не математическая цепочка. Сначала `3 > 2` дает `true`, потом `true` приводится к числу `1`, и выражение становится `1 > 1`.\n\n### 2. Почему `null >= 0` дает `true`, а `null == 0` дает `false`?\n\nОжидаем: кандидат объясняет, что `>=` запускает численное сравнение, где `null` становится `0`. А в `==` для `null` есть отдельное правило: он равен только `undefined` и самому себе.\n\n### 3. Почему массивы в сравнении `\u003C` могут сравниваться как строки?\n\nОжидаем: кандидат говорит, что массив сначала приводится к примитиву. Массив с одним элементом часто дает строку этого элемента, и если с другой стороны тоже строка, дальше идет строковое сравнение.\n\n## Референсы\n\n- [ru.javascript.info: Операторы сравнения](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F02-first-steps\u002F09-comparison\u002Farticle.md) - численное и строковое сравнение, `null` и `undefined`.\n- [MDN: Less than operator](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Foperators\u002Fless_than\u002Findex.md) - порядок приведения в сравнении `\u003C`.\n- [Вы не знаете JS: Типы и грамматика — глава 4 Приведение](https:\u002F\u002Fgithub.com\u002Fazat-io\u002Fyou-dont-know-js-ru\u002Fblob\u002Fmaster\u002Ftypes%20%26%20grammar\u002Fch4.md) - разбор неявного приведения в операторах.\n- [ECMA-262: IsLessThan](https:\u002F\u002Fgithub.com\u002Ftc39\u002Fecma262\u002Fblob\u002Fmain\u002Fspec.html#sec-islessthan) - формальный алгоритм сравнения отношений.",{"slug":4058,"title":4059,"baseQuestion":4060,"goodAnswer":4061,"followUps":4062,"references":4072,"programSlug":40,"lessonSlug":40,"order":930,"status":13,"rawBody":4077},"browser-network-q10-chto-pokazyvaet-chrome-network","Что показывает Chrome Network?","Какие части запроса и ответа мы смотрим во вкладке Network в Chrome DevTools?","Простой ответ: Network показывает сетевую активность страницы. В таблице мы видим список запросов, а внутри конкретного запроса смотрим детали: Headers, Payload, Preview, Response, Initiator и Timing.\n\nХороший кандидат объясняет не только названия вкладок, но и когда ими пользоваться:\n\n- Headers показывают URL, method, status, request headers и response headers.\n- Payload показывает query string, form data или request payload.\n- Preview помогает быстро прочитать JSON, HTML или картинку в удобном виде.\n- Response показывает сырое тело ответа.\n- Initiator помогает понять, кто запустил запрос.\n- Timing показывает, где ушло время.\n\nНа практике Network нужен не только для \"посмотреть статус\". Он помогает проверить, ушел ли запрос вообще, с какими данными он ушел, что вернул сервер и кто был источником запроса.",[4063,4066,4069],{"question":4064,"expected":4065},"Где мы смотрим тело POST-запроса?","кандидат говорит про вкладку Payload. Там могут быть form data, request payload или query string parameters.",{"question":4067,"expected":4068},"Чем Preview отличается от Response?","кандидат объясняет, что Preview это удобное представление данных, а Response ближе к сырому телу ответа.",{"question":4070,"expected":4071},"Зачем смотреть Initiator?","кандидат говорит, что Initiator помогает найти код, ресурс или цепочку, из-за которой появился запрос.",[4073,4075],{"title":1753,"url":1754,"note":4074},"базовая работа с Network.",{"title":3992,"url":3993,"note":4076},"вкладки и возможности Network.","# Q10. Что показывает Chrome Network?\n\n## Базовый вопрос\n\nКакие части запроса и ответа мы смотрим во вкладке Network в Chrome DevTools?\n\n## Хороший ответ\n\nПростой ответ: Network показывает сетевую активность страницы. В таблице мы видим список запросов, а внутри конкретного запроса смотрим детали: Headers, Payload, Preview, Response, Initiator и Timing.\n\nХороший кандидат объясняет не только названия вкладок, но и когда ими пользоваться:\n\n- Headers показывают URL, method, status, request headers и response headers.\n- Payload показывает query string, form data или request payload.\n- Preview помогает быстро прочитать JSON, HTML или картинку в удобном виде.\n- Response показывает сырое тело ответа.\n- Initiator помогает понять, кто запустил запрос.\n- Timing показывает, где ушло время.\n\nНа практике Network нужен не только для \"посмотреть статус\". Он помогает проверить, ушел ли запрос вообще, с какими данными он ушел, что вернул сервер и кто был источником запроса.\n\n## Уточняющие вопросы\n\n### 1. Где мы смотрим тело POST-запроса?\n\nОжидаем: кандидат говорит про вкладку Payload. Там могут быть form data, request payload или query string parameters.\n\n### 2. Чем Preview отличается от Response?\n\nОжидаем: кандидат объясняет, что Preview это удобное представление данных, а Response ближе к сырому телу ответа.\n\n### 3. Зачем смотреть Initiator?\n\nОжидаем: кандидат говорит, что Initiator помогает найти код, ресурс или цепочку, из-за которой появился запрос.\n\n## Референсы\n\n- [Chrome DevTools: Inspect network activity](https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fdevtools\u002Fnetwork\u002F) - базовая работа с Network.\n- [Chrome DevTools: Network features reference](https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fdevtools\u002Fnetwork\u002Freference\u002F) - вкладки и возможности Network.",{"slug":4079,"title":2132,"baseQuestion":2133,"goodAnswer":2134,"followUps":4080,"references":4084,"programSlug":59,"lessonSlug":59,"order":930,"status":13,"rawBody":2153},"mock-interview-javascript-core-q10-chem-mikrozadachi-otlichayutsya-ot-zadach-event-loop",[4081,4082,4083],{"question":2137,"expected":2138},{"question":2140,"expected":2141},{"question":2143,"expected":2144},[4085,4086,4087],{"title":1830,"url":1831,"note":1832},{"title":1803,"url":1804,"note":2148},{"title":2150,"url":2151,"note":2152},{"slug":4089,"title":4090,"baseQuestion":4090,"goodAnswer":4091,"followUps":4092,"references":4102,"programSlug":41,"lessonSlug":41,"order":930,"status":13,"rawBody":4109},"rendering-dom-events-forms-q10-chto-delaet-stoppropagation","Что делает `stopPropagation()`?","`stopPropagation()` останавливает дальнейшее движение события по DOM-дереву. Если событие было на пути всплытия, оно не пойдет к следующим родителям. Если оно было на пути погружения, оно не пойдет дальше по этому пути.\n\nВажно не перепутать: `stopPropagation()` не отменяет действие браузера по умолчанию. Ссылка все еще может перейти по `href`, форма все еще может отправиться, если мы отдельно не вызвали `preventDefault()`.\n\nЕще одна важная деталь: `stopPropagation()` не обязан остановить другие обработчики на том же элементе. Для этого есть отдельный механизм `stopImmediatePropagation()`.\n\nНа собеседовании хороший ответ должен звучать так: мы останавливаем маршрут события, но не отменяем само событие и не отменяем стандартное действие браузера.",[4093,4096,4099],{"question":4094,"expected":4095},"Мы вызвали `stopPropagation()` в обработчике кнопки. Что произойдет с обработчиком на родителе?","кандидат говорит, что родительский обработчик на дальнейшем пути события не сработает.",{"question":4097,"expected":4098},"Почему после `stopPropagation()` ссылка все еще может перейти по `href`?","кандидат объясняет, что переход по ссылке это действие по умолчанию. Его отменяют через `preventDefault()`, а не через остановку распространения.",{"question":4100,"expected":4101},"Почему другой обработчик на той же кнопке все еще может выполниться?","кандидат говорит, что `stopPropagation()` останавливает движение по дереву, но не обязательно прекращает все listeners на текущем элементе.",[4103,4107],{"title":4104,"url":4105,"note":4106},"MDN: Event stopPropagation","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fevent\u002Fstoppropagation\u002Findex.md","описывает остановку распространения события.",{"title":3448,"url":3449,"note":4108},"объясняет, как остановка влияет на всплытие.","# Q10. Что делает `stopPropagation()`?\n\n## Базовый вопрос\n\nЧто делает `stopPropagation()`?\n\n## Хороший ответ\n\n`stopPropagation()` останавливает дальнейшее движение события по DOM-дереву. Если событие было на пути всплытия, оно не пойдет к следующим родителям. Если оно было на пути погружения, оно не пойдет дальше по этому пути.\n\nВажно не перепутать: `stopPropagation()` не отменяет действие браузера по умолчанию. Ссылка все еще может перейти по `href`, форма все еще может отправиться, если мы отдельно не вызвали `preventDefault()`.\n\nЕще одна важная деталь: `stopPropagation()` не обязан остановить другие обработчики на том же элементе. Для этого есть отдельный механизм `stopImmediatePropagation()`.\n\nНа собеседовании хороший ответ должен звучать так: мы останавливаем маршрут события, но не отменяем само событие и не отменяем стандартное действие браузера.\n\n## Уточняющие вопросы\n\n### 1. Мы вызвали `stopPropagation()` в обработчике кнопки. Что произойдет с обработчиком на родителе?\n\nОжидаем: кандидат говорит, что родительский обработчик на дальнейшем пути события не сработает.\n\n### 2. Почему после `stopPropagation()` ссылка все еще может перейти по `href`?\n\nОжидаем: кандидат объясняет, что переход по ссылке это действие по умолчанию. Его отменяют через `preventDefault()`, а не через остановку распространения.\n\n### 3. Почему другой обработчик на той же кнопке все еще может выполниться?\n\nОжидаем: кандидат говорит, что `stopPropagation()` останавливает движение по дереву, но не обязательно прекращает все listeners на текущем элементе.\n\n## Референсы\n\n- [MDN: Event stopPropagation](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fevent\u002Fstoppropagation\u002Findex.md) - описывает остановку распространения события.\n- [ru.javascript.info: Всплытие и погружение](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F02-bubbling-and-capturing\u002Farticle.md) - объясняет, как остановка влияет на всплытие.",{"slug":4111,"title":4112,"baseQuestion":4112,"goodAnswer":4113,"followUps":4114,"references":4124,"programSlug":21,"lessonSlug":21,"order":930,"status":13,"rawBody":4141},"types-coercion-symbol-json-q10-chem-polnoe-chislennoe-privedenie-otlichaetsya-ot-chastichnogo-parsinga","Чем полное численное приведение отличается от частичного парсинга?","Полное численное приведение и частичный парсинг решают разные задачи.\n\n`Number(value)` и унарный `+` пытаются превратить все значение целиком в number. Если вся строка не является корректным числовым представлением, результат будет `NaN`. Поэтому `Number(\"100x\")` дает `NaN`: лишний символ `x` ломает все преобразование.\n\n`parseInt` и `parseFloat` читают строку слева направо и останавливаются на первом символе, который уже не подходит. Поэтому `parseInt(\"100x\", 10)` дает `100`, а `parseFloat(\"12.5x\")` дает `12.5`. Если первый символ нельзя прочитать как часть числа, результат будет `NaN`.\n\nДля `parseInt` важен второй аргумент `radix`. Он задает систему счисления. На интервью лучше показывать привычку явно писать `10`, если мы ожидаем десятичное число.\n\nПроверки тоже отличаются. Глобальные `isNaN` и `isFinite` сначала приводят значение к number. Методы `Number.isNaN` и `Number.isFinite` не делают такого приведения и проверяют только уже числовые значения.",[4115,4118,4121],{"question":4116,"expected":4117},"Почему `Number(\"100x\")` дает `NaN`, а `parseInt(\"100x\", 10)` дает `100`?","кандидат говорит, что `Number` требует успешного преобразования всей строки. `parseInt` читает допустимую числовую часть с начала строки и останавливается на `x`.",{"question":4119,"expected":4120},"Почему `parseInt(\"a123\", 10)` дает `NaN`?","кандидат объясняет, что частичный парсинг все равно должен начать с допустимой цифры для выбранного основания. Если первая позиция не читается, возвращать уже нечего.",{"question":4122,"expected":4123},"Почему `isNaN(\"a\")` дает `true`, а `Number.isNaN(\"a\")` дает `false`?","кандидат говорит, что глобальный `isNaN` сначала приводит строку к number и получает `NaN`. `Number.isNaN` не приводит строку и поэтому видит обычное значение типа `string`.",[4125,4129,4133,4137],{"title":4126,"url":4127,"note":4128},"ru.javascript.info: Числа","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F02-number\u002Farticle.md","`isNaN`, `isFinite`, `parseInt`, `parseFloat` и radix.",{"title":4130,"url":4131,"note":4132},"MDN: Number.isNaN","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fnumber\u002Fisnan\u002Findex.md","отличие строгой проверки от глобального `isNaN`.",{"title":4134,"url":4135,"note":4136},"MDN: parseInt","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fparseint\u002Findex.md","частичный разбор строки и основание системы счисления.",{"title":4138,"url":4139,"note":4140},"MDN: parseFloat","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fparsefloat\u002Findex.md","чтение дробного числа из начала строки.","# Q10. Чем полное численное приведение отличается от частичного парсинга?\n\n## Базовый вопрос\n\nЧем полное численное приведение отличается от частичного парсинга?\n\n## Хороший ответ\n\nПолное численное приведение и частичный парсинг решают разные задачи.\n\n`Number(value)` и унарный `+` пытаются превратить все значение целиком в number. Если вся строка не является корректным числовым представлением, результат будет `NaN`. Поэтому `Number(\"100x\")` дает `NaN`: лишний символ `x` ломает все преобразование.\n\n`parseInt` и `parseFloat` читают строку слева направо и останавливаются на первом символе, который уже не подходит. Поэтому `parseInt(\"100x\", 10)` дает `100`, а `parseFloat(\"12.5x\")` дает `12.5`. Если первый символ нельзя прочитать как часть числа, результат будет `NaN`.\n\nДля `parseInt` важен второй аргумент `radix`. Он задает систему счисления. На интервью лучше показывать привычку явно писать `10`, если мы ожидаем десятичное число.\n\nПроверки тоже отличаются. Глобальные `isNaN` и `isFinite` сначала приводят значение к number. Методы `Number.isNaN` и `Number.isFinite` не делают такого приведения и проверяют только уже числовые значения.\n\n## Уточняющие вопросы\n\n### 1. Почему `Number(\"100x\")` дает `NaN`, а `parseInt(\"100x\", 10)` дает `100`?\n\nОжидаем: кандидат говорит, что `Number` требует успешного преобразования всей строки. `parseInt` читает допустимую числовую часть с начала строки и останавливается на `x`.\n\n### 2. Почему `parseInt(\"a123\", 10)` дает `NaN`?\n\nОжидаем: кандидат объясняет, что частичный парсинг все равно должен начать с допустимой цифры для выбранного основания. Если первая позиция не читается, возвращать уже нечего.\n\n### 3. Почему `isNaN(\"a\")` дает `true`, а `Number.isNaN(\"a\")` дает `false`?\n\nОжидаем: кандидат говорит, что глобальный `isNaN` сначала приводит строку к number и получает `NaN`. `Number.isNaN` не приводит строку и поэтому видит обычное значение типа `string`.\n\n## Референсы\n\n- [ru.javascript.info: Числа](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F02-number\u002Farticle.md) - `isNaN`, `isFinite`, `parseInt`, `parseFloat` и radix.\n- [MDN: Number.isNaN](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fnumber\u002Fisnan\u002Findex.md) - отличие строгой проверки от глобального `isNaN`.\n- [MDN: parseInt](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fparseint\u002Findex.md) - частичный разбор строки и основание системы счисления.\n- [MDN: parseFloat](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fparsefloat\u002Findex.md) - чтение дробного числа из начала строки.",{"slug":4143,"title":4144,"baseQuestion":4145,"goodAnswer":4146,"followUps":4147,"references":4157,"programSlug":40,"lessonSlug":40,"order":1001,"status":13,"rawBody":4162},"browser-network-q11-zachem-nuzhen-abortcontroller","Зачем нужен AbortController?","Как отменяют `fetch` в браузере?","Простой ответ: для отмены `fetch` используют `AbortController`. Мы создаем контроллер, передаем `controller.signal` в `fetch`, а когда запрос больше не нужен, вызываем `controller.abort()`.\n\nЭто особенно важно в интерфейсах. Пользователь мог уйти со страницы, поменять фильтр, быстро набрать новый поисковый запрос или закрыть модальное окно. Старый запрос уже не нужен, и его результат не должен перезаписать более свежие данные.\n\nТехнически отмена не возвращает HTTP-ответ. Promise отклоняется, обычно с ошибкой `AbortError`. Поэтому код должен отличать ожидаемую отмену от настоящей сетевой или серверной проблемы.",[4148,4151,4154],{"question":4149,"expected":4150},"Почему отмена запроса полезна при автокомплите?","кандидат говорит, что старые запросы могут завершиться позже новых и испортить интерфейс устаревшими данными. Отмена уменьшает риск гонки и лишнюю работу.",{"question":4152,"expected":4153},"Что попадет в `catch` при отмене `fetch`?","кандидат говорит про ошибку отмены, обычно `AbortError`, а не про `Response` со статусом.",{"question":4155,"expected":4156},"Почему нельзя просто игнорировать все ошибки в `catch`?","кандидат объясняет, что отмена может быть нормальным сценарием, а настоящие ошибки сети или парсинга нужно обработать и показать пользователю или залогировать.",[4158,4160],{"title":3586,"url":3587,"note":4159},"создание сигнала и отмена операций.",{"title":3528,"url":3529,"note":4161},"использование `fetch`.","# Q11. Зачем нужен AbortController?\n\n## Базовый вопрос\n\nКак отменяют `fetch` в браузере?\n\n## Хороший ответ\n\nПростой ответ: для отмены `fetch` используют `AbortController`. Мы создаем контроллер, передаем `controller.signal` в `fetch`, а когда запрос больше не нужен, вызываем `controller.abort()`.\n\nЭто особенно важно в интерфейсах. Пользователь мог уйти со страницы, поменять фильтр, быстро набрать новый поисковый запрос или закрыть модальное окно. Старый запрос уже не нужен, и его результат не должен перезаписать более свежие данные.\n\nТехнически отмена не возвращает HTTP-ответ. Promise отклоняется, обычно с ошибкой `AbortError`. Поэтому код должен отличать ожидаемую отмену от настоящей сетевой или серверной проблемы.\n\n## Уточняющие вопросы\n\n### 1. Почему отмена запроса полезна при автокомплите?\n\nОжидаем: кандидат говорит, что старые запросы могут завершиться позже новых и испортить интерфейс устаревшими данными. Отмена уменьшает риск гонки и лишнюю работу.\n\n### 2. Что попадет в `catch` при отмене `fetch`?\n\nОжидаем: кандидат говорит про ошибку отмены, обычно `AbortError`, а не про `Response` со статусом.\n\n### 3. Почему нельзя просто игнорировать все ошибки в `catch`?\n\nОжидаем: кандидат объясняет, что отмена может быть нормальным сценарием, а настоящие ошибки сети или парсинга нужно обработать и показать пользователю или залогировать.\n\n## Референсы\n\n- [MDN: AbortController](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fabortcontroller\u002Findex.md) - создание сигнала и отмена операций.\n- [MDN: Window fetch](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fwindow\u002Ffetch\u002Findex.md) - использование `fetch`.",{"slug":4164,"title":4165,"baseQuestion":4165,"goodAnswer":4166,"followUps":4167,"references":4177,"programSlug":41,"lessonSlug":41,"order":1001,"status":13,"rawBody":4182},"rendering-dom-events-forms-q11-chto-oznachaet-passive-true-u-obrabotchika-sobytiya","Что означает `passive: true` у обработчика события?","`passive: true` означает, что обработчик обещает не отменять действие браузера по умолчанию через `preventDefault()`.\n\nСмысл этого обещания особенно важен для событий, связанных с прокруткой и жестами. Браузеру не нужно ждать, вдруг обработчик отменит прокрутку. Он может начать стандартное действие быстрее, а интерфейс ощущается плавнее.\n\nЕсли внутри passive обработчика вызвать `preventDefault()`, браузер проигнорирует отмену. В консоли может появиться предупреждение, но событие не станет `defaultPrevented`.\n\nНа собеседовании хорошо сказать так: passive listener - это не про фазу события и не про приоритет обработчика. Это договор с браузером про то, что обработчик не будет блокировать действие по умолчанию.",[4168,4171,4174],{"question":4169,"expected":4170},"Зачем браузеру знать заранее, что обработчик не вызовет `preventDefault()`?","кандидат говорит, что браузер может не ждать окончания обработчика перед действием по умолчанию, например перед прокруткой.",{"question":4172,"expected":4173},"Что будет, если в passive обработчике вызвать `preventDefault()`?","кандидат объясняет, что отмена будет проигнорирована и событие не станет отмененным.",{"question":4175,"expected":4176},"Это то же самое, что `{ capture: true }`?","кандидат говорит, что нет. `capture` выбирает фазу обработки события, а `passive` говорит про возможность отменить действие по умолчанию.",[4178,4180],{"title":3452,"url":3453,"note":4179},"описывает опцию `passive`.",{"title":4025,"url":4026,"note":4181},"объясняет passive listeners на примере действий браузера.","# Q11. Что означает `passive: true` у обработчика события?\n\n## Базовый вопрос\n\nЧто означает `passive: true` у обработчика события?\n\n## Хороший ответ\n\n`passive: true` означает, что обработчик обещает не отменять действие браузера по умолчанию через `preventDefault()`.\n\nСмысл этого обещания особенно важен для событий, связанных с прокруткой и жестами. Браузеру не нужно ждать, вдруг обработчик отменит прокрутку. Он может начать стандартное действие быстрее, а интерфейс ощущается плавнее.\n\nЕсли внутри passive обработчика вызвать `preventDefault()`, браузер проигнорирует отмену. В консоли может появиться предупреждение, но событие не станет `defaultPrevented`.\n\nНа собеседовании хорошо сказать так: passive listener - это не про фазу события и не про приоритет обработчика. Это договор с браузером про то, что обработчик не будет блокировать действие по умолчанию.\n\n## Уточняющие вопросы\n\n### 1. Зачем браузеру знать заранее, что обработчик не вызовет `preventDefault()`?\n\nОжидаем: кандидат говорит, что браузер может не ждать окончания обработчика перед действием по умолчанию, например перед прокруткой.\n\n### 2. Что будет, если в passive обработчике вызвать `preventDefault()`?\n\nОжидаем: кандидат объясняет, что отмена будет проигнорирована и событие не станет отмененным.\n\n### 3. Это то же самое, что `{ capture: true }`?\n\nОжидаем: кандидат говорит, что нет. `capture` выбирает фазу обработки события, а `passive` говорит про возможность отменить действие по умолчанию.\n\n## Референсы\n\n- [MDN: EventTarget addEventListener](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Feventtarget\u002Faddeventlistener\u002Findex.md) - описывает опцию `passive`.\n- [ru.javascript.info: Действия браузера по умолчанию](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F2-events\u002F04-default-browser-action\u002Farticle.md) - объясняет passive listeners на примере действий браузера.",{"slug":4184,"title":4185,"baseQuestion":4185,"goodAnswer":4186,"followUps":4187,"references":4197,"programSlug":21,"lessonSlug":21,"order":1001,"status":13,"rawBody":4212},"types-coercion-symbol-json-q11-kogda-nuzhen-bigint-i-pochemu-ego-nelzya-smeshivat-s-number","Когда нужен `BigInt` и почему его нельзя смешивать с `number`?","Обычный `number` в JavaScript хранится в формате с ограниченной точностью. Он хорошо подходит для большинства чисел, дробей и обычной прикладной математики, но не может надежно представлять все целые числа бесконечного размера.\n\nБезопасная граница для целых чисел задается через `Number.MAX_SAFE_INTEGER`. После этой границы соседние математические целые могут оказаться одним и тем же значением `number`. Поэтому `Number.MAX_SAFE_INTEGER + 1` и `Number.MAX_SAFE_INTEGER + 2` могут сравниваться как равные.\n\n`BigInt` нужен для целых чисел произвольной длины. Он создается через литерал с `n`, например `1n`, или через `BigInt(...)`. Это отдельный тип значения, а не более точный режим для `number`.\n\nАрифметику `BigInt` и `number` нельзя смешивать напрямую. JavaScript не выбирает автоматически, какой тип результата нам нужен, потому что такой выбор может потерять точность или изменить смысл вычисления. Мы должны явно привести одно значение к нужному типу, если это безопасно и осознанно.\n\nПри сравнении через `==` совместимые `BigInt` и `number` могут оказаться равными по математическому значению, например `1n == 1`. Но `1n === 1` дает `false`, потому что типы разные.",[4188,4191,4194],{"question":4189,"expected":4190},"Почему после `Number.MAX_SAFE_INTEGER` соседние целые могут стать равными?","кандидат говорит, что формат `number` хранит число с ограниченным количеством значащих бит. Когда целое слишком большое, не все соседние значения можно представить отдельно.",{"question":4192,"expected":4193},"Почему `1n + 1` бросает ошибку, а не дает `2n` или `2`?","кандидат объясняет, что `BigInt` и `number` являются разными числовыми типами. JavaScript не делает неявный выбор между точным целым `BigInt` и обычным `number`.",{"question":4195,"expected":4196},"Почему `1n == 1` дает `true`, а `1n === 1` дает `false`?","кандидат говорит, что `==` может сравнить `BigInt` и `number` по математическому значению, если это возможно. Строгое равенство не приводит типы, поэтому разные типы сразу не равны.",[4198,4200,4204,4208],{"title":4126,"url":4127,"note":4199},"точность `number`, безопасные целые числа и числовые проверки.",{"title":4201,"url":4202,"note":4203},"ru.javascript.info: BigInt","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F99-js-misc\u002F06-bigint\u002Farticle.md","создание `BigInt` и запрет смешивания с `number` в арифметике.",{"title":4205,"url":4206,"note":4207},"MDN: Number.MAX_SAFE_INTEGER","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fnumber\u002Fmax_safe_integer\u002Findex.md","безопасная граница целых чисел.",{"title":4209,"url":4210,"note":4211},"MDN: BigInt","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fbigint\u002Findex.md","особенности типа `bigint` и операции с ним.","# Q11. Когда нужен `BigInt` и почему его нельзя смешивать с `number`?\n\n## Базовый вопрос\n\nКогда нужен `BigInt` и почему его нельзя смешивать с `number`?\n\n## Хороший ответ\n\nОбычный `number` в JavaScript хранится в формате с ограниченной точностью. Он хорошо подходит для большинства чисел, дробей и обычной прикладной математики, но не может надежно представлять все целые числа бесконечного размера.\n\nБезопасная граница для целых чисел задается через `Number.MAX_SAFE_INTEGER`. После этой границы соседние математические целые могут оказаться одним и тем же значением `number`. Поэтому `Number.MAX_SAFE_INTEGER + 1` и `Number.MAX_SAFE_INTEGER + 2` могут сравниваться как равные.\n\n`BigInt` нужен для целых чисел произвольной длины. Он создается через литерал с `n`, например `1n`, или через `BigInt(...)`. Это отдельный тип значения, а не более точный режим для `number`.\n\nАрифметику `BigInt` и `number` нельзя смешивать напрямую. JavaScript не выбирает автоматически, какой тип результата нам нужен, потому что такой выбор может потерять точность или изменить смысл вычисления. Мы должны явно привести одно значение к нужному типу, если это безопасно и осознанно.\n\nПри сравнении через `==` совместимые `BigInt` и `number` могут оказаться равными по математическому значению, например `1n == 1`. Но `1n === 1` дает `false`, потому что типы разные.\n\n## Уточняющие вопросы\n\n### 1. Почему после `Number.MAX_SAFE_INTEGER` соседние целые могут стать равными?\n\nОжидаем: кандидат говорит, что формат `number` хранит число с ограниченным количеством значащих бит. Когда целое слишком большое, не все соседние значения можно представить отдельно.\n\n### 2. Почему `1n + 1` бросает ошибку, а не дает `2n` или `2`?\n\nОжидаем: кандидат объясняет, что `BigInt` и `number` являются разными числовыми типами. JavaScript не делает неявный выбор между точным целым `BigInt` и обычным `number`.\n\n### 3. Почему `1n == 1` дает `true`, а `1n === 1` дает `false`?\n\nОжидаем: кандидат говорит, что `==` может сравнить `BigInt` и `number` по математическому значению, если это возможно. Строгое равенство не приводит типы, поэтому разные типы сразу не равны.\n\n## Референсы\n\n- [ru.javascript.info: Числа](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F05-data-types\u002F02-number\u002Farticle.md) - точность `number`, безопасные целые числа и числовые проверки.\n- [ru.javascript.info: BigInt](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F1-js\u002F99-js-misc\u002F06-bigint\u002Farticle.md) - создание `BigInt` и запрет смешивания с `number` в арифметике.\n- [MDN: Number.MAX_SAFE_INTEGER](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fnumber\u002Fmax_safe_integer\u002Findex.md) - безопасная граница целых чисел.\n- [MDN: BigInt](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fjavascript\u002Freference\u002Fglobal_objects\u002Fbigint\u002Findex.md) - особенности типа `bigint` и операции с ним.",{"slug":4214,"title":4215,"baseQuestion":4216,"goodAnswer":4217,"followUps":4218,"references":4228,"programSlug":40,"lessonSlug":40,"order":1070,"status":13,"rawBody":4241},"browser-network-q12-chto-delaet-service-worker-s-setyu","Что делает Service Worker с сетью?","Как Service Worker может влиять на сетевые запросы страницы?","Сначала можно объяснить просто: Service Worker это скрипт браузера, который работает отдельно от страницы и может перехватывать запросы этой страницы. Когда страница просит ресурс, Service Worker может сходить в сеть, взять ответ из Cache Storage, собрать ответ вручную или выбрать смешанную стратегию.\n\nВажно сказать, что Service Worker не имеет доступа к DOM. Его задача не менять элементы страницы напрямую, а работать как промежуточный слой для событий, кеша, пушей и сетевых запросов.\n\nВ Chrome DevTools Service Worker обычно проверяют во вкладке Application. Там можно увидеть регистрацию, состояние, обновить или unregister. Cache Storage тоже смотрят в Application, а сами запросы и признаки перехвата удобно проверять в Network.",[4219,4222,4225],{"question":4220,"expected":4221},"Почему Service Worker может отдавать страницу офлайн?","кандидат говорит, что он может перехватить fetch-событие и вернуть ранее сохраненный Response из Cache Storage.",{"question":4223,"expected":4224},"Почему Service Worker не меняет DOM напрямую?","кандидат объясняет, что он работает вне страницы и без доступа к DOM. Для связи со страницей нужны сообщения или другие браузерные механизмы.",{"question":4226,"expected":4227},"Где в Chrome посмотреть зарегистрированный Service Worker?","кандидат говорит про вкладку Application и раздел Service Workers. Для кешей рядом используется Cache Storage.",[4229,4233,4237],{"title":4230,"url":4231,"note":4232},"MDN: Service Worker API","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fservice_worker_api\u002Findex.md","роль Service Worker.",{"title":4234,"url":4235,"note":4236},"MDN: Using Service Workers","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fservice_worker_api\u002Fusing_service_workers\u002Findex.md","перехват fetch и кеширование.",{"title":4238,"url":4239,"note":4240},"Chrome DevTools: Application panel","https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fdevtools\u002Fapplication","где смотреть Service Workers и Cache Storage.","# Q12. Что делает Service Worker с сетью?\n\n## Базовый вопрос\n\nКак Service Worker может влиять на сетевые запросы страницы?\n\n## Хороший ответ\n\nСначала можно объяснить просто: Service Worker это скрипт браузера, который работает отдельно от страницы и может перехватывать запросы этой страницы. Когда страница просит ресурс, Service Worker может сходить в сеть, взять ответ из Cache Storage, собрать ответ вручную или выбрать смешанную стратегию.\n\nВажно сказать, что Service Worker не имеет доступа к DOM. Его задача не менять элементы страницы напрямую, а работать как промежуточный слой для событий, кеша, пушей и сетевых запросов.\n\nВ Chrome DevTools Service Worker обычно проверяют во вкладке Application. Там можно увидеть регистрацию, состояние, обновить или unregister. Cache Storage тоже смотрят в Application, а сами запросы и признаки перехвата удобно проверять в Network.\n\n## Уточняющие вопросы\n\n### 1. Почему Service Worker может отдавать страницу офлайн?\n\nОжидаем: кандидат говорит, что он может перехватить fetch-событие и вернуть ранее сохраненный Response из Cache Storage.\n\n### 2. Почему Service Worker не меняет DOM напрямую?\n\nОжидаем: кандидат объясняет, что он работает вне страницы и без доступа к DOM. Для связи со страницей нужны сообщения или другие браузерные механизмы.\n\n### 3. Где в Chrome посмотреть зарегистрированный Service Worker?\n\nОжидаем: кандидат говорит про вкладку Application и раздел Service Workers. Для кешей рядом используется Cache Storage.\n\n## Референсы\n\n- [MDN: Service Worker API](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fservice_worker_api\u002Findex.md) - роль Service Worker.\n- [MDN: Using Service Workers](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fservice_worker_api\u002Fusing_service_workers\u002Findex.md) - перехват fetch и кеширование.\n- [Chrome DevTools: Application panel](https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fdevtools\u002Fapplication) - где смотреть Service Workers и Cache Storage.",{"slug":4243,"title":4244,"baseQuestion":4244,"goodAnswer":4245,"followUps":4246,"references":4256,"programSlug":41,"lessonSlug":41,"order":1070,"status":13,"rawBody":4269},"rendering-dom-events-forms-q12-kogda-vybirat-input-vmesto-change","Когда выбирать `input` вместо `change`?","Если говорить просто, `input` сообщает о текущем изменении значения, а `change` обычно сообщает о завершенном изменении.\n\nДля текстового поля `input` срабатывает по мере ввода. Пользователь добавил символ - мы можем сразу отреагировать. `change` для текстового поля обычно срабатывает позже, когда значение зафиксировано, например после потери фокуса.\n\nДля других контролов поведение может отличаться. У checkbox, radio или select `change` часто срабатывает сразу после выбора, потому что действие пользователя уже меняет зафиксированное значение.\n\nВажно помнить: программная запись в `element.value` сама по себе не обязана отправлять `input` или `change`. Если в тесте или коде мы хотим имитировать событие, его нужно отправить отдельно.",[4247,4250,4253],{"question":4248,"expected":4249},"Почему для живого поиска обычно выбирают `input`, а не `change`?","кандидат говорит, что живому поиску нужно реагировать на каждое изменение значения, а `change` может прийти только после завершения редактирования.",{"question":4251,"expected":4252},"Мы присвоили `input.value` значение `1`. Почему обработчик `input` не обязан сработать сам?","кандидат объясняет, что программное изменение свойства не равно пользовательскому вводу и не обязано автоматически отправлять DOM-событие.",{"question":4254,"expected":4255},"Почему у checkbox `change` ощущается иначе, чем у текстового поля?","кандидат говорит, что выбор checkbox сразу фиксирует новое состояние, поэтому `change` обычно приходит сразу после действия пользователя.",[4257,4261,4265],{"title":4258,"url":4259,"note":4260},"ru.javascript.info: События change input cut copy paste","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F4-forms-controls\u002F3-events-change-input\u002Farticle.md","объясняет разницу между `input` и `change`.",{"title":4262,"url":4263,"note":4264},"MDN: Element input event","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Felement\u002Finput_event\u002Findex.md","описывает событие `input`.",{"title":4266,"url":4267,"note":4268},"MDN: HTMLElement change event","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlelement\u002Fchange_event\u002Findex.md","описывает событие `change`.","# Q12. Когда выбирать `input` вместо `change`?\n\n## Базовый вопрос\n\nКогда выбирать `input` вместо `change`?\n\n## Хороший ответ\n\nЕсли говорить просто, `input` сообщает о текущем изменении значения, а `change` обычно сообщает о завершенном изменении.\n\nДля текстового поля `input` срабатывает по мере ввода. Пользователь добавил символ - мы можем сразу отреагировать. `change` для текстового поля обычно срабатывает позже, когда значение зафиксировано, например после потери фокуса.\n\nДля других контролов поведение может отличаться. У checkbox, radio или select `change` часто срабатывает сразу после выбора, потому что действие пользователя уже меняет зафиксированное значение.\n\nВажно помнить: программная запись в `element.value` сама по себе не обязана отправлять `input` или `change`. Если в тесте или коде мы хотим имитировать событие, его нужно отправить отдельно.\n\n## Уточняющие вопросы\n\n### 1. Почему для живого поиска обычно выбирают `input`, а не `change`?\n\nОжидаем: кандидат говорит, что живому поиску нужно реагировать на каждое изменение значения, а `change` может прийти только после завершения редактирования.\n\n### 2. Мы присвоили `input.value` значение `1`. Почему обработчик `input` не обязан сработать сам?\n\nОжидаем: кандидат объясняет, что программное изменение свойства не равно пользовательскому вводу и не обязано автоматически отправлять DOM-событие.\n\n### 3. Почему у checkbox `change` ощущается иначе, чем у текстового поля?\n\nОжидаем: кандидат говорит, что выбор checkbox сразу фиксирует новое состояние, поэтому `change` обычно приходит сразу после действия пользователя.\n\n## Референсы\n\n- [ru.javascript.info: События change input cut copy paste](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F4-forms-controls\u002F3-events-change-input\u002Farticle.md) - объясняет разницу между `input` и `change`.\n- [MDN: Element input event](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Felement\u002Finput_event\u002Findex.md) - описывает событие `input`.\n- [MDN: HTMLElement change event](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlelement\u002Fchange_event\u002Findex.md) - описывает событие `change`.",{"slug":4271,"title":4272,"baseQuestion":4272,"goodAnswer":4273,"followUps":4274,"references":4284,"programSlug":41,"lessonSlug":41,"order":1140,"status":13,"rawBody":4301},"rendering-dom-events-forms-q13-kak-rabotaet-sobytie-submit","Как работает событие `submit`?","`submit` - это событие отправки формы. Его обычно слушают на самом элементе `form`, а не на кнопке. Когда пользователь отправляет форму кнопкой или клавишей Enter, браузер проходит стандартную механику формы и генерирует `submit`.\n\nВ обработчике `submit` мы часто вызываем `preventDefault()`, если хотим обработать данные на клиенте и не делать обычный переход страницы. Это типичный сценарий для SPA и учебных форм.\n\nУ `SubmitEvent` есть `submitter` - элемент, через который отправили форму. Это полезно, когда в одной форме несколько submit-кнопок с разным смыслом.\n\nВажный нюанс для интервью: программный `form.submit()` отличается от пользовательской отправки. Он отправляет форму напрямую и не проходит тот же путь с событием `submit`. Если нужно имитировать настоящую отправку через кнопку, используют более подходящий механизм вроде `requestSubmit()`.",[4275,4278,4281],{"question":4276,"expected":4277},"Почему обработчик `submit` обычно ставят на `form`, а не только на кнопку?","кандидат говорит, что форму можно отправить не только кликом по кнопке. Событие относится к форме как к целому.",{"question":4279,"expected":4280},"Что мы отменяем через `preventDefault()` в обработчике `submit`?","кандидат объясняет, что мы отменяем обычную отправку формы браузером и возможный переход страницы.",{"question":4282,"expected":4283},"Зачем может понадобиться `event.submitter`?","кандидат говорит, что он показывает элемент, через который была отправлена форма, например одну из нескольких submit-кнопок.",[4285,4289,4293,4297],{"title":4286,"url":4287,"note":4288},"ru.javascript.info: Отправка формы событие и метод submit","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F4-forms-controls\u002F4-forms-submit\u002Farticle.md","объясняет событие и метод отправки формы.",{"title":4290,"url":4291,"note":4292},"MDN: HTMLFormElement submit event","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlformelement\u002Fsubmit_event\u002Findex.md","описывает событие `submit`.",{"title":4294,"url":4295,"note":4296},"MDN: HTMLFormElement requestSubmit","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlformelement\u002Frequestsubmit\u002Findex.md","описывает программную отправку через стандартный путь формы.",{"title":4298,"url":4299,"note":4300},"MDN: SubmitEvent","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fsubmitevent\u002Findex.md","описывает объект события отправки формы.","# Q13. Как работает событие `submit`?\n\n## Базовый вопрос\n\nКак работает событие `submit`?\n\n## Хороший ответ\n\n`submit` - это событие отправки формы. Его обычно слушают на самом элементе `form`, а не на кнопке. Когда пользователь отправляет форму кнопкой или клавишей Enter, браузер проходит стандартную механику формы и генерирует `submit`.\n\nВ обработчике `submit` мы часто вызываем `preventDefault()`, если хотим обработать данные на клиенте и не делать обычный переход страницы. Это типичный сценарий для SPA и учебных форм.\n\nУ `SubmitEvent` есть `submitter` - элемент, через который отправили форму. Это полезно, когда в одной форме несколько submit-кнопок с разным смыслом.\n\nВажный нюанс для интервью: программный `form.submit()` отличается от пользовательской отправки. Он отправляет форму напрямую и не проходит тот же путь с событием `submit`. Если нужно имитировать настоящую отправку через кнопку, используют более подходящий механизм вроде `requestSubmit()`.\n\n## Уточняющие вопросы\n\n### 1. Почему обработчик `submit` обычно ставят на `form`, а не только на кнопку?\n\nОжидаем: кандидат говорит, что форму можно отправить не только кликом по кнопке. Событие относится к форме как к целому.\n\n### 2. Что мы отменяем через `preventDefault()` в обработчике `submit`?\n\nОжидаем: кандидат объясняет, что мы отменяем обычную отправку формы браузером и возможный переход страницы.\n\n### 3. Зачем может понадобиться `event.submitter`?\n\nОжидаем: кандидат говорит, что он показывает элемент, через который была отправлена форма, например одну из нескольких submit-кнопок.\n\n## Референсы\n\n- [ru.javascript.info: Отправка формы событие и метод submit](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F4-forms-controls\u002F4-forms-submit\u002Farticle.md) - объясняет событие и метод отправки формы.\n- [MDN: HTMLFormElement submit event](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlformelement\u002Fsubmit_event\u002Findex.md) - описывает событие `submit`.\n- [MDN: HTMLFormElement requestSubmit](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlformelement\u002Frequestsubmit\u002Findex.md) - описывает программную отправку через стандартный путь формы.\n- [MDN: SubmitEvent](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fsubmitevent\u002Findex.md) - описывает объект события отправки формы.",{"slug":4303,"title":4304,"baseQuestion":4304,"goodAnswer":4305,"followUps":4306,"references":4316,"programSlug":41,"lessonSlug":41,"order":1196,"status":13,"rawBody":4329},"rendering-dom-events-forms-q14-chto-proishodit-pri-smene-fokusa-u-elementa","Что происходит при смене фокуса у элемента?","`focus` срабатывает, когда элемент получает фокус, а `blur` - когда элемент его теряет. Это базовые события для полей ввода, кнопок и других фокусируемых элементов.\n\nВажная особенность: `focus` и `blur` не всплывают как обычный `click`. Поэтому обработчик на родительском контейнере не увидит их через обычное всплытие.\n\nЕсли нужно ловить смену фокуса на контейнере, часто используют `focusin` и `focusout`. Они похожи по смыслу, но всплывают, поэтому подходят для делегирования внутри формы или сложного виджета.\n\nНа собеседовании хороший ответ должен показать практический вывод: для одного поля можно слушать `focus` и `blur` на самом поле, а для группы полей удобнее смотреть в сторону `focusin` и `focusout`.",[4307,4310,4313],{"question":4308,"expected":4309},"Почему обработчик `focus` на родителе может не увидеть фокус дочернего input?","кандидат говорит, что `focus` не всплывает, поэтому обычный bubbling обработчик родителя не сработает.",{"question":4311,"expected":4312},"Когда удобнее использовать `focusin` вместо `focus`?","кандидат объясняет, что `focusin` всплывает и подходит, когда мы хотим ловить фокус внутри контейнера одним обработчиком.",{"question":4314,"expected":4315},"Чем потеря фокуса отличается от изменения значения поля?","кандидат говорит, что `blur` описывает уход фокуса, а не само изменение значения. Значение могло измениться раньше, позже или не измениться вообще.",[4317,4321,4325],{"title":4318,"url":4319,"note":4320},"ru.javascript.info: Фокусировка focus blur","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F4-forms-controls\u002F2-focus-blur\u002Farticle.md","объясняет события фокуса и методы `focus`\u002F`blur`.",{"title":4322,"url":4323,"note":4324},"MDN: Element focus event","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Felement\u002Ffocus_event\u002Findex.md","описывает событие `focus`.",{"title":4326,"url":4327,"note":4328},"MDN: Element blur event","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Felement\u002Fblur_event\u002Findex.md","описывает событие `blur`.","# Q14. Что происходит при смене фокуса у элемента?\n\n## Базовый вопрос\n\nЧто происходит при смене фокуса у элемента?\n\n## Хороший ответ\n\n`focus` срабатывает, когда элемент получает фокус, а `blur` - когда элемент его теряет. Это базовые события для полей ввода, кнопок и других фокусируемых элементов.\n\nВажная особенность: `focus` и `blur` не всплывают как обычный `click`. Поэтому обработчик на родительском контейнере не увидит их через обычное всплытие.\n\nЕсли нужно ловить смену фокуса на контейнере, часто используют `focusin` и `focusout`. Они похожи по смыслу, но всплывают, поэтому подходят для делегирования внутри формы или сложного виджета.\n\nНа собеседовании хороший ответ должен показать практический вывод: для одного поля можно слушать `focus` и `blur` на самом поле, а для группы полей удобнее смотреть в сторону `focusin` и `focusout`.\n\n## Уточняющие вопросы\n\n### 1. Почему обработчик `focus` на родителе может не увидеть фокус дочернего input?\n\nОжидаем: кандидат говорит, что `focus` не всплывает, поэтому обычный bubbling обработчик родителя не сработает.\n\n### 2. Когда удобнее использовать `focusin` вместо `focus`?\n\nОжидаем: кандидат объясняет, что `focusin` всплывает и подходит, когда мы хотим ловить фокус внутри контейнера одним обработчиком.\n\n### 3. Чем потеря фокуса отличается от изменения значения поля?\n\nОжидаем: кандидат говорит, что `blur` описывает уход фокуса, а не само изменение значения. Значение могло измениться раньше, позже или не измениться вообще.\n\n## Референсы\n\n- [ru.javascript.info: Фокусировка focus blur](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F4-forms-controls\u002F2-focus-blur\u002Farticle.md) - объясняет события фокуса и методы `focus`\u002F`blur`.\n- [MDN: Element focus event](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Felement\u002Ffocus_event\u002Findex.md) - описывает событие `focus`.\n- [MDN: Element blur event](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Felement\u002Fblur_event\u002Findex.md) - описывает событие `blur`.",{"slug":4331,"title":4332,"baseQuestion":4332,"goodAnswer":4333,"followUps":4334,"references":4344,"programSlug":41,"lessonSlug":41,"order":1253,"status":13,"rawBody":4353},"rendering-dom-events-forms-q15-zachem-nuzhna-kollekciya-form-elements","Зачем нужна коллекция `form.elements`?","`form.elements` дает доступ к элементам управления внутри формы. Это не просто все DOM-узлы формы, а именно controls, которые относятся к форме: input, button, select, textarea, fieldset и похожие элементы.\n\nЧерез `form.elements` можно пройтись по контролам или получить элемент по `name`. Это удобно, когда мы обрабатываем форму как единый объект, а не ищем каждое поле отдельным `querySelector`.\n\nВажно помнить, что форма - это не только визуальная группа элементов. У элементов управления есть связь с формой, имена, значения, состояние валидности и поведение при отправке.\n\nНа собеседовании хороший ответ должен показать практический смысл: `form.elements` помогает работать с настоящими form controls и их значениями, а не просто с произвольной DOM-разметкой.",[4335,4338,4341],{"question":4336,"expected":4337},"Чем `form.elements` отличается от поиска всех потомков через `querySelectorAll('*')`?","кандидат говорит, что `form.elements` возвращает элементы управления формы, а не любые вложенные DOM-узлы.",{"question":4339,"expected":4340},"Почему `name` важен для формы?","кандидат объясняет, что `name` связывает control с именем поля, через него можно обращаться к элементам и формировать данные формы.",{"question":4342,"expected":4343},"Почему кнопку формы мы тоже можем увидеть среди элементов формы?","кандидат говорит, что button тоже является элементом управления формы и может участвовать в отправке или действиях формы.",[4345,4349],{"title":4346,"url":4347,"note":4348},"ru.javascript.info: Свойства и методы формы","https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F4-forms-controls\u002F1-form-elements\u002Farticle.md","объясняет навигацию по формам и элементам формы.",{"title":4350,"url":4351,"note":4352},"MDN: HTMLFormElement elements","https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlformelement\u002Felements\u002Findex.md","описывает коллекцию элементов управления формы.","# Q15. Зачем нужна коллекция `form.elements`?\n\n## Базовый вопрос\n\nЗачем нужна коллекция `form.elements`?\n\n## Хороший ответ\n\n`form.elements` дает доступ к элементам управления внутри формы. Это не просто все DOM-узлы формы, а именно controls, которые относятся к форме: input, button, select, textarea, fieldset и похожие элементы.\n\nЧерез `form.elements` можно пройтись по контролам или получить элемент по `name`. Это удобно, когда мы обрабатываем форму как единый объект, а не ищем каждое поле отдельным `querySelector`.\n\nВажно помнить, что форма - это не только визуальная группа элементов. У элементов управления есть связь с формой, имена, значения, состояние валидности и поведение при отправке.\n\nНа собеседовании хороший ответ должен показать практический смысл: `form.elements` помогает работать с настоящими form controls и их значениями, а не просто с произвольной DOM-разметкой.\n\n## Уточняющие вопросы\n\n### 1. Чем `form.elements` отличается от поиска всех потомков через `querySelectorAll('*')`?\n\nОжидаем: кандидат говорит, что `form.elements` возвращает элементы управления формы, а не любые вложенные DOM-узлы.\n\n### 2. Почему `name` важен для формы?\n\nОжидаем: кандидат объясняет, что `name` связывает control с именем поля, через него можно обращаться к элементам и формировать данные формы.\n\n### 3. Почему кнопку формы мы тоже можем увидеть среди элементов формы?\n\nОжидаем: кандидат говорит, что button тоже является элементом управления формы и может участвовать в отправке или действиях формы.\n\n## Референсы\n\n- [ru.javascript.info: Свойства и методы формы](https:\u002F\u002Fgithub.com\u002Fjavascript-tutorial\u002Fru.javascript.info\u002Fblob\u002Fmaster\u002F2-ui\u002F4-forms-controls\u002F1-form-elements\u002Farticle.md) - объясняет навигацию по формам и элементам формы.\n- [MDN: HTMLFormElement elements](https:\u002F\u002Fgithub.com\u002Fmdn\u002Fcontent\u002Fblob\u002Fmain\u002Ffiles\u002Fen-us\u002Fweb\u002Fapi\u002Fhtmlformelement\u002Felements\u002Findex.md) - описывает коллекцию элементов управления формы.",[4355,4364,4373,4381,4387,4393,4400,4406,4412,4414,4420,4427,4433,4439,4445,4451,4457,4463,4469,4471,4478,4484,4490,4496,4502,4508,4514,4520,4528,4534,4539,4545,4550,4556,4562,4568,4574,4580,4586,4592,4598,4604,4610,4616,4622,4628,4634,4640,4647,4653,4659,4666,4672,4678,4684,4689,4695],{"slug":4356,"title":4357,"benefit":4358,"frequency":4359,"difficulty":4360,"platform":4361,"taskUrl":4362,"programSlug":40,"lessonSlug":40,"order":12,"status":13,"rawBody":4363},"browser-network-t1-urlsearchparams","URLSearchParams","Вам предстоит собрать строку параметров для URL из объекта.\n\nПосле решения вы лучше почувствуете, как данные интерфейса превращаются в адрес запроса. Это поможет на интервью объяснять, какие значения уходят в query string и почему порядок, пустые значения и повторяющиеся параметры нужно обрабатывать осознанно.","8\u002F10","Hard","BFE.dev","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-your-own-URLSearchParams","# T1. URLSearchParams\n\n## Польза\n\nВам предстоит собрать строку параметров для URL из объекта.\n\nПосле решения вы лучше почувствуете, как данные интерфейса превращаются в адрес запроса. Это поможет на интервью объяснять, какие значения уходят в query string и почему порядок, пустые значения и повторяющиеся параметры нужно обрабатывать осознанно.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень BFE.dev   |\n| ----------------- |\n| Hard \u003C-- вы здесь |\n| Medium            |\n| Easy              |\n\n## Ссылка на задачу\n\n[BFE.dev 80. implement your own URLSearchParams](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-your-own-URLSearchParams)",{"slug":4365,"title":4366,"benefit":4367,"frequency":4368,"difficulty":4369,"platform":4370,"taskUrl":4371,"programSlug":17,"lessonSlug":17,"order":12,"status":13,"rawBody":4372},"collections-iteration-arrays-t1-apply-transform-over-each-element-in-array","Apply Transform Over Each Element in Array","Вам предстоит получить новый список значений из исходного списка.\n\nПосле решения вы лучше почувствуете разницу между изменением исходных данных и построением нового результата. Это поможет в задачах, где данные проходят через последовательные преобразования перед выводом в интерфейс.","7\u002F10","Easy","LeetCode","https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fapply-transform-over-each-element-in-array\u002F","# T1. Apply Transform Over Each Element in Array\n\n## Польза\n\nВам предстоит получить новый список значений из исходного списка.\n\nПосле решения вы лучше почувствуете разницу между изменением исходных данных и построением нового результата. Это поможет в задачах, где данные проходят через последовательные преобразования перед выводом в интерфейс.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень LeetCode  |\n| ----------------- |\n| Hard              |\n| Medium            |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[LeetCode 2635 Apply Transform Over Each Element in Array](https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fapply-transform-over-each-element-in-array\u002F)",{"slug":4374,"title":4375,"benefit":4376,"frequency":4377,"difficulty":4378,"platform":4361,"taskUrl":4379,"programSlug":30,"lessonSlug":30,"order":12,"status":13,"rawBody":4380},"event-loop-promises-async-await-t1-promise-all","Promise.all","Вам предстоит реализовать `Promise.all` для координации нескольких асинхронных операций.\n\nПосле решения вы научитесь отличать параллельный запуск от согласования общего результата. Это поможет проектировать несколько API-запросов, где важно дождаться группы операций и сохранить понятное поведение при неудаче.","10\u002F10","Medium","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-Promise-all","# T1. Promise.all\n\n## Польза\n\nВам предстоит реализовать `Promise.all` для координации нескольких асинхронных операций.\n\nПосле решения вы научитесь отличать параллельный запуск от согласования общего результата. Это поможет проектировать несколько API-запросов, где важно дождаться группы операций и сохранить понятное поведение при неудаче.\n\n## Насколько часто встречается\n\n10\u002F10\n\n## Сложность\n\n| Уровень BFE.dev |\n| --- |\n| Hard |\n| Medium \u003C-- вы здесь |\n| Easy |\n\n## Ссылка на задачу\n\n[BFE.dev 32 Implement Promise.all](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-Promise-all)",{"slug":4382,"title":4383,"benefit":4384,"frequency":4359,"difficulty":4378,"platform":4361,"taskUrl":4385,"programSlug":31,"lessonSlug":31,"order":12,"status":13,"rawBody":4386},"event-loop-promises-deep-dive-t1-promise-allsettled","Promise.allSettled","Вам предстоит реализовать `Promise.allSettled` для группы асинхронных операций.\n\nПосле решения вы научитесь отличать сценарий \"ждем все исходы\" от сценария \"останавливаемся на первой ошибке\". Это поможет в интерфейсах, где часть запросов может завершиться неудачно, но успешные данные все равно нужно показать пользователю.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-Promise-allSettled","# T1. Promise.allSettled\n\n## Польза\n\nВам предстоит реализовать `Promise.allSettled` для группы асинхронных операций.\n\nПосле решения вы научитесь отличать сценарий \"ждем все исходы\" от сценария \"останавливаемся на первой ошибке\". Это поможет в интерфейсах, где часть запросов может завершиться неудачно, но успешные данные все равно нужно показать пользователю.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень BFE.dev |\n| --- |\n| Hard |\n| Medium \u003C-- вы здесь |\n| Easy |\n\n## Ссылка на задачу\n\n[BFE.dev 33. implement Promise.allSettled](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-Promise-allSettled)",{"slug":4388,"title":4389,"benefit":4390,"frequency":4359,"difficulty":4378,"platform":4370,"taskUrl":4391,"programSlug":59,"lessonSlug":59,"order":12,"status":13,"rawBody":4392},"mock-interview-javascript-core-mock-t1-memoize","memoize","Вам предстоит реализовать `memoize`, чтобы повторные вызовы с теми же входными данными не выполняли лишнюю работу.\n\nПосле решения вы научитесь видеть, как замыкание помогает функции помнить приватное состояние между вызовами. Это поможет на интервью объяснять, где в прикладном коде появляется кеширование и почему оно связано с поведением функции, а не с магией библиотеки.","https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fmemoize\u002F","# T1. memoize\n\n## Польза\n\nВам предстоит реализовать `memoize`, чтобы повторные вызовы с теми же входными данными не выполняли лишнюю работу.\n\nПосле решения вы научитесь видеть, как замыкание помогает функции помнить приватное состояние между вызовами. Это поможет на интервью объяснять, где в прикладном коде появляется кеширование и почему оно связано с поведением функции, а не с магией библиотеки.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень LeetCode |\n| --- |\n| Hard |\n| Medium \u003C-- вы здесь |\n| Easy |\n\n## Ссылка на задачу\n\n[LeetCode 2623 Memoize](https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fmemoize\u002F)",{"slug":4394,"title":4395,"benefit":4396,"frequency":4397,"difficulty":4378,"platform":4361,"taskUrl":4398,"programSlug":18,"lessonSlug":18,"order":12,"status":13,"rawBody":4399},"objects-prototypes-classes-t1-completeassign","completeAssign","Вам предстоит реализовать копирование свойств так, чтобы сохранялась их настоящая структура, а не только результат чтения.\n\nПосле решения вы научитесь отличать копирование значений от копирования свойств и понимать, почему внешне похожие способы копирования объекта могут давать разное поведение. Это поможет на собеседовании объяснять, где обычное копирование объекта теряет важные детали свойства.","5\u002F10","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-completeAssign","# T1. completeAssign\n\n## Польза\n\nВам предстоит реализовать копирование свойств так, чтобы сохранялась их настоящая структура, а не только результат чтения.\n\nПосле решения вы научитесь отличать копирование значений от копирования свойств и понимать, почему внешне похожие способы копирования объекта могут давать разное поведение. Это поможет на собеседовании объяснять, где обычное копирование объекта теряет важные детали свойства.\n\n## Насколько часто встречается\n\n5\u002F10\n\n## Сложность\n\n| Уровень BFE.dev |\n| --- |\n| Hard |\n| Medium \u003C-- вы здесь |\n| Easy |\n\n## Ссылка на задачу\n\n[BFE.dev 27. implement completeAssign()](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-completeAssign)",{"slug":4401,"title":4402,"benefit":4403,"frequency":4359,"difficulty":4369,"platform":4370,"taskUrl":4404,"programSlug":50,"lessonSlug":50,"order":12,"status":13,"rawBody":4405},"recursion-t1-fibonacci-number","Fibonacci Number","Вам предстоит описать значение через два предыдущих значения и аккуратно остановить рекурсивный спуск.\n\nПосле решения вы лучше почувствуете, почему рекурсивная формула должна иметь простые крайние случаи. Это поможет на интервью быстро объяснять разницу между самой идеей рекурсии и ее стоимостью.","https:\u002F\u002Fleetcode.com\u002Fproblems\u002Ffibonacci-number\u002F","# T1. Fibonacci Number\n\n## Польза\n\nВам предстоит описать значение через два предыдущих значения и аккуратно остановить рекурсивный спуск.\n\nПосле решения вы лучше почувствуете, почему рекурсивная формула должна иметь простые крайние случаи. Это поможет на интервью быстро объяснять разницу между самой идеей рекурсии и ее стоимостью.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень LeetCode  |\n| ----------------- |\n| Hard              |\n| Medium            |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[LeetCode 509. Fibonacci Number](https:\u002F\u002Fleetcode.com\u002Fproblems\u002Ffibonacci-number\u002F)",{"slug":4407,"title":4408,"benefit":4409,"frequency":4368,"difficulty":4378,"platform":4361,"taskUrl":4410,"programSlug":41,"lessonSlug":41,"order":12,"status":13,"rawBody":4411},"rendering-dom-events-forms-t1-classnames","classNames","Вам предстоит собрать итоговую строку классов из разных входных значений.\n\nПосле решения вы лучше поймете, как состояние интерфейса превращается в набор CSS-классов. Это поможет в задачах, где внешний вид элемента меняется декларативно, а браузер потом пересчитывает применимые стили.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-classnames","# T1. classNames\n\n## Польза\n\nВам предстоит собрать итоговую строку классов из разных входных значений.\n\nПосле решения вы лучше поймете, как состояние интерфейса превращается в набор CSS-классов. Это поможет в задачах, где внешний вид элемента меняется декларативно, а браузер потом пересчитывает применимые стили.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень BFE.dev     |\n| ------------------- |\n| Hard                |\n| Medium \u003C-- вы здесь |\n| Easy                |\n\n## Ссылка на задачу\n\n[BFE.dev 125 implement classNames](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-classnames)",{"slug":4413,"title":4389,"benefit":4390,"frequency":4359,"difficulty":4378,"platform":4370,"taskUrl":4391,"programSlug":20,"lessonSlug":20,"order":12,"status":13,"rawBody":4392},"scope-hoisting-closures-this-t1-memoize",{"slug":4415,"title":4416,"benefit":4417,"frequency":4368,"difficulty":4378,"platform":4370,"taskUrl":4418,"programSlug":21,"lessonSlug":21,"order":12,"status":13,"rawBody":4419},"types-coercion-symbol-json-t1-compact-object","Compact Object","Вам предстоит очистить вложенные данные от значений, которые в JavaScript считаются ложными.\n\nПосле решения вы лучше почувствуете, где обычная человеческая интуиция про \"пустое\" расходится с правилами языка. Это поможет на интервью спокойно объяснять, почему разные значения ведут себя по-разному в условиях и фильтрации данных.","https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fcompact-object\u002F","# T1. Compact Object\n\n## Польза\n\nВам предстоит очистить вложенные данные от значений, которые в JavaScript считаются ложными.\n\nПосле решения вы лучше почувствуете, где обычная человеческая интуиция про \"пустое\" расходится с правилами языка. Это поможет на интервью спокойно объяснять, почему разные значения ведут себя по-разному в условиях и фильтрации данных.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень LeetCode    |\n| ------------------- |\n| Hard                |\n| Medium \u003C-- вы здесь |\n| Easy                |\n\n## Ссылка на задачу\n\n[LeetCode 2705 Compact Object](https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fcompact-object\u002F)",{"slug":4421,"title":4422,"benefit":4423,"frequency":4424,"difficulty":4378,"platform":4361,"taskUrl":4425,"programSlug":40,"lessonSlug":40,"order":26,"status":13,"rawBody":4426},"browser-network-t2-apis-with-pagination","APIs With Pagination","Вам предстоит получить данные через HTTP и вернуть результат в удобном для кода виде.\n\nПосле решения вы увереннее разделите сам запрос, проверку ответа и чтение данных. Это помогает в задачах, где кандидат должен не просто написать `fetch`, а объяснить, что происходит на каждом асинхронном шаге.","9\u002F10","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fcall-APIs-with-pagination","# T2. APIs With Pagination\n\n## Польза\n\nВам предстоит получить данные через HTTP и вернуть результат в удобном для кода виде.\n\nПосле решения вы увереннее разделите сам запрос, проверку ответа и чтение данных. Это помогает в задачах, где кандидат должен не просто написать `fetch`, а объяснить, что происходит на каждом асинхронном шаге.\n\n## Насколько часто встречается\n\n9\u002F10\n\n## Сложность\n\n| Уровень BFE.dev     |\n| ------------------- |\n| Hard                |\n| Medium \u003C-- вы здесь |\n| Easy                |\n\n## Ссылка на задачу\n\n[BFE.dev 56. call APIs with pagination](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fcall-APIs-with-pagination)",{"slug":4428,"title":4429,"benefit":4430,"frequency":4368,"difficulty":4369,"platform":4370,"taskUrl":4431,"programSlug":17,"lessonSlug":17,"order":26,"status":13,"rawBody":4432},"collections-iteration-arrays-t2-filter-elements-from-array","Filter Elements from Array","Вам предстоит вернуть только те элементы списка, которые подходят под заданное правило.\n\nПосле решения вы научитесь аккуратно отделять отбор данных от их дальнейшей обработки. Это поможет в задачах с поиском подходящих элементов, фильтрами таблиц и подготовкой данных для отображения.","https:\u002F\u002Fleetcode.com\u002Fproblems\u002Ffilter-elements-from-array\u002F","# T2. Filter Elements from Array\n\n## Польза\n\nВам предстоит вернуть только те элементы списка, которые подходят под заданное правило.\n\nПосле решения вы научитесь аккуратно отделять отбор данных от их дальнейшей обработки. Это поможет в задачах с поиском подходящих элементов, фильтрами таблиц и подготовкой данных для отображения.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень LeetCode  |\n| ----------------- |\n| Hard              |\n| Medium            |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[LeetCode 2634 Filter Elements from Array](https:\u002F\u002Fleetcode.com\u002Fproblems\u002Ffilter-elements-from-array\u002F)",{"slug":4434,"title":4435,"benefit":4436,"frequency":4424,"difficulty":4378,"platform":4361,"taskUrl":4437,"programSlug":30,"lessonSlug":30,"order":26,"status":13,"rawBody":4438},"event-loop-promises-async-await-t2-throttle","throttle","Вам предстоит реализовать `throttle`, чтобы ограничить частоту выполнения функции.\n\nПосле решения вы научитесь отличать ограничение частоты от ожидания паузы после последнего события. Это поможет обрабатывать `scroll`, `resize` и pointer-события без лишней нагрузки на интерфейс.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-basic-throttle","# T2. throttle\n\n## Польза\n\nВам предстоит реализовать `throttle`, чтобы ограничить частоту выполнения функции.\n\nПосле решения вы научитесь отличать ограничение частоты от ожидания паузы после последнего события. Это поможет обрабатывать `scroll`, `resize` и pointer-события без лишней нагрузки на интерфейс.\n\n## Насколько часто встречается\n\n9\u002F10\n\n## Сложность\n\n| Уровень BFE.dev |\n| --- |\n| Hard |\n| Medium \u003C-- вы здесь |\n| Easy |\n\n## Ссылка на задачу\n\n[BFE.dev 4 Implement Basic Throttle](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-basic-throttle)",{"slug":4440,"title":4441,"benefit":4442,"frequency":4368,"difficulty":4378,"platform":4361,"taskUrl":4443,"programSlug":31,"lessonSlug":31,"order":26,"status":13,"rawBody":4444},"event-loop-promises-deep-dive-t2-promise-any","Promise.any","Вам предстоит реализовать `Promise.any`, где важен первый успешный результат из нескольких асинхронных операций.\n\nПосле решения вы научитесь не путать \"первый завершившийся исход\" и \"первый успешный исход\". Это поможет проектировать fallback-сценарии, где один источник может сломаться, но другой еще способен дать рабочий результат.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-Promise-any","# T2. Promise.any\n\n## Польза\n\nВам предстоит реализовать `Promise.any`, где важен первый успешный результат из нескольких асинхронных операций.\n\nПосле решения вы научитесь не путать \"первый завершившийся исход\" и \"первый успешный исход\". Это поможет проектировать fallback-сценарии, где один источник может сломаться, но другой еще способен дать рабочий результат.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень BFE.dev |\n| --- |\n| Hard |\n| Medium \u003C-- вы здесь |\n| Easy |\n\n## Ссылка на задачу\n\n[BFE.dev 34. implement Promise.any](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-Promise-any)",{"slug":4446,"title":4447,"benefit":4448,"frequency":4377,"difficulty":4378,"platform":4370,"taskUrl":4449,"programSlug":59,"lessonSlug":59,"order":26,"status":13,"rawBody":4450},"mock-interview-javascript-core-mock-t2-debounce","debounce","Вам предстоит реализовать `debounce` для ситуации, где частые вызовы должны превратиться в один отложенный запуск.\n\nПосле решения вы научитесь отличать немедленную реакцию на событие от реакции после паузы. Это поможет уверенно разбирать автосохранение, поиск при вводе и обработчики браузерных событий без привязки к готовым библиотекам.","https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fdebounce\u002F","# T2. debounce\n\n## Польза\n\nВам предстоит реализовать `debounce` для ситуации, где частые вызовы должны превратиться в один отложенный запуск.\n\nПосле решения вы научитесь отличать немедленную реакцию на событие от реакции после паузы. Это поможет уверенно разбирать автосохранение, поиск при вводе и обработчики браузерных событий без привязки к готовым библиотекам.\n\n## Насколько часто встречается\n\n10\u002F10\n\n## Сложность\n\n| Уровень LeetCode |\n| --- |\n| Hard |\n| Medium \u003C-- вы здесь |\n| Easy |\n\n## Ссылка на задачу\n\n[LeetCode 2627 Debounce](https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fdebounce\u002F)",{"slug":4452,"title":4453,"benefit":4454,"frequency":4359,"difficulty":4378,"platform":4361,"taskUrl":4455,"programSlug":18,"lessonSlug":18,"order":26,"status":13,"rawBody":4456},"objects-prototypes-classes-t2-object-assign","Object.assign","Вам предстоит реализовать поведение `Object.assign` как знакомого способа объединять данные из нескольких объектов.\n\nПосле решения вы научитесь отличать удобное поверхностное копирование от точного переноса всей структуры объекта. Это поможет понимать, почему похожие способы копирования подходят для разных задач и по-разному ведут себя в сложных объектах.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-object-assign","# T2. Object.assign\n\n## Польза\n\nВам предстоит реализовать поведение `Object.assign` как знакомого способа объединять данные из нескольких объектов.\n\nПосле решения вы научитесь отличать удобное поверхностное копирование от точного переноса всей структуры объекта. Это поможет понимать, почему похожие способы копирования подходят для разных задач и по-разному ведут себя в сложных объектах.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень BFE.dev |\n| --- |\n| Hard |\n| Medium \u003C-- вы здесь |\n| Easy |\n\n## Ссылка на задачу\n\n[BFE.dev 26. implement Object.assign()](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-object-assign)",{"slug":4458,"title":4459,"benefit":4460,"frequency":4424,"difficulty":4369,"platform":4370,"taskUrl":4461,"programSlug":50,"lessonSlug":50,"order":26,"status":13,"rawBody":4462},"recursion-t2-maximum-depth-of-binary-tree","Maximum Depth of Binary Tree","Вам предстоит найти глубину дерева через глубину его частей.\n\nПосле решения вы научитесь объяснять дерево как структуру из меньших деревьев. Это один из самых частых сценариев, где рекурсия на собеседовании звучит естественно, а не как искусственная замена цикла.","https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fmaximum-depth-of-binary-tree\u002F","# T2. Maximum Depth of Binary Tree\n\n## Польза\n\nВам предстоит найти глубину дерева через глубину его частей.\n\nПосле решения вы научитесь объяснять дерево как структуру из меньших деревьев. Это один из самых частых сценариев, где рекурсия на собеседовании звучит естественно, а не как искусственная замена цикла.\n\n## Насколько часто встречается\n\n9\u002F10\n\n## Сложность\n\n| Уровень LeetCode  |\n| ----------------- |\n| Hard              |\n| Medium            |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[LeetCode 104. Maximum Depth of Binary Tree](https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fmaximum-depth-of-binary-tree\u002F)",{"slug":4464,"title":4465,"benefit":4466,"frequency":4368,"difficulty":4378,"platform":4361,"taskUrl":4467,"programSlug":41,"lessonSlug":41,"order":26,"status":13,"rawBody":4468},"rendering-dom-events-forms-t2-implement-immutability-helper","Implement Immutability helper","Вам предстоит обновлять вложенное состояние так, чтобы новое значение можно было сравнивать со старым без полного пересоздания всего дерева.\n\nПосле решения вы лучше поймете, почему фреймворкам важно видеть границу между старым и новым состоянием. Это поможет связывать изменение данных, новый render и последующий patch настоящего DOM.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-Immutability-helper","# T2. Implement Immutability helper\n\n## Польза\n\nВам предстоит обновлять вложенное состояние так, чтобы новое значение можно было сравнивать со старым без полного пересоздания всего дерева.\n\nПосле решения вы лучше поймете, почему фреймворкам важно видеть границу между старым и новым состоянием. Это поможет связывать изменение данных, новый render и последующий patch настоящего DOM.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень BFE.dev     |\n| ------------------- |\n| Hard                |\n| Medium \u003C-- вы здесь |\n| Easy                |\n\n## Ссылка на задачу\n\n[BFE.dev 12 implement Immutability helper](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-Immutability-helper)",{"slug":4470,"title":4447,"benefit":4448,"frequency":4377,"difficulty":4378,"platform":4370,"taskUrl":4449,"programSlug":20,"lessonSlug":20,"order":26,"status":13,"rawBody":4450},"scope-hoisting-closures-this-t2-debounce",{"slug":4472,"title":4473,"benefit":4474,"frequency":4475,"difficulty":4369,"platform":4370,"taskUrl":4476,"programSlug":21,"lessonSlug":21,"order":26,"status":13,"rawBody":4477},"types-coercion-symbol-json-t2-array-wrapper","Array Wrapper","Вам предстоит сделать объект, который по-разному ведет себя в численном и строковом контексте.\n\nПосле решения вы лучше поймете, почему один и тот же объект может давать разные результаты рядом с оператором и при явном превращении в строку. Это полезно для задач, где интервьюер проверяет не синтаксис, а понимание скрытого приведения значений.","6\u002F10","https:\u002F\u002Fleetcode.com\u002Fproblems\u002Farray-wrapper\u002F","# T2. Array Wrapper\n\n## Польза\n\nВам предстоит сделать объект, который по-разному ведет себя в численном и строковом контексте.\n\nПосле решения вы лучше поймете, почему один и тот же объект может давать разные результаты рядом с оператором и при явном превращении в строку. Это полезно для задач, где интервьюер проверяет не синтаксис, а понимание скрытого приведения значений.\n\n## Насколько часто встречается\n\n6\u002F10\n\n## Сложность\n\n| Уровень LeetCode  |\n| ----------------- |\n| Hard              |\n| Medium            |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[LeetCode 2695 Array Wrapper](https:\u002F\u002Fleetcode.com\u002Fproblems\u002Farray-wrapper\u002F)",{"slug":4479,"title":4480,"benefit":4481,"frequency":4359,"difficulty":4378,"platform":4361,"taskUrl":4482,"programSlug":40,"lessonSlug":40,"order":36,"status":13,"rawBody":4483},"browser-network-t3-retry","Retry","Вам предстоит повторять асинхронную операцию после неудачи и остановиться в нужный момент.\n\nПосле решения вы лучше поймете, как в интерфейсе отделять временный сетевой сбой от окончательной ошибки. Это пригодится в задачах про надежную загрузку данных и аккуратную обработку неуспешных запросов.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fretry-promise-on-rejection","# T3. Retry\n\n## Польза\n\nВам предстоит повторять асинхронную операцию после неудачи и остановиться в нужный момент.\n\nПосле решения вы лучше поймете, как в интерфейсе отделять временный сетевой сбой от окончательной ошибки. Это пригодится в задачах про надежную загрузку данных и аккуратную обработку неуспешных запросов.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень BFE.dev     |\n| ------------------- |\n| Hard                |\n| Medium \u003C-- вы здесь |\n| Easy                |\n\n## Ссылка на задачу\n\n[BFE.dev 64. auto-retry Promise on rejection](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fretry-promise-on-rejection)",{"slug":4485,"title":4486,"benefit":4487,"frequency":4359,"difficulty":4369,"platform":4370,"taskUrl":4488,"programSlug":17,"lessonSlug":17,"order":36,"status":13,"rawBody":4489},"collections-iteration-arrays-t3-array-reduce-transformation","Array Reduce Transformation","Вам предстоит превратить список значений в один итоговый результат.\n\nПосле решения вы лучше поймете, как накапливается промежуточное состояние при проходе по коллекции. Это поможет в задачах с суммированием, группировкой, построением словарей и расчетом итогов.","https:\u002F\u002Fleetcode.com\u002Fproblems\u002Farray-reduce-transformation\u002F","# T3. Array Reduce Transformation\n\n## Польза\n\nВам предстоит превратить список значений в один итоговый результат.\n\nПосле решения вы лучше поймете, как накапливается промежуточное состояние при проходе по коллекции. Это поможет в задачах с суммированием, группировкой, построением словарей и расчетом итогов.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень LeetCode  |\n| ----------------- |\n| Hard              |\n| Medium            |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[LeetCode 2626 Array Reduce Transformation](https:\u002F\u002Fleetcode.com\u002Fproblems\u002Farray-reduce-transformation\u002F)",{"slug":4491,"title":4492,"benefit":4493,"frequency":4359,"difficulty":4378,"platform":4361,"taskUrl":4494,"programSlug":30,"lessonSlug":30,"order":36,"status":13,"rawBody":4495},"event-loop-promises-async-await-t3-throttlepromises","throttlePromises","Вам предстоит запустить асинхронные операции с ограничением параллельности.\n\nПосле решения вы научитесь отличать запуск всех задач сразу от управляемой нагрузки. Это поможет в реальном фронтенде не отправлять десятки запросов одновременно и аккуратнее работать с API.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fthrottle-Promises","# T3. throttlePromises\n\n## Польза\n\nВам предстоит запустить асинхронные операции с ограничением параллельности.\n\nПосле решения вы научитесь отличать запуск всех задач сразу от управляемой нагрузки. Это поможет в реальном фронтенде не отправлять десятки запросов одновременно и аккуратнее работать с API.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень BFE.dev |\n| --- |\n| Hard |\n| Medium \u003C-- вы здесь |\n| Easy |\n\n## Ссылка на задачу\n\n[BFE.dev 92 Throttle Promises](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fthrottle-Promises)",{"slug":4497,"title":4498,"benefit":4499,"frequency":4359,"difficulty":4378,"platform":4361,"taskUrl":4500,"programSlug":31,"lessonSlug":31,"order":36,"status":13,"rawBody":4501},"event-loop-promises-deep-dive-t3-promise-prototype-finally","Promise.prototype.finally","Вам предстоит реализовать `Promise.prototype.finally` для действия, которое должно сработать после любого исхода промиса.\n\nПосле решения вы лучше поймете, почему финальная очистка не должна случайно менять успешный результат или исходную ошибку. Это поможет писать предсказуемую логику для loader, блокировок, временных ресурсов и повторного включения UI.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-Promise-prototype-finally","# T3. Promise.prototype.finally\n\n## Польза\n\nВам предстоит реализовать `Promise.prototype.finally` для действия, которое должно сработать после любого исхода промиса.\n\nПосле решения вы лучше поймете, почему финальная очистка не должна случайно менять успешный результат или исходную ошибку. Это поможет писать предсказуемую логику для loader, блокировок, временных ресурсов и повторного включения UI.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень BFE.dev |\n| --- |\n| Hard |\n| Medium \u003C-- вы здесь |\n| Easy |\n\n## Ссылка на задачу\n\n[BFE.dev 123. implement Promise.prototype.finally](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-Promise-prototype-finally)",{"slug":4503,"title":4504,"benefit":4505,"frequency":4475,"difficulty":4369,"platform":4361,"taskUrl":4506,"programSlug":18,"lessonSlug":18,"order":36,"status":13,"rawBody":4507},"objects-prototypes-classes-t3-two-way-binding","Two-way binding","Вам предстоит связать состояние и DOM-элемент так, чтобы изменение с одной стороны отражалось на другой.\n\nПосле решения вы научитесь видеть свойство объекта как точку связи между моделью данных и интерфейсом. Это поможет понимать, откуда растут frontend-подходы к реактивности и почему обновление DOM должно быть управляемым.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Ftwo-way-binding","# T3. Two-way binding\n\n## Польза\n\nВам предстоит связать состояние и DOM-элемент так, чтобы изменение с одной стороны отражалось на другой.\n\nПосле решения вы научитесь видеть свойство объекта как точку связи между моделью данных и интерфейсом. Это поможет понимать, откуда растут frontend-подходы к реактивности и почему обновление DOM должно быть управляемым.\n\n## Насколько часто встречается\n\n6\u002F10\n\n## Сложность\n\n| Уровень BFE.dev |\n| --- |\n| Hard |\n| Medium |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[BFE.dev 154. Two-way binding](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Ftwo-way-binding)",{"slug":4509,"title":4510,"benefit":4511,"frequency":4359,"difficulty":4369,"platform":4370,"taskUrl":4512,"programSlug":50,"lessonSlug":50,"order":36,"status":13,"rawBody":4513},"recursion-t3-invert-binary-tree","Invert Binary Tree","Вам предстоит изменить дерево так, чтобы одинаковое действие применялось к каждому узлу.\n\nПосле решения вы лучше поймете, как рекурсивный обход проходит по структуре и возвращает наружу уже обработанные части. Это помогает уверенно говорить о мутациях и возврате результата в задачах на деревья.","https:\u002F\u002Fleetcode.com\u002Fproblems\u002Finvert-binary-tree\u002F","# T3. Invert Binary Tree\n\n## Польза\n\nВам предстоит изменить дерево так, чтобы одинаковое действие применялось к каждому узлу.\n\nПосле решения вы лучше поймете, как рекурсивный обход проходит по структуре и возвращает наружу уже обработанные части. Это помогает уверенно говорить о мутациях и возврате результата в задачах на деревья.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень LeetCode  |\n| ----------------- |\n| Hard              |\n| Medium            |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[LeetCode 226. Invert Binary Tree](https:\u002F\u002Fleetcode.com\u002Fproblems\u002Finvert-binary-tree\u002F)",{"slug":4515,"title":4516,"benefit":4517,"frequency":4368,"difficulty":4378,"platform":4361,"taskUrl":4518,"programSlug":41,"lessonSlug":41,"order":36,"status":13,"rawBody":4519},"rendering-dom-events-forms-t3-virtual-dom-i","Virtual DOM I","Вам предстоит перевести дерево интерфейса между настоящими элементами и обычным объектным описанием.\n\nПосле решения вы лучше почувствуете, что Virtual DOM - это не отдельный браузерный механизм, а структура данных поверх настоящего DOM. Это поможет объяснять, где заканчивается описание UI и где начинается работа браузера по layout, paint и compositing.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002FVirtual-DOM-I","# T3. Virtual DOM I\n\n## Польза\n\nВам предстоит перевести дерево интерфейса между настоящими элементами и обычным объектным описанием.\n\nПосле решения вы лучше почувствуете, что Virtual DOM - это не отдельный браузерный механизм, а структура данных поверх настоящего DOM. Это поможет объяснять, где заканчивается описание UI и где начинается работа браузера по layout, paint и compositing.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень BFE.dev     |\n| ------------------- |\n| Hard                |\n| Medium \u003C-- вы здесь |\n| Easy                |\n\n## Ссылка на задачу\n\n[BFE.dev 113 Virtual DOM I](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002FVirtual-DOM-I)",{"slug":4521,"title":4522,"benefit":4523,"frequency":4397,"difficulty":4524,"platform":4525,"taskUrl":4526,"programSlug":20,"lessonSlug":20,"order":36,"status":13,"rawBody":4527},"scope-hoisting-closures-this-t3-can-you-keep-a-secret","Can you keep a secret?","Вам предстоит сделать объект, где значение недоступно напрямую, но с ним можно работать через публичный интерфейс.\n\nПосле решения вы научитесь отличать приватное состояние от обычного свойства объекта. Это поможет понимать, как инкапсуляция появляется в JavaScript даже без классов и специальных модификаторов доступа.","6 kyu","Codewars","https:\u002F\u002Fwww.codewars.com\u002Fkata\u002F5351b35ebaeb67f9110012d2","# T3. Can you keep a secret?\n\n## Польза\n\nВам предстоит сделать объект, где значение недоступно напрямую, но с ним можно работать через публичный интерфейс.\n\nПосле решения вы научитесь отличать приватное состояние от обычного свойства объекта. Это поможет понимать, как инкапсуляция появляется в JavaScript даже без классов и специальных модификаторов доступа.\n\n## Насколько часто встречается\n\n5\u002F10\n\n## Сложность\n\n| Уровень Codewars |\n| --- |\n| 1 kyu |\n| 2 kyu |\n| 3 kyu |\n| 4 kyu |\n| 5 kyu |\n| 6 kyu \u003C-- вы здесь |\n| 7 kyu |\n| 8 kyu |\n\n## Ссылка на задачу\n\n[Codewars Can you keep a secret?](https:\u002F\u002Fwww.codewars.com\u002Fkata\u002F5351b35ebaeb67f9110012d2)",{"slug":4529,"title":4530,"benefit":4531,"frequency":4368,"difficulty":4369,"platform":4361,"taskUrl":4532,"programSlug":21,"lessonSlug":21,"order":36,"status":13,"rawBody":4533},"types-coercion-symbol-json-t3-implement-object-is","implement Object.is()","Вам предстоит реализовать проверку одинаковости значений ближе к тому, как ее понимает сам язык в отдельных внутренних операциях.\n\nПосле решения вы сможете увереннее различать несколько похожих способов сравнения и объяснять, почему \"равно\" в JavaScript не всегда означает одно и то же. Это частая зона ловушек на собеседованиях по базовой механике языка.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-Object.is","# T3. implement Object.is()\n\n## Польза\n\nВам предстоит реализовать проверку одинаковости значений ближе к тому, как ее понимает сам язык в отдельных внутренних операциях.\n\nПосле решения вы сможете увереннее различать несколько похожих способов сравнения и объяснять, почему \"равно\" в JavaScript не всегда означает одно и то же. Это частая зона ловушек на собеседованиях по базовой механике языка.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень BFE.dev   |\n| ----------------- |\n| Hard              |\n| Medium            |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[BFE.dev 116. implement Object.is()](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-Object.is)",{"slug":4535,"title":4536,"benefit":4537,"frequency":4368,"difficulty":4378,"platform":4361,"taskUrl":4494,"programSlug":40,"lessonSlug":40,"order":46,"status":13,"rawBody":4538},"browser-network-t4-throttle-api-calls","Throttle API Calls","Вам предстоит ограничить количество одновременно выполняющихся асинхронных задач.\n\nПосле решения вы лучше поймете, почему браузерному коду часто нельзя бездумно запускать много сетевых операций сразу. Это поможет обсуждать очереди запросов, загрузку списков и контроль нагрузки на API.","# T4. Throttle API Calls\n\n## Польза\n\nВам предстоит ограничить количество одновременно выполняющихся асинхронных задач.\n\nПосле решения вы лучше поймете, почему браузерному коду часто нельзя бездумно запускать много сетевых операций сразу. Это поможет обсуждать очереди запросов, загрузку списков и контроль нагрузки на API.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень BFE.dev     |\n| ------------------- |\n| Hard                |\n| Medium \u003C-- вы здесь |\n| Easy                |\n\n## Ссылка на задачу\n\n[BFE.dev 92. throttle Promises](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fthrottle-Promises)",{"slug":4540,"title":4541,"benefit":4542,"frequency":4359,"difficulty":4378,"platform":4370,"taskUrl":4543,"programSlug":17,"lessonSlug":17,"order":46,"status":13,"rawBody":4544},"collections-iteration-arrays-t4-flatten-deeply-nested-array","Flatten Deeply Nested Array","Вам предстоит получить плоский список из вложенной структуры.\n\nПосле решения вы научитесь видеть разницу между одним уровнем вложенности и произвольной глубиной. Это поможет в задачах, где данные приходят слоями и их нужно привести к форме, удобной для дальнейшей обработки.","https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fflatten-deeply-nested-array\u002F","# T4. Flatten Deeply Nested Array\n\n## Польза\n\nВам предстоит получить плоский список из вложенной структуры.\n\nПосле решения вы научитесь видеть разницу между одним уровнем вложенности и произвольной глубиной. Это поможет в задачах, где данные приходят слоями и их нужно привести к форме, удобной для дальнейшей обработки.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень LeetCode    |\n| ------------------- |\n| Hard                |\n| Medium \u003C-- вы здесь |\n| Easy                |\n\n## Ссылка на задачу\n\n[LeetCode 2625 Flatten Deeply Nested Array](https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fflatten-deeply-nested-array\u002F)",{"slug":4546,"title":4547,"benefit":4548,"frequency":4368,"difficulty":4378,"platform":4361,"taskUrl":4482,"programSlug":30,"lessonSlug":30,"order":46,"status":13,"rawBody":4549},"event-loop-promises-async-await-t4-fetchwithautoretry","fetchWithAutoRetry","Вам предстоит реализовать автоматический повтор асинхронной операции после неудачи.\n\nПосле решения вы научитесь отличать временный сбой от окончательной ошибки и понимать, зачем интерфейсу иногда нужна контролируемая повторная попытка. Это поможет писать более устойчивую работу с API, где сеть или сервер могут временно дать сбой.","# T4. fetchWithAutoRetry\n\n## Польза\n\nВам предстоит реализовать автоматический повтор асинхронной операции после неудачи.\n\nПосле решения вы научитесь отличать временный сбой от окончательной ошибки и понимать, зачем интерфейсу иногда нужна контролируемая повторная попытка. Это поможет писать более устойчивую работу с API, где сеть или сервер могут временно дать сбой.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень BFE.dev |\n| --- |\n| Hard |\n| Medium \u003C-- вы здесь |\n| Easy |\n\n## Ссылка на задачу\n\n[BFE.dev 64 Auto-retry Promise on Rejection](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fretry-promise-on-rejection)",{"slug":4551,"title":4552,"benefit":4553,"frequency":4368,"difficulty":4378,"platform":4361,"taskUrl":4554,"programSlug":31,"lessonSlug":31,"order":46,"status":13,"rawBody":4555},"event-loop-promises-deep-dive-t4-create-a-fake-timer","create a fake timer","Вам предстоит реализовать управляемый таймер для кода, который обычно зависит от `setTimeout`.\n\nПосле решения вы лучше почувствуете, что таймеры не выполняют callback прямо сейчас, а планируют работу на будущее. Это поможет понимать event loop и увереннее тестировать код, где время влияет на поведение.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fcreate-a-fake-timer","# T4. create a fake timer\n\n## Польза\n\nВам предстоит реализовать управляемый таймер для кода, который обычно зависит от `setTimeout`.\n\nПосле решения вы лучше почувствуете, что таймеры не выполняют callback прямо сейчас, а планируют работу на будущее. Это поможет понимать event loop и увереннее тестировать код, где время влияет на поведение.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень BFE.dev |\n| --- |\n| Hard |\n| Medium \u003C-- вы здесь |\n| Easy |\n\n## Ссылка на задачу\n\n[BFE.dev 36. create a fake timer(setTimeout)](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fcreate-a-fake-timer)",{"slug":4557,"title":4558,"benefit":4559,"frequency":4475,"difficulty":4378,"platform":4370,"taskUrl":4560,"programSlug":18,"lessonSlug":18,"order":46,"status":13,"rawBody":4561},"objects-prototypes-classes-t4-check-if-object-instance-of-class","Check if Object Instance of Class","Вам предстоит проверить, связан ли объект с заданным классом через prototype chain.\n\nПосле решения вы научитесь понимать, как объект связан с родительскими прототипами и почему проверка типа в JavaScript не сводится к имени конструктора. Это поможет объяснять, как работает `instanceof`, и находить ошибки в задачах на наследование.","https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fcheck-if-object-instance-of-class\u002Fdescription\u002F","# T4. Check if Object Instance of Class\n\n## Польза\n\nВам предстоит проверить, связан ли объект с заданным классом через prototype chain.\n\nПосле решения вы научитесь понимать, как объект связан с родительскими прототипами и почему проверка типа в JavaScript не сводится к имени конструктора. Это поможет объяснять, как работает `instanceof`, и находить ошибки в задачах на наследование.\n\n## Насколько часто встречается\n\n6\u002F10\n\n## Сложность\n\n| Уровень LeetCode |\n| --- |\n| Hard |\n| Medium \u003C-- вы здесь |\n| Easy |\n\n## Ссылка на задачу\n\n[LeetCode 2618. Check if Object Instance of Class](https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fcheck-if-object-instance-of-class\u002Fdescription\u002F)",{"slug":4563,"title":4564,"benefit":4565,"frequency":4368,"difficulty":4378,"platform":4370,"taskUrl":4566,"programSlug":50,"lessonSlug":50,"order":46,"status":13,"rawBody":4567},"recursion-t4-generate-parentheses","Generate Parentheses","Вам предстоит построить все корректные варианты через последовательный выбор следующего шага.\n\nПосле решения вы увидите, как рекурсия помогает не просто идти в глубину структуры, а перебрать пространство вариантов. Это полезно для задач, где нужно строить комбинации и вовремя отсекать неподходящие ветки.","https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fgenerate-parentheses\u002F","# T4. Generate Parentheses\n\n## Польза\n\nВам предстоит построить все корректные варианты через последовательный выбор следующего шага.\n\nПосле решения вы увидите, как рекурсия помогает не просто идти в глубину структуры, а перебрать пространство вариантов. Это полезно для задач, где нужно строить комбинации и вовремя отсекать неподходящие ветки.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень LeetCode    |\n| ------------------- |\n| Hard                |\n| Medium \u003C-- вы здесь |\n| Easy                |\n\n## Ссылка на задачу\n\n[LeetCode 22. Generate Parentheses](https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fgenerate-parentheses\u002F)",{"slug":4569,"title":4570,"benefit":4571,"frequency":4368,"difficulty":4369,"platform":4361,"taskUrl":4572,"programSlug":41,"lessonSlug":41,"order":46,"status":13,"rawBody":4573},"rendering-dom-events-forms-t4-virtual-dom-ii-createelement","Virtual DOM II - createElement","Вам предстоит описать элемент как структуру данных и получить из этого описания настоящий элемент интерфейса.\n\nПосле решения вы лучше почувствуете границу между декларативным описанием UI и реальной работой с DOM. Это поможет объяснять, почему фреймворк сначала строит описание, а потом применяет изменения к браузеру.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fvirtual-dom-II-createElement","# T4. Virtual DOM II - createElement\n\n## Польза\n\nВам предстоит описать элемент как структуру данных и получить из этого описания настоящий элемент интерфейса.\n\nПосле решения вы лучше почувствуете границу между декларативным описанием UI и реальной работой с DOM. Это поможет объяснять, почему фреймворк сначала строит описание, а потом применяет изменения к браузеру.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень BFE.dev   |\n| ----------------- |\n| Hard              |\n| Medium            |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[BFE.dev 118 Virtual DOM II - createElement](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fvirtual-dom-II-createElement)",{"slug":4575,"title":4576,"benefit":4577,"frequency":4359,"difficulty":4378,"platform":4370,"taskUrl":4578,"programSlug":20,"lessonSlug":20,"order":46,"status":13,"rawBody":4579},"scope-hoisting-closures-this-t4-bind-function-to-context","Bind Function to Context","Вам предстоит реализовать привязку функции к заданному контексту.\n\nПосле решения вы научитесь замечать, почему одна и та же функция может вести себя по-разному в разных формах вызова. Это поможет на интервью спокойно разбирать callbacks, методы объектов и потерю контекста.","https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fbind-function-to-context\u002F","# T4. Bind Function to Context\n\n## Польза\n\nВам предстоит реализовать привязку функции к заданному контексту.\n\nПосле решения вы научитесь замечать, почему одна и та же функция может вести себя по-разному в разных формах вызова. Это поможет на интервью спокойно разбирать callbacks, методы объектов и потерю контекста.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень LeetCode |\n| --- |\n| Hard |\n| Medium \u003C-- вы здесь |\n| Easy |\n\n## Ссылка на задачу\n\n[LeetCode 2754 Bind Function to Context](https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fbind-function-to-context\u002F)",{"slug":4581,"title":4582,"benefit":4583,"frequency":4475,"difficulty":4378,"platform":4361,"taskUrl":4584,"programSlug":21,"lessonSlug":21,"order":46,"status":13,"rawBody":4585},"types-coercion-symbol-json-t4-tobe-or-not-tobe","toBe() or not.toBe()","Вам предстоит собрать маленький механизм ожиданий, который явно сообщает, совпало значение с ожидаемым или нет.\n\nПосле решения вы лучше поймете, как сравнение значений превращается в понятный контракт для проверки результата. Это помогает на интервью говорить не только \"что вернет код\", но и как мы фиксируем ожидаемое поведение.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fjest-assertion","# T4. toBe() or not.toBe()\n\n## Польза\n\nВам предстоит собрать маленький механизм ожиданий, который явно сообщает, совпало значение с ожидаемым или нет.\n\nПосле решения вы лучше поймете, как сравнение значений превращается в понятный контракт для проверки результата. Это помогает на интервью говорить не только \"что вернет код\", но и как мы фиксируем ожидаемое поведение.\n\n## Насколько часто встречается\n\n6\u002F10\n\n## Сложность\n\n| Уровень BFE.dev     |\n| ------------------- |\n| Hard                |\n| Medium \u003C-- вы здесь |\n| Easy                |\n\n## Ссылка на задачу\n\n[BFE.dev 161. toBe() or not.toBe()](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fjest-assertion)",{"slug":4587,"title":4588,"benefit":4589,"frequency":4368,"difficulty":4378,"platform":4361,"taskUrl":4590,"programSlug":40,"lessonSlug":40,"order":55,"status":13,"rawBody":4591},"browser-network-t5-merge-identical-api-calls","Merge Identical API Calls","Вам предстоит объединить одинаковые запросы, которые появились почти одновременно.\n\nПосле решения вы лучше поймете, как интерфейс может уменьшать лишнюю сетевую активность без изменения пользовательского сценария. Это полезно для интервью, где обсуждают кеширование на клиенте, гонки запросов и повторные обращения к одному API.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fmerge-identical-API-calls","# T5. Merge Identical API Calls\n\n## Польза\n\nВам предстоит объединить одинаковые запросы, которые появились почти одновременно.\n\nПосле решения вы лучше поймете, как интерфейс может уменьшать лишнюю сетевую активность без изменения пользовательского сценария. Это полезно для интервью, где обсуждают кеширование на клиенте, гонки запросов и повторные обращения к одному API.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень BFE.dev     |\n| ------------------- |\n| Hard                |\n| Medium \u003C-- вы здесь |\n| Easy                |\n\n## Ссылка на задачу\n\n[BFE.dev 101. merge identical API calls](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fmerge-identical-API-calls)",{"slug":4593,"title":4594,"benefit":4595,"frequency":4424,"difficulty":4369,"platform":4370,"taskUrl":4596,"programSlug":17,"lessonSlug":17,"order":55,"status":13,"rawBody":4597},"collections-iteration-arrays-t5-valid-anagram","Valid Anagram","Вам предстоит определить, состоят ли две строки из одного набора символов.\n\nПосле решения вы лучше поймете, как превращать строку в данные для сравнения. Это поможет в задачах, где нужно считать повторения, сравнивать текстовые данные и выбирать подходящую структуру для быстрых проверок.","https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fvalid-anagram\u002F","# T5. Valid Anagram\n\n## Польза\n\nВам предстоит определить, состоят ли две строки из одного набора символов.\n\nПосле решения вы лучше поймете, как превращать строку в данные для сравнения. Это поможет в задачах, где нужно считать повторения, сравнивать текстовые данные и выбирать подходящую структуру для быстрых проверок.\n\n## Насколько часто встречается\n\n9\u002F10\n\n## Сложность\n\n| Уровень LeetCode  |\n| ----------------- |\n| Hard              |\n| Medium            |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[LeetCode 242 Valid Anagram](https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fvalid-anagram\u002F)",{"slug":4599,"title":4600,"benefit":4601,"frequency":4368,"difficulty":4378,"platform":4361,"taskUrl":4602,"programSlug":30,"lessonSlug":30,"order":55,"status":13,"rawBody":4603},"event-loop-promises-async-await-t5-sequence","sequence","Вам предстоит выстроить асинхронные операции в строгую последовательность.\n\nПосле решения вы научитесь отличать независимые операции от зависимых шагов одного процесса. Это поможет в сценариях, где порядок выполнения важнее скорости параллельного запуска.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-async-helper-sequence","# T5. sequence\n\n## Польза\n\nВам предстоит выстроить асинхронные операции в строгую последовательность.\n\nПосле решения вы научитесь отличать независимые операции от зависимых шагов одного процесса. Это поможет в сценариях, где порядок выполнения важнее скорости параллельного запуска.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень BFE.dev |\n| --- |\n| Hard |\n| Medium \u003C-- вы здесь |\n| Easy |\n\n## Ссылка на задачу\n\n[BFE.dev 29 Implement Async Helper Sequence](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-async-helper-sequence)",{"slug":4605,"title":4606,"benefit":4607,"frequency":4359,"difficulty":4378,"platform":4370,"taskUrl":4608,"programSlug":31,"lessonSlug":31,"order":55,"status":13,"rawBody":4609},"event-loop-promises-deep-dive-t5-promise-time-limit","Promise Time Limit","Вам предстоит обернуть асинхронную функцию так, чтобы у нее появился лимит по времени выполнения.\n\nПосле решения вы научитесь думать о timeout как об отдельном асинхронном исходе, который конкурирует с основной операцией. Это поможет в реальных запросах, фоновых действиях и UI-сценариях, где нельзя ждать бесконечно.","https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fpromise-time-limit\u002F","# T5. Promise Time Limit\n\n## Польза\n\nВам предстоит обернуть асинхронную функцию так, чтобы у нее появился лимит по времени выполнения.\n\nПосле решения вы научитесь думать о timeout как об отдельном асинхронном исходе, который конкурирует с основной операцией. Это поможет в реальных запросах, фоновых действиях и UI-сценариях, где нельзя ждать бесконечно.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень LeetCode |\n| --- |\n| Hard |\n| Medium \u003C-- вы здесь |\n| Easy |\n\n## Ссылка на задачу\n\n[LeetCode 2637. Promise Time Limit](https:\u002F\u002Fleetcode.com\u002Fproblems\u002Fpromise-time-limit\u002F)",{"slug":4611,"title":4612,"benefit":4613,"frequency":4359,"difficulty":4369,"platform":4361,"taskUrl":4614,"programSlug":18,"lessonSlug":18,"order":55,"status":13,"rawBody":4615},"objects-prototypes-classes-t5-create-your-own-new-operator","create your own `new` operator","Вам предстоит реализовать поведение оператора `new` в отдельной функции.\n\nПосле решения вы научитесь объяснять, как создание экземпляра связывает объект, constructor и prototype chain. Это поможет понимать вопросы про `class`, функции-конструкторы и то, что реально происходит при создании нового объекта.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fcreate-your-own-new-operator","# T5. create your own `new` operator\n\n## Польза\n\nВам предстоит реализовать поведение оператора `new` в отдельной функции.\n\nПосле решения вы научитесь объяснять, как создание экземпляра связывает объект, constructor и prototype chain. Это поможет понимать вопросы про `class`, функции-конструкторы и то, что реально происходит при создании нового объекта.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень BFE.dev |\n| --- |\n| Hard |\n| Medium |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[BFE.dev 60. create your own `new` operator](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fcreate-your-own-new-operator)",{"slug":4617,"title":4618,"benefit":4619,"frequency":4368,"difficulty":4369,"platform":4361,"taskUrl":4620,"programSlug":50,"lessonSlug":50,"order":55,"status":13,"rawBody":4621},"recursion-t5-flatten-a-multidimensional-array","Flatten a Multidimensional Array","Вам предстоит превратить вложенную структуру в плоский список.\n\nПосле решения вы лучше поймете, как рекурсивный обход отличает обычное значение от вложенной части и переносит результат обратно наверх. Это близко к реальным frontend-задачам с меню, деревьями категорий и вложенными данными API.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-Array-prototype.flat","# T5. Flatten a Multidimensional Array\n\n## Польза\n\nВам предстоит превратить вложенную структуру в плоский список.\n\nПосле решения вы лучше поймете, как рекурсивный обход отличает обычное значение от вложенной части и переносит результат обратно наверх. Это близко к реальным frontend-задачам с меню, деревьями категорий и вложенными данными API.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень BFE.dev   |\n| ----------------- |\n| Hard              |\n| Medium            |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[BFE.dev 67. create your own Array.prototype.flat](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-Array-prototype.flat)",{"slug":4623,"title":4624,"benefit":4625,"frequency":4368,"difficulty":4378,"platform":4361,"taskUrl":4626,"programSlug":41,"lessonSlug":41,"order":55,"status":13,"rawBody":4627},"rendering-dom-events-forms-t5-twitters-website-layout","Twitter's website layout","Вам предстоит собрать адаптивный layout, который меняет расположение колонок при разной ширине viewport.\n\nПосле решения вы лучше почувствуете, что layout - это не абстрактное слово из rendering pipeline, а конкретный расчет размеров и позиций элементов. Это поможет увереннее объяснять, почему изменение размеров viewport или правил раскладки приводит к перерасчету layout.","https:\u002F\u002Fbigfrontend.dev\u002Fcss\u002Ftwitter-layout","# T5. Twitter's website layout\n\n## Польза\n\nВам предстоит собрать адаптивный layout, который меняет расположение колонок при разной ширине viewport.\n\nПосле решения вы лучше почувствуете, что layout - это не абстрактное слово из rendering pipeline, а конкретный расчет размеров и позиций элементов. Это поможет увереннее объяснять, почему изменение размеров viewport или правил раскладки приводит к перерасчету layout.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень BFE.dev     |\n| ------------------- |\n| Hard                |\n| Medium \u003C-- вы здесь |\n| Easy                |\n\n## Ссылка на задачу\n\n[BFE.dev CSS 8 Twitter's website layout](https:\u002F\u002Fbigfrontend.dev\u002Fcss\u002Ftwitter-layout)",{"slug":4629,"title":4630,"benefit":4631,"frequency":4359,"difficulty":4369,"platform":4361,"taskUrl":4632,"programSlug":20,"lessonSlug":20,"order":55,"status":13,"rawBody":4633},"scope-hoisting-closures-this-t5-implement-curry","implement curry()","Вам предстоит реализовать `curry`, чтобы функция могла получать данные не одним вызовом, а несколькими последовательными вызовами.\n\nПосле решения вы научитесь смотреть на функцию как на цепочку маленьких вызовов, которые постепенно собирают общий результат. Это поможет разбирать функциональные хелперы и интервью-задачи, где привычный вызов функции разбивается на несколько шагов.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-curry","# T5. implement curry()\n\n## Польза\n\nВам предстоит реализовать `curry`, чтобы функция могла получать данные не одним вызовом, а несколькими последовательными вызовами.\n\nПосле решения вы научитесь смотреть на функцию как на цепочку маленьких вызовов, которые постепенно собирают общий результат. Это поможет разбирать функциональные хелперы и интервью-задачи, где привычный вызов функции разбивается на несколько шагов.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень BFE.dev |\n| --- |\n| Hard |\n| Medium |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[BFE.dev 1. implement curry()](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-curry)",{"slug":4635,"title":4636,"benefit":4637,"frequency":4397,"difficulty":4369,"platform":4361,"taskUrl":4638,"programSlug":21,"lessonSlug":21,"order":55,"status":13,"rawBody":4639},"types-coercion-symbol-json-t5-undefined-to-null","undefined to null","Вам предстоит привести вложенные данные к форме, где отсутствие значения выражено единообразно.\n\nПосле решения вы лучше почувствуете практическую разницу между `undefined` и `null` в данных, которые уходят между фронтендом и внешней системой. Это полезно для собеседований, где базовые типы обсуждают не в вакууме, а через реальные форматы обмена данными.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fundefined-to-null","# T5. undefined to null\n\n## Польза\n\nВам предстоит привести вложенные данные к форме, где отсутствие значения выражено единообразно.\n\nПосле решения вы лучше почувствуете практическую разницу между `undefined` и `null` в данных, которые уходят между фронтендом и внешней системой. Это полезно для собеседований, где базовые типы обсуждают не в вакууме, а через реальные форматы обмена данными.\n\n## Насколько часто встречается\n\n5\u002F10\n\n## Сложность\n\n| Уровень BFE.dev   |\n| ----------------- |\n| Hard              |\n| Medium            |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[BFE.dev 176. undefined to null](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fundefined-to-null)",{"slug":4641,"title":4642,"benefit":4643,"frequency":4359,"difficulty":4644,"platform":4525,"taskUrl":4645,"programSlug":40,"lessonSlug":40,"order":650,"status":13,"rawBody":4646},"browser-network-t6-objectify-query-string","Objectify Query String","Вам предстоит разобрать query string и превратить параметры адреса в объект.\n\nПосле решения вы лучше поймете, как строковое состояние URL становится данными для приложения. Это поможет на интервью уверенно обсуждать фильтры, пагинацию, deep links и повторяющиеся параметры в адресе.","4 kyu","https:\u002F\u002Fwww.codewars.com\u002Fkata\u002F5286d92ec6b5a9045c000087\u002Fjavascript","# T6. Objectify Query String\n\n## Польза\n\nВам предстоит разобрать query string и превратить параметры адреса в объект.\n\nПосле решения вы лучше поймете, как строковое состояние URL становится данными для приложения. Это поможет на интервью уверенно обсуждать фильтры, пагинацию, deep links и повторяющиеся параметры в адресе.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень Codewars   |\n| ------------------ |\n| 1 kyu              |\n| 2 kyu              |\n| 3 kyu              |\n| 4 kyu \u003C-- вы здесь |\n| 5 kyu              |\n| 6 kyu              |\n| 7 kyu              |\n| 8 kyu              |\n\n## Ссылка на задачу\n\n[Codewars: Objectify a URL Query String](https:\u002F\u002Fwww.codewars.com\u002Fkata\u002F5286d92ec6b5a9045c000087\u002Fjavascript)",{"slug":4648,"title":4649,"benefit":4650,"frequency":4475,"difficulty":4369,"platform":4361,"taskUrl":4651,"programSlug":30,"lessonSlug":30,"order":650,"status":13,"rawBody":4652},"event-loop-promises-async-await-t6-promise-race","Promise.race","Вам предстоит реализовать `Promise.race`, где исход зависит от первой завершившейся асинхронной операции.\n\nПосле решения вы научитесь думать об асинхронности как о соревновании событий, а не только как о цепочке ожиданий. Это поможет понимать timeout-сценарии и UI-логику, где важен первый полученный результат.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-Promise-race","# T6. Promise.race\n\n## Польза\n\nВам предстоит реализовать `Promise.race`, где исход зависит от первой завершившейся асинхронной операции.\n\nПосле решения вы научитесь думать об асинхронности как о соревновании событий, а не только как о цепочке ожиданий. Это поможет понимать timeout-сценарии и UI-логику, где важен первый полученный результат.\n\n## Насколько часто встречается\n\n6\u002F10\n\n## Сложность\n\n| Уровень BFE.dev   |\n| ----------------- |\n| Hard              |\n| Medium            |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[BFE.dev 35 Implement Promise.race](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-Promise-race)",{"slug":4654,"title":4655,"benefit":4656,"frequency":4359,"difficulty":4378,"platform":4361,"taskUrl":4657,"programSlug":41,"lessonSlug":41,"order":650,"status":13,"rawBody":4658},"rendering-dom-events-forms-t6-create-an-event-emitter","Create an Event Emitter","Вам предстоит реализовать простую модель подписок и уведомлений.\n\nПосле решения вы лучше почувствуете, что обработка событий - это не только браузерный DOM, а общий способ связывать источник события и несколько независимых реакций. Это поможет увереннее объяснять подписку, отписку и порядок вызова обработчиков.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fcreate-an-Event-Emitter","# T6. Create an Event Emitter\n\n## Польза\n\nВам предстоит реализовать простую модель подписок и уведомлений.\n\nПосле решения вы лучше почувствуете, что обработка событий - это не только браузерный DOM, а общий способ связывать источник события и несколько независимых реакций. Это поможет увереннее объяснять подписку, отписку и порядок вызова обработчиков.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень BFE.dev     |\n| ------------------- |\n| Hard                |\n| Medium \u003C-- вы здесь |\n| Easy                |\n\n## Ссылка на задачу\n\n[BFE.dev 16 create an Event Emitter](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fcreate-an-Event-Emitter)",{"slug":4660,"title":4661,"benefit":4662,"frequency":4475,"difficulty":4663,"platform":4361,"taskUrl":4664,"programSlug":21,"lessonSlug":21,"order":650,"status":13,"rawBody":4665},"types-coercion-symbol-json-t6-implement-json-stringify","implement JSON.stringify()","Вам предстоит превратить значение в строковое представление для передачи или хранения данных.\n\nПосле решения вы лучше поймете, почему сериализация в JavaScript не является простым \"объект в строку\". Это помогает на интервью аккуратно рассуждать о типах, вложенных данных и ограничениях формата, не сваливая все в одну общую фразу про JSON.","Hard?","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-JSON-stringify","# T6. implement JSON.stringify()\n\n## Польза\n\nВам предстоит превратить значение в строковое представление для передачи или хранения данных.\n\nПосле решения вы лучше поймете, почему сериализация в JavaScript не является простым \"объект в строку\". Это помогает на интервью аккуратно рассуждать о типах, вложенных данных и ограничениях формата, не сваливая все в одну общую фразу про JSON.\n\n## Насколько часто встречается\n\n6\u002F10\n\n## Сложность\n\n| Уровень BFE.dev    |\n| ------------------ |\n| Hard? \u003C-- вы здесь |\n| Medium             |\n| Easy               |\n\n## Ссылка на задачу\n\n[BFE.dev 21. implement JSON.stringify()](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-JSON-stringify)",{"slug":4667,"title":4668,"benefit":4669,"frequency":4368,"difficulty":4378,"platform":4361,"taskUrl":4670,"programSlug":30,"lessonSlug":30,"order":725,"status":13,"rawBody":4671},"event-loop-promises-async-await-t7-create-an-observable","Create an Observable","Вам предстоит реализовать Observable, который доставляет значения подписчикам и позволяет остановить подписку.\n\nПосле решения вы лучше поймете модель асинхронного потока данных: значения могут приходить не один раз, подписчиков может быть несколько, а завершение и ошибка меняют дальнейшее поведение. Это поможет разбирать реактивность, подписки и UI-сценарии, где данные приходят частями.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fcreate-an-Observable","# T7. Create an Observable\n\n## Польза\n\nВам предстоит реализовать Observable, который доставляет значения подписчикам и позволяет остановить подписку.\n\nПосле решения вы лучше поймете модель асинхронного потока данных: значения могут приходить не один раз, подписчиков может быть несколько, а завершение и ошибка меняют дальнейшее поведение. Это поможет разбирать реактивность, подписки и UI-сценарии, где данные приходят частями.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень BFE.dev     |\n| ------------------- |\n| Hard                |\n| Medium \u003C-- вы здесь |\n| Easy                |\n\n## Ссылка на задачу\n\n[BFE.dev 57 create an Observable](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fcreate-an-Observable)",{"slug":4673,"title":4674,"benefit":4675,"frequency":4359,"difficulty":4378,"platform":4361,"taskUrl":4676,"programSlug":41,"lessonSlug":41,"order":725,"status":13,"rawBody":4677},"rendering-dom-events-forms-t7-event-delegation","Event Delegation","Вам предстоит сделать обработку кликов через общий корневой элемент.\n\nПосле решения вы лучше поймете, как одно событие проходит через DOM-дерево и как использовать это для динамических интерфейсов. Это поможет в задачах со списками, таблицами, меню и элементами, которые появляются после первой отрисовки.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fevent-delegation","# T7. Event Delegation\n\n## Польза\n\nВам предстоит сделать обработку кликов через общий корневой элемент.\n\nПосле решения вы лучше поймете, как одно событие проходит через DOM-дерево и как использовать это для динамических интерфейсов. Это поможет в задачах со списками, таблицами, меню и элементами, которые появляются после первой отрисовки.\n\n## Насколько часто встречается\n\n8\u002F10\n\n## Сложность\n\n| Уровень BFE.dev     |\n| ------------------- |\n| Hard                |\n| Medium \u003C-- вы здесь |\n| Easy                |\n\n## Ссылка на задачу\n\n[BFE.dev 117 event delegation](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fevent-delegation)",{"slug":4679,"title":4680,"benefit":4681,"frequency":4475,"difficulty":4378,"platform":4361,"taskUrl":4682,"programSlug":21,"lessonSlug":21,"order":725,"status":13,"rawBody":4683},"types-coercion-symbol-json-t7-validate-number-string","validate number string","Вам предстоит определить, можно ли считать строку корректной записью числа.\n\nПосле решения вы лучше увидите границу между строкой, числом и правилами валидации пользовательского ввода. Это помогает на собеседовании не путать \"JavaScript как-то приведет\" с явным решением, какое поведение мы считаем допустимым.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fvalidate-number-string-1","# T7. validate number string\n\n## Польза\n\nВам предстоит определить, можно ли считать строку корректной записью числа.\n\nПосле решения вы лучше увидите границу между строкой, числом и правилами валидации пользовательского ввода. Это помогает на собеседовании не путать \"JavaScript как-то приведет\" с явным решением, какое поведение мы считаем допустимым.\n\n## Насколько часто встречается\n\n6\u002F10\n\n## Сложность\n\n| Уровень BFE.dev     |\n| ------------------- |\n| Hard                |\n| Medium \u003C-- вы здесь |\n| Easy                |\n\n## Ссылка на задачу\n\n[BFE.dev 166. validate number string](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fvalidate-number-string-1)",{"slug":4685,"title":4686,"benefit":4687,"frequency":4368,"difficulty":4369,"platform":4361,"taskUrl":4506,"programSlug":41,"lessonSlug":41,"order":796,"status":13,"rawBody":4688},"rendering-dom-events-forms-t8-two-way-binding","Two-way Binding","Вам предстоит связать состояние и поле формы так, чтобы изменение с одной стороны отражалось на другой.\n\nПосле решения вы лучше поймете, почему формы во frontend-разработке почти всегда требуют явной синхронизации между DOM-значением и данными приложения. Это поможет объяснять controlled inputs, обработку изменений и границу между состоянием интерфейса и состоянием приложения.","# T8. Two-way Binding\n\n## Польза\n\nВам предстоит связать состояние и поле формы так, чтобы изменение с одной стороны отражалось на другой.\n\nПосле решения вы лучше поймете, почему формы во frontend-разработке почти всегда требуют явной синхронизации между DOM-значением и данными приложения. Это поможет объяснять controlled inputs, обработку изменений и границу между состоянием интерфейса и состоянием приложения.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень BFE.dev   |\n| ----------------- |\n| Hard              |\n| Medium            |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[BFE.dev 154 Two-way binding](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Ftwo-way-binding)",{"slug":4690,"title":4691,"benefit":4692,"frequency":4368,"difficulty":4369,"platform":4361,"taskUrl":4693,"programSlug":21,"lessonSlug":21,"order":796,"status":13,"rawBody":4694},"types-coercion-symbol-json-t8-semver-compare","semver compare","Вам предстоит сравнить версии так, чтобы текстовое представление не сбивало порядок числовых частей.\n\nПосле решения вы лучше почувствуете, где строковое сравнение расходится с численным смыслом данных. Это полезно для интервью, потому что задача выглядит бытовой, но быстро вскрывает понимание парсинга и сравнений.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fsemver-compare","# T8. semver compare\n\n## Польза\n\nВам предстоит сравнить версии так, чтобы текстовое представление не сбивало порядок числовых частей.\n\nПосле решения вы лучше почувствуете, где строковое сравнение расходится с численным смыслом данных. Это полезно для интервью, потому что задача выглядит бытовой, но быстро вскрывает понимание парсинга и сравнений.\n\n## Насколько часто встречается\n\n7\u002F10\n\n## Сложность\n\n| Уровень BFE.dev   |\n| ----------------- |\n| Hard              |\n| Medium            |\n| Easy \u003C-- вы здесь |\n\n## Ссылка на задачу\n\n[BFE.dev 157. semver compare](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fsemver-compare)",{"slug":4696,"title":4697,"benefit":4698,"frequency":4397,"difficulty":4378,"platform":4361,"taskUrl":4699,"programSlug":21,"lessonSlug":21,"order":860,"status":13,"rawBody":4700},"types-coercion-symbol-json-t9-implement-bigint-multiplication","implement BigInt multiplication","Вам предстоит выполнить умножение чисел, которые слишком велики для обычного безопасного целого.\n\nПосле решения вы лучше поймете практическую границу между привычными числами JavaScript и задачами, где точность важнее удобства. Это помогает на интервью уверенно объяснять, почему большие числовые значения требуют отдельного внимания.","https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-BigInt-multiplication","# T9. implement BigInt multiplication\n\n## Польза\n\nВам предстоит выполнить умножение чисел, которые слишком велики для обычного безопасного целого.\n\nПосле решения вы лучше поймете практическую границу между привычными числами JavaScript и задачами, где точность важнее удобства. Это помогает на интервью уверенно объяснять, почему большие числовые значения требуют отдельного внимания.\n\n## Насколько часто встречается\n\n5\u002F10\n\n## Сложность\n\n| Уровень BFE.dev     |\n| ------------------- |\n| Hard                |\n| Medium \u003C-- вы здесь |\n| Easy                |\n\n## Ссылка на задачу\n\n[BFE.dev 114. implement BigInt multiplication](https:\u002F\u002Fbigfrontend.dev\u002Fproblem\u002Fimplement-BigInt-multiplication)",[4702],{"slug":4703,"title":4704,"description":4705,"status":13,"questions":4706,"language":65,"runtime":66,"order":12,"seoTitle":4764,"seoDescription":4765,"programSlug":30,"lessonSlug":30},"javascript-core","Порядок выполнения JavaScript","Проверьте порядок синхронного кода, Promise и таймеров.",[4707,4720,4731,4742,4753],{"prompt":4708,"answer":4709,"id":4710,"correctAnswerId":4711,"incorrectExplanation":4712,"options":4713},"В каком порядке выполнятся синхронный console.log, Promise.then и setTimeout?","sync, promise, timeout","event-loop-order","sync-micro-macro","Сначала выполняется синхронный код, затем микрозадача Promise и только после неё задача таймера.",[4714,4716],{"id":4711,"label":4715,"text":4709},"A",{"id":4717,"label":4718,"text":4719},"timer-first","B","timeout, promise, sync",{"prompt":4721,"answer":4722,"id":4723,"correctAnswerId":4724,"incorrectExplanation":4725,"options":4726},"Что произойдёт, если Promise.then добавит ещё один Promise.then?","Новая реакция выполнится до следующего таймера","nested-microtask","same-checkpoint","Очередь микрозадач опустошается полностью перед переходом к следующей задаче.",[4727,4728],{"id":4724,"label":4715,"text":4722},{"id":4729,"label":4718,"text":4730},"after-timer","Новая реакция выполнится только после таймера",{"prompt":4732,"answer":4733,"id":4734,"correctAnswerId":4735,"incorrectExplanation":4736,"options":4737},"Куда попадает продолжение async-функции после await уже выполненного Promise?","В очередь микрозадач","await-continuation","microtask","Продолжение async-функции после await планируется как микрозадача.",[4738,4739],{"id":4735,"label":4715,"text":4733},{"id":4740,"label":4718,"text":4741},"timer-task","В очередь таймеров",{"prompt":4743,"answer":4744,"id":4745,"correctAnswerId":4746,"incorrectExplanation":4747,"options":4748},"Гарантирует ли setTimeout(callback, 0), что callback выполнится немедленно?","Нет, callback ждёт следующей задачи","timeout-zero","no","Нулевая задержка не прерывает текущий код: callback ждёт следующей доступной задачи.",[4749,4752],{"id":4750,"label":4715,"text":4751},"yes","Да, callback вызывается в текущем стеке",{"id":4746,"label":4718,"text":4744},{"prompt":4754,"answer":4755,"id":4756,"correctAnswerId":4757,"incorrectExplanation":4758,"options":4759},"Когда браузер проверяет очередь микрозадач после выполнения JavaScript-задачи?","После опустошения стека и до следующей задачи","microtask-checkpoint","after-stack","После опустошения стека браузер выполняет checkpoint микрозадач до перехода к следующей задаче.",[4760,4761],{"id":4757,"label":4715,"text":4755},{"id":4762,"label":4718,"text":4763},"before-stack","Перед выполнением синхронного кода","Проверка знаний JavaScript event loop","Пять вопросов про синхронный код, микрозадачи Promise и таймеры в JavaScript.",[4767],{"slug":4447,"title":4768,"brief":4769,"starterCode":4770,"solutionNotes":4771,"difficulty":4772,"status":13,"language":65,"runtime":66,"order":12,"seoTitle":4773,"seoDescription":4774,"tests":4775,"programSlug":20,"lessonSlug":20,"starterFile":4780,"runnerFile":4781,"toolchain":4782,"entrypoint":4780,"testCommand":4783,"timeoutMs":4784,"memoryLimitMb":4785},"Debounce","Реализуйте debounce: повторный вызов должен сбрасывать таймер, а исходная функция — получать актуальные this и аргументы.","export function debounce(fn, wait) {\n  let timeoutId;\n\n  return function debounced(...args) {\n    \u002F\u002F Сбросьте таймер и вызовите fn с исходными this и args.\n  };\n}\n","Храните идентификатор таймера в замыкании, сбрасывайте его перед каждым новым вызовом и вызывайте исходную функцию через apply.","medium","Задача Debounce на JavaScript","Реализация debounce с таймером, замыканием, this и открытыми автотестами.",[4776],{"fileName":4777,"code":4778,"visibility":4779},"tests\u002Fvisible.test.js","import { debounce } from \"..\u002Ffiles\u002Fstarter.js\";\n\nexport async function runVisibleTests(assert) {\n  const calls = [];\n  const context = { label: \"input\" };\n  const debounced = debounce(function save(value) {\n    calls.push({ thisValue: this, value });\n  }, 10);\n\n  debounced.call(context, \"first\");\n  debounced.call(context, \"second\");\n\n  await new Promise((resolve) => setTimeout(resolve, 20));\n\n  assert.equal(calls.length, 1, \"повторные вызовы сбрасывают таймер\");\n  assert.equal(calls[0].value, \"second\", \"используются последние аргументы\");\n  assert.equal(\n    calls[0].thisValue,\n    context,\n    \"сохраняется исходный this\",\n  );\n}\n","public","files\u002Fstarter.js","runner.json","javascript-wasm-v1","runVisibleTests",1000,64,1784291969984]