איזה כיף שיש כבר Generators ב JavaScript
הרבה אומרים שאופטימיות מובילה להצלחה בחיים. בתכנות בכל מקרה האופטימיות מביאה בדרך כלל למבנה קוד שנקרא רקורסיה. יש לזה אפילו ביטוי באנגלית: Wishful Thinking. בואו נראה איך זה קורה ואיך זה קשור ל Generators.
1. האתגר
ניקח לדוגמא את אתגר מגדלי האנוי. באתגר יש לנו שלושה עמודים ועל העמוד הראשון מושחלות טבעות בקוטר הולך וקטן, כלומר בתחתית כל עמוד נמצאת הטבעת הגדולה ביותר, אחריה טבעת קצת יותר קטנה וכך הלאה עד הטבעת העליונה ביותר שהיא הקטנה ביותר.
המשימה שלנו היא להעביר את כל הטבעות מהעמוד הראשון לעמוד השלישי כך שגם בעמוד השלישי הטבעות יהיו מסודרות מהגדולה לקטנה - אבל וזה הטריק - מותר להזיז רק טבעת אחת כל פעם, ואסור להניח אותה על טבעת שקטנה ממנה.
2. הגישה האופטימית
לתרגיל הזה יש פיתרון רקורסיבי ממש פשוט:
function hanoi(size, start, end, extra) {
if (size > 0) {
hanoi(size - 1, start, extra, end);
console.log(`Move from ${start} to ${end}`);
hanoi(size - 1, extra, end, start);
}
}
hanoi(3, 'a', 'b', 'c');
אבל הבעיה עם פיתרונות רקורסיביים היא שקשה לעבוד איתם. נסו לדמיין איך יראה קוד שבלחיצה על כפתור מזיז רק טבעת אחת בין שני עמודים. הפיתרון הרקורסיבי לוקח גישה של "הכל או כלום" ובעצם רק בסיום הפעלת הפונקציה אנחנו מקבלים את כל התוצאות, ואין לנו שום נקודת התערבות באמצע.
3. גנרטורים ב JavaScript
פיצ'ר חמוד ויחסית לא נפוץ של JavaScript שנקרא Generators מאפשר לעקוף בקלות את הבעיה. בעזרת Generators נוכל להוסיף לפונקציה אינסוף נקודות יציאה באמצע הריצה שלה, כך שקוד חיצוני יוכל כל פעם להתקדם רק קצת עד נקודת היציאה הבאה. זה נקרא Generator כי במקום פונקציה שמחזירה ערך בודד תהיה לנו פונקציה שמחזירה סידרה של ערכים, וכל פעם בעצם יודעת איך לבנות את הערך הבא.
כך זה נראה אחרי שכתוב ל Generators:
function* hanoi(size, start, end, extra) {
if (size > 0) {
yield* hanoi(size - 1, start, extra, end);
yield [start, end];
yield *hanoi(size - 1, extra, end, start);
}
}
const solution = hanoi(3, 'a', 'b', 'c');
for (let step of solution) {
const [start, end] = step;
console.log(`Move from ${start} to ${end}`);
}
ארגון הקוד מחדש איפשר לי להוציא החוצה את הלולאה - כך שעכשיו יש לי שליטה הרבה יותר מדויקת על מה מופעל ומתי. הקוד יכול להדפיס רק מספר מהלכים ראשונים או אפילו יותר נחמד, להתקדם מהלך-מהלך כל פעם שמשתמש לוחץ על כפתור.
ולסקרנים הכנתי דוגמא מלאה על קודפן שעושה בדיוק את זה: מתחילים עם 5 טבעות בעמוד השמאלי ביותר, כל לחיצה על הכפתור מזיזה טבעת אחת ובסוף כל הטבעות עוברות לפי החוקים לעמוד הימני ביותר. הקוד נמצא בקישור כאן: https://codepen.io/ynonp/pen/PoZgodw
ואפשר לשחק איתו גם לייב בהטמעה הבאה:
4. וואו איזה מדליק! איפה אפשר ללמוד יותר על Generators ב JavaScript?
שאלה מצוינת! קורס JavaScript ES6/7/8 שלנו כאן בטוקוד ילמד אתכם כל מה שחלמתם לדעת (וקצת יותר) על היכולות החדשות של JavaScript מהשנים האחרונות ועל דרכים יצירתיות להשתמש בהן. יש שם על Generators, async/await, פונקציות חץ, כתיב ה import וכמובן Destructuring ועוד מלא נושאים קטנים שחשוב להכיר.
סילבוס, שיעורים לדוגמא וכל הפרטים בדף הקורס: קורס JavaScript ES6/7/8.