ECMAScript 6 – לולאת for of

על לולאת for of, ההבדל שלה מאיטרטורים אחרים ולמה היא נורא חשובה במקרה של גנרטורים.

במאמר הקודם דיברנו על גנרטורים ובסוף הזכרתי שממש מעניין וחשוב להשתמש בגנרטורים ב-for of. מה זו לולאת for of? בואו נדבר קצת על לולאות. הלולאה המוכרת ביותר, שאותה כולנו מכירים היא לולאת for. היא כבר די ותיקה. הנה היא להזכירכם:


var arr = [ 'a', 'b', 'c' ];

for (var i=0; i

יש כמה בעיות עם זה – בראשונה הוא מניח מערך ממוספר מ1 ועד n. אבל אם אין לנו כזה (למשל מערך שבו יש 5 איברים אבל מקום 2 ו-3 חסרים לחלוטין ומקומות 6 עד 7 מאוכלסים) אז הלולאה חסרת ערך לחלוטין.

בדיוק בשביל מקרים כאלו יש לנו את for in שעובד יפה עם מערכים ועם אובייקטים.


var person = {fname:'John', lname:'Doe', age:25}; 

for (var prop in person){
    if (Object.prototype.hasOwnProperty.call(person, prop)){
        console.log(prop+' : '+person[prop]); //"fname : John", "lname : Doe", "age : 25"
    }
}

מה הבעיה איתו? יש איתו כמה בעיות. הבעיה הראשונה היא שהוא לא עובר על איברי המערך או על תכונות האובייקט בסדר שאתה מצפה לו. בנוסף, הוא גם ידלג על איברים ריקים. הוא גם יעבור על כל האיברים המשותפים בשרשרת הפרוטוטייפ, יש גם בעיות עם המימוש שלו והוא באופן עקרוני לא מומלץ. אני אתן את הדוגמה הפשוטה ביותר :


let iterable = [3, 5, 7];
iterable.foo = "hello";

for (let i in iterable) {
  console.log(i); // logs 0, 1, 2, "foo"
}

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

יש גם את forEach שהיה אפשר להפעיל אותו על ערכים בלבד. הבעיה איתו שאי אפשר לעצור אותו באמצע הפעולה והוא עובד אך ורק במערך.

בגלל זה רוב האנשים השתמשו ב-lodash או ב-underscore ואפילו jQuery על מנת לעשות foreach כמו שצריך על מערך או על אובייקט. for of פותר את הבעיה במערכים ודומיהם כאשר הוא מספק דרך נוחה, קלה וניתנת לעצירה לבצע לולאות בלי להסתבך.

איך זה עובד? פשוט שבפשוטים:


var arr = ['hello', 'world', 'I', 'am', 'Ran'];

for ( var arrValue of arr ) {
  console.log(arrValue); // 'hello', 'world', 'I', 'am', 'Ran'
}

אם אני אוסיף כל מיני דברים מוזרים למערך (עם או בלי שרשרת פרוטוטייפ) ה-for of יתעלם באלגנטיות. הנה:


var arr = ['hello', 'world', 'I', 'am', 'Ran'];
arr.moshe = 'Levi';

for ( var arrValue of arr ) {
  console.log(arrValue); // 'hello', 'world', 'I', 'am', 'Ran'
}

אפשר לעבור גם על מחרוזות טקסט:


var string = 'hello';

for ( var value of string ) {
  console.log(value); // 'h', 'e', 'l', 'l', 'o'
}

גם בנוגע לאובייקטים יש מעקף נאה שאפשר לעשות:


var obj = { foo : 'hello', bar : 'world' };

for ( var key of Object.keys(obj) ) {
  console.log(key + "->" + obj[key]); // 'foo->hello', 'bar->world'
}

כפי שהבטחתי בהתחלה, אחד הדברים הטובים ב-for of זה שאפשר לשבור אותה באמצע. דבר מעולה כשמדברים על גנרטורים. רוצים דוגמה? הנה:


function* myGenerator() { // a generator function
  var curr = 0;
  while (true) {
    curr++;
    yield curr;
  }
}

for (var n of myGenerator()) {
  console.log(n);
  // truncate the sequence at 100
  if (n >= 100) {
    break;
  }
}

מה קורה פה? יש לנו גנרטור פשוט למדי שעושה איטרציה מ-0 עד אינסוף. בכל איטרציה הוא עושה yield. אני מפעיל את הלולאה for על ה-myGenerator, הלולאה תעבור על כל yield. כיוון שאין לי תנאי עצירה, אני אקבל 1,2,3,4 עד שה-for of יחליט לשבור את הגנרטור. במקרה שלנו כאשר המספר יהיה גדול או שווה למאה.
שימו לב שלא השתמשתי פה ב-next, האיטרטור for of עושה את זה בשבילי.

מסובך? אני אנסה עם דוגמה אחרת:


function* myGenerator() { // a generator function
yield 'a';
yield 'b';
yield 'c';
yield 44;
}

for (var n of myGenerator()) {
  console.log(n); //'a', 'b', 'c', 44
  
}

אולי זה יותר פשוט להבנה, במקום לעשות איזה foreach מגעיל ולעשות next באופן ידני כדי להביא את ה-yield הבא. אני מריץ באמצעות for of את הגנרטור. בכל איטרציה יש לי תוצאה של ה-yield בלי צורך ב-next. אני יכול לשבור את הfor of בכל רגע נתון כמובן עם break.

זו כמובן דוגמה תיאורטית. במציאות לגנרטור יהיו משימות יותר כבדות לבצע והמשמעות של שבירה תהיה משמעותית מבחינת ביצועים. מה שחשוב הוא שבעוד במקומות אחרים אני חייב לעשות next כל הזמן ולחשוב על המשמעות של next, בלולאת for of זה נעשה בשבילי ואני רק צריך לפרט תנאי עצירה. במידה ולא פירטתי, הגנרטור ימשיך עד שייגמרו לו ה-yield. מה שהופך את for of למאוד משמעותי בנוגע לגנרטורים. אולי יותר מכל דבר אחר.

פוסטים נוספים שכדאי לקרוא

DALL·E 2024-09-06 12.34.24 - A visually engaging post about Python and cryptographic problems. The image should feature a dark-themed background with a glowing, futuristic Python
פתרונות ומאמרים על פיתוח אינטרנט

בעיות במימוש של פונקציות קריפטוגרפיות בפייתון

היום (16 לספטמבר) ממש, אני מעביר הרצאה ב-PyconIL 2024 על בעיות קריפטוגרפיות באפליקציות פייתון. לצערי אי אפשר להכניס את כל הבעיות הקריפטוגרפיות להרצאה אחת או

גלילה לראש העמוד