ECMAScript 6 – שמירת מידע ב-Map ו-Set

מבני המידע החדשים והשימושיים להפליא של es6.

אחסון מידע היה מתבצע בג'אווהסקריפט באופן קבוע באובייקטים או במערכים של אובייקטים. לג'אווהסקריפט, עד ECMAScript 6 לא היה אובייקט מסוג map (ברוב השפות מבנה שאמור לשמור מידע) ולפכיך היינו צריכים להשתמש באובייקטים לאחסנת מידע. למשל:


var o = {1: 'a', 2: 'b'};

יש כמה בעיות עם חוסר באובייקט map מסודר. הראשונה היא שיש כמה פעולות שעושים על אובייקטים שעלולים להסתבך בגלל שרשרת הפרוטוטייפ ואובייקט עלול לרשת תכונות מאובייקט האב שלנו. זה מאוד בעייתי באיטרציות (ראינו שזה בעייתי באיטרציה forEach לאובייקטים) ובהערכת גדלים של אובייקטים. למשל, גודל של אובייקט:


Object.size = function(obj) {
    var size = 0, key;
    for (key in obj) {
        if (obj.hasOwnProperty(key)) size++;
    }
    return size;
};

// Get the size of an object
var size = Object.size(myArray);

גם יש בעיה עם המפתחות שתמיד חייבים להיות טקסט, למשל:


var o = {1: 'a', 2: 'b'};
o[1] // a
o['1'] // a

הקיצר, שימוש באובייקט כ-map הוא אפשרי אך בעייתי. תודה לאל, בדיוק בשביל זה יש את ECMAScript 6 ואובייקט map. עושים instance ל-map עם new ויש יש כמה מתודות בסיסיות: get ו-set שמשמשות להכנסה והוצאת נתונים לפי key value וכמובן את has שמחזירה בוליאני (כלומר true או false) אם יש בכלל את המפתח. הנה הדוגמאות המיוחלות:


var myMap = new Map();
    
myMap.set('foo', 123);
var a = myMap.get('foo');
console.log(a); //123
console.log(myMap.has('foo')); //true
myMap.delete('foo')
console.log(myMap.has('foo')); //false

כמובן שכל דבר (אפילו אובייקט) יכול להיות מפתח – בלי שום קשר לכך שהוא מספר או מחרוזת טקסט. למשל:


var myMap = new Map();
    
myMap.set(1, 'some value');
console.log(myMap.has(1)); //true
console.log(myMap.has('1')); //false


מתודות נוספות הן size שמחזירה את גודל ה-map ו-clear שמנקה אותו. פה אני מראה דוגמה כאשר כבר ביצירת ה-map אני מכניס איברים.


var myMap = new Map([
  [1, 'some value'],
  [2, 'another value']
  ]);
    
console.log(myMap.size); //2
myMap.clear();
console.log(myMap.size); //0

כמובן שקל לעשות איטרציות על map. ככה עושים את זה עם for of בנוגע ל-keys:


var myMap = new Map([
  [1, 'some value'],
  [2, 'another value']
  ]);
    
for (var key of myMap.keys()) {
    console.log(key);
} //1, 2

וגם עם values:


var myMap = new Map([
  [1, 'some value'],
  [2, 'another value']
  ]);
    
for (var value of myMap.values()) {
    console.log(value);
} //"some value", "another value"

חדי העין ישימו לב שהשתמשתי פה בשתי תכונות – values ו-keys שמוציאות מערך של המפתחות ושל הערכים. אפשר להוציא גם entries שהם מערך של ה-key וה-value:


var myMap = new Map([
  [1, 'some value'],
  [2, 'another value']
  ]);
    
for (var entry of myMap.entries()) {
    console.log(entry[0], entry[1]);
} //1 "some value", 2 "another value"

WeakMap

קשה להבין את WeakMap בלי להבין את עניין זליגות הזכרון של JavaScript. באופן עקרוני, WeakMapהוא בדיוק כמו map, רק שהוא מקבל רק אובייקטים כ-keys ואי אפשר לעשות לו איטרציה. כלומר יש את כל המתודות, אבל לא תצליחו לעשות לזה איטרציה. למה צריך את WeakMap בכלל? בשביל זה אני צריך להבין קצת בנושא זליגות זכרון. בואו נתאר מצב כזה – נניח שיש לי אלמנטים ב-DOM. את חלקם אני שומר ב-map מכל מיני סיבות. אם אני מוחק אותם מה-DOM. הייתי מצפה ש-JS יפנה את המקום בזכרון של האלמנטים האלו. אבל ה-map ישמור את הרפרנסים לאלמנטים האלו למרות שהם נמחקו! כי ה-garbage collector לא יבין שהוא יכול למחוק את האלמנטים האלו.
בדיוק בשביל זה יש לי את weakMap – המפתחות של ה-map הזה הם 'חלשים' ולא יכולים למנוע ממה שנכנס לתוכם להתפוגג כפלוץ ברוח. מאוד קשה להדגים את זה, אבל אני מקווה שהדוגמה הזו תהיה ברורה:

See the Pen ALrrBk by Ran Bar-Zik (@barzik) on CodePen.

בגדול – WeakMap היא כמו map, אבל עם אובייקטים בתור מפתחות ובלי size או איטרציה. אם אתם מאחסנים מידע באובייקטים ואחר כך מוחקים אותם. יש מצב ש-WeakMap יחסוך לכם הרבה צרות.

Set ו-WeakSet

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


var set = new Set();
set.add('red')
console.log(set.has('red')); //true
set.delete('red')
console.log(set.has('red')); //false

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


var set = new Set(['red', 'green', 'blue']);
for (var x of set) {
    console.log(x); //red, green, blue
}

יש לי גם את מתודת clear לניקוי מוחלט של ה-set ותכונת size לגודל ה-set.

כמו שיש לנו את WeakMap, יש לנו גם את WeakSet שיש לה שלוש מתודות – has, set ו-delete. גם WeakSet מאפשרת לזכרון להשתחרר אם אובייקטים שנכנסים לתוכה נמחקים.

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

תמונת תצוגה של מנעול על מחשב
פתרונות ומאמרים על פיתוח אינטרנט

הגנה מפני XSS עם Trusted Types

תכונה ב-CSP שמאפשרת מניעה כמעט הרמטית להתקפות XSS שכל מפתח ווב צריך להכיר וכדאי שיכיר.

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 על בעיות קריפטוגרפיות באפליקציות פייתון. לצערי אי אפשר להכניס את כל הבעיות הקריפטוגרפיות להרצאה אחת או

רספברי פיי

התקנת OpenCanary על רספברי פיי

מה זה OpenCanary ואיך אפשר להתקין אותה על רספברי פיי ולשדרג את אבטחת הרשת הביתית או המשרדית.

רספברי פיי

מה זה AIoT? ואיך אפשר להתחיל?

פוסט עם המון קישורים, מידע, סרטונים ופרק בפודקאסט שיפתח לכם שער לעולם ה-AIoT המרתק.

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