חידון: שליטה מתקדמת בשגיאות JS
האם החריגות שלך באמת חריגות?
חושבים שאתם מכירים שגיאות JavaScript מבפנים ומבחוץ?
- בחנו את המומחיות שלכם בטיפול בשגיאות! 💥
- אין צורך בהתחברות או הרשמה. ✨
- רב-ברירה. 🤖 … אלו לא שאלות try-catch טיפוסיות!
מה מחזירה JSON.stringify(error)?
const error = new Error('Oops');console.log(JSON.stringify(error));חשוב על מאפיינים ניתנים למנייה באובייקטי Error.
לאובייקטי שגיאה יש מאפיינים שאינם ניתנים למנייה (message, name, stack), לכן JSON.stringify() מחזירה {}. זוהי מלכודת נפוצה בעת שליחת שגיאות בתגובות API. השתמש ב-JSON.stringify(error, Object.getOwnPropertyNames(error)) או צור אובייקט רגיל במקום.
מה ההבדל בין השניים?
const err = new Error('Test');console.log(err);console.log(JSON.stringify(err));חשוב על האופן שבו console.log מטפל באובייקטים לעומת סריאליזציה ב-JSON.
console.log(err) מציג את השגיאה עם ההודעה ומחסנית הקריאות כי לקונסול יש טיפול מיוחד באובייקטי Error. JSON.stringify(err) מחזיר '{}' כי מאפייני Error אינם ניתנים למנייה. ההבדל הזה מבלבל מפתחים רבים בעת ניפוי באגים ב-API.
מה התוצאות של בדיקות אלו?
class CustomError extends Error {}const err = new CustomError('test');
console.log(err instanceof CustomError);console.log(err instanceof Error);console.log(err instanceof Object);זכור את שרשרת האב-טיפוס בירושה של JavaScript.
כל השלוש מחזירות true. CustomError מרחיב את Error, שמרחיב את Object. האופרטור instanceof בודק את כל שרשרת האב-טיפוס, כך שמופע של CustomError הוא גם מופע של Error ו-Object.
נניח ש־iframeError הוא אובייקט Error שנוצר ב־iframe מאותו מקור והועבר לחלון האב. מה עשויה להחזיר הבדיקה בחלון האב?
console.log(iframeError instanceof Error);להקשרים שונים יש בנאי Error שונים.
לכל הקשר הרצה יש בנאי Error ושרשרת אב־טיפוס משלו. לכן instanceof Error בחלון האב עשוי להחזיר false עבור שגיאה מה־iframe. Object.prototype.toString.call(obj) יכול לעזור בזיהוי בין הקשרים, אך Symbol.toStringTag מאפשר לזייף את התגית; זו אינה בדיקת אותנטיות מהימנה.
מה קורה כשזורקים מחרוזת?
try { throw "Oops!";} catch (e) { console.log(e instanceof Error); console.log(typeof e);}JavaScript מאפשרת לזרוק כל ערך, לא רק אובייקטי שגיאה.
JavaScript מאפשרת לזרוק כל ערך. כאן, e instanceof Error הוא false ו-typeof e הוא "string". זה יכול לשבור קוד טיפול בשגיאות שמניח שכל החריגות שנתפסו הן אובייקטי שגיאה. תמיד זרוק מופעי Error לצורך ניפוי טוב יותר.
מה הערך של err.name?
class CustomError extends Error { constructor(message) { super(message); this.name = this.constructor.name; }}const err = new CustomError('test');console.log(err.name);תסתכל על מה ש-this.constructor.name מחזיר.
err.name הוא "CustomError" מכיוון ש-this.constructor.name מחזיר את שם המחלקה. הגדרת this.name = this.constructor.name היא תבנית נפוצה כדי להבטיח שמחלקות שגיאה מותאמות אישית יציגו את השם הנכון ב-stack traces ובהודעות שגיאה.
מה הפלט מבלי להגדיר name?
class MyError extends Error { // No constructor or name setting}const err = new MyError('test');console.log(err.name);מהו ערך ברירת המחדל של name במחלקת Error?
ללא הגדרה מפורשת של this.name, השגיאה יורשת את מאפיין ה-name המוגדר כברירת מחדל ממחלקת Error, שהוא "Error". לכן מחלקות שגיאה מותאמות אישית צריכות תמיד להגדיר this.name = this.constructor.name בבנאי שלהן.
מה מחזירה wrapper.cause.message?
const original = new Error('Original error');const wrapper = new Error('Wrapper', { cause: original });console.log(wrapper.cause.message);Error.cause הוא תכונה מודרנית ב-JavaScript לשרשור שגיאות.
Error.cause (ES2022) מאפשר לשרשר שגיאות כדי לשמור על הקשר השגיאה המקורי. wrapper.cause מתייחס לשגיאה המקורית, ולכן wrapper.cause.message מחזירה "Original error". זה שימושי לעטיפת שגיאות ברמה נמוכה עם הקשר ברמה גבוהה יותר.
בסביבת V8 או Node.js, מה עושה Error.captureStackTrace כאן?
function createError(msg) { const err = new Error(msg); Error.captureStackTrace(err, createError); return err;}const error = createError('test');זו תכונה ספציפית ל-V8 ליצירת עקבות מחסנית נקיות יותר.
Error.captureStackTrace (V8/Node.js) מסיר את הפונקציה שצוינה (createError) מעקבות המחסנית, מה שהופך פונקציות יצירת שגיאות לבלתי נראות למשתמשי הקצה. זה יוצר עקבות מחסנית נקיות יותר שמצביעות על המקום שבו נקראה הפונקציה היוצרת, ולא על הפונקציה עצמה.
מהי הודעת השגיאה?
function validate(value) { if (!value) { throw new Error( `Value ${value} is invalid` ); }}try { validate(undefined);} catch (e) { console.log(e.message);}כיצד אינטרפולציה של תבניות מחרוזת מטפלת ב-undefined?
תבניות מחרוזת ממירות את undefined למחרוזת "undefined" במהלך אינטרפולציה. הודעת השגיאה הופכת ל-"Value undefined is invalid". להודעות נקיות יותר, שקול להשתמש ב-value ?? 'null' או בבדיקות דומות לפני האינטרפולציה.
מה נשלח ללקוח?
// Express.js routeapp.get('/api/data', (req, res) => { const error = new Error('Database failed'); res.json({ error });});זכור כיצד אובייקטי Error עוברים סריאליזציה על ידי JSON.stringify.
res.json() משתמש ב-JSON.stringify() פנימית, כך שאובייקט השגיאה הופך ל-{}. הלקוח מקבל {"error":{}}. כדי לתקן זאת, השתמש ב-res.json({ error: error.message }) או res.json({ error: { message: error.message, name: error.name } }).
מה יכול Promise.reject() לקבל?
Promise.reject('string').catch(e => console.log(typeof e));Promise.reject({code: 404}).catch(e => console.log(e.code));Promise.reject(42).catch(e => console.log(e));דחיות Promise פועלות בדומה להצהרות throw.
בדומה ל-throw, Promise.reject() מקבל כל ערך - מחרוזות, אובייקטים, מספרים וכו’. זה מדפיס "string", 404, ו-42. תמיד בדוק את הסוג של ערכים שנתפסו בשרשראות Promise, במיוחד כשמתמודדים עם קוד צד שלישי שעלול לדחות עם ערכים שאינם Error.
עד כמה אמינים error.code ו-error.errno?
const fs = require('fs');fs.readFile('missing.txt', (err, data) => { if (err) { console.log(err.code); // 'ENOENT' console.log(err.errno); // -2 }});שקול סביבות JavaScript שונות וסוגי שגיאות.
מאפיינים כמו code ו-errno תלויים בסביבה (Node.js במקרה זה) ואינם חלק מאובייקט השגיאה הסטנדרטי. שגיאות דפדפן לא יכילו מאפיינים אלה. תמיד בדוק את קיומם: if (err.code === 'ENOENT') במקום להניח שהם קיימים.
מה מחזירות הבדיקות הללו?
const fakeError = { name: 'Error', message: 'Fake error', stack: 'fake stack'};
console.log(fakeError instanceof Error);console.log(Object.prototype.toString.call( fakeError) === '[object Error]');בדיקה אחת עוקבת אחר שרשרת אב־הטיפוס; האחרת מחזירה תגית אובייקט שאפשר להשפיע עליה באמצעות Symbol.toStringTag.
שתי הבדיקות מחזירות false. האובייקט אינו יורש מ־Error.prototype, ו־Object.prototype.toString.call(fakeError) מחזירה כאן "[object Object]". הבדיקה השנייה אינה הוכחת אותנטיות: מאפיין Symbol.toStringTag יכול לשנות את התגית המוחזרת.
שליטה באומנות טיפול השגיאות
ממלכודות סריאליזציה ועד כשלי instanceof בין הקשרים שונים, המושגים המתקדמים האלה מפרידים בין מפתחים זוטרים לבין מקצוענים מנוסים שחוקים.
מוכן לאתגרים נוספים? בדוק את אוסף החידות המלא לעוד תרגילי חשיבה על JavaScript, אלגוריתמים ועוד!
