خطاها و اشکال‌زدایی

Error Object و انواع خطاها، try/catch/finally و throw، خطاهای سفارشی، Stack Trace، ابزارهای Debugging و DevTools، Breakpoint و Watch.

خطا چیست؟

خطا (Error) وضعیتی است که اجرای عادی برنامه را مختل می‌کند. جاوا اسکریپت خطاها را به‌صورت Exception پرتاب می‌کند:

// خطاهای زمان اجرا:
console.log(x);        // ReferenceError — تعریف نشده
null.foo;              // TypeError — null ویژگی ندارد
decodeURIComponent("%"); // URIError
// JSON.parse("{");    // SyntaxError

// خطاها اجرا را متوقف می‌کنند — مگر اینکه مدیریت شوند

Error Object — شیء خطا

const err = new Error("مشکلی پیش آمد");

console.log(err.name);    // "Error"
console.log(err.message); // "مشکلی پیش آمد"
console.log(err.stack);   // محل وقوع + Stack Trace

// خطا بدون throw فقط یک شیء است:
console.log(typeof err); // object

انواع خطاهای داخلی

نوعچه زمانیمثال
Errorخطای عمومیthrow new Error("...")
SyntaxErrorسینتکس غلطeval("if(")
ReferenceErrorمتغیر ناموجودundefinedVar
TypeErrorنوع اشتباهnull.x، "a".push()
RangeErrorخارج از محدودهnew Array(-1)
URIErrorencode/decode غلطdecodeURIComponent("%")

try...catch — مدیریت خطا

try {
    // کد پرخطر:
    const data = JSON.parse("{غلط}");
    console.log("این هرگز اجرا نمی‌شود");
} catch (error) {
    // فقط اگر خطا رخ دهد:
    console.log("نوع:", error.name);     // SyntaxError
    console.log("پیام:", error.message);
} 
// اجرای برنامه ادامه می‌یابد!
try/catch فقط خطاهای همگام را می‌گیرد — خطاهای داخل callback و Promise نیاز به روش‌های دیگر دارند.

finally — همیشه اجرا می‌شود

function readFile(path) {
    console.log("باز کردن فایل...");
    try {
        if (!path) throw new Error("مسیر خالی");
        return "محتوا";
    } catch (e) {
        console.log("خطا:", e.message);
        return null;
    } finally {
        console.log("بستن فایل — همیشه!"); // حتی با return!
    }
}

console.log(readFile("test.txt"));
// باز کردن... بستن... محتوا

throw — پرتاب خطا

function divide(a, b) {
    if (b === 0) {
        throw new Error("تقسیم بر صفر مجاز نیست");
    }
    return a / b;
}

try {
    divide(10, 0);
} catch (e) {
    console.log(e.message); // تقسیم بر صفر مجاز نیست
}

// پرتاب انواع خطای خاص:
function setAge(age) {
    if (typeof age !== "number") {
        throw new TypeError("سن باید عدد باشد");
    }
    if (age < 0 || age > 150) {
        throw new RangeError("سن بین 0 و 150");
    }
}

خطاهای سفارشی (Custom Errors)

// کلاس خطای سفارشی:
class ValidationError extends Error {
    constructor(message, field) {
        super(message);
        this.name = "ValidationError";
        this.field = field;
    }
}

class NetworkError extends Error {
    constructor(message, statusCode) {
        super(message);
        this.name = "NetworkError";
        this.statusCode = statusCode;
        this.retryable = statusCode >= 500;
    }
}

// استفاده:
function validateUser(user) {
    if (!user.email) throw new ValidationError("ایمیل لازم است", "email");
    if (!user.name) throw new ValidationError("نام لازم است", "name");
}

try {
    validateUser({ name: "علی" });
} catch (e) {
    if (e instanceof ValidationError) {
        console.log("فیلد:", e.field); // email
    } else {
        throw e; // خطای ناشناخته — دوباره پرتاب
    }
}

مدیریت خطا بر اساس نوع

function riskyOperation() {
    const rand = Math.random();
    if (rand < 0.3) throw new TypeError("نوع اشتباه");
    if (rand < 0.6) throw new RangeError("محدوده غلط");
    return "موفق";
}

try {
    riskyOperation();
} catch (e) {
    switch (e.name) {
        case "TypeError":
            console.log("مشکل نوع — بررسی ورودی");
            break;
        case "RangeError":
            console.log("مشکل محدوده — بررسی مقادیر");
            break;
        default:
            console.log("خطای ناشناخته:", e.message);
    }
}

Stack Trace — ردیابی پشته

زنجیره فراخوانی‌هایی که به خطا منجر شده:

function level3() {
    throw new Error("خطای عمیق");
}
function level2() { level3(); }
function level1() { level2(); }

try {
    level1();
} catch (e) {
    console.log(e.stack);
    // Error: خطای عمیق
    //     at level3 (...)      ← محل پرتاب
    //     at level2 (...)      ← فراخواننده
    //     at level1 (...)
}

Debugging — اشکال‌زدایی

ابزارهای یافتن خطا:

// تکنیک‌های console:
const users = [{ name: "علی", age: 25 }, { name: "سارا", age: 30 }];
console.table(users);          // جدول زیبا
console.trace("اینجا کجاست؟"); // مسیر فراخوانی
console.time("loop");
for (let i = 0; i < 100000; i++) {}
console.timeEnd("loop");       // loop: 2ms

// debugger — فقط وقتی DevTools باز است:
function complexCalc(x) {
    debugger; // توقف اینجا — بررسی step by step
    return x * 2;
}

Breakpoint و Watch در DevTools

Error Cause — علت خطا (ES2022)

try {
    try {
        JSON.parse("{bad");
    } catch (innerError) {
        // خطای جدید با حفظ علت:
        throw new Error("پارس داده ناموفق", { cause: innerError });
    }
} catch (e) {
    console.log(e.message);        // پارس داده ناموفق
    console.log(e.cause.message);  // Unexpected token...
}

جمع‌بندی — بهترین شیوه‌ها

این مبحث بخشی از دوره آموزش کامل جاوا اسکریپت است.

ابزارهای مرتبط