خطاها و اشکالزدایی
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) |
URIError | encode/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.log — سادهترین روش برای مقادیر
- console.table — نمایش جدولی آرایه/شیء
- console.trace — چاپ Stack Trace فعلی
- debugger — توقف در DevTools
- Breakpoint — توقف شرطی در سورس
// تکنیکهای 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
- Line Breakpoint: کلیک روی شماره خط در Sources
- Conditional Breakpoint: کلیک راست → فقط وقتی شرط درست است
- Watch: بررسی مقادیر متغیرها هنگام توقف
- Step Over / Into / Out: اجرای قدمبهقدم
- Call Stack: دیدن زنجیره فراخوانی
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...
}
جمعبندی — بهترین شیوهها
- همیشه ورودیها را اعتبارسنجی و
throwکن - برای خطاهای برنامه، کلاسهای سفارشی بساز
finallyبرای پاکسازی (بستن فایل، توقف تایمر)- خطاهای ناشناخته را دوباره پرتاب کن — قورت نده!
- پیامهای واضح فارسی/انگلیسی بنویس
این مبحث بخشی از دوره آموزش کامل جاوا اسکریپت است.