ה-console הוא יותר מ-log
console.log הוא כלי הדיבוג הראשון שרוב האנשים לומדים, והאחרון שרבים מפסיקים להשתמש בו. הוא עובד, אבל לאובייקט console יש עוד תריסר מתודות שהופכות דיבוג למהיר וברור יותר. וברגע שתרגישו בנוח ב-DevTools עצמו, נקודות עצירה, מחסנית הקריאות, ביטויי מעקב, תשתמשו ב-log פחות משהשתמשתם בעבר.
נתחיל בסקירה מהירה:
כל הארבעה מדפיסים לאותו console, אבל דפדפנים מעצבים אותם אחרת: אזהרות מקבלות רקע צהוב, שגיאות מקבלות אדום ואייקון, ושתיהן כוללות stack trace. מסננים ב-DevTools מאפשרים להסתיר או לבודד כל רמה, וזה חשוב ברגע שאפליקציה מייצרת מאות הודעות.
הדפסה של כמה ערכים בדרך העצלה
כשרוצים לראות כמה משתנים בבת אחת, אל תשרשרו אותם למחרוזת. העבירו אותם כארגומנטים נפרדים, או עדיף, עטפו אותם באובייקט כך שלכל אחד תהיה תווית:
הטריק { user, count } משתמש בקיצור של אובייקטים: שם המשתנה הופך למפתח. ב-console תראו { user: {...}, count: 3 } ותוכלו לפתוח את user כדי לבדוק אותו. לא מאבדים את המבנה של האובייקט בהמרה למחרוזת.
console.table למערכים של אובייקטים
כשבוהים במערך של אובייקטים, console.log נותן בלגן מקופל. console.table מציג אותו כטבלה אמיתית:
ב-console של דפדפן, הקריאה הראשונה מדפיסה את כל שלוש השורות עם עמודות שאפשר למיין. הקריאה השנייה מגבילה את זה ל-name ו-role בלבד. זה שדרוג ענק בנוחות לכל דבר שנראה כמו נתונים: תגובות API, תוצאות שאילתות, קבצי CSV מפוענחים.
console.dir מול console.log
הם נראים דומים, אבל מתנהגים אחרת באלמנטים של DOM:
const el = document.querySelector("button");
console.log(el); // prints the HTML: <button>Click me</button>
console.dir(el); // prints the JS object view with all properties
log מעצב אלמנטים כ-HTML. dir מראה לכם את האובייקט: כל מאפיין, כל event handler, כל הפניה לסגנון מחושב. כשרוצים לדעת אילו מתודות או תכונות יש לאלמנט, dir הוא הכלי.
קיבוץ פלט קשור
סשנים ארוכים של דיבוג ממלאים את ה-console ברעש. console.group ו-console.groupEnd עוטפים הודעות קשורות בבלוק שאפשר לקפל:
כל קריאה יוצרת קבוצה עם שם שאפשר לקפל. השתמשו ב-console.groupCollapsed אם רוצים שהקבוצות יתחילו מקופלות כברירת מחדל: שימושי כשרוצים לפתוח רק את אלה שנראות חשודות.
מדידת זמן עם console.time
לבדיקות ביצועים מהירות, קשה לנצח את console.time ו-console.timeEnd:
התווית ב-time וב-timeEnd חייבת להיות זהה. אפשר להריץ כמה טיימרים בבת אחת עם תוויות שונות. לכל דבר רציני יותר מ"האם הלולאה הזו איטית?", עברו ללוח Performance ב-DevTools, שמקליט ציר זמן מלא ו-flame chart.
Assertions: להדפיס רק כשמשהו לא בסדר
console.assert מדפיס רק כשהתנאי falsy. זו דרך שקטה להשאיר בדיקות שפיות בקוד בלי להציף את ה-console כשהכול תקין:
טוב לאינווריאנטים ש_אמורים_ להתקיים תמיד. לא טוב לדברים שעלולים להיכשל באופן לגיטימי: במקרים האלה, זרקו שגיאה.
Stack traces לפי דרישה
console.trace מדפיס את מחסנית הקריאות הנוכחית בלי לזרוק שום דבר. שימושי כשמנסים להבין מי קרא לפונקציה:
הפלט מראה inner → outer → (top level). באפליקציה אמיתית, כך מגלים שה-click handler שאתם מדבגים מופעל משלושה מקומות שונים.
הפקודה debugger
הדרך המהירה ביותר לעצור ריצה של JavaScript היא מילה אחת:
function computeTotal(items) {
const subtotal = items.reduce((s, i) => s + i.price, 0);
debugger;
return subtotal * 1.08;
}
כש-DevTools פתוח, debugger; מתנהג כמו נקודת עצירה: הריצה נעצרת בשורה הזו ומקבלים את הדיבאגר המלא: המשתנים ב-scope, מחסנית הקריאות, כפתורי step-over ו-step-into, והיכולת להעריך ביטויים מול המצב הנוכחי. כש-DevTools סגור, debugger; לא עושה כלום.
בפעם הראשונה שמשתמשים בדיבאגר אמיתי במקום ב-console.log, זה מרגיש כמו כוח על. רואים כל משתנה ב-scope בלי להחליט מראש מה להדפיס. אפשר לעבור צעד אחר צעד על תנאים ולראות איזה ענף רץ. תיקון באג מסובך יורד מדקות לשניות.
הסירו את שורת ה-debugger לפני commit, או עדיף, הגדירו נקודות עצירה ישירות ב-DevTools בלחיצה על מספר שורה בלוח Sources.
טריקים ב-DevTools ששווה להכיר
כמה יכולות שאנשים מפספסים במשך שנים:
- נקודות עצירה מותנות: לחצו לחיצה ימנית על מספר שורה ב-Sources והגדירו תנאי כמו
user.id === 42. נקודת העצירה תופעל רק כשהתנאי מתקיים. - Logpoints: באותו תפריט, "Add logpoint". מדפיס הודעה בלי לעצור ובלי לערוך את הקוד.
$_ב-console: הביטוי האחרון שהוערך. הריצו משהו, ואז השתמשו ב-$_כדי לתפוס אותו.$0: האלמנט שנבחר כרגע בלוח Elements.$0.textContentבודק את מה שלחצתם עליו.- העתקה כאובייקט: לחצו לחיצה ימנית על כל ערך ב-console ובחרו "Store as global variable". מקבלים
temp1,temp2וכן הלאה, לשחק איתם. - לוח Network → Copy as fetch: הופך כל בקשה לקריאת
fetch()שאפשר להדביק ב-console ולשנות.
אף אחד מאלה לא הכרחי. כולם חוסכים זמן ברגע שהם נכנסים לזיכרון השרירים.
ניקיון לפני שמעלים לאוויר
קריאות console.log שנשכחו לא מזיקות בפיתוח ורועשות בפרודקשן. כמה הרגלים שעוזרים:
- השתמשו בכלל lint (
no-consoleב-ESLint) כדי לסמן הדפסות שנשכחו, עם חריגים ל-warnול-error. - עטפו לוגים מפורטים בבדיקה:
if (process.env.NODE_ENV !== "production") console.log(...). - העדיפו
console.debugלפלט ברמת trace: רוב ה-bundlers וכלי איסוף הלוגים יכולים לסנן אותו. - ועוד יותר טוב: השתמשו במודול logger קטן (או בספרייה כמו
debug) כדי שתוכלו להפעיל ולכבות קטגוריות של לוגים בלי לערוך קוד.
לוגים לא בחינם. כל קריאה ממירה את הארגומנטים שלה וכותבת לבאפר. בלולאה חמה, לוג שנשכח יכול להאט דברים באופן מדיד.
הבא בתור: ביטויים רגולריים
תדבגו הרבה קוד שמעבד מחרוזות, והרבה מהקוד הזה כולל regex, היכולת הכי קומפקטית והכי סתומה בשפה. הפרק הבא מתחיל בסיור עדין בביטויים רגולריים ב-JavaScript ובמתודות שמשתמשות בהם.
שאלות נפוצות
מה ההבדל בין console.log ל-console.dir?
console.log מדפיס ערכים לפי העיצוב ברירת המחדל של הדפדפן: באלמנטים של DOM זה אומר להציג אותם כ-HTML. console.dir תמיד מדפיס את תצוגת האובייקט של JavaScript עם המאפיינים שלו, וזה מה שרוצים כשצריך לבדוק את המאפיינים של אלמנט ולא את ה-markup שלו.
איך מדבגים JavaScript ב-Chrome DevTools בלי console.log?
פתחו את לוח Sources, מצאו את הקובץ, ולחצו על מספר שורה כדי להגדיר נקודת עצירה. כשהריצה מגיעה לשורה הזו היא נעצרת, ואפשר לבדוק משתנים, להתקדם בקוד צעד אחר צעד ולהעריך ביטויים ב-console. אפשר גם לשים פקודת debugger; בקוד כדי להפעיל נקודת עצירה מתוך קוד המקור.
איך מודדים כמה זמן לוקח לקוד JavaScript לרוץ?
עטפו את הקוד ב-console.time('label') וב-console.timeEnd('label') עם תוויות תואמות. ה-console מדפיס את הזמן שעבר במילישניות. לפרופיילינג מפורט יותר, השתמשו בלוח Performance ב-DevTools כדי להקליט flame chart של כל מה שרץ.
למה משמש console.table?
console.table מציג מערכים ואובייקטים כטבלה שאפשר למיין ב-console, וזה הרבה יותר קל לסריקה מהדפסה של אובייקט מקונן. הוא מושלם למערכים של אובייקטים: כל אובייקט הופך לשורה, והמפתחות שלו הופכים לעמודות. אפשר להעביר ארגומנט שני כדי להגביל אילו עמודות יופיעו.