{
  "assessmentTests": {
    "javascript_test": {
      "name": "JavaScript сынағы",
      "desc": "Негізгі синтаксис пен айырбастау, функциялар/облыс/жабулар (closures) және this, объектілер/массивтер мен деректер құрылымдары, сондай-ақ оқиға циклі/async/прототип идиомалары бойынша 30 сценарийлік сұрақ — JavaScript-іңіз жұмыс хабарландыруы білдіретін JavaScript біліктілігіне сай келе ме, соны біліңіз.",
      "recommendation": "Сіздің JavaScript дағдыларыңыздың профилі",
      "results": {
        "beginner": {
          "name": "Бастауыш",
          "desc": "Сіз жұмыс істейтін функциялар мен объектілер жаза аласыз, бірақ жіберіп алған сұрақтарыңыз синтаксиске емес, типтерді айырбастауға (type coercion) және сілтеме семантикасына топтасады — == салыстырудан бұрын типтерді үнсіз айырбастайды, бір массивті меншіктеу оны көшірмей, бір ғана объектіні ортақ пайдаланады, неге NaN өзіне-өзі ешқашан тең емес. Бұның бәрі JavaScript-ті нашар білу туралы емес; бұл — мәндер мен сілтемелердің нақты қалай әрекет ететінін үйренудің орнына, жай ғана жұмыс істеп тұрған кодты жазу арқылы тілді үйренген адамдарды шатастыратын нақты ережелер. Олар жұмыста маңызды, өйткені әрқайсысы код қатесіз орындалып тұрып, бәрібір қате нәтиже беретін жер.",
          "recommendation": "Үш нәрседен бастаңыз, дәл осы ретпен: == неге салыстырудан бұрын типтерді айырбастайды, ал === неге айырбастамайды; бір массивті немесе объектіні жаңа айнымалыға меншіктеу неге мәнін емес, сілтемесін көшіреді; және var неге көтеріліп (hoisted), undefined мәнімен инициализацияланады, ал let мен const декларациясы орындалғанша \"уақытша өлі аймақта\" (temporal dead zone) қалады. MDN-нің JavaScript нұсқаулығы осы үшеуін де орындалатын мысалдармен қамтиды."
        },
        "intermediate": {
          "name": "Орта деңгей",
          "desc": "Сіз күнделікті қолданба кодын еркін меңгергенсіз — функциялар, массив әдістері, қарапайым басқару ағыны — және әдеттегі функция жасау жұмысы сізді тежемейді. Мұнда мен Жетілген деңгей арасындағы алшақтық негізінен JavaScript-тің облыс (scope) пен уақыт ережелері бір-бірімен қиылысқанда пайда болады: циклдің callback-терінің бәрі бір ғана соңғы санауыш мәнін оқитын var, әдіс объектіден бөлінген сәтте оған сілтеуін үнсіз тоқтататын this, тереңдей көрінетін, бірақ тек бір деңгейді ғана көшіретін spread көшірмесі. Бұлар жылдам оқығанда байқалмай қалатын, тек белгілі бір орындалу жағдайында ғана көрінетін қателер.",
          "recommendation": "Облыс пен this-тің декларация уақытында емес, шақыру уақытында қалай анықталатынына назар аударыңыз: var негізіндегі for циклі неге әрбір callback-ке бірдей соңғы санауыш мәнін береді, ал let бермейді; this функцияны қалай шақырғаныңызға байланысты анықталады, қайда жазылғанына емес; және spread немесе Object.assign объектінің тек жоғарғы деңгейін ғана көшіреді. Содан кейін оқиға циклін (event loop) үйреніңіз, өйткені promise-терді жеке-жеке білетін адамдарды дәл сол шатастырады."
        },
        "advanced": {
          "name": "Жетілген",
          "desc": "Көптеген жұмыс хабарландырулары \"мықты JavaScript\" дегенде дәл осы деңгейді меңзейді. Сіз filter/map/reduce тізбегін оқып, бастапқы массивті өзгертпей, ол нақты нені қайтаратынын болжай аласыз; синхронды console.log әрқашан микротапсырманы (microtask) жеңетінін, ол өз кезегінде setTimeout-ты жеңетінін білесіз; және Promise.all-ды, ол қалғандарын күтпей, кез келген бір promise бас тартқан сәтте-ақ бас тартатынын біле тұра пайдаланасыз. Бұл деңгейді ең жоғарғысынан бөлетін — прототип пен объект моделі жағы: прототип тізбегі мұраланған әдісті hasOwnProperty-ден қалай ажыратады және жеке класс өрісі (private field) нақты нені жасырады.",
          "recommendation": "Басқа код та қатысатын күйді қорғайтын бөліктерге тереңдеңіз: JavaScript-тің прототип тізбегі инстанцияда жоқ әдіс іздеулерін қалай шешеді, класстың жеке #өрістері сырттан қандай қолжетімділікті жасырады, және JSON.stringify undefined мен функцияларды қарапайым объект ішінде мен массив ішінде неге әртүрлі өңдейді. MDN-нің оқиға циклі мен прототип тізбегі туралы материалдары екеуі үшін де келесі логикалық қадам."
        },
        "expert": {
          "name": "Сарапшы",
          "desc": "Сіз әрбір бөлімде ең жоғары ұпай жинадыңыз — негізгі синтаксис, типтер мен айырбастау; функциялар, облыс, жабулар (closures) және this; объектілер, массивтер және деректер құрылымдары; async, оқиға циклі, прототиптер мен идиомалар. Тәжірибе жүзінде бұл сізге бөтен адамның функциясын беріп, ол не үшін дәл осы нәтижені қайтаратынын түсіндіре алатыныңызды білдіреді — синтаксис не істеу керек дейтінін емес, ал бұл әлдеқайда қиын әрі құндырақ дағды. Осы деңгейде тілдің өзі сирек шектеуші факторға айналады; шектеу әдетте асинхронды басқару ағыны немесе астындағы деректер құрылымы болады.",
          "recommendation": "Енді нәтиже жобалау мен диагностикада: Promise.all мен Promise.race арасындағы жарыс жағдайы туралы анықтамаларын жаттап айтудың орнына, ол туралы ойлана білу; жеке күй үшін жабу (closure) дұрыс құрал болатын кезді, класстың жеке өрісі дұрыс болатын кезден ажырата білу; және микротапсырма мен макротапсырма ретін тестте емес, өндірістік логтарда оқи білу. Егер сізді рөлге іріктеп жатса, JavaScript мүмкіндіктерін атаудың орнына, өзіңіз тапқан уақыттау қатесін — ескірген жабу айнымалысын немесе ретсіз асинхронды callback-ті — сипаттаңыз; бұл сөздік қорды емес, ойлау қабілетін көрсетеді."
        }
      },
      "questions": [
        {
          "question": "console.log(x);\nvar x = 5;\nБұл не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "5 — var декларациялары кез келген басқа коддан бұрын, бірден орындалады"
            },
            {
              "icon": "",
              "label": "ReferenceError: x анықталмаған"
            },
            {
              "icon": "",
              "label": "undefined — var декларациялары өз облысының басына көтеріледі (hoisted) және undefined мәнімен инициализацияланады, бірақ меншіктеу өз орнында орындалады, сондықтан ол орындалғанға дейін айнымалы бар болады, бірақ ол undefined мәнін ұстайды"
            },
            {
              "icon": "",
              "label": "null"
            }
          ]
        },
        {
          "question": "console.log(y);\nlet y = 5;\nНе болады?",
          "options": [
            {
              "icon": "",
              "label": "ReferenceError лақтырады: 'y' инициализацияланғанға дейін қолжетімсіз — let өз облысының басына көтеріледі, бірақ декларация жолы нақты орындалғанға дейін \"уақытша өлі аймақта\" (temporal dead zone) қалады"
            },
            {
              "icon": "",
              "label": "undefined басып шығарады, var сияқты"
            },
            {
              "icon": "",
              "label": "5 басып шығарады"
            },
            {
              "icon": "",
              "label": "Талдау кезінде SyntaxError лақтырады"
            }
          ]
        },
        {
          "question": "const arr = [1, 2, 3];\narr.push(4);\nconsole.log(arr.length);\nБұл не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "4 — const тек arr байланысының өзін қайта меншіктеуге ғана тыйым салады, ол көрсетіп тұрған массив объектісін өзгертуге емес, сондықтан push жұмыс істей береді"
            },
            {
              "icon": "",
              "label": "TypeError лақтырады, себебі arr — const"
            },
            {
              "icon": "",
              "label": "3 — push const массивте бұғатталған"
            },
            {
              "icon": "",
              "label": "undefined"
            }
          ]
        },
        {
          "question": "console.log('' == 0);\nconsole.log('' === 0);\nЕкі жол не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "true, содан кейін true"
            },
            {
              "icon": "",
              "label": "false, содан кейін false"
            },
            {
              "icon": "",
              "label": "true, содан кейін false — == салыстырудан бұрын бос жолды 0-ге айырбастайды, ал === типі мен мәнін ешбір айырбастаусыз салыстырады, ал жол санға ешқашан қатаң түрде тең емес"
            },
            {
              "icon": "",
              "label": "false, содан кейін true"
            }
          ]
        },
        {
          "question": "console.log(NaN === NaN);\nconsole.log(Number.isNaN(NaN));\nЕкі жол не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "true, содан кейін true"
            },
            {
              "icon": "",
              "label": "true, содан кейін false"
            },
            {
              "icon": "",
              "label": "false, содан кейін false"
            },
            {
              "icon": "",
              "label": "false, содан кейін true — NaN — JavaScript-те === бойынша өзіне-өзі тең емес жалғыз мән, бірақ Number.isNaN() оны бәрібір дұрыс анықтайды"
            }
          ]
        },
        {
          "question": "console.log(typeof null);\nБұл не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "\"null\""
            },
            {
              "icon": "",
              "label": "\"object\" — тілдегі көне қате: typeof null \"object\" қайтарады, null қарапайым (primitive) мән болса да, кері үйлесімділік үшін солай сақталып қалған"
            },
            {
              "icon": "",
              "label": "\"undefined\""
            },
            {
              "icon": "",
              "label": "\"boolean\""
            }
          ]
        },
        {
          "question": "Мыналардың қайсысы if шартында қолданылғанда ақиқат (truthy) болады?",
          "options": [
            {
              "icon": "",
              "label": "0"
            },
            {
              "icon": "",
              "label": "\"\" (бос жол)"
            },
            {
              "icon": "",
              "label": "null"
            },
            {
              "icon": "",
              "label": "\"0\" — бос емес жол JavaScript-те әрқашан ақиқат болады, тіпті оның мазмұны \"0\" жолы болса да"
            }
          ]
        },
        {
          "question": "foo();\nfunction foo() { console.log('a'); }\nbar();\nvar bar = function() { console.log('b'); };\nНе болады?",
          "options": [
            {
              "icon": "",
              "label": "Екі шақыру да басып шығарады, \"a\" содан кейін \"b\""
            },
            {
              "icon": "",
              "label": "foo() \"a\" басып шығарады; bar() TypeError лақтырады: bar функция емес — функция декларациялары денесімен толық көтеріледі, ал var-мен меншіктелген функция өрнегі тек var-дың өзін ғана көтереді (undefined ретінде), меншіктеуді емес"
            },
            {
              "icon": "",
              "label": "Екі шақыру да ReferenceError лақтырады"
            },
            {
              "icon": "",
              "label": "foo() қате лақтырады; bar() \"b\" басып шығарады"
            }
          ]
        },
        {
          "question": "function makeCounter() {\n  let count = 0;\n  return function() { count++; return count; };\n}\nconst counter = makeCounter();\nconsole.log(counter());\nconsole.log(counter());\nЕкі жол не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "1, содан кейін 1"
            },
            {
              "icon": "",
              "label": "0, содан кейін 1"
            },
            {
              "icon": "",
              "label": "undefined, содан кейін undefined"
            },
            {
              "icon": "",
              "label": "1, содан кейін 2 — қайтарылған функция makeCounter облысындағы сол count айнымалысын жабады (closes over), және ол айнымалы шақырулар арасында қайта орнатылмай сақталады"
            }
          ]
        },
        {
          "question": "for (var i = 0; i < 3; i++) {\n  setTimeout(() => console.log(i), 0);\n}\nБұл не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "0, 1, 2"
            },
            {
              "icon": "",
              "label": "3, 3, 3 — var функция-облысты қолданады, блок-облысты емес, сондықтан үш callback-тің бәрі бір ғана i айнымалысын жабады, ол оның кез келгені нақты орындалғанша циклді аяқтап, 3-ке тең болып үлгереді"
            },
            {
              "icon": "",
              "label": "0, 0, 0"
            },
            {
              "icon": "",
              "label": "undefined, undefined, undefined"
            }
          ]
        },
        {
          "question": "for (let i = 0; i < 3; i++) {\n  setTimeout(() => console.log(i), 0);\n}\nБұл не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "3, 3, 3"
            },
            {
              "icon": "",
              "label": "0, 0, 0"
            },
            {
              "icon": "",
              "label": "undefined, undefined, undefined"
            },
            {
              "icon": "",
              "label": "0, 1, 2 — let әрбір цикл қадамы үшін i-дің жаңа данасын жасайды, сондықтан әрбір callback ортақ бір айнымалыны емес, өзінің жеке көшірмесін жабады"
            }
          ]
        },
        {
          "question": "function greet() { return `Hi, ${this.name}`; }\nconst person = { name: 'Ana' };\nconsole.log(greet.call(person));\nБұл не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "\"Hi, Ana\" — Function.prototype.call функцияны this-ін бірінші аргументіне тікелей орнатып шақырады, сондықтан this.name person-ға қатысты анықталады"
            },
            {
              "icon": "",
              "label": "\"Hi, undefined\" — call() тек объектінің әдісі болып қойылған функцияларда ғана жұмыс істейді"
            },
            {
              "icon": "",
              "label": "TypeError лақтырады, себебі greet — person-ның әдісі емес"
            },
            {
              "icon": "",
              "label": "\"Hi, ${this.name}\" — call() шаблон әдебиетін есептемейді"
            }
          ]
        },
        {
          "question": "const timer = {\n  seconds: 0,\n  start: function() {\n    setInterval(() => { this.seconds++; }, 1000);\n  },\n};\nАдамдар мұнда setInterval ішінде function() { this.seconds++ } орнына неге arrow функциясын жөн көреді?",
          "options": [
            {
              "icon": "",
              "label": "Arrow функцияларының өз this-і жоқ — олар this-ті қоршаған start функциясынан лексикалық түрде алады, ол timer болып табылады (себебі start timer.start() ретінде шақырылды), сондықтан this.seconds әр tick сайын дұрыс түрде timer.seconds-қа сілтейді"
            },
            {
              "icon": "",
              "label": "Arrow функциялары әдеттегі функцияларға қарағанда орындалу уақытында жылдамырақ жұмыс істейді"
            },
            {
              "icon": "",
              "label": "Arrow функциялары this-ті автоматты түрде глобалды объектіге байланыстырады, ол кездейсоқ timer-ге тең болады"
            },
            {
              "icon": "",
              "label": "Arrow функциялары this-ті автоматты түрде глобалды айнымалыға айналдырады"
            }
          ]
        },
        {
          "question": "function multiply(a, b) { return a * b; }\nconst double = multiply.bind(null, 2);\nconsole.log(double(5));\nБұл не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "Қате лақтырады, себебі bind барлық аргументті алдын ала талап етеді"
            },
            {
              "icon": "",
              "label": "10 — bind this пен алдыңғы аргументтер алдын ала орнатылған жаңа функция қайтарады; double(5) шақыруы қалған b=5 аргументін береді, сондықтан multiply(2, 5) орындалады"
            },
            {
              "icon": "",
              "label": "NaN"
            },
            {
              "icon": "",
              "label": "7, себебі bind өз аргументтерін шақырудың аргументтеріне қосады, оларды алмастырмайды"
            }
          ]
        },
        {
          "question": "function outer() {\n  let x = 10;\n  function inner() {\n    let x = 20;\n    console.log(x);\n  }\n  inner();\n  console.log(x);\n}\nouter();\nЕкі console.log шақыруы не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "20, содан кейін 20"
            },
            {
              "icon": "",
              "label": "20, содан кейін 10 — inner-дің өз let x-і outer-дің x-ін тек inner-дің облысы ішінде ғана жасырады (shadow); outer-дің өз x-і ешқашан өзгертілмейді"
            },
            {
              "icon": "",
              "label": "10, содан кейін 10"
            },
            {
              "icon": "",
              "label": "ReferenceError лақтырады, себебі x екі рет декларацияланған"
            }
          ]
        },
        {
          "question": "const a = [1, 2, 3];\nconst b = a;\nb.push(4);\nconsole.log(a.length);\nБұл не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "3 — b — a-ның жеке көшірмесі"
            },
            {
              "icon": "",
              "label": "undefined"
            },
            {
              "icon": "",
              "label": "TypeError лақтырады, себебі a — const"
            },
            {
              "icon": "",
              "label": "4 — массивтер объектілер болғандықтан, const b = a сілтемені көшіреді, массивтің өзін емес; push арқылы b-ні өзгерту a көрсетіп тұрған дәл сол массивті де өзгертеді"
            }
          ]
        },
        {
          "question": "const original = { name: 'Ana', tags: ['x', 'y'] };\nconst copy = { ...original };\ncopy.name = 'Bea';\ncopy.tags.push('z');\nconsole.log(original.name, original.tags.length);\nБұл не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "'Ana' 2 — spread ішіндегі әрбір объект пен массивті терең клондайды"
            },
            {
              "icon": "",
              "label": "'Ana' 3 — spread тек беткі көшірме жасайды: name сияқты қарапайым қасиет мәні бойынша көшіріледі, сондықтан copy.name-ді қайта меншіктеу original-ге әсер етпейді, бірақ tags сияқты ішкі массив сілтеме бойынша көшіріледі, сондықтан copy.tags-қа push жасау original.tags көрсетіп тұрған дәл сол массивті өзгертеді"
            },
            {
              "icon": "",
              "label": "'Bea' 3 — spread бәрін сілтеме бойынша көшіреді, сондықтан жоғарғы деңгейдегі де, ішкі өзгерістер де original-ге қайтып әсер етеді"
            },
            {
              "icon": "",
              "label": "'Bea' 2"
            }
          ]
        },
        {
          "question": "const { a: x = 10, b: y = 20 } = { a: 5 };\nconsole.log(x, y);\nБұл не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "undefined undefined"
            },
            {
              "icon": "",
              "label": "5 undefined"
            },
            {
              "icon": "",
              "label": "10 20"
            },
            {
              "icon": "",
              "label": "5 20 — a x деп қайта аталды және бар болғандықтан, өз мәні 5-ті сақтайды; b y деп қайта аталды және жоқ болғандықтан, өзінің әдепкі мәні 20-ға ауысады"
            }
          ]
        },
        {
          "question": "const [first, ...rest] = [1, 2, 3, 4];\nconsole.log(rest);\nБұл не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "[1, 2, 3, 4]"
            },
            {
              "icon": "",
              "label": "[2, 3, 4] — rest first-тен кейін қалған әрбір элементті жаңа массивке жинайды"
            },
            {
              "icon": "",
              "label": "2"
            },
            {
              "icon": "",
              "label": "[1]"
            }
          ]
        },
        {
          "question": "const nums = [10, 1, 2];\nnums.sort();\nconsole.log(nums);\nБұл не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "[1, 2, 10] — sort сандарды әдепкі бойынша әрқашан сандық түрде өсу ретімен реттейді"
            },
            {
              "icon": "",
              "label": "[10, 1, 2] — sort бастапқы массивті өзгертпейді"
            },
            {
              "icon": "",
              "label": "[1, 10, 2] — Array.prototype.sort-тың әдепкі салыстырғышы элементтерді жолдарға айналдырып, оларды лексикографиялық түрде салыстырады, сондықтан \"10\" \"2\"-ден бұрын келеді; сонымен қатар sort жаңа массив қайтармай, бастапқы массивтің өзін өзгертеді"
            },
            {
              "icon": "",
              "label": "[2, 1, 10]"
            }
          ]
        },
        {
          "question": "const user = { profile: { age: 0 } };\nconsole.log(user.profile?.age ?? 'unknown');\nconsole.log(user.address?.city ?? 'unknown');\nЕкі жол не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "'unknown', содан кейін 'unknown' — ?? 0-ді || сияқты жоқ мән деп есептейді"
            },
            {
              "icon": "",
              "label": "0, содан кейін 'unknown' — ?? тек null немесе undefined жағдайында ғана әдепкі мәнге ауысады, 0 сияқты басқа жалған (falsy) мәндерде емес, сондықтан age (0) өзгеріссіз қалады; user.address undefined болғандықтан, ?. бүкіл тізбекті undefined-ге қысқартады, содан кейін ?? 'unknown' береді"
            },
            {
              "icon": "",
              "label": "0, содан кейін undefined"
            },
            {
              "icon": "",
              "label": "'unknown', содан кейін 0"
            }
          ]
        },
        {
          "question": "const obj = { a: undefined, b: function(){}, c: NaN, d: [undefined, function(){}, 1] };\nconsole.log(JSON.stringify(obj));\nБұл не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "'{\"a\":null,\"b\":null,\"c\":null,\"d\":[null,null,1]}' — қолдау таппаған кез келген мән объектілерде де, массивтерде де бірдей null болады"
            },
            {
              "icon": "",
              "label": "'{\"a\":undefined,\"b\":undefined,\"c\":NaN,\"d\":[undefined,null,1]}'"
            },
            {
              "icon": "",
              "label": "'{\"c\":null,\"d\":[null,null,1]}' — мәні undefined немесе функция болатын объект қасиеттері толығымен алынып тасталады, ал NaN null-ға сериализацияланады, бірақ массив ішінде дәл сол қолдау таппаған мәндер алынып тасталудың орнына null болады, себебі элементті алып тастау кейінгі барлық индекстерді жылжытар еді"
            },
            {
              "icon": "",
              "label": "TypeError лақтырады, себебі NaN JSON-ге сериализацияланбайды"
            }
          ]
        },
        {
          "question": "console.log('1');\nsetTimeout(() => console.log('2'), 0);\nPromise.resolve().then(() => console.log('3'));\nconsole.log('4');\nБұлар қандай ретпен басып шығарылады?",
          "options": [
            {
              "icon": "",
              "label": "1, 2, 3, 4"
            },
            {
              "icon": "",
              "label": "1, 4, 2, 3"
            },
            {
              "icon": "",
              "label": "1, 4, 3, 2 — синхронды код бірінші орындалады (сондықтан 1 мен 4 бірден басылады), содан кейін микротапсырма кезегі (Promise callback-тері) оқиға циклі келесі макротапсырмаға көшпес бұрын толығымен босатылады, сондықтан 3 setTimeout callback-тің 2-сінен бұрын басылады"
            },
            {
              "icon": "",
              "label": "1, 3, 4, 2"
            }
          ]
        },
        {
          "question": "async function foo() {\n  console.log('a');\n  await null;\n  console.log('b');\n}\nconsole.log('start');\nfoo();\nconsole.log('end');\nБұлар қандай ретпен басып шығарылады?",
          "options": [
            {
              "icon": "",
              "label": "start, a, end, b — foo() алғашқы await-ке дейін синхронды түрде орындалады, сондықтан foo() шақырылғанда 'a' бірден жазылады; содан кейін await foo-ны тоқтата тұрып, басқаруды шақырушыға қайтарады, сондықтан 'end' кейінірек микротапсырма ретінде орындалатын қайта жалғасқан 'b'-ден бұрын жазылады"
            },
            {
              "icon": "",
              "label": "start, a, b, end"
            },
            {
              "icon": "",
              "label": "start, end, a, b"
            },
            {
              "icon": "",
              "label": "a, start, end, b"
            }
          ]
        },
        {
          "question": "Promise.all([\n  Promise.resolve(1),\n  Promise.reject('err'),\n  Promise.resolve(3),\n]).then(r => console.log('ok', r)).catch(e => console.log('fail', e));\nБұл не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "'fail err' — Promise.all кіріс promise-терінің кез келгені бас тартқан сәтте-ақ, қалғандарының нәтижесін елемей, бас тартады, сондықтан catch өңдеушісі сол бас тарту себебімен орындалады"
            },
            {
              "icon": "",
              "label": "'ok' [1, 3]"
            },
            {
              "icon": "",
              "label": "'ok' [1, undefined, 3]"
            },
            {
              "icon": "",
              "label": "Синхронды түрде қате лақтырады, және ешбір өңдеуші орындалмайды"
            }
          ]
        },
        {
          "question": "const fast = new Promise(res => setTimeout(() => res('fast'), 10));\nconst slow = new Promise(res => setTimeout(() => res('slow'), 100));\nPromise.race([fast, slow]).then(v => console.log(v));\nБұл не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "'slow'"
            },
            {
              "icon": "",
              "label": "['fast', 'slow']"
            },
            {
              "icon": "",
              "label": "'fast' — Promise.race кіріс promise-терінің біріншісі шешілген сәтте-ақ шешіледі, ал 10мс таймер 100мс-тікінен әлдеқайда бұрын шешіледі"
            },
            {
              "icon": "",
              "label": "Қате лақтырады, себебі race дәл екі promise талап етеді"
            }
          ]
        },
        {
          "question": "function Animal(name) { this.name = name; }\nAnimal.prototype.speak = function() { return `${this.name} makes a sound`; };\nconst dog = new Animal('Rex');\nconsole.log(dog.speak());\nconsole.log(dog.hasOwnProperty('speak'));\nЕкі жол не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "'Rex makes a sound' содан кейін true"
            },
            {
              "icon": "",
              "label": "undefined, содан кейін false"
            },
            {
              "icon": "",
              "label": "TypeError лақтырады, себебі dog-тың өз speak әдісі жоқ"
            },
            {
              "icon": "",
              "label": "'Rex makes a sound' содан кейін false — speak Animal.prototype-де анықталған, dog данасының өзінде емес; dog оны шақырылғанда прототип тізбегі арқылы табады, бірақ hasOwnProperty тек данасының өз қасиеттерін тексереді, мұраланғанды емес"
            }
          ]
        },
        {
          "question": "class Counter {\n  #count = 0;\n  increment() { this.#count++; return this.#count; }\n}\nconst c = new Counter();\nconsole.log(c.increment());\nconsole.log(c.count);\nЕкі жол не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "1, содан кейін undefined — #count — жеке (private) класс өрісі, тек класстың өз әдістерінің ішінен ғана оқуға/жазуға болады; c.count (# белгісінсіз) — ешқашан орнатылмаған, мүлдем бөлек, қарапайым қасиет, сондықтан ол undefined"
            },
            {
              "icon": "",
              "label": "1, содан кейін 0"
            },
            {
              "icon": "",
              "label": "1, содан кейін 1"
            },
            {
              "icon": "",
              "label": "c.count-қа қатынағанда SyntaxError лақтырады"
            }
          ]
        },
        {
          "question": "const items = ['a', 'b'];\nconst label = `Items: ${items.length > 0 ? items.join(', ') : 'none'}`;\nconsole.log(label);\nБұл не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "'Items: ${items.length > 0 ? items.join(\\', \\') : \\'none\\'}'"
            },
            {
              "icon": "",
              "label": "'Items: none'"
            },
            {
              "icon": "",
              "label": "'Items: a, b' — шаблон әдебиеттері ${...} ішіне қойылған кез келген өрнекті, соның ішінде толық тернарлы өрнекті де, есептеп, оның нәтижесін жолға тікелей енгізеді"
            },
            {
              "icon": "",
              "label": "Тернарлы өрнектерге шаблон әдебиеттерінің ішінде тыйым салынғандықтан, SyntaxError лақтырады"
            }
          ]
        },
        {
          "question": "const nums = [1, 2, 3, 4, 5];\nconst result = nums.filter(n => n % 2 === 0).map(n => n * 10).reduce((sum, n) => sum + n, 0);\nconsole.log(result, nums);\nБұл не басып шығарады?",
          "options": [
            {
              "icon": "",
              "label": "60 [1, 2, 3, 4, 5] — filter, map және reduce әрқайсысы бастапқы массивті өзгертпей, жаңа массив немесе мән қайтарады, сондықтан nums өзгеріссіз қалады, ал result — соңғы қорытылған қосынды (2 мен 4, екі еселеніп 20 мен 40 болады, қосындысы 60)"
            },
            {
              "icon": "",
              "label": "60 [2, 4, 20, 40]"
            },
            {
              "icon": "",
              "label": "150 [1, 2, 3, 4, 5]"
            },
            {
              "icon": "",
              "label": "60 [20, 40]"
            }
          ]
        }
      ],
      "optionOrderVersion": "50fc0eba818f2d72"
    }
  }
}
