לדלג לתוכן

4.1 קלוז׳רים וסקופ תרגול

תרגול - קלוז׳רים וסקופ


תרגיל 1 - חידות scope chain

מה ידפיס כל אחד מקטעי הקוד הבאים? ענו בלי להריץ, ואז בדקו.

חידה א:

let x = 1;

function a() {
    let x = 2;

    function b() {
        console.log(x);
    }

    return b;
}

const fn = a();
fn();

חידה ב:

let count = 0;

function increment() {
    count++;
    console.log(count);
}

function reset() {
    let count = 0;
    console.log(count);
}

increment();
increment();
reset();
increment();

חידה ג:

function outer() {
    let x = 10;

    function middle() {
        let y = 20;

        function inner() {
            let z = 30;
            console.log(x + y + z);
        }

        x = 100;
        inner();
    }

    middle();
}

outer();

תרגיל 2 - מונה עם closure

כתבו פונקציה createCounter שמקבלת ערך התחלתי ומחזירה אובייקט עם הפונקציות הבאות:

  • increment() - מעלה את הערך ב-1 ומחזירה את הערך החדש
  • decrement() - מורידה את הערך ב-1 ומחזירה את הערך החדש
  • getValue() - מחזירה את הערך הנוכחי
  • reset() - מחזירה את הערך לערך ההתחלתי
const counter = createCounter(10);
console.log(counter.increment()); // 11
console.log(counter.increment()); // 12
console.log(counter.decrement()); // 11
console.log(counter.getValue());  // 11
counter.reset();
console.log(counter.getValue());  // 10

ודאו שלא ניתן לגשת ישירות למשתנה הפנימי מבחוץ.


תרגיל 3 - פונקציית memoize

כתבו פונקציה memoize שמקבלת פונקציה ומחזירה גרסה ממואיזית שלה. הגרסה הממואיזית שומרת תוצאות קודמות ומחזירה אותן מהמטמון אם אותם ארגומנטים כבר חושבו.

function slowSquare(n) {
    console.log("Computing...");
    return n * n;
}

const fastSquare = memoize(slowSquare);

console.log(fastSquare(5));  // "Computing..." -> 25
console.log(fastSquare(5));  // 25 (no "Computing..." - from cache)
console.log(fastSquare(3));  // "Computing..." -> 9
console.log(fastSquare(5));  // 25 (from cache)

בונוס: הוסיפו מתודה cache.clear() שמנקה את המטמון.


תרגיל 4 - משתנים פרטיים

צרו פונקציה createPasswordManager שמחזירה אובייקט לניהול סיסמה:

  • setPassword(newPassword) - מגדירה סיסמה חדשה (מינימום 8 תווים, אחרת מחזירה false)
  • checkPassword(attempt) - בודקת אם הסיסמה נכונה ומחזירה true/false
  • getHint() - מחזירה את שני התווים הראשונים של הסיסמה ואחריהם כוכביות

הסיסמה עצמה חייבת להיות בלתי נגישה מבחוץ.

const pm = createPasswordManager();
pm.setPassword("abc");            // false (too short)
pm.setPassword("mySecret123");    // true
pm.checkPassword("wrong");        // false
pm.checkPassword("mySecret123");  // true
pm.getHint();                     // "my*********"

תרגיל 5 - closure בלולאה

חלק א - זהו את הבאג

מה ידפיס הקוד הבא ולמה?

const buttons = [];

for (var i = 0; i < 5; i++) {
    buttons.push({
        label: `Button ${i}`,
        click: function() {
            console.log(`Clicked button ${i}`);
        }
    });
}

buttons[0].click();
buttons[2].click();
buttons[4].click();

חלק ב - תקנו את הבאג

תקנו את הקוד בשתי דרכים שונות:
1. באמצעות let
2. באמצעות IIFE


תרגיל 6 - תבנית המודול - module pattern

צרו מודול TaskManager באמצעות IIFE ו-closures שמנהל רשימת משימות:

  • addTask(title) - מוסיפה משימה חדשה עם id ייחודי (אוטומטי) ו-done: false
  • completeTask(id) - מסמנת משימה כ-done: true
  • removeTask(id) - מוחקת משימה
  • getTasks() - מחזירה עותק של כל המשימות
  • getPending() - מחזירה רק משימות שלא הושלמו
  • getStats() - מחזירה אובייקט עם { total, done, pending }
TaskManager.addTask("Learn closures");
TaskManager.addTask("Practice exercises");
TaskManager.addTask("Build project");

console.log(TaskManager.getStats()); // { total: 3, done: 0, pending: 3 }

TaskManager.completeTask(1);
console.log(TaskManager.getPending().length); // 2
console.log(TaskManager.getStats()); // { total: 3, done: 1, pending: 2 }

תרגיל 7 - createMultiplier ושרשרת פונקציות

חלק א

כתבו פונקציה createMultiplier(factor) שמחזירה פונקציה שמכפילה מספר ב-factor:

const double = createMultiplier(2);
const triple = createMultiplier(3);

console.log(double(5));  // 10
console.log(triple(5));  // 15

חלק ב

כתבו פונקציה compose(...fns) שמקבלת מספר כלשהו של פונקציות ומחזירה פונקציה חדשה שמפעילה אותן בזו אחר זו (מימין לשמאל):

const double = createMultiplier(2);
const addOne = (x) => x + 1;
const square = (x) => x * x;

const transform = compose(addOne, double, square);
// transform(3) should compute: square(3) -> 9, double(9) -> 18, addOne(18) -> 19

console.log(transform(3)); // 19
console.log(transform(5)); // 51

הסבירו: איפה ה-closure בפונקציה compose?