בדיקות null ב JavaScript
בפוסט היום נראה שלושה אופרטורים לבדיקת Null Values והתמודדות עם ערכים ריקים.
1. למה להתמודד עם ערכים ריקים
תוכניות JavaScript משתמשות בערכים ריקים כדי לייצג שגיאה או מידע חסר. בכל תוכנית שאנחנו כותבים נרצה להתמודד עם שגיאות או מידע חסר בתוך חישובים מורכבים. השאלה היא מה עושים עם המידע החסר או השגיאה מחישובים קודמים בכתיבת חישוב מורכב. האפשרויות הן:
לזהות שיש מידע חסר ולעצור את החישוב המורכב.
להמשיך את החישוב עם "המידע החסר", ומי שצריך את התוצאה של החישוב כבר יתמודד עם הבעיה.
נדמיין פונקציה שמקבלת מערך ומספר ומחזירה את מספר המספרים מהמערך הגדולים מהמספר שקיבלה:
function largerThan(items, start) {
return items.filter(x => x > start).length;
}
מה קורה אם מנסים להפעיל אותה אבל מעבירים רק את items בלי start? מה אנחנו רוצים שיקרה? הגישה הראשונה היא לזהות בתוך הפונקציה שחסר מידע ולעצור את החישוב באמצעות זריקת קוד שגיאה. גישה זו עובדת כשאנחנו יודעים שהקוד החיצוני הפעיל את largerThan
בתוך בלוק try/catch ומוכן להתמודד גם עם מסלול ההצלחה וגם עם מסלול הטעות.
גישה שניה אומרת שננסה להתמודד באמצעות הכנסת הערך החסר לתוך החישוב, כלומר נחזיר למי שקרא לנו את הערך 0 או אפילו את הערך null, מתוך הבנה שמי שקרא לפונקציה יוכל לטפל בחישוב עם הערך החסר. התמודדות כזאת עם ערכים ריקים יכולה לאפשר כתיבת קוד ממוקד יותר שיש לו רק מסלול פעולה אחד.
בקוד הדוגמה אגב אם אנחנו מעבירים רק פרמטר אחד לפונקציה היא תחזיר 0 וכך גם אם נעביר טקסט או undefined בתור הפרמטר השני, אבל אם נעביר null היא תהפוך את ה null ל 0 ותחזיר את מספר האיברים במערך שגדולים מאפס, וזו התנהגות קצת מבלבלת.
גירסת ES2020 הוסיפה שתי פעולות לעבודה עם ערכי null ב JavaScript מבוססות על סימן השאלה.
2. אופרטור Nullish coalescing
אופרטור ??
נקרא Nullish Coalescing ותפקידו לבחור את הערך שאינו null מבין שני ערכים. נוכל להשתמש בו באופן הבא:
function printTimes(text, aTimes) {
const times = aTimes ?? 5;
for (let i=0; i < times; i++) {
console.count(text);
}
}
הפונקציה תדפיס את הטקסט שהיא קיבלה times פעמים, או אם times אינו מוגדר או null היא תשתמשת בברירת המחדל 5. נשים לב שאם מעבירים ערך 0 או false ל aTimes אז הערך של times יהיה 0 והטקסט לא יודפס.
3. השמה ובדיקת null
אפשר לשלב את ??
עם אופרטור השמה וזה נראה כך:
function printTimes(text, times) {
times ??= 5;
for (let i=0; i < times; i++) {
console.count(text);
}
}
התוצאה זהה - אם times היה null או לא מוגדר נשמור בו את הערך 5, בכל מצב אחר הוא ישמור על ערכו.
4. שרשור אופציונאלי Optional Chaining
פעולה אחרונה שקשורה לעבודה עם ערכים ריקים בחישוב ולכן הכנסתי אותה לרשימה זו (למרות שהיא לא לגמרי קשורה לפעולות על null) נקראת Optional Chaining. הרעיון שלה הוא לאפשר לנו להמשיך חישוב גם כשחסר שדה באוביקט, מתוך הנחה שבהמשך התוכנית מישהו כבר ידע להתמודד עם הערך הריק.
נתבונן בדוגמה הבאה:
const data = {
x: { times: 7 },
y: { times: 2 },
};
const f = (what) => printTimes(what, data[what].times);
אפשר להשתמש בפונקציה כדי להדפיס את x או y באופן הבא:
f('x');
f('y');
אבל אם ננסה להשתמש בה כדי להדפיס משהו שלא נמצא באוביקט למשל את המחרוזת z נקבל שגיאה - הערך של data[what]
הוא undefined ולכן אי אפשר לגשת לשדה times שלו.
פעולת Optional Chaining מאפשרת לדלג על השגיאה הזאת ובמצב בו מנסים לגשת לשדה של undefined היא מחזירה undefined במקום לזרוק שגיאה. הפעולה מסומנת עם ?.
ובדוגמה שלנו תיראה כך:
const f = (what) => printTimes(what, data[what]?.times);
f('z');
הפעם ההדפסה האחרונה לא זורקת שגיאה ומדפיסה את הטקסט 5 פעמים - הפונקציה printTimes נקראת עם ערך undefined במשתנה השני ותשתמש בברירת המחדל שלה 5 כדי להדפיס.