{
  "assessmentTests": {
    "javascript_test": {
      "name": "آزمون JavaScript",
      "desc": "30 سؤال سناریو درباره نحو اصلی و اجبار نوع، توابع/محدوده/بسته شدن و this، اشیاء/آرایه‌ها و ساختارهای داده، و حلقه رویداد/ناهمزمان/الگوهای نمونه اولیه — آزمایش کنید که آیا مهارات JavaScript شما با آنچه اعلانات شغلی به معنی تسلط بر JavaScript می‌دانند منطبق است یا نه.",
      "recommendation": "نمایه مهارات JavaScript شما",
      "results": {
        "beginner": {
          "name": "مبتدی",
          "desc": "می‌توانید توابع و اشیاء کاری بنویسید، اما سؤالاتی که از دست داده‌اید در اطراف اجبار نوع و معناشناسی مرجع متمرکز است نه نحو — == انواع را بی‌سر و صدا قبل از مقایسه تبدیل می‌کند، تخصیص آرایه که یک شی را به اشتراک می‌گذارد به جای کپی کردن، چرا NaN هرگز برابر با خود نیست. هیچ کدام از اینها با بد بودن در JavaScript نیست؛ این قوانین خاصی هستند که افرادی که زبان را با نوشتن کدی که به اتفاق کار می‌کرد یاد گرفتند، اشتباه می‌اندازند. آنها در کار مهم هستند زیرا هر یک جایی است که کد بدون خطا اجرا می‌شود و هنوز هم کار اشتباه را انجام می‌دهد.",
          "recommendation": "با سه چیز شروع کنید، به این ترتیب: چرا == انواع را قبل از مقایسه اجبار می‌کند در حالی که === نمی‌کند، چرا تخصیص یک آرایه یا شی به یک متغیر جدید مرجع را کپی می‌کند نه مقدار، و چگونه var بالا میرود و به undefined شروع می‌شود در حالی که let و const در منطقه زمانی مرده می‌مانند تا اعلان آنها واقعاً اجرا شود. راهنمای JavaScript MDN هر سه مورد را با نمونه‌های قابل اجرا پوشش می‌دهد."
        },
        "intermediate": {
          "name": "واسطه",
          "desc": "کد برنامه روزمره را با راحتی کنار می‌زنید — توابع، روش‌های آرایه، جریان کنترل سریع — و با کار نگهداری روتینی کند نمی‌شوید. شکاف بین اینجا و پیشرفته عمدتاً در مورد آنچه اتفاق می‌افتد وقتی قوانین محدوده و زمان JavaScript با یکدیگر تعامل دارند است: var دستگیر شده در داخل تماس‌های حلقه که همه مقدار نهایی یکسانی را می‌خوانند، این که بی‌سر و صدا از اشاره به شی دست می‌کشد وقتی روش از آن جدا می‌شود، کپی spread که عمیق به نظر می‌رسد اما فقط یک سطح کپی می‌کند. اینها انواع خرابی‌هایی هستند که یک نگاه سریع را می‌گذرانند و فقط تحت شرط اجرای خاصی ظاهر می‌شوند.",
          "recommendation": "بر چگونگی حل محدوده و this در زمان فراخوانی تمرکز کنید نه زمان تعریف: چرا یک حلقه for مبتنی بر var هر تماس را مقدار شمارنده نهایی یکسانی می‌دهد در حالی که let نمی‌دهد، چگونه this توسط نحوه فراخوانی تابع تعیین می‌شود نه جایی که نوشته می‌شود، و چرا کپی spread یا Object.assign فقط سطح بالایی یک شی را کپی می‌کند. سپس حلقه رویداد، زیرا این چیزی است که افرادی که قبلاً Promises را می‌شناسند را گیج می‌کند."
        },
        "advanced": {
          "name": "پیشرفته",
          "desc": "این سطحی است که اکثر اعلانات شغلی به معنای \"JavaScript قوی\" می‌دانند. یک زنجیره filter/map/reduce را می‌خوانید و دقیقاً می‌توانید پیش‌بینی کنید که چه چیزی را بدون تغییر آرایه اصلی برمی‌گرداند، می‌دانید چرا console.log همزمان همیشه یک microtask را شکست می‌دهد که یک setTimeout را شکست می‌دهد، و به Promise.all دست می‌زنید و می‌دانید که در لحظه ای که هر وعده ای رد می‌شود رد می‌شود نه صبر برای بقیه. آنچه این سطح را از بالاترین جدا می‌کند جنبه نمونه اولیه و مدل شی کار است: نحوه حل زنجیره نمونه اولیه برای روش ارث شده در مقابل hasOwnProperty، و آنچه که یک فیلد کلاس خصوصی واقعاً پنهان می‌کند.",
          "recommendation": "به بخش‌هایی فشار دهید که حالتی را محافظت می‌کنند که کد دیگر نیز لمس می‌کند: چگونه زنجیره نمونه اولیه JavaScript نگاه‌های روش برای چیزهای روی نمونه خود نیست را حل می‌کند، آنچه فیلدهای خصوصی # کلاس واقعاً از دسترسی خارجی پنهان می‌کند، و چگونه JSON.stringify undefined و توابع را متفاوت درون یک شی ساده در مقابل درون یک آرایه رفتار می‌کند. مطالب MDN در مورد حلقه رویداد و زنجیره نمونه اولیه ایستگاه طبیعی بعدی برای هر دو است."
        },
        "expert": {
          "name": "متخصص",
          "desc": "شما در بالای هر بخش نمره گرفتید — نحو اصلی و انواع و اجبار؛ توابع و محدوده و بسته شدن و this؛ اشیاء و آرایه‌ها و ساختارهای داده؛ و ناهمزمان و حلقه رویداد و نمونه‌های اولیه و الگوها. عملاً این به معنای این است که می‌توانید یک تابع غریبه را دریافت کنید و توضیح دهید چرا آنچه را که برمی‌گرداند برمی‌گرداند، نه فقط آنچه نحو می‌گوید باید انجام دهد، که مهارت سخت‌تر و ارزشمندتر است. در این سطح، خود زبان به ندرت فاکتور محدود است؛ حد معمولاً جریان کنترل ناهمزمان یا شکل داده‌های زیر آن است.",
          "recommendation": "بازگشت اکنون در طراحی و تشخیص است: استدلال در مورد یک مسابقه شرط بین Promise.all و Promise.race به جای تکرار تعریف آنها، انتخاب زمانی که یک بسته شدن ابزار مناسب برای حالت خصوصی است یا یک فیلد خصوصی کلاس است، و خواندن یک خرابی ترتیب ریز ریخت-در-مقابل-ماکروتسک در ورودی‌های تولید به جای در یک تست. اگر برای نقش در حال بررسی‌اید، یک خرابی زمانی را که پیدا کردید توصیف کنید — یک متغیر بسته شدن قدیمی یا یک تماس ناهمزمان خارج از ترتیب — به جای نام‌گذاری ویژگی‌های JavaScript؛ این استدلال را نه فقط واژگان نشان می‌دهد."
        }
      },
      "questions": [
        {
          "question": "console.log(x);\nvar x = 5;\nاین چه چاپ می‌کند؟",
          "options": [
            {
              "icon": "",
              "label": "5 — اعلانات var بلافاصله اجرا می‌شوند، قبل از هر کد دیگری"
            },
            {
              "icon": "",
              "label": "ReferenceError: x is not defined"
            },
            {
              "icon": "",
              "label": "undefined — اعلانات var به بالای محدوده خود بالا می‌رود و به undefined شروع می‌شود، اما تخصیص در محل خود اجرا می‌شود، بنابراین قبل از اینکه اجرا شود متغیر موجود است اما undefined را نگاه می‌دارد"
            },
            {
              "icon": "",
              "label": "null"
            }
          ]
        },
        {
          "question": "console.log(y);\nlet y = 5;\nچه اتفاقی می‌افتد؟",
          "options": [
            {
              "icon": "",
              "label": "ReferenceError را می‌اندازد: Cannot access 'y' before initialization — let به بالای محدوده خود بالا می‌رود اما تا زمانی که خط اعلان واقعاً اجرا شود در منطقه مرده زمانی می‌ماند"
            },
            {
              "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);\ndو خط چه چاپ می‌کنند؟",
          "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));\ndو خط چه چاپ می‌کنند؟",
          "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 بدائی است، و برای سازگاری عقب‌رو از آن زمان حفظ شده است"
            },
            {
              "icon": "",
              "label": "\"undefined\""
            },
            {
              "icon": "",
              "label": "\"boolean\""
            }
          ]
        },
        {
          "question": "کدام یک از موارد زیر هنگام استفاده در شرط if صحیح است؟",
          "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 is not a function — اعلانات تابع به طور کامل با بدنه خود بالا می‌رود، اما یک عبارت تابع var-assigned فقط 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());\ndو خط چه چاپ می‌کنند؟",
          "options": [
            {
              "icon": "",
              "label": "1 سپس 1"
            },
            {
              "icon": "",
              "label": "0 سپس 1"
            },
            {
              "icon": "",
              "label": "undefined سپس undefined"
            },
            {
              "icon": "",
              "label": "1 سپس 2 — تابع بازگشتی شامل متغیر count یکسانی از محدوده makeCounter است، و آن متغیر بین تماس‌ها باقی می‌ماند بجای تنظیم مجدد"
            }
          ]
        },
        {
          "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 محدوده تابع است، نه محدوده بلوک، بنابراین هر سه تماس شامل 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 برای هر تکرار حلقه ایجاد می‌کند، بنابراین هر تماس شامل کپی جداگانه خود به جای یک متغیر مشترک است"
            }
          ]
        },
        {
          "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چرا افراد تابع پیکان را بر function() { this.seconds++ } داخل setInterval ترجیح می‌دهند؟",
          "options": [
            {
              "icon": "",
              "label": "توابع پیکان خود this را ندارند — this را از تابع start محیط کننده به صورت معجمی دریافت می‌کنند، که timer است (زیرا start به عنوان timer.start() فراخوانی شد)، بنابراین this.seconds به درستی در هر tick به timer.seconds اشاره می‌کند"
            },
            {
              "icon": "",
              "label": "توابع پیکان در زمان اجرا سریع‌تر از توابع معمول اجرا می‌شوند"
            },
            {
              "icon": "",
              "label": "توابع پیکان this را به طور خودکار به شی جهانی متصل می‌کنند، که به طور تصادفی برابر با timer است"
            },
            {
              "icon": "",
              "label": "توابع پیکان 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 — x از inner سایه x از outer فقط داخل محدوده inner است; x از outer هرگز لمس نمی‌شود"
            },
            {
              "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 مرجع را کپی می‌کند، نه آرایه; تغییر b از طریق push همچنین آرایه دقیق را که 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 همچنین آرایه دقیق را که 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');\ndو خط چه چاپ می‌کنند؟",
          "options": [
            {
              "icon": "",
              "label": "'unknown' سپس 'unknown' — ?? 0 را مثل || است غایب بدانید"
            },
            {
              "icon": "",
              "label": "0 سپس 'unknown' — ?? فقط روی null یا undefined برمی‌گردد، نه در مقادیر دیگر نادرست مثل 0، بنابراین 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 serialized می‌شود، اما داخل یک آرایه همان مقادیر غیر پشتیبانی شده بجای حذف null می‌شوند، زیرا حذف یک عنصر آرایه هر شاخص بعدی را تغییر می‌دهد"
            },
            {
              "icon": "",
              "label": "TypeError می‌اندازد، زیرا NaN نمی‌تواند به JSON serialized شود"
            }
          ]
        },
        {
          "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 بلافاصله چاپ می‌شوند)، سپس صف microtask (تماس‌های Promise) کاملاً تخلیه می‌شود قبل از اینکه حلقه رویداد به macrotask بعدی برود، بنابراین 3 قبل از تماس setTimeout 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 خود به صورت همزمان اجرا می‌شود، بنابراین 'a' بلافاصله هنگام فراخوانی foo() ثبت می‌شود; await foo را معلق می‌کند و کنترل را به فراخوانی‌کننده برمی‌گرداند، بنابراین 'end' قبل از ازسر گیری 'b' ثبت می‌شود، که بعداً به عنوان microtask اجرا می‌شود"
            },
            {
              "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 فوراً نزدیک می‌شود اگر هر یک از وعده‌های ورودی رد شود، نتایج دیگران را نادیده می‌گیرد، بنابراین تماس 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 به محض آنکه اولین وعده ورودی خود حل شود حل می‌شود، و مؤقت 10ms بسیار قبل از مؤقت 100ms حل می‌شود"
            },
            {
              "icon": "",
              "label": "خطا می‌اندازد، زیرا race دقیقاً دو وعده نیاز دارد"
            }
          ]
        },
        {
          "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'));\ndو خط چه چاپ می‌کنند؟",
          "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);\ndو خط چه چاپ می‌کنند؟",
          "options": [
            {
              "icon": "",
              "label": "1 سپس undefined — #count یک فیلد کلاس خصوصی است، خواندنی و نوشتنی فقط از داخل روش‌های خود کلاس؛ c.count (بدون #) ویژگی معمول کاملاً متفاوت است که هرگز تنظیم نشد، بنابراین undefined است"
            },
            {
              "icon": "",
              "label": "1 سپس 0"
            },
            {
              "icon": "",
              "label": "1 سپس 1"
            },
            {
              "icon": "",
              "label": "SyntaxError می‌اندازد هنگام دسترسی به c.count"
            }
          ]
        },
        {
          "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' — قوالب رشته‌ای هر عبارت درون ${...} را ارزیابی می‌کنند، از جمله یک ternary کامل، و نتیجه را مستقیماً در رشته درون‌یابی می‌کنند"
            },
            {
              "icon": "",
              "label": "SyntaxError می‌اندازد، زیرا ternaries درون قوالب رشته‌ای مجاز نیستند"
            }
          ]
        },
        {
          "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"
    }
  }
}
