{
  "assessmentTests": {
    "javascript_test": {
      "name": "בדיקת JavaScript",
      "desc": "30 שאלות תרחיש על תחביר בסיסי והכפיית סוגים, פונקציות/היקף/סגירות ו-this, אובייקטים/מערכים ומבני נתונים, ולולאת אירועים/async/דפוסי אב-טיפוס — גלה אם ה-JavaScript שלך תואם את מה שפרסום מעסיקה מתכוון כשאומר יכולת JavaScript.",
      "recommendation": "פרופיל כישוריך ב-JavaScript",
      "results": {
        "beginner": {
          "name": "מתחיל",
          "desc": "אתה יכול לכתוב פונקציות ואובייקטים שעובדים, אך השאלות שהחסרת מתקבצות סביב הכפיית סוגים וסמנטיקה של הפניות בעיקר, בניגוד לתחביר — == המרה שקטה של סוגים לפני השוואה, הקצאת מערך החולקת אובייקט אחד במקום להעתיק אותו, למה NaN לעולם לא שווה לעצמו. זה לא שום דבר על היותך רע ב-JavaScript; אלו הם הכללים הספציפיים שמדרדרים אנשים שלמדו את השפה על ידי כתיבת קוד שרק עבד במקום ללמוד איך ערכים והפניות למעשה מתנהגים. זה חשוב בעבודה כי כל אחד מאלו הוא מקום שבו קוד רץ ללא שגיאה וזה עדיין עושה את הדבר הלא נכון.",
          "recommendation": "התחל עם שלושה דברים, בסדר זה: למה == הוא חיוב סוגים לפני השוואה בעוד === לא, למה הקצאת מערך או אובייקט למשתנה חדש מעתיקה את ההפניה ולא הערך, וכיצד var מורם וממותחל ל-undefined בעוד let ו-const נשארים באזור מת זמני עד שהצהרתם בפועל מבצעת. מדריך JavaScript של MDN מכסה את כל שלושת עם דוגמאות שניתן להריץ."
        },
        "intermediate": {
          "name": "בינוני",
          "desc": "אתה מטפל בנוחות בקוד יישום יומיומי — פונקציות, שיטות מערך, זרימת בקרה ישירה — ולא תהיה מואטה על ידי עבודה שגרתית. הפער בין כאן לבין מתקדם הוא בעיקר מה שקורה כשכללי ההיקף והעיתוי של JavaScript מקיימים אינטראקציה: var שנתפסה בתוך קריאות החזרה של לולאה שכולן קוראות את אותו ערך סיום, this שעוצר בשקט להצביע על האובייקט ברגע שהשיטה מנותקת ממנה, העתק spread שנראה עמוק אך מעתיק רק רמה אחת. אלו הם הסוג של באגים שעוברים קריאה מהירה וחשפים רק בתנאי זמן ריצה ספציפי.",
          "recommendation": "התמקד בכיצד ההיקף ו-this למעשה נפתרים בזמן קריאה ולא בזמן הגדרה: למה לולאת for מבוססת-var מעביר כל קריאת חזרה את אותו ערך מונה סוף בעוד let לא, כיצד this נקבע על ידי איך פונקציה נקראת ולא איפה היא כתובה, ולמה spread או Object.assign מעתיק רק את הרמה העליונה של אובייקט. אז את הלולאה האירועים, כי זה מה שמדרדר אנשים שכבר יודעים promises בנפרד."
        },
        "advanced": {
          "name": "מתקדם",
          "desc": "זה הרמה ש-job postings רוב הזמן מתכוונים כשהם אומרים \"JavaScript חזק\". אתה קורא שרשרת של filter/map/reduce ויכול לחזות בדיוק מה היא מחזירה ללא מוטציה של המערך המקורי, אתה יודע למה console.log סינכרוני תמיד מנצח microtask שתמיד מנצח setTimeout, ואתה מטפל ב-Promise.all בידע שהיא דוחה ברגע שכל promise אחד עושה בעיקר שלא מחכה לשאר. מה מפריד את הרצועה הזאת מהחלק העליון הוא הצד של prototype וןobject-model של העבודה: כיצד שרשרת prototype פותרת שיטה inherited לעומת hasOwnProperty, ומה שדה class private למעשה מסתיר.",
          "recommendation": "דחוף לתוך החלקים שמגנים על מצב שקוד אחר גם נוגע: כיצד שרשרת prototype של JavaScript פותרת חיפושי שיטה שלא על ה-instance עצמו, מה שדה private #fields של class למעשה מסתיר מגישה חיצונית, וכיצד JSON.stringify מתייחס ל-undefined ופונקציות שונות בתוך אובייקט רגיל לעומת בתוך מערך. חומר MDN על לולאת האירועים ושרשרת prototype הוא הצעד הטבעי הבא לשניהם."
        },
        "expert": {
          "name": "מומחה",
          "desc": "קיבלת ניקוד בחלק העליון של כל קטגוריה — תחביר בסיסי, סוגים והכפיית סוגים; פונקציות, היקף, סגירות ו-this; אובייקטים, מערכים ומבני נתונים; ו-async, לולאת אירועים, prototypes וdפוסים. במעשי, זה אומר שאתה יכול להיות מועבר פונקציה זרה והסבר למה היא מחזירה מה שהיא מחזירה, לא רק מה התחביר אומר שהיא צריכה לעשות, מה זה יותר קשה ויותר כישורון בעל ערך. ברמה זאת השפה עצמה כמעט לעולם לא הגורם המגביל; הגבול הוא בדרך כלל זרימת בקרה async או הצורה של הנתונים מתחתיה.",
          "recommendation": "ההחזרים הם כעת בעיצוב וביניחוח: חשיבה על מצב race בין Promise.all ו-Promise.race במקום לתיגע את ההגדרות שלהם, בחירה מתי סגירה היא הכלי הנכון למצב פרטי לעומת מתי שדה private של class היא, וקריאת microtask-vs-macrotask ordering bug בלוגי הייצור במקום בחידון. אם אתה מנושא על תפקיד, תאר בעיית timing שמצאת — משתנה סגירה מיושנה או async callback מחוץ לסדר — במקום שם features של 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 מונע רק reassignment של הקשר arr עצמו, לא mutation של אובייקט המערך הוא מצביע על, אז 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 — == כורח הרוקח הן קדימה השוואה, בעוד === משוואה סוג וערך ללא כפיית סוגים, ומחרוזת לעולם לא שווה לחומר מספר בחומרות"
            },
            {
              "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, והוא נשמר לצורך הזה compatibility"
            },
            {
              "icon": "",
              "label": "\"undefined\""
            },
            {
              "icon": "",
              "label": "\"boolean\""
            }
          ]
        },
        {
          "question": "איזה מהבאים הוא truthy כשמשתמשים בתנאי if?",
          "options": [
            {
              "icon": "",
              "label": "0"
            },
            {
              "icon": "",
              "label": "\"\" (מחרוזת ריקה)"
            },
            {
              "icon": "",
              "label": "null"
            },
            {
              "icon": "",
              "label": "\"0\" — מחרוזת ללא-ריקה הוא תמיד truthy ב-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 — הצהרות function מורמות לגמרי עם הגוף שלהם, אך expression function שהוקצה 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 — פונקציה מוחזרת סוגרת על אותו משתנה count מהיקף של makeCounter, וזה משתנה persists בין הקריאות במקום לאפס"
            }
          ]
        },
        {
          "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 היא function-scoped, לא block-scoped, אז כל שלושת קריאות החזרה סוגרות את אותו 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 בעיקר מתייחס timer.seconds בכל tick"
            },
            {
              "icon": "",
              "label": "פונקציות חץ לבצע מהר יותר מאשר פונקציות רגילות בזמן הריצה"
            },
            {
              "icon": "",
              "label": "פונקציות חץ automatically הקשור זה אל הגלובל אובייקט, אשר קורה להיות שווה timer"
            },
            {
              "icon": "",
              "label": "פונקציות חץ המיר this לבתוך גלובל משתנה automatically"
            }
          ]
        },
        {
          "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 וכל טיעוני ראש pre-set; קורא 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 העתקות הפנייה, לא המערך; mutation b דרך push גם mutations את אותו מערך בדיוק 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 עמוק-clones כל הקן אובייקט ומערך"
            },
            {
              "icon": "",
              "label": "'Ana' 3 — spread הוא רק עותק עילי: רכוש primitive כמו name הוא העתק על ידי ערך, אז reassigning copy.name לא touches original, אך מערך מקון כמו tags הוא העתק על ידי הפנייה, אז pushing לתוך copy.tags mutations את אותו מערך בדיוק original.tags מצביע על"
            },
            {
              "icon": "",
              "label": "'Bea' 3 — spread העתקות הכל על ידי הפנייה, אז גם הכמות התעלומה וקן changes חוזרות לOrigin"
            },
            {
              "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 לא mutations המערך המקורי"
            },
            {
              "icon": "",
              "label": "[1, 10, 2] — comparator כברירת מחדל של Array.prototype.sort משנה אלמנטים מחרוזות והשווה אותם lexicographically, אז \"10\" סידורים לפני \"2\"; sort גם mutations המערך בתוך במקום במקום להחזיר זה"
            },
            {
              "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' — ?? treats 0 כמו-lost, באותה צורה || עושה"
            },
            {
              "icon": "",
              "label": "0 ואז 'unknown' — ?? רק חזרה על null או undefined, לא על ערכים falsy אחרים כמו 0, אז age (0) הוא שמור כמו-היא; user.address היא undefined, אז ?. קצר-circuits את כל השרשרת ל-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]}' — כל unsupported ערך הופך null everywhere, בתוך אובייקטים ומערכים"
            },
            {
              "icon": "",
              "label": "'{\"a\":undefined,\"b\":undefined,\"c\":NaN,\"d\":[undefined,null,1]}'"
            },
            {
              "icon": "",
              "label": "'{\"c\":null,\"d\":[null,null,1]}' — אובייקט כלים שערך undefined או פונקציה הם omitted בשלמות, ו-NaN serializes ל-null, אך בתוך מערך אלו unsupported ערכים הופכים null בעיקר מובושים, כי מחיקה אלמנט מערך היא להסתער כל מאוחר יותר אינדקס"
            },
            {
              "icon": "",
              "label": "זה זורק TypeError, כי NaN לא יכול להיות serialized ל-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 callbacks) מרוקנים בשלמות לפני לולאה אירועים עובר הבא macrotask, אז 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, אז 'a' מדפיסה מיד כאשר foo() הוא קרא; await ואז suspends foo ו-return בקרה לקורא, אז 'end' מדפיסה לפני resumed '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 דחויות ברגע כל אחד מהקלט לו promises דחוי, ignoring תוצאות של האחרים, אז catch טיפול רץ עם תוכן של להיות דחוי"
            },
            {
              "icon": "",
              "label": "'ok' [1, 3]"
            },
            {
              "icon": "",
              "label": "'ok' [1, undefined, 3]"
            },
            {
              "icon": "",
              "label": "זה זורק סינכרוני ו-no מטפל לא פעם רץ"
            }
          ]
        },
        {
          "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 מתיישב ברגע ראשון שלו קלט promises מתיישב, ו-10ms טיימר פותר בעדיפות קדומה את 100ms אחד"
            },
            {
              "icon": "",
              "label": "זה זורק שגיאה, כי race דורש בדיוק שתיים promises"
            }
          ]
        },
        {
          "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 instance עצמו; dog מוצא אותו דרך prototype שרשרת כשזה קרא, אבל hasOwnProperty בדקו רק instance שלו properties, לא כל דבר inherited"
            }
          ]
        },
        {
          "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 יוצר שדה, readable וwritable רק מתוך זה 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' — תבנית ליטרלים הערכה כל ביטוי שום בתוך ${...}, כולל מלא ternary, ו-interpolate תוצאתו ישירות לתוך מחרוזת"
            },
            {
              "icon": "",
              "label": "זה זורק SyntaxError, כי ternaries לא allowed בתוך תבנית ליטרלים"
            }
          ]
        },
        {
          "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 כל אחד חוזר מערך חדש או ערך ללא mutation המקורי מערך, אז nums הוא משנה בעוד result הוא סופי reduced סכום (2 ו-4, doubled ל-20 ו-40, summed ל-60)"
            },
            {
              "icon": "",
              "label": "60 [2, 4, 20, 40]"
            },
            {
              "icon": "",
              "label": "150 [1, 2, 3, 4, 5]"
            },
            {
              "icon": "",
              "label": "60 [20, 40]"
            }
          ]
        }
      ],
      "optionOrderVersion": "50fc0eba818f2d72"
    }
  }
}
