אובייקט הוא שק של ערכים עם שמות
מערך מקבץ ערכים לפי מיקום. אובייקט מקבץ אותם לפי שם. כשלדבר שאתם ממדלים יש חלקים עם תוויות, משתמש עם שם וגיל, בקשה עם method ו-URL, השתמשו באובייקט.
הדרך הקצרה ביותר ליצור אחד היא ליטרל של אובייקט:
כל רשומה היא זוג key: value. מאחורי הקלעים המפתחות הם מחרוזות (המירכאות אופציונליות עבור מזהים תקינים כמו name). הערכים יכולים להיות כל דבר ש-JavaScript יודעת לייצג: מספרים, מחרוזות, ערכים בוליאניים, מערכים, פונקציות, ואפילו אובייקטים אחרים.
פסיק אחרי הרשומה האחרונה זה בסדר. רוב הצוותים משאירים אותו: זה שומר על diffs נקיים כשמוסיפים מאפיין חדש בהמשך.
קריאה וכתיבה של מאפיינים
שתי דרכים לגשת למאפיין: סימון נקודה וסימון סוגריים מרובעים.
סימון נקודה מסודר יותר, ובו תשתמשו כברירת מחדל. סימון סוגריים מרובעים מוכיח את עצמו כשהמפתח שמור במשתנה, או כשהמפתח אינו מזהה תקין:
קריאה של מאפיין שלא קיים מחזירה undefined, בלי שגיאה:
זה יכול להסתיר בשקט שגיאות הקלדה. אם אתם רוצים כישלון רועש, תצטרכו לבדוק את זה במפורש.
הוספה ומחיקה של מאפיינים
אובייקטים פתוחים לשינויים: אפשר להוסיף מפתחות בכל רגע:
ולהסיר אותם עם delete:
delete הוא אחד האופרטורים שלא תשתמשו בהם כל יום, אבל כשצריך להיפטר ממפתח לגמרי (ולא רק להציב בו undefined), זה הכלי הנכון. הצבה של user.email = undefined משאירה את המפתח: "email" in user עדיין יחזיר true.
בדיקה אם מאפיין קיים
שלוש דרכים, לכל אחת משמעות מעט שונה:
inבודק אם המפתח קיים, כולל מפתחות שעברו בירושה משרשרת ה-prototype.Object.hasOwn(obj, key)בודק רק את המפתחות העצמיים של האובייקט. השתמשו בו כשאתם רוצים להתעלם ממה שעבר בירושה. הוא מחליף את הקריאה הישנהhasOwnProperty.obj.key !== undefinedעובד ברוב המקרים, אבל משקר כשמאפיין הוגדר במפורש כ-undefined.
כשאתם לא בטוחים, בחרו ב-Object.hasOwn: הוא עושה את מה שכנראה התכוונתם.
מתודות: פונקציות שחיות על אובייקטים
מאפיין שהערך שלו הוא פונקציה נקרא מתודה. יש תחביר מקוצר להגדרה שלהן בתוך ליטרל של אובייקט:
this בתוך מתודה מתייחס לאובייקט שעליו המתודה נקראה, במקרה הזה user. כך greet יודעת של מי השם שבו להשתמש.
דבר אחד שכדאי לשים לב אליו: לפונקציות חץ אין this משלהן, ולכן הן הבחירה הלא נכונה למתודות שצריכות לקרוא מאפיינים אחרים של האובייקט:
השתמשו בתחביר המתודה המקוצר (greet() { ... }) לכל דבר שנוגע ב-this. פונקציות חץ מצוינות ל-callbacks, לא למתודות של אובייקטים.
אובייקטים מקוננים
גם ערכים יכולים להיות אובייקטים, לכל עומק:
קריאה של מאפיין מקונן עובדת בשרשור: user.address.city. המלכודת: אם אחד השלבים בדרך הוא null או undefined, תקבלו TypeError:
console.log(user.profile.city);
// TypeError: Cannot read properties of undefined (reading 'city')
Optional chaining (user.profile?.city) הוא הפתרון המודרני: הוא מחזיר undefined במקום לזרוק שגיאה כשחוליה חסרה. יש על זה עמוד נפרד בהמשך הפרק.
לולאה על אובייקט
כשצריך לעבור על כל מפתח באובייקט, המשפחה Object.keys, Object.values ו-Object.entries היא מה שאתם צריכים:
Object.entries הכי שימושי: הוא נותן לכם גם את המפתח וגם את הערך בבת אחת, ומשתלב יפה עם פירוק מערכים.
יש גם לולאת for...in, אבל היא עוברת גם על מאפיינים שעברו בירושה, ובדרך כלל זה לא מה שרוצים:
for (const key in scores) {
console.log(key); // works, but includes inherited keys
}
העדיפו Object.keys / Object.entries, אלא אם אתם רוצים במפורש גם מאפיינים שעברו בירושה.
תחביר מקוצר ששווה להכיר
שתי פיסות של סוכר תחבירי שתראו בכל מקום:
קיצור המאפיינים נכנס לפעולה כששם המשתנה תואם למפתח. מפתחות מחושבים (הצורה [expr]) מאפשרים לבנות שמות מאפיינים באופן דינמי: שימושי כשכותבים פונקציות שמעדכנות שדה לפי שם.
שוויון בין אובייקטים נבדק לפי הפניה
זה מפיל כמעט את כולם לפחות פעם אחת:
=== על אובייקטים בודק אם שני הצדדים מתייחסים לאותו אובייקט בזיכרון, לא אם יש להם אותו תוכן. שני אובייקטים עם מאפיינים זהים הם עדיין שני אובייקטים שונים.
כדי לבדוק "האם יש להם אותו מבנה?" תצטרכו להשוות שדות ידנית, או להשתמש בפונקציית עזר להשוואה עמוקה. JSON.stringify(a) === JSON.stringify(b) היא בדיקה מהירה ומלוכלכת שעובדת לנתונים פשוטים, אבל נכשלת על כל דבר עם פונקציות, undefined או הפניות מעגליות.
אובייקטים ניתנים לשינוי גם עם const
const נועל את המשתנה לערך אחד. הוא לא מקפיא את האובייקט שהערך מצביע עליו:
אם אתם באמת רוצים אי-שינוי, Object.freeze(user) עוצר שינויים נוספים (באופן רדוד: אובייקטים מקוננים עדיין ניתנים לשינוי). בפועל, רוב הקוד נשען על מוסכמות ולא על Object.freeze: התייחסו לאובייקטים ב-const כ"לא להציב מחדש את הקישור הזה", וטפלו באי-שינוי ברמת התכנון.
הבא בתור: מערכים
אובייקטים ומערכים הם שתי אבני הבניין שמהן בנוי כל השאר. אובייקטים מטפלים בנתונים עם תוויות; מערכים מטפלים בנתונים מסודרים. בהמשך: איך מערכים ב-JavaScript עובדים, וקומץ המתודות (push, slice, map וחברותיהן) שעושות את רוב העבודה הקשה.
שאלות נפוצות
איך יוצרים אובייקט ב-JavaScript?
הדרך הרגילה היא ליטרל של אובייקט: const user = { name: 'Ada', age: 30 }. הסוגריים המסולסלים מכילים זוגות של מפתח וערך מופרדים בפסיקים. המפתחות הם מחרוזות (המירכאות אופציונליות עבור מזהים תקינים), והערכים יכולים להיות כל דבר: מספרים, מחרוזות, מערכים, פונקציות, אובייקטים אחרים.
מה ההבדל בין סימון נקודה לסימון סוגריים מרובעים?
user.name ו-user['name'] עושים אותו דבר כשהמפתח הוא מזהה ידוע. השתמשו בסוגריים מרובעים כשהמפתח שמור במשתנה (user[key]), כשהוא מכיל תווים שסימון הנקודה לא יודע לפענח (רווחים, מקפים), או כשהוא מתחיל בספרה. לכל השאר סימון הנקודה מסודר יותר.
איך בודקים אם מאפיין קיים באובייקט?
השתמשו ב-'name' in user כדי לבדוק את המפתח, כולל מפתחות שעברו בירושה. השתמשו ב-Object.hasOwn(user, 'name') כדי לבדוק רק את המאפיינים העצמיים של האובייקט: זה התחליף המודרני ל-hasOwnProperty. גם בדיקה של user.name !== undefined עובדת, אבל היא משקרת אם המאפיין הוגדר במפורש כ-undefined.
איך עוברים בלולאה על אובייקט ב-JavaScript?
for (const key in obj) עובר על המפתחות, כולל אלה שעברו בירושה. בדרך כלל עדיף להשתמש ב-Object.keys(obj), Object.values(obj) או Object.entries(obj) עם לולאת for...of או .forEach(). Object.entries שימושי כשצריך גם את המפתח וגם את הערך באותה איטרציה.