Menu
العربية

أنواع الأخطاء في JavaScript: SyntaxError وTypeError وغيرها

تعرّف على أنواع الأخطاء المدمجة في JavaScript، ومتى يظهر كل نوع، وكيف تقرأ رسالة الخطأ وتفهم سببها الحقيقي بدل التخمين.

الأخطاء في JavaScript كائنات لها نوع

عندما ترمي JavaScript خطأً ما، فهي لا تعطيك مجرد نص — بل تسلّمك كائناً. وهذا الكائن له نوع (أي الـ constructor الخاص به) ومجموعة من الخصائص القياسية: name وmessage وstack.

index.js
Output
Click Run to see the output here.

err.name عبارة عن تسمية مختصرة مثل "TypeError"، بينما err.message فهو الوصف الذي يقرأه البشر. أما err instanceof TypeError فيخبرك بالصنف المحدد للخطأ. معرفة نوع الخطأ أمر مهم: فهي تكشف لك ما إذا كانت المشكلة مجرد خطأ إملائي، أو قيمة غير صالحة، أو حتى كود لم يُقرأ أصلاً.

هناك سبعة أنواع مدمجة من الأخطاء في JavaScript؛ ثلاثة منها ستصادفها باستمرار، وأربعة ستقابلها بين الحين والآخر.

SyntaxError: الكود لم يُقرأ أصلاً

الخطأ SyntaxError يعني أن محرك JavaScript لم يستطع حتى قراءة الكود الذي كتبته. وهو في الحقيقة ليس خطأً في وقت التشغيل، لأن المحرك يفشل أثناء مرحلة التحليل (Parsing)، أي قبل أن يُنفَّذ أي سطر. ولهذا السبب لا يمكنك التقاط SyntaxError باستخدام try/catch داخل نفس الملف، لأن الملف كله يُرفض دفعة واحدة.

function greet(name {
    return "مرحباً، " + name;
}
// SyntaxError: Unexpected token '{'

قوس ناقص، فاصلة شاردة، أو return خارج دالة — أي شيء يكسر قواعد اللغة يُطلق هذا الخطأ. الحل دائمًا هو تصحيح الكود المصدري. الموضع الوحيد الذي يمكنك فيه التقاط SyntaxError هو عند التحليل أثناء التشغيل، مثل JSON.parse:

index.js
Output
Click Run to see the output here.

JSON.parse يستقبل نصًا وقت التشغيل، لذا فإن أخطاء الصياغة الناتجة عنه يمكن التقاطها. أما أخطاء الصياغة في ملفات الشيفرة الخاصة بك فلا يمكن التقاطها.

ReferenceError: هذا الاسم غير موجود

يظهر الخطأ ReferenceError في جافاسكربت عندما تحاول استخدام متغير لم يُعرَّف في أي نطاق يمكن للشيفرة الحالية الوصول إليه.

index.js
Output
Click Run to see the output here.

في تسعين بالمئة من الحالات، يكون السبب مجرد خطأ إملائي (مثل كتابة totl بدل total). أما النسبة المتبقية، فغالبًا ما تكون مشكلة نطاق (scope) — أي أنك تحاول استخدام متغير معرَّف داخل دالة أو موديول آخر.

لكن هناك سبب أدق من ذلك يستحق الانتباه: المنطقة الميتة الزمنية (Temporal Dead Zone). فالمتغيرات المُعرَّفة باستخدام let وconst تكون موجودة فعليًا منذ بداية الكتلة التي تحتويها، غير أنه لا يمكن الوصول إليها قبل السطر الذي تُعلَن فيه:

index.js
Output
Click Run to see the output here.

x يصبح مُعرَّفًا فعليًا عند تنفيذ console.log(x)، لكنه لم يُهيَّأ بقيمة بعد، ولهذا يظهر خطأ المرجع. الحل بسيط: انقل السطر الذي يستخدم المتغير إلى ما بعد تعريفه.

خطأ TypeError في JavaScript: القيمة ليست من النوع المتوقع

خطأ TypeError يعني أن القيمة موجودة فعلًا، لكنها ليست من النوع الذي تتطلبه العملية. فحين تستدعي شيئًا ليس دالة، أو تحاول قراءة خاصية من null أو undefined، أو تُسند قيمة إلى متغير مُعرَّف بـ const، فكل هذه الحالات تُنتج TypeError.

index.js
Output
Click Run to see the output here.

خطأ Cannot read properties of null (reading 'name') هو على الأرجح أكثر رسالة خطأ شيوعًا في JavaScript على الإطلاق. الحل إمّا أن تتأكّد من أنّ القيمة موجودة فعلًا، أو أن تحمي الوصول باستخدام الـ optional chaining هكذا: user?.name.

أشكال أخرى من TypeError:

index.js
Output
Click Run to see the output here.

استدعاء رقم كأنه دالة، أو إعادة تعيين متغير const، أو استدعاء دالة غير موجودة أصلاً — كل هذه الحالات تعني أن نوع القيمة لا يناسب العملية التي طلبتها منها.

خطأ RangeError: الرقم خارج النطاق المسموح

يظهر خطأ RangeError عندما يكون الرقم صحيحاً من الناحية التقنية، لكنه يقع خارج النطاق المسموح به لعملية معينة.

index.js
Output
Click Run to see the output here.

المصدر الكلاسيكي لهذا الخطأ هو التكرار اللانهائي (infinite recursion)، الذي يُفجّر مكدس الاستدعاءات (call stack):

index.js
Output
Click Run to see the output here.

رسالة "Maximum call stack size exceeded" تعني في الغالب أن هناك دالة تستدعي نفسها دون شرط توقف (base case)، أو أن دالتين تستدعيان بعضهما في حلقة لا نهائية.

خطأ URIError وEvalError: الأنواع النادرة

يظهر خطأ URIError عند استخدام دوال التعامل مع روابط URI (مثل encodeURI وdecodeURIComponent وأخواتها) عند تمرير مُدخَلات غير صالحة لها:

index.js
Output
Click Run to see the output here.

EvalError هو بقايا من الماضي. محركات JavaScript الحديثة لا تُطلق هذا النوع من الأخطاء فعلياً لأي سبب — لكنه لا يزال موجوداً كـ constructor للحفاظ على التوافق مع الإصدارات القديمة. يمكنك إنشاء واحد يدوياً، لكنك لن تصادفه في الشيفرات الحقيقية.

سلسلة الوراثة في كائن Error

جميع هذه الأنواع ترث من كائن Error الأساسي. هذا يعني أن err instanceof Error ستكون قيمته true لأي منها، وهذا مفيد جداً داخل كتلة catch عامة:

index.js
Output
Click Run to see the output here.

كتلة catch تلتقط كل شيء — حتى القيم التي ليست أخطاءً إذا استخدم أحدهم throw "oops". هذا الفرع الأخير مهم. تحقّق دائماً باستخدام instanceof قبل أن تتعامل مع القيمة الملتقطة على أنها كائن خطأ.

كيفية إطلاق الأخطاء يدوياً في JavaScript

يمكنك أن ترمي أي نوع من الأنواع المدمجة بنفسك عندما يكتشف كودك وجود مشكلة. اختر النوع الذي يناسب طبيعة الخلل:

index.js
Output
Click Run to see the output here.

مطابقة نوع الخطأ مع طبيعة المشكلة ليست مجرد تفصيلة شكلية، بل تفتح الباب أمام الكود المستدعي ليكتب منطق catch موجّه ودقيق بدلاً من اللجوء إلى تحليل نصوص رسائل الخطأ.

إنشاء فئات أخطاء مخصصة في JavaScript

عندما لا تفي الأنواع المدمجة بالغرض، نلجأ إلى توريث Error:

index.js
Output
Click Run to see the output here.

شيئان يجب تذكّرهما: نادِ super(message) حتى يُهيَّأ كائن Error الأساسي بشكل صحيح، واضبط this.name ليظهر الاسم الصحيح في السجلّات. أمّا الحقول المخصّصة مثل field فهي تتيح للمستدعي التعامل مع حالات فشل بعينها دون الحاجة إلى تحليل النصوص.

التالي: الكونسول وأدوات المطوّر

معرفة أنواع الأخطاء نصف المعركة فقط — أمّا النصف الآخر فهو قراءة الـ stack trace وفحص حالة البرنامج أثناء تشغيله. أدوات المطوّر في المتصفّح (وكذلك مُنقِّح Node) تحوّل "رمى استثناءً ولا أعرف السبب" إلى ثوانٍ معدودة من الفحص. وهذا ما سنتناوله تاليًا.

الأسئلة الشائعة

ما هي أنواع الأخطاء المدمجة في JavaScript؟

لدى JavaScript سبعة أنواع: Error (وهو الأساس)، وSyntaxError، وReferenceError، وTypeError، وRangeError، وURIError، وEvalError. كل واحد منها عبارة عن constructor يُنتج كائن خطأ يحتوي على الخصائص name وmessage وstack. الأنواع الثلاثة الأولى التي ستقابلها كثيرًا في العمل اليومي هي SyntaxError وReferenceError وTypeError.

ما الفرق بين SyntaxError وTypeError؟

SyntaxError يعني أن الكود نفسه غير صالح، أي أن المحرك لا يستطيع حتى قراءته وتحليله. أما TypeError فيعني أن الكود تم تحليله بنجاح، لكنه قام أثناء التشغيل بعملية غير مشروعة، مثل استدعاء قيمة ليست دالة أو قراءة خاصية من null. الفرق المهم: أخطاء الصياغة توقف تنفيذ السكربت بالكامل، بينما أخطاء النوع لا تظهر إلا عند الوصول فعليًا إلى السطر المعطوب.

متى يظهر خطأ ReferenceError في JavaScript؟

يظهر عند استخدام اسم لم يُعرَّف أصلًا، أو عند محاولة الوصول إلى متغير مُعلَن بـ let أو const داخل ما يُعرف بـ temporal dead zone (قبل تنفيذ سطر التعريف). والسبب الأشهر هو أخطاء الكتابة؛ فمثلًا consoel.log(x) يُطلق الخطأ ReferenceError: consoel is not defined. لذلك راجع الإملاء والنطاق (scope) أولًا.

هل يمكنني إنشاء أنواع أخطاء مخصصة؟

نعم، ويكفي أن ترث من الكلاس المدمج Error هكذا: class ValidationError extends Error { }. والأفضل أن تضبط this.name داخل الـ constructor حتى تستطيع السجلات وفروع catch التمييز بين الأخطاء. استخدام كلاسات أخطاء مخصصة يكون مفيدًا جدًا عندما تحتاج كل حالة فشل إلى معالجة مختلفة.

تعلّم البرمجة مع Coddy

ابدأ الآن