אובייקטים של JavaScript, סוגריים מרובעים ואלגוריתמים

אחד ההיבטים החזקים ביותר של JavaScript הוא היכולת להתייחס באופן דינמי למאפיינים של אובייקטים. במאמר זה נבחן כיצד זה עובד ואילו יתרונות זה עשוי לתת לנו. אנו נסתכל במהירות על כמה ממבני הנתונים המשמשים במדעי המחשב. בנוסף נבחן משהו שנקרא Big O notation המשמש לתיאור ביצועים של אלגוריתם.

אובייקטים מבוא

נתחיל ביצירת אובייקט פשוט המייצג מכונית. לכל אובייקט יש משהו שנקרא properties. מאפיין הוא משתנה השייך לאובייקט. אובייקט המכונית שלנו יהיה שלושה מאפיינים: make, modelו color.

בואו נראה איך זה יכול להיראות:

const car = { make: 'Ford', model: 'Fiesta', color: 'Red'};

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

אנחנו אפילו יכולים להפיק את זה באמצעות console.log:

console.log(car.color); //outputs: Red

דרך נוספת להתייחס לנכס היא שימוש בסימני סוגריים מרובעים:

console.log(car['color']); //outputs: Red

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

כלומר, במקום לקודד שם מאפיין ספציפי, אנו יכולים לציין אותו כמחרוזת במשתנה:

const propertyName = 'color';const console.log(car[propertyName]); //outputs: Red

שימוש בחיפוש דינמי עם סימון סוגריים מרובע

בואו נסתכל על דוגמה שבה נוכל להשתמש בזה. נניח שאנחנו מנהלים מסעדה ואנחנו רוצים להיות מסוגלים לקבל את מחירי הפריטים בתפריט שלנו. אחת הדרכים לעשות זאת היא שימוש if/elseבהצהרות.

בואו נכתוב פונקציה שתקבל שם פריט ותחזיר מחיר:

function getPrice(itemName){ if(itemName === 'burger') { return 10; } else if(itemName === 'fries') { return 3; } else if(itemName === 'coleslaw') { return 4; } else if(itemName === 'coke') { return 2; } else if(itemName === 'beer') { return 5; }}

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

גישה טובה יותר תהיה להפריד בין הנתונים שלנו לבין ההיגיון שלנו. הנתונים יכילו את התפריט שלנו וההיגיון יחפש מחירים מאותו תפריט.

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

במקרה זה המפתח יהיה שם הפריט והערך יהיה מחיר הפריט:

const menu = { burger: 10, fries: 3, coleslaw: 4, coke: 2, beer: 5};

באמצעות סימון סוגריים מרובעים אנו יכולים ליצור פונקציה שתקבל שני ארגומנטים:

  • אובייקט תפריט
  • מחרוזת עם שם פריט

והחזר את מחיר הפריט:

const menu = { burger: 10, fries: 3, coleslaw: 4, coke: 2, beer: 5};
function getPrice(itemName, menu){ const itemPrice = menu[itemName]; return itemPrice;}
const priceOfBurger = getPrice('burger', menu);console.log(priceOfBurger); // outputs: 10

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

מבני נתונים ואלגוריתמים

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

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

אחת הדרכים לעשות זאת היא לעבור על המערך, לבדוק את ערך ה- ISBN של כל ספר ואם הוא תואם להחזרתו:

const books = [{ isbn: '978-0099540946', author: 'Mikhail Bulgakov', title: 'Master and Margarita'}, { isbn: '978-0596517748', author: 'Douglas Crockford', title: 'JavaScript: The Good Parts'}, { isbn: '978-1593275846', author: 'Marijn Haverbeke', title: 'Eloquent JavaScript'}];
function getBookByIsbn(isbn, books){ for(let i = 0; i < books.length; i++){ if(books[i].isbn === isbn) { return books[i]; } }}
const myBook = getBookByIsbn('978-1593275846', books);

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

סימון Big O משמש במדעי המחשב כדי לתאר ביצועים של אלגוריתם. לדוגמא אם n הוא מספר הספרים באוסף שלנו, עלות השימוש באיטרציה לחיפוש ספר בתרחיש במקרה הגרוע ביותר (הספר שאנחנו מחפשים הוא האחרון ברשימה) יהיה O (n) . פירוש הדבר שאם מספר הספרים באוסף שלנו יוכפל, עלות מציאת הספר באמצעות איטרציה תכפיל גם כן.

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

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

המפתח יהיה ה- ISBN והערך יהיה אובייקט הספר המתאים:

const books = { '978-0099540946':{ isbn: '978-0099540946', author: 'Mikhail Bulgakov', title: 'Master and Margarita' }, '978-0596517748': { isbn: '978-0596517748', author: 'Douglas Crockford', title: 'JavaScript: The Good Parts' }, '978-1593275846': { isbn: '978-1593275846', author: 'Marijn Haverbeke', title: 'Eloquent JavaScript' }};
function getBookByIsbn(isbn, books){ return books[isbn];}
const myBook = getBookByIsbn('978-1593275846', books);

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

מבחינת ביצועים, חיפוש במפה יספק שיפור עצום בהשוואה לאיטרציה. הסיבה לכך היא כי לחיפוש המפה יש מחיר קבוע מבחינת החישוב. ניתן לכתוב זאת באמצעות סימון Big O כ- O (1) . לא משנה אם יש לנו שלושה או שלושה מיליון ספרים, אנחנו יכולים להשיג את הספר שאנחנו רוצים באותה מהירות על ידי חיפוש במפה באמצעות מקש ISBN.

לסכם

  • We have seen we can access the values of object properties using dot notation and square bracket notation
  • We learned how we can dynamically look up values of property by using variables with square bracket notation
  • We have also learned that a map datastructure maps keys to values. We can use keys to directly look up values in a map which we implement using an object.
  • We had a first glance at how algorithm performance is described using Big O notation. In addition, we saw how we can improve the performance of a search by converting an array of objects into a map and using direct lookup rather than iteration.

Want to test your new found skills? Try the Crash Override exercise on Codewars.

Want to learn how to write web applications using JavaScript? I run Constructor Labs, a 12 week JavaScript coding bootcamp in London. The technologies taught include HMTL, CSS, JavaScript, React, Redux, Node and Postgres. Everything you need to create an entire web app from scratch and get your first job in the industry. Fees are £3,000 and next cohort starts on 29th May. Applications are open now.