تخطَّ إلى المحتوى

١٢ يوليو ٢٠٢٦

الفرق بين == و === في جافاسكريبت

شارك المقال:

أقصر سؤال يفصل مبتدئ جافاسكريبت عن متقنها — وأحد أثبت أسئلة المقابلات: ما الفرق بين == و ===؟ والأهم: لماذا ستكتب الثلاثية دائمًا بعد هذا المقال؟

الفكرة في سطرين

  • === (الصارمة): تقارن القيمة والنوع معًا — نوعان مختلفان؟ النتيجة false فورًا، بلا ألاعيب.
  • == (المرنة): إن اختلف النوعان حوّلت أحدهما للآخر ضمنيًا ثم قارنت — وهنا تبدأ المفاجآت.
"5" === 5   // false — نص لا يساوي رقمًا، انتهى
"5" == 5    // true!  — حوّلت النص لرقم قبل المقارنة

معرض العجائب: لماذا لا يثق أحد بـ ==

قواعد التحويل الضمني معقدة لدرجة أن نتائجها تبدو نكاتًا:

0 == ""          // true  (كلاهما يتحول لـ 0)
0 == "0"         // true
"" == "0"        // false 🤯 (نصان — لا تحويل — مختلفان!)
false == "0"     // true
null == 0        // false (null لا تتحول هنا)
" \t\n" == 0     // true  (المسافات البيضاء → 0)
[] == false      // true
[[]] == false    // true 😵

لاحظ الكارثة المنطقية: 0 == "" و0 == "0" صحيحتان لكن "" == "0" خاطئة — المساواة المرنة ليست علاقة متعدية أصلًا. قواعد لا يحفظها أحد عمليًا = أخطاء تختبئ بهدوء في الشروط.

المقارنة الصارمة تمسح كل هذا الجدول: كل ما سبق false ببساطة لأن الأنواع مختلفة.

الاستثناء الوحيد المحترم: x == null

توأم الغياب null وundefined تحدثنا عنهما بتفصيل كامل هنا — والمساواة المرنة تعتبرهما متساويين ولا تساوي بهما أي شيء آخر:

x == null
// true فقط إذا كانت x هي null أو undefined — لا 0 ولا "" ولا false

يعني if (x == null) تختصر if (x === null || x === undefined) بأمان تام. هذا الاستخدام الوحيد الذي يقبله المحترفون لـ == — وحتى هو صار أقل حاجة مع ?? و?. الحديثتين.

حدود === نفسها (لتكتمل الصورة)

الكائنات: مرجع لا محتوى

{ a: 1 } === { a: 1 }   // false — كائنان مختلفان بالذاكرة
[1, 2]  === [1, 2]      // false — نفس القصة

const a = { x: 1 };
const b = a;
a === b                  // true — نفس الكائن الواحد

هذا سلوك اللغة مع الكائنات عمومًا (وهو نفسه سرّ حلقة useEffect اللانهائية في React!).

حالتا NaN والأصفار — وObject.is

NaN === NaN              // false! الوحيدة التي لا تساوي نفسها
Object.is(NaN, NaN)      // true
Number.isNaN(x)          // الفحص العملي المعتمد

0 === -0                 // true
Object.is(0, -0)         // false (تفرقة نادرة الأهمية)

Object.is مساواة ثالثة أدق في هاتين الحالتين الهامشيتين — اعرفها للمقابلات، واستعمل === لليوميات.

قائمة تحقّق سريعة

  • اكتب === و!== دائمًا — افتراضك الدائم بلا تفكير.
  • الاستثناء المقبول الوحيد: x == null لفحص الغيابين معًا.
  • كائنات ومصفوفات؟ المقارنة بالمرجع — قارن المحتوى بنفسك.
  • NaN تُفحص بـ Number.isNaN حصرًا.
  • فعّل ESLint بقاعدة eqeqeq فيصير النسيان مستحيلًا.

الخلاصة

=== تقارن بصدق: نفس النوع ونفس القيمة أو لا. == تجاملك بتحويلات خفية قواعدها أغرب من أن تُحفظ — والمجاملات في الكود تنتهي أخطاءً صامتة. ثلاثية دائمًا، و== null رخصتك الوحيدة.

رسّخ الأساس في مسار جافاسكريبت بالعربي، وأكمل الثلاثية الذهبية مع الفرق بين var و let و const و الفرق بين undefined و null — وإن أردت لغة تمنع هذا الصداع من أصله فاقرأ الفرق بين JavaScript و TypeScript.

📚 مصادر رسمية للتعمّق: توثيق JavaScript على MDN

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

لماذا وُجدت == أصلًا إذا كانت مصدر مشاكل؟

تاريخيًا: جافاسكريبت صُممت عام 1995 لتتسامح مع صفحات ويب يكتبها غير مبرمجين، فكان التحويل التلقائي بين النصوص والأرقام «تسهيلًا». لاحقًا اتضح أن التسامح يخفي الأخطاء بدل منعها، فأضيفت === الصارمة — وبقيت == للتوافق مع الكود القديم.

هل NaN === NaN صحيحة؟

لا — NaN هي القيمة الوحيدة في اللغة التي لا تساوي نفسها بأي من العمليتين. لفحصها استخدم Number.isNaN(x)، أو Object.is(x, NaN) التي تعتبرها مساوية لنفسها. هذه من أشهر أسئلة المقابلات الخادعة.

لماذا تفشل المقارنة بين كائنين متطابقين حتى بـ ===؟

لأن الكائنات والمصفوفات تُقارن بالمرجع لا بالمحتوى: {a:1} === {a:1} خاطئة لأنهما كائنان مختلفان في الذاكرة وإن تطابق شكلهما. للمقارنة بالمحتوى قارن الحقول يدويًا أو عبر JSON.stringify للحالات البسيطة — وهذا سلوك العمليتين معًا، لا عيب في إحداهما.

اقرأ أيضًا

تصفّح كل المقالات في المدوّنة، أو ابدأ التعلّم من المسارات و خرائط الطريق.