סגירות ב-JavaScript

סגירות ב-JavaScript

מאמר זה מסביר את מנגנון ה-closure ב-JavaScript.

YouTube Video

סגירות ב-JavaScript

ב-JavaScript, 'closure' הוא אחד המושגים החשובים והחזקים ביותר. על ידי הבנה של closures, ניתן להרוויח ידע שמועיל במצבים רבים, כמו התנהגות וטווח של פונקציות, וכן עיבוד אסינכרוני וטיפול באירועים ב-JavaScript. כאן נסביר בפירוט כל דבר, מההגדרה הבסיסית של closures ועד לדוגמאות קונקרטיות ויישומים שלהן.

מהו Closure?

closure מתייחס למנגנון שבו פונקציה יכולה לגשת למשתנים בתחום שבו נוצרה, גם כאשר היא נקראת מחוץ לתחום זה. באמצעות שימוש ב-closures, פונקציות יכולות להמשיך 'לזכור' משתנים חיצוניים.

closure מורכב מהשני מרכיבים הבאים.

  1. הגדרת הפונקציה (הפונקציה עצמה)

  2. תחום בו הפונקציה מוגדרת (משתנים ופונקציות נוספות מחוץ לפונקציה עצמה)

ב-JavaScript, closures אפשריים בגלל שלפונקציות יש יכולת לגשת למשתנים בטווח שבו הן נוצרו.

דוגמה בסיסית

ראשית, בוא נבחן דוגמה בסיסית של closure. בקוד הבא, outerFunction מחזירה פונקציה בשם innerFunction. הנקודה החשובה היא ש-innerFunction יכולה לגשת למשתנה בשם count שהוגדר בתחום של outerFunction.

 1function outerFunction() {
 2    let count = 0;
 3
 4    function innerFunction() {
 5        count++;
 6        console.log(`Current count: ${count}`);
 7    }
 8
 9    return innerFunction;
10}
11
12const counter = outerFunction();
13counter(); // Current count: 1
14counter(); // Current count: 2
15counter(); // Current count: 3

כיצד closures פועלים

כפי שנראה בדוגמה למעלה, count נשמר ב-innerFunction גם לאחר ש-outerFunction בוצעה. innerFunction יכולה להמשיך ולגשת לטווח של outerFunction, ולכן count מתעדכן בתוך innerFunction. זוהי המנגנון הבסיסי של closure.

זו היא innerFunction המושמת במשתנה בשם counter, ואנו רואים כי המצב של count נשמר למרות ש-outerFunction כבר הושלם. הסיבה לכך היא ש-JavaScript 'זוכרת' את התחום בזמן שבו הפונקציה הוגדרה.

שימוש בפועל: closures כמשתנים פרטיים

closures יכולים לשמש כ'משתנים פרטיים' בתכנות מונחה עצמים. בדרך כלל, ב-JavaScript, תכונות של אובייקטים גלויות לגישה ישירה מבחוץ, אך באמצעות שימוש ב-closures, ניתן למנוע גישה ישירה למשתנים מתוך תחום הפונקציה.

בדוגמה הבאה, הפונקציה createCounter משתמשת ב-closure כדי ליצור מונה ומחזירה מונה עם משתנה פרטי בשם count.

 1function createCounter() {
 2    let count = 0;
 3
 4    return {
 5        increment: function() {
 6            count++;
 7            console.log(`Count: ${count}`);
 8        },
 9        decrement: function() {
10            count--;
11            console.log(`Count: ${count}`);
12        },
13        getCount: function() {
14            return count;
15        }
16    };
17}
18
19const myCounter = createCounter();
20myCounter.increment(); // Count: 1
21myCounter.increment(); // Count: 2
22myCounter.decrement(); // Count: 1
23console.log(myCounter.getCount()); // 1

בדוגמה זו, count נמצא בטווח של הפונקציה createCounter, ולכן אין אפשרות לגשת אליו ישירות מבחוץ. עם זאת, ניתן להשפיע עליו באמצעות השיטות increment ו-decrement. בדרך זו, באמצעות שימוש ב-closures, ניתן להכניס את מושג המשתנים הפרטיים ב-JavaScript.

דוגמאות מעשיות ל-closures

שילוב עם פונקציות callback

closures לעיתים משולבים עם פונקציות callback לניהול עיבוד אסינכרוני. לדוגמה, נשקול דוגמה עם טיימר.

 1function startTimer(duration) {
 2    let timeLeft = duration;
 3
 4    function countdown() {
 5        console.log(`Time left: ${timeLeft} seconds`);
 6        timeLeft--;
 7
 8        if (timeLeft >= 0) {
 9            setTimeout(countdown, 1000);
10        }
11    }
12
13    countdown();
14}
15
16startTimer(5);
17// Time left: 5 seconds
18// Time left: 4 seconds
19// Time left: 3 seconds
20// Time left: 2 seconds
21// Time left: 1 second
22// Time left: 0 seconds

בדוגמה הזו, פונקציית countdown ניגשת למשתנה timeLeft בתחום של startTimer. בדרך זו, closures שימושיים מאוד לעיבוד אסינכרוני כמו טיימרים, כי הם שומרים על מצב המשתנים לאורך זמן.

מטפלי אירועים (Event Handlers)

closures נוחים גם בעת הגדרת מטפלי אירועים. בדוגמה הבאה, נעשה שימוש ב-closure לתיעוד מספר הלחיצות על כפתור.

 1function setupClickCounter(buttonId) {
 2    let clickCount = 0;
 3
 4    const button = document.getElementById(buttonId);
 5    button.addEventListener('click', function() {
 6        clickCount++;
 7        console.log(`Button clicked ${clickCount} times`);
 8    });
 9}
10
11setupClickCounter('myButton');

במקרה זה, הערך של clickCount גדל בכל לחיצה ונשמר. באמצעות שימוש ב-closures, ניתן להקצות מונה עצמאי לכל כפתור.

סיום

closures הם מושג שמסמל את הגמישות והעוצמה של JavaScript. הם מחזיקים משתנים הסגורים בטווח של פונקציה ומאפשרים פעולות עליהם דרך פונקציות הנגישות מבחוץ. בהבנה ושימוש במנגנון הזה, ניתן לרכוש טכניקות מתקדמות יותר בתכנות JavaScript.

היישום של closures נפוץ במצבים שונים, החל מטיפול באירועים ועיבוד אסינכרוני ועד ליישום מדומה של תכנות מונחה עצמים.

תוכלו לעקוב אחר המאמר שלמעלה באמצעות Visual Studio Code בערוץ היוטיוב שלנו. נא לבדוק גם את ערוץ היוטיוב.

YouTube Video