{
  "assessmentTests": {
    "javascript_test": {
      "name": "اختبار جافاسكريبت",
      "desc": "30 سؤال سيناريو حول الصيغة الأساسية والإكراه، الدوال والنطاق والإغلاقات و this، الكائنات والمصفوفات وهياكل البيانات، وحلقة الأحداث والعمليات غير المتزامنة و prototype - تحقق ما إذا كانت مهارات جافاسكريبت الخاصة بك تطابق ما تقصده إعلانات الوظائف بكفاءة جافاسكريبت.",
      "recommendation": "ملف ملخص مهارات جافاسكريبت الخاصة بك",
      "results": {
        "beginner": {
          "name": "مبتدئ",
          "desc": "يمكنك كتابة دوال وكائنات تعمل، لكن الأسئلة التي فشلت بها تتجمع حول إكراه النوع ودلالات المرجع بدلاً من الصيغة — == تحول الأنواع بهدوء قبل المقارنة، تعيين مصفوفة ينسخ مرجعاً واحداً بدلاً من نسخ الكائن، لماذا NaN لا تساوي أبداً نفسها. لا يتعلق أي من هذا بكونك سيئاً في جافاسكريبت؛ هذه هي القواعد المحددة التي تربك الأشخاص الذين تعلموا اللغة بكتابة كود يحدث أنه يعمل بدلاً من تعلم كيفية تتصرف القيم والمراجع فعلاً. تأتي أهميتها في العمل لأن كل واحدة منها هي حيث يعمل الكود بدون خطأ وما زال يفعل الشيء الخاطئ.",
          "recommendation": "ابدأ بثلاثة أشياء، بهذا الترتيب: لماذا == يكره الأنواع قبل المقارنة بينما === لا يفعل، لماذا تعيين مصفوفة أو كائن إلى متغير جديد ينسخ المرجع وليس القيمة، وكيفية رفع var وتهيئتها إلى undefined بينما let و const تبقى في المنطقة الزمنية الميتة حتى تشغيل إعلانهما. يغطي دليل MDN لجافاسكريبت جميع الثلاثة بأمثلة قابلة للتشغيل."
        },
        "intermediate": {
          "name": "متوسط",
          "desc": "تتعامل مع كود التطبيق اليومي براحة — دوال، طرق مصفوفة، تدفق تحكم مباشر — ولن تتباطأ بسبب عمل الصيانة الروتينية. الفجوة بين هنا والمتقدم تتعلق بشكل أساسي بما يحدث عندما تتفاعل قواعد النطاق والتوقيت في جافاسكريبت: var المُلتقطة داخل استدعاءات حلقة تقرأ جميعها نفس القيمة النهائية، this التي توقفت بهدوء عن الإشارة إلى الكائن بمجرد فصل الطريقة عنها، نسخة spread تبدو عميقة لكنها تنسخ مستوى واحد فقط. هذه هي أنواع الأخطاء التي تمر في قراءة سريعة وتظهر فقط تحت شرط وقت تشغيل معين.",
          "recommendation": "ركز على كيفية حل النطاق و this في وقت الاستدعاء وليس وقت التعريف: لماذا لولب for القائم على var يعطي كل استدعاء نفس قيمة العداد النهائية بينما let لا يفعل، كيفية تحديد this بكيفية استدعاء دالة بدلاً من المكان الذي تُكتب فيه، ولماذا نسخة spread أو Object.assign تنسخ المستوى الأعلى فقط من كائن. ثم حلقة الأحداث، لأن تلك هي التي تربك الأشخاص الذين يعرفون الوعود بالفعل على حدة."
        },
        "advanced": {
          "name": "متقدم",
          "desc": "هذا هو المستوى الذي تعنيه معظم إعلانات الوظائف بـ \"جافاسكريبت قوي\". تقرأ سلسلة من filter/map/reduce وتتنبأ بدقة بما تعيده بدون تغيير المصفوفة الأصلية، تعرف لماذا يفوز console.log المتزامن دائماً على microtask والذي يفوز على setTimeout، وتصل إلى Promise.all معرفة أنها ترفض على الفور إذا رفضت أي وعد واحد بدلاً من انتظار البقية. ما يفصل هذا المستوى عن الأعلى هو جانب prototype و object-model من العمل: كيفية حل سلسلة prototype لطريقة موروثة مقابل hasOwnProperty، وما يخفيه حقل class الخاص فعلاً.",
          "recommendation": "ادفع إلى الأجزاء التي تحمي الحالة التي يلمسها الكود الآخر أيضاً: كيفية حل سلسلة prototype في جافاسكريبت للبحث عن طريقة ليست على المثيل ذاته، ما تخفيه حقول private # في class من الوصول الخارجي، وكيفية معاملة JSON.stringify للقيم غير المعرّفة والدوال بشكل مختلف داخل كائن عادي مقابل داخل مصفوفة. مادة MDN على حلقة الأحداث وسلسلة prototype هي المحطة التالية الطبيعية لكليهما."
        },
        "expert": {
          "name": "خبير",
          "desc": "حققت نتيجة في أعلى كل قسم — الصيغة الأساسية والأنواع والإكراه؛ الدوال والنطاق والإغلاقات و this؛ الكائنات والمصفوفات وهياكل البيانات؛ والعمليات غير المتزامنة وحلقة الأحداث و prototypes والعبارات. من الناحية العملية، يعني ذلك أنه يمكنك تسليم دالة غريبة وشرح لماذا تعيد ما تعيده، وليس فقط ما يجب أن تفعله الصيغة، وهي المهارة الأصعب والأكثر قيمة. على هذا المستوى، اللغة نفسها نادراً ما تكون عامل التحديد؛ الحد الأقصى عادة ما يكون تدفق التحكم غير المتزامن أو شكل البيانات الأساسية له.",
          "recommendation": "العائدات الآن في التصميم والتشخيص: التفكير في حالة race بين Promise.all و Promise.race بدلاً من تكرار تعريفاتهم، اختيار متى تكون الإغلاقة الأداة الصحيحة للحالة الخاصة مقابل متى يكون حقل private في class، وقراءة خطأ microtask-vs-macrotask في سجلات الإنتاج بدلاً من في اختبار. إذا كنت تخضع للفحص لدور ما، صِف خطأ توقيت وجدته — متغير إغلاقة قديم أو استدعاء غير متزامن خارج الترتيب — بدلاً من تسمية ميزات جافاسكريبت؛ يوضح التفكير وليس فقط المفردات."
        }
      },
      "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);\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 هي القيمة الوحيدة في جافاسكريبت التي لا تساوي نفسها تحت ===، لكن 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": "أيّ من الخيارات التالية صحيح (truthy) عند استخدامه في شرط if؟",
          "options": [
            {
              "icon": "",
              "label": "0"
            },
            {
              "icon": "",
              "label": "\"\" (سلسلة فارغة)"
            },
            {
              "icon": "",
              "label": "null"
            },
            {
              "icon": "",
              "label": "\"0\" — السلسلة غير الفارغة دائماً صحيحة في جافاسكريبت، حتى عندما يكون محتواها هو السلسلة \"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 function expression فقط ترفع var نفسها (as 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 — الدالة المعادة تغلق على نفس متغير 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لماذا يفضل الناس دالة arrow على function() { this.seconds++ } داخل setInterval هنا؟",
          "options": [
            {
              "icon": "",
              "label": "دوال Arrow لا تملك this الخاصة بها — تلتقط this بشكل معجمي من دالة start المحيطة، التي هي timer (لأن start تم استدعاؤها كـ timer.start())، لذا this.seconds بشكل صحيح يشير إلى 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 — let 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 يتغير أيضاً المصفوفة الدقيقة التي تشير إليها"
            }
          ]
        },
        {
          "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');\nماذا تطبع السطور الاثنان؟",
          "options": [
            {
              "icon": "",
              "label": "'unknown' ثم 'unknown' — ?? تعامل 0 كغائبة، نفس الطريقة || تفعل"
            },
            {
              "icon": "",
              "label": "0 ثم 'unknown' — ?? فقط تعود على null أو undefined، وليس على قيم كاذبة أخرى مثل 0، لذا age (0) يُحتفظ به كما هو؛ user.address غير محددة، لذا ?. توقف العملية برمتها إلى 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 يطبعان فوراً)، ثم رتل 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'));\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 تجد لها من خلال سلسلة prototype عند استدعاؤها، لكن 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 هي حقل class خاص، قابل للقراءة والكتابة فقط من داخل طرق class نفسها؛ 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' — القوالب النموذجية تُقيّم أي تعبير وضع داخل ${...}، بما في ذلك ثلاثي كامل، وتُقحم نتيجته مباشرة في السلسلة"
            },
            {
              "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"
    }
  }
}
