סגירות ב-JavaScript
מאמר זה מסביר את מנגנון ה-closure ב-JavaScript.
YouTube Video
סגירות ב-JavaScript
ב-JavaScript, 'closure' הוא אחד המושגים החשובים והחזקים ביותר. על ידי הבנה של closures, ניתן להרוויח ידע שמועיל במצבים רבים, כמו התנהגות וטווח של פונקציות, וכן עיבוד אסינכרוני וטיפול באירועים ב-JavaScript. כאן נסביר בפירוט כל דבר, מההגדרה הבסיסית של closures ועד לדוגמאות קונקרטיות ויישומים שלהן.
מהו Closure?
closure מתייחס למנגנון שבו פונקציה יכולה לגשת למשתנים בתחום שבו נוצרה, גם כאשר היא נקראת מחוץ לתחום זה. באמצעות שימוש ב-closures, פונקציות יכולות להמשיך 'לזכור' משתנים חיצוניים.
closure מורכב מהשני מרכיבים הבאים.
-
הגדרת הפונקציה (הפונקציה עצמה)
-
תחום בו הפונקציה מוגדרת (משתנים ופונקציות נוספות מחוץ לפונקציה עצמה)
ב-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 בערוץ היוטיוב שלנו. נא לבדוק גם את ערוץ היוטיוב.