GammaCyber

JavaScript מודרני

תכנות, אלגוריתמיקה ו-Web · 5–6 שעות

// סקירה

שיעור 16 — JavaScript מודרני

JavaScript היא שפת הדפדפן. שיעור זה מכסה ES6+, DOM manipulation, Event Loop, Closures, ו-async programming — כל הכלים לבניית אפליקציית Web אמיתית.

✓נושאי השיעור
  • ES6+: const/let, Arrow Functions, Destructuring, Spread, Optional Chaining
  • DOM: querySelector, classList, addEventListener, Event Delegation
  • Event Loop: Call Stack → Microtask Queue → Callback Queue
  • Closures: פונקציה שסגורה על הסביבה שנוצרה בה
  • Async: Callbacks (הבעיה) → Promises (.then/.catch) → async/await
  • Fetch API: GET/POST, response.ok, JSON.stringify/parse
  • localStorage: שמירה בדפדפן, אסור לסיסמאות/tokens
  • ES Modules: import/export, default vs named
// פרק 1

JavaScript מודרני — ES6+

ES6 (2015) שינתה את JavaScript לחלוטין. כל הקוד שתכתוב היום משתמש בתכונות אלו.

const, let, var

// var — ישן: Function scoped, hoisting מוזר. אל תשתמש! var x = 1; if (true) { var x = 2; } // אותו x! console.log(x); // 2 — מפתיע! // let — Block scoped (כמו Python) let y = 1; if (true) { let y = 2; } // y שונה בתוך block console.log(y); // 1 — כצפוי // const — Block scoped + לא ניתן להשמה מחדש const PI = 3.14; // PI = 3; // TypeError! // ⚠️ const לא אומר "immutable"! const arr = [1, 2, 3]; arr.push(4); // OK — שינוי תוכן מותר // arr = [5]; // TypeError — השמה מחדש אסורה // כלל: תמיד const. אם צריך לשנות — let. לעולם לא var.

Arrow Functions

// פונקציה רגילה vs Arrow: function add(a, b) { return a + b; } const add = (a, b) => a + b; // one-liner: return implicit const square = x => x * x; // param אחד: ללא () const greet = () => "Hello!"; // ללא params // map/filter/reduce — שימוש נפוץ: const nums = [1, 2, 3, 4, 5]; const doubled = nums.map(n => n * 2); // [2,4,6,8,10] const evens = nums.filter(n => n%2===0); // [2,4] const total = nums.reduce((acc,n)=>acc+n, 0); // 15
! this ב-Arrow Functions — הטעות הנפוצה! ›
// Arrow function לא יוצרת this משלה — יורשת מהסביבה const obj = { name: "Bob", greet: function() { setTimeout(function() { console.log(this.name); // undefined! this = window }, 1000); }, greetFixed: function() { setTimeout(() => { console.log(this.name); // "Bob" — arrow ירש this ✓ }, 1000); } };

Destructuring, Spread, Optional Chaining

// Array Destructuring: const [first, second, ...rest] = [1, 2, 3, 4, 5]; // first=1, second=2, rest=[3,4,5] // Object Destructuring: const user = { name: "Alice", age: 30, role: "admin" }; const { name, age } = user; const { name: userName, role = "user" } = user; // rename + default // Spread Operator: const arr2 = [...arr, 4, 5]; // copy + extend const obj2 = { ...obj1, b: 99 }; // copy + override // Optional Chaining — מונע "Cannot read property of undefined": const user = null; console.log(user?.address?.city); // undefined (לא throw!) console.log(user?.getName?.()); // undefined // Nullish Coalescing: const port = config.port ?? 3000; // רק null/undefined → 3000 // (לא כמו || שגם 0 ו-"" גורמים ל-fallback)
✏תרגול — ES6+4 שאלות
שאלה 1
const arr=[1,2,3]; arr.push(4); console.log(arr.length);
✓ תשובה: א) 4 — const מונע השמה מחדש, לא שינוי תוכן. push משנה את המערך — arr.length = 4.
שאלה 2
const {a: x = 10} = {b: 5}; — מה ערך x?
✓ תשובה: ב) 10 — Destructuring: מחפשים a באובייקט. a לא קיים (רק b) → ברירת מחדל 10. x = 10.
שאלה 3 — typeof null
console.log(typeof null);
✓ תשובה: א) "object" — זוהי באג היסטורי ב-JS שנשמר לתאימות לאחור. typeof null === "object" בכל הגרסאות!
שאלה 4 — || vs ??
console.log(0 || "default"); console.log(0 ?? "default");
✓ תשובה: ב) — || = falsy check: 0 הוא falsy → "default". ?? = nullish check: 0 אינו null/undefined → 0 נשמר.
// פרק 2

DOM Manipulation ו-Events

JS + DOM = דפים דינמיים. JS יכול לשנות כל דבר בדף בזמן אמת — ללא רענון.

בחירת אלמנטים

document.getElementById("main") // by ID — מהיר document.querySelector(".btn") // CSS selector — ראשון document.querySelectorAll("p.text") // כולם → NodeList (static) document.getElementsByClassName("card") // HTMLCollection (live!) // ניווט: el.parentElement // הורה el.children // ילדים el.closest(".card") // מחפש למעלה בעץ

שינוי DOM

el.textContent = "Hello"; // טקסט בטוח ✓ el.innerHTML = "<b>Hello</b>"; // מפרסר HTML — סכנת XSS! el.classList.add("active"); el.classList.toggle("open"); // הוסף אם אין, הסר אם יש el.setAttribute("href", "..."); el.style.color = "red"; // עדיף class toggling

Event Listeners + Bubbling

btn.addEventListener("click", handleClick); btn.removeEventListener("click", handleClick); // חייב reference! function handleClick(event) { event.preventDefault(); // מניעת ברירת מחדל event.stopPropagation(); // עצירת Bubbling console.log(event.target); // האלמנט שנלחץ } // Event Delegation — listener אחד לכל הילדים: list.addEventListener("click", (e) => { if (e.target.matches("li")) { console.log("Clicked:", e.target.textContent); } }); // יעיל מ-listener על כל li בנפרד! // Bubbling: click על btn → inner → outer → document // stopPropagation() עוצר את העלייה
✏תרגול — DOM + Events4 שאלות
שאלה 1
מה מחזיר document.querySelectorAll("p")?
✓ תשובה: ד) — querySelectorAll → NodeList static. getElementsByTagName → HTMLCollection live (מתעדכן אוטומטי).
שאלה 2
מה עושה addEventListener("click", fn, { once: true })?
✓ תשובה: ד) — { once: true } מסיר את ה-listener אוטומטית אחרי ההפעלה הראשונה. שימושי ל-one-time actions.
שאלה 3 — Bug Hunt
מה שגוי בקוד?
for (var i=0; i<3; i++) { setTimeout(() => console.log(i), 0); } // מצפים: 0 1 2 // מקבלים: ???
✓ תשובה: ב) 3 3 3 — var = function-scoped, משותף. כשcallbacks רצים הלולאה כבר סיימה ו-i=3. תיקון: let יוצר i חדש לכל iteration.
שאלה 4
מה ההבדל בין == ל-===?
✓ תשובה: א) — "5" == 5 → true (coercion). "5" === 5 → false (טיפוסים שונים). תמיד השתמש ב-===.
// פרק 3

Event Loop ו-Closures

JS היא Single-Threaded אבל לא חסומת. Event Loop מאפשר async. Closures הן אחת התכונות החזקות ביותר של JS.

מרכיבי Event Loop

מרכיבתפקידדוגמה
Call Stackקוד סינכרוני רץ כאןהפונקציה הנוכחית
Web APIsמשימות ב-background (דפדפן)setTimeout, fetch
Microtask Queueעדיפות גבוהה — לפני CallbackPromise.then, await
Callback Queuecallbacks שמחכיםsetTimeout callback
Event LoopStack ריק? → Microtask → Callbackהלב של async
console.log("1 — Start"); // Call Stack setTimeout(() => console.log("2 — Timeout"), 0); // Callback Queue Promise.resolve().then(() => console.log("3 — Promise")); // Microtask Queue console.log("4 — End"); // Call Stack // סדר הפלט: // 1 — Start // 4 — End // 3 — Promise ← Microtask Queue לפני Callback! // 2 — Timeout

Closures

// Closure = פונקציה שזוכרת את הסביבה שנוצרה בה function makeCounter() { let count = 0; // "נסתר" מבחוץ return { increment: () => ++count, decrement: () => --count, value: () => count }; } const counter = makeCounter(); counter.increment(); // 1 counter.increment(); // 2 counter.decrement(); // 1 console.log(counter.value()); // 1 (count לא נגיש מבחוץ!) // Closure בפועל — createAdder: function createAdder(x) { return function(y) { x += y; return x; }; } const add = createAdder(10); add(5); // 15 (x: 10→15) add(3); // 18 (x: 15→18, x השתנה!) const add2 = createAdder(0); // closure נפרד לחלוטין! add2(7); // 7
✏תרגול — Event Loop + Closures4 שאלות
שאלה 1 — Event Loop
console.log('A'); setTimeout(() => console.log('B'), 100); setTimeout(() => console.log('C'), 0); Promise.resolve().then(() => console.log('D')); console.log('G');מה סדר הפלט?
✓ תשובה: ד) A→G→D→C→B — A,G = סינכרוני. D = Microtask (לפני Callback!). C = setTimeout 0ms (Callback Queue). B = setTimeout 100ms (אחרון).
שאלה 2 — Closure
const x = 1; function outer() { const x = 2; return () => x; } console.log(outer()());
✓ תשובה: ג) 2 — Closure: הarrow function נוצרה בתוך outer ולכן סגורה על x=2 של outer. הx הגלובלי (=1) לא נגיש.
שאלה 3 — arguments
const fn = () => arguments; try { fn() } catch(e) { console.log(e.constructor.name); }
✓ תשובה: ב) ReferenceError — Arrow functions אין להן arguments object. גישה ל-arguments בarrow = ReferenceError. השתמש ב-...args במקום.
שאלה 4 — async function return
async function f() { await Promise.resolve(); return 42; } console.log(f());
✓ תשובה: ד) — async function תמיד מחזירה Promise. בגלל ה-await הפונקציה נעצרת, וה-Promise עדיין ב-pending כש-console.log רץ. כדי לקבל 42: await f() או f().then(v => ...).
// פרק 4

Async JavaScript — Promises ו-async/await

הבעיה: Callback Hell. הפתרון: Promises. הסינטקס הנוח: async/await. כל שלוש השיטות חיות יחד.

Promises

// Promise מצבים: Pending → Fulfilled / Rejected const promise = new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() > 0.5) resolve({ data: "result" }); else reject(new Error("Something failed")); }, 1000); }); promise .then(data => console.log("Success:", data)) .catch(err => console.error("Error:", err)) .finally(() => console.log("Done (always runs)")); // Promise Chaining — פתרון ל-Callback Hell: getUser(userId) .then(user => getPosts(user.id)) .then(posts => getComments(posts[0].id)) .catch(err => console.error(err)); // Promise.all — מקביל, מחכה לכולם: Promise.all([fetchUser(), fetchPosts(), fetchConfig()]) .then(([user, posts, config]) => { /* כולם הושלמו */ });

async/await

// async/await = סינטקס סוכר על Promises async function loadUserData(userId) { try { const user = await getUser(userId); // עוצרת עד resolve const posts = await getPosts(user.id); // אחרי user return posts; } catch (err) { console.error("Error:", err); throw err; // re-throw אם צריך } } // מקביל עם async/await: async function parallel() { const [user, config] = await Promise.all([getUser(1), getConfig()]); // שניהם מבוצעים במקביל! לא כל אחד בתורו }
! await בלי async = SyntaxError ›

await חייב להיות בתוך async function. לא ניתן ב-top-level (אלא ב-ES modules). תיקון: עטוף ב-async IIFE: (async () => { const data = await fetch("..."); })()

✏תרגול — Promises + async4 שאלות
שאלה 1 — Promise Chain
Promise.resolve(1) .then(v => v + 1) .then(v => { throw v; }) .catch(v => v + 3) .then(v => console.log(v));
✓ תשובה: ד) 5 — 1 → then: 1+1=2 → then: throw 2 → catch: 2+3=5 → then: log(5).
שאלה 2 — Promise one-shot
const p = new Promise((res, rej) => { res(1); res(2); rej(3); }); p.then(console.log).catch(console.log);
✓ תשובה: ב) 1 — Promise יכולה להסתיים פעם אחת בלבד. ה-res(1) הראשון מנצח, ה-res(2) וה-rej(3) מתעלמים.
שאלה 3 — ביצועים
מה הבעיה בקוד זה ואיך מתקנים?
async function loadAll() { const user = await getUser(); // 1 שניה const config = await getConfig(); // 1 שניה return { user, config }; // סה"כ: 2 שניות! }
✓ תשובה: ב) — תיקון: const [user, config] = await Promise.all([getUser(), getConfig()]); — מקביל, סה"כ 1 שניה!
שאלה 4 — fetch + 404
למה fetch לא זורק שגיאה על 404?
✓ תשובה: א) — תמיד בדוק if (!response.ok) throw new Error(...); אחרי fetch! רק שגיאות רשת גורמות ל-rejection.
// פרקים 5–6 + סיכום

Fetch API, localStorage ו-סיכום

Fetch = HTTP מהדפדפן. localStorage = שמירה מקומית. ES Modules = ארגון קוד. כל אלה הם הבסיס לאפליקציה מלאה.

Fetch API

// GET Request: async function getUsers() { const response = await fetch("https://api.example.com/users"); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } const data = await response.json(); // פרסור JSON return data; } // POST Request: async function createUser(userData) { const response = await fetch("https://api.example.com/users", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${getToken()}`, }, body: JSON.stringify(userData), // object → JSON string }); if (!response.ok) throw new Error("Request failed"); return response.json(); }

localStorage

// שמירה — ערכים חייבים להיות strings localStorage.setItem("theme", "dark"); localStorage.setItem("user", JSON.stringify({ name: "Alice" })); // קריאה const theme = localStorage.getItem("theme"); // "dark" or null const user = JSON.parse(localStorage.getItem("user") || "null"); // מחיקה localStorage.removeItem("theme"); localStorage.clear(); // מחיקת הכל
⚠️ localStorage ואבטחה
localStorage נגיש ל-כל JS על אותו Origin — כולל XSS! לעולם אל תשמור: tokens, sessions, passwords ב-localStorage. Token נכון = HttpOnly Cookie. localStorage מתאים ל: Preferences, UI state, cached data לא רגיש.

ES Modules

// utils.js — יצוא export const PI = 3.14159; export function add(a, b) { return a + b; } export default class Calculator { /* ... */ } // main.js — ייבוא import Calculator from "./utils.js"; // default import import { PI, add } from "./utils.js"; // named imports import { add as sum } from "./utils.js"; // alias import * as Utils from "./utils.js"; // הכל // ב-HTML: <script type="module" src="main.js"></script> // type="module": defer אוטומטי, strict mode, own scope
✓מה למדנו — שיעור 16
  • ES6+: const/let (לא var!), Arrow functions, Destructuring, Spread, Optional Chaining (?.), Nullish (??)
  • DOM: querySelector, classList, addEventListener, Event Delegation, Bubbling
  • Event Loop: Microtasks (Promise.then) לפני Callbacks (setTimeout)!
  • Closures: פונקציה שסגורה על scope יצירתה. var בלולאה = באג. let = תיקון.
  • Async: Callback Hell → Promises (.then/.catch) → async/await (קריא)
  • Fetch: תמיד בדוק response.ok. POST עם JSON.stringify. לא throw על 404.
  • localStorage: JSON.stringify/parse. אסור ל-tokens! HttpOnly Cookie = נכון.
  • ES Modules: import/export, default vs named, dynamic import
🎯 לפני שיעור 17 (React)
כתוב Search Component מלא שמחפש ב-GitHub API, עם Debounce + Loading state + Error handling + שמירת היסטוריה ב-localStorage.
✏תרגול סיכום — גאמא סטייל5 שאלות
סיכום 1 — Spread copy
const obj={x:1}; const copy={...obj}; copy.x=99; console.log(obj.x);
✓ תשובה: ב) 1 — Spread יוצר shallow copy — copy הוא object חדש. שינוי copy.x לא משפיע על obj.x (primitives = by value).
סיכום 2 — Array destructuring
const arr=[1,2,3]; const [, second]=arr; console.log(second);
✓ תשובה: א) 2 — [, second] = דילוג על אלמנט ראשון. second = arr[1] = 2.
סיכום 3 — localStorage object
localStorage.setItem("key", {a:1}); מה נשמר?
✓ תשובה: ד) "[object Object]" — localStorage מקבל strings. Object ממיר ל-string אוטומטית. תיקון: JSON.stringify({a:1})!
סיכום 4 — שאילתה מקבילה
הדרך המהירה ביותר לשלוח 3 API calls במקביל?
✓ תשובה: ד) — Promise.all מריץ הכל במקביל. אפשרות א = סדרתי (זמן כולל = סכום). ב = מקביל (זמן כולל = הארוך שבהם).
סיכום 5 — flat
const result = [1, [2, [3]]].flat(Infinity);
✓ תשובה: א) [1,2,3] — flat(Infinity) מפרק מערכים מקוננים לכל העומק. flat(1) = [1, 2, [3]].
// תרגול נוסף

תרגול נוסף — JavaScript: Event Loop ו-Promises

שאלות העשרה נוספות לחיזוק החומר של השיעור — באותו פורמט בחירה של הקורס.

✏תרגול נוסף3 שאלות
שאלה 1 [בינוני]
מה הפלט?
console.log("A");
setTimeout(() => console.log("B"), 0);
Promise.resolve().then(() => console.log("C"));
console.log("D");
✓ תשובה נכונה: ב — סדר: (1) סינכרוני A, D. (2) Microtasks — Promise .then → C. (3) Macrotasks — setTimeout → B. לכן 'A D C B'.
שאלה 2 [בינוני]
מה ההבדל בין async function לפונקציה רגילה?
✓ תשובה נכונה: ד — async מחזירה Promise תמיד; await בתוכה 'מחכה' לתוצאה בלי לחסום את ה-Thread. סוכר תחבירי מעל Promises.
שאלה 3 [קשה]
מה הבעיה בקוד?
async function getAll(ids) {
  const results = [];
  for (const id of ids) {
    const data = await fetch(`/api/${id}`);
    results.push(await data.json());
  }
  return results;
}
✓ תשובה נכונה: ד — await בלולאה = בקשות טוריות (זו אחרי זו). Promise.all(ids.map(id => fetch(...))) מריץ במקביל. שיפור דרמטי לזמן תגובה.
// אתגר מעשי

אתגר מעשי — JavaScript: אירועים ו-Async

שיא השיעור: לממש את הלוגיקה שמאחורי ה-Web — פרסור, אירועים, state ואבטחה. פתרו את החובה ואז את האתגר; ההגשה נבדקת אוטומטית מול מקרי-קצה נסתרים.

T2 · בסיסי250 נק'~18 דק'algorithmic
EventEmitter — מערכת אירועים
ממש מחלקה EventEmitter המדמה את מערכת האירועים של הדפדפן: on(event, handler) רושם handler · off(event, handler) מסיר · emit(event, *args) קורא לכל ה-handlers של האירוע לפי סדר הרישום ומחזיר רשימה של הערכים שהם החזירו. אירוע לא-מוכר → רשימה ריקה.
דוגמאות
em.on('e', f1); em.on('e', f2); em.emit('e', 10) # f1=x+1, f2=x*2 → [11, 20]
em.off('e', f1); em.emit('e', 10) → [20]
em.emit('unknown') → []
הפתרון נשמר מקומית ומשותף עם עמוד „כתיבת קוד”.
פתרון-ייחוס EventEmitter — מערכת אירועים ›
class EventEmitter: def __init__(self): self._h = {} def on(self, ev, fn): self._h.setdefault(ev, []).append(fn) def off(self, ev, fn): if fn in self._h.get(ev, []): self._h[ev].remove(fn) def emit(self, ev, *args): return [fn(*args) for fn in self._h.get(ev, [])] # לפי סדר הרישום
T3 · בינוני350 נק'~25 דק'algorithmic
Debounce על זרם אירועים
ב-JS משתמשים ב-debounce כדי לא להפעיל handler על כל הקשה. נתונה רשימת אירועים events, כל אחד (t, key), ממוינת לפי t, וחלון w. אירוע 'נורה' אם אין אירוע נוסף *עם אותו key* בתוך w יחידות זמן אחריו (כלומר עבר שקט של יותר מ-w, או שזה האירוע האחרון של אותו key). החזר את האירועים שנורו לפי סדר הופעתם.
דוגמאות
debounce([(0,'a'),(1,'a'),(5,'a')], 2) → [(1, 'a'), (5, 'a')]
debounce([(0,'x'),(1,'x')], 5) → [(1, 'x')]
הפתרון נשמר מקומית ומשותף עם עמוד „כתיבת קוד”.
פתרון-ייחוס Debounce על זרם אירועים ›
def debounce(events, w): fired = [] for i, (t, k) in enumerate(events): nxt = next((t2 for t2, k2 in events[i+1:] if k2 == k), None) if nxt is None or nxt - t > w: # אין אירוע-המשך לאותו מפתח בתוך החלון fired.append((t, k)) return fired
שאלות תרגול ותשובות (10)

שאלה 1 · מה יודפס?

const arr = [1, 2, 3];
arr.push(4);
console.log(arr.length);
  • א. 4
  • ב. 3
  • ג. שגיאה — arr הוא const
  • ד. undefined
תשובה: א

const אוסר השמה מחדש, לא שינוי תוכן. push מוסיף איבר → 4.

שאלה 2 · מה ערך x?

const { a: x = 10 } = { b: 5 };
  • א. 5
  • ב. 10
  • ג. undefined
  • ד. שגיאה
תשובה: ב

המפתח a לא קיים באובייקט → נכנסת ברירת המחדל 10.

שאלה 3 · מה מחזיר typeof null?

console.log(typeof null);
  • א. "object"
  • ב. "null"
  • ג. "undefined"
  • ד. "boolean"
תשובה: א

באג היסטורי שנשמר לתאימות לאחור — typeof null הוא תמיד "object".

שאלה 4 · מה יודפס בשתי השורות?

console.log(0 || "default");
console.log(0 ?? "default");
  • א. default, default
  • ב. default, 0
  • ג. 0, 0
  • ד. 0, default
תשובה: ב

|| בודק falsy (0 נופל), ?? בודק רק null/undefined (0 נשמר).

שאלה 5 · למה עדיף textContent על innerHTML כשמציגים קלט משתמש?

  • א. הוא מהיר יותר
  • ב. הוא כותב טקסט בלבד ולא מריץ HTML/סקריפט
  • ג. הוא תומך בעברית
  • ד. הוא שומר על עיצוב CSS
תשובה: ב

innerHTML מפרסר HTML → פתח ל-XSS. textContent מכניס מחרוזת בלבד.

שאלה 6 · מהו Event Delegation?

  • א. רישום מאזין לכל אלמנט בנפרד
  • ב. ביטול בועות האירוע
  • ג. מאזין אחד על ההורה שמזהה את היעד דרך event.target
  • ד. הרצת אירועים בתוך Web Worker
תשובה: ג

מאזין אחד על ההורה חוסך זיכרון ועובד גם על אלמנטים שנוספו אחרי הטעינה.

שאלה 7 · מה סדר ההדפסה?

console.log("A");
setTimeout(() => console.log("B"), 0);
Promise.resolve().then(() => console.log("C"));
console.log("D");
  • א. A D C B
  • ב. A B C D
  • ג. A C D B
  • ד. A D B C
תשובה: א

קוד סינכרוני (A, D) → Microtasks (Promise: C) → Macrotasks (setTimeout: B). 🎯 דגש למבחן — מעקב אחרי ה-Event Loop: ציירו בטיוטה 3 עמודות — Call Stack | Microtasks | Macrotasks. כל שורה נכנסת לעמודה שלה, ואז שולפים לפי הסדר: קודם כל ה-Stack, אחריו כל ה-Microtasks, ורק בסוף Macrotask אחד.

שאלה 8 · מה יודפס?

function counter() {
  let c = 0;
  return () => ++c;
}
const inc = counter();
inc(); inc();
console.log(inc());
  • א. 1
  • ב. 3
  • ג. undefined
  • ד. שגיאה — c לא בטווח
תשובה: ב

Closure: הפונקציה המוחזרת שומרת גישה ל-c גם אחרי שה-counter הסתיים → 1,2,3.

שאלה 9 · למה התנאי הזה לא מספיק כדי לזהות כישלון?

const res = await fetch(url);
const data = await res.json();
  • א. צריך גם try/catch על json בלבד
  • ב. fetch לא זורק שגיאה על 404/500 — חייבים לבדוק res.ok
  • ג. fetch מחזיר מחרוזת ולא אובייקט
  • ד. חייבים להוסיף method: "GET"
תשובה: ב

fetch נדחה רק על תקלת רשת. תגובת 404/500 מגיעה כ-resolved — לכן בודקים res.ok.

שאלה 10 · מה נכון לגבי localStorage?

  • א. הוא מוצפן על ידי הדפדפן
  • ב. הוא נמחק בסגירת הלשונית
  • ג. הוא נגיש ל-JavaScript ולכן אסור לשמור בו טוקנים
  • ד. הוא נשלח אוטומטית בכל בקשה לשרת
תשובה: ג

localStorage נשמר כטקסט גלוי ונגיש מכל סקריפט בדף — XSS גונב אותו מיד. sessionStorage הוא זה שנמחק בסגירת הלשונית.