Menu
العربية
جرّب في Playground

الفرق بين == و === و Object.is في JavaScript

كيف تعمل المساواة في JavaScript فعلياً: الفرق بين == و ===، غرائب التحويل التلقائي، سلوك NaN والكائنات، ومتى تلجأ إلى Object.is.

طريقتان للسؤال: "هل هاتان القيمتان متساويتان؟"

توفّر لك جافا سكريبت عاملَين للمساواة: === (المساواة الصارمة) و == (المساواة المرنة). يبدوان متطابقَين تقريباً في الشكل، لكنّ سلوكهما مختلف تماماً.

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

=== يتحقّق هل الطرفان من نفس النوع وَ نفس القيمة. أمّا == فيقوم أوّلًا بتحويل الطرفين إلى نوع مشترك ثم يقارن. هذا التحويل — أو ما يُعرف بـ Type Coercion في جافا سكريبت — هو السبب الرئيسي في السمعة السيّئة التي لحقت بعوامل المساواة في جافا سكريبت.

باختصار: اعتمد === افتراضيًا. لكن يستحق الأمر أن تقرأ التفاصيل مرّة واحدة حتى تعرف ما الذي تتجنّبه بالضبط.

المساواة الصارمة في جافا سكريبت: ما تحتاجه غالبًا

يُعيد === القيمة true فقط عندما يتطابق الطرفان في النوع والقيمة معًا. لا تحويل ضمني، ولا مفاجآت:

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

إذا اختلف النوعان، فالنتيجة false مباشرةً. أما إذا تطابقا، فتقارن جافا سكريبت القيمتين: مقارنة قيمة للأنواع البدائية، ومقارنة مرجع للكائنات (وسنعود لهذه النقطة بعد قليل).

أما !== فهو عامل عدم المساواة الصارمة، ويتبع القواعد نفسها ولكن بالعكس.

المساواة المرنة: تحويل أنواع متخفٍّ

يسمح العامل == بأن يكون الطرفان من نوعين مختلفين، إذ يُجري قبل المقارنة رقصة تحويل (Type Coercion) ليحاول توحيد النوعين:

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

القواعد الدقيقة موجودة في المواصفة (spec)، وهي في الحقيقة ليست بذلك السوء، لكن تذكّرها وأنت في خضم تصحيح الأخطاء قصة أخرى تماماً. فمثلاً "0" == false يُرجِع true، وهذا يوقع حتى المطوّرين المخضرمين في فخّه. ونفس الشيء مع [] == false (يُرجِع true أيضاً، لأن المصفوفة تتحوّل إلى ""، التي تتحوّل بدورها إلى 0).

ولهذا السبب تنصحك معظم أدلة الأسلوب البرمجي — وكذلك قاعدة eqeqeq في ESLint — باستخدام === افتراضياً. أنت تضيف حرفاً واحداً فقط في الكتابة، وتتخلّص في المقابل من قواعد يصعب حفظها.

النمط الوحيد المفيد لاستخدام ==

يوجد تعبير اصطلاحي وحيد يستحقّ التعلّم في المساواة المرنة (loose equality): فالتحقّق x == null يُرجِع true عندما تكون قيمة x إمّا null أو undefined، ويُرجِع false فيما عدا ذلك.

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

البديل الصارم هو x === null || x === undefined، وهو يؤدي الغرض لكنه يبدو مزعجًا بصريًا. لهذا السبب تسمح كثير من المشاريع باستخدام == null كاستثناء وحيد مقبول. اختر قاعدة واحدة والتزم بها في كل مكان.

مقارنة الكائنات في javascript تتم بالمرجع

حين يتعلق الأمر بالكائنات والمصفوفات والدوال، فإن كلًا من === و == يطرحان نفس السؤال: "هل الطرفان يشيران إلى نفس الكائن في الذاكرة؟" وليس "هل يحملان نفس المحتوى؟"

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

كائنان حرفيّان بنفس المحتوى يظلّان كائنَين مختلفَين. هذه نقطة يقع فيها الجميع مرّة على الأقل.

لمقارنة الكائنات في javascript اعتمادًا على القيم، إمّا أن تكتب دالّة مساعدة خاصة بك، أو تستعين بمكتبة مثل lodash.isequal، أو تلجأ إلى JSON.stringify إذا كانت الكائنات بسيطة ومسطّحة:

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

JSON.stringify تنفع فقط مع البيانات البسيطة — فهي تتجاهل الدوال وundefined والرموز (symbols)، كما أنها لا تضمن ترتيب المفاتيح بين محركات JavaScript المختلفة في جميع الحالات. إنها حل سريع للفحص، لا حل عام يُعتمد عليه.

لماذا NaN لا يساوي أي شيء حتى نفسه؟

القيمة NaN (اختصار لـ "not a number") هي ما تُرجعه جافا سكريبت عندما لا يكون للعملية الرقمية نتيجة منطقية — مثل 0/0 أو Number("abc") أو Math.sqrt(-1). عاملا المساواة كلاهما يُرجعان false إذا كان أحد الطرفين NaN، حتى لو كان الطرفان كلاهما NaN:

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

للكشف عن NaN، استخدم Number.isNaN(value). تجنّب الدالة العامة القديمة isNaN، لأنها تُجري تحويلًا للنوع قبل الفحص، فمثلًا isNaN("hello") يُرجع true، وهذه نتيجة نادرًا ما تكون مطلوبة.

Object.is: شبيهة بـ === مع تصحيحين

الدالة Object.is(a, b) تتصرف تمامًا مثل ===، باستثناء حالتين فقط:

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

في أغلب الأحيان === هو ما تحتاجه فعلاً. أما Object.is فاستعمله عندما تريد تحديداً أن تعتبر NaN مساوياً لنفسه، أو أن تميّز بين +0 و-0 — وكلتا الحالتين نادرتان، لكنهما تصبحان مهمتين أحياناً في الشيفرات التي تتعامل مع الأرقام بدقة وفي البنية الداخلية لبعض أُطر العمل (مثلاً React يعتمد على Object.is في مقارنة الحالة).

عوامل عدم المساواة تتبع نفس التقسيم

!== صارم، و!= فضفاض، ونفس النصيحة السابقة تنطبق هنا:

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

الافتراضي هو استخدام !==. وإذا كنت تسمح في مشروعك باستعمال == null، فلا مانع من السماح بنظيره != null للتحقق من أن القيمة ليست null وليست undefined في آنٍ واحد.

قائمة مرجعية للمقارنة بين القيم

كلما احتجت إلى المقارنة بين قيمتين، مرّ على هذه الأسئلة:

  • قيم أولية من النوع نفسه؟ استخدم ===.
  • تتحقق من null أو undefined؟ x == null خيار مقبول إذا سمح به دليل كتابة الأكواد لديك، وإلا فاكتبها صراحةً: x === null || x === undefined.
  • تتحقق من NaN؟ استعمل Number.isNaN(x).
  • مقارنة الكائنات بالمرجع (الهوية)؟ === يقوم بالمطلوب تمامًا.
  • مقارنة الكائنات بالمحتوى؟ عليك بكتابة دالة مساعدة، أو استخدام مكتبة جاهزة، أو تحويل الكائنين إلى نص عبر التسلسل. العوامل المدمجة لن تفيدك هنا.

التزم بـ ===، وتعامل مع == كأداة خاصة لحالة == null فقط، وبهذا ستتجنّب معظم غرائب المساواة التي تملأ أسئلة جافا سكريبت الشائعة.

التالي: العوامل (Operators)

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

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

ما الفرق بين == و === في JavaScript؟

=== هو عامل المساواة الصارمة (Strict Equality)، ويرجع true فقط إذا تطابق المعاملان في النوع والقيمة معاً. أما == فهو المساواة المرنة (Loose Equality)، ويقوم بتحويل المعاملين إلى نفس النوع قبل المقارنة. لذلك 1 === '1' يرجع false، بينما 1 == '1' يرجع true لأن == يحوّل النص إلى رقم أولاً.

هل يجب استخدام === دائماً في JavaScript؟

كقاعدة افتراضية، نعم. === سلوكه متوقع وقواعده واضحة وسهل تتبّعها ذهنياً. الاستثناء الشائع الوحيد هو x == null، لأنه يلتقط القيمتين null و undefined معاً في فحص واحد. معظم أدوات الـ linting (مثل قاعدة eqeqeq في ESLint) تفرض استخدام === وتسمح بهذا النمط تحديداً كاستثناء اختياري.

لماذا NaN === NaN يرجع false؟

لأن مواصفة IEEE 754 تنص على أن NaN لا يساوي أي شيء، حتى نفسه. لذلك أي عامل مساواة سيرجع false إذا كان أحد الطرفين NaN. للتحقق من أن قيمة ما هي NaN استخدم Number.isNaN(x)، أو Object.is(NaN, NaN) الذي يرجع true.

كيف أقارن بين كائنين (Objects) في JavaScript؟

كلا من == و === يقارنان الكائنات بالمرجع (Reference) لا بالمحتوى. فمثلاً {a: 1} === {a: 1} يرجع false لأنهما كائنان مختلفان في الذاكرة. للمقارنة بالقيم تحتاج إلى كتابة دالة مقارنة خاصة، أو استخدام مكتبة مثل isEqual من Lodash، أو الاعتماد على JSON.stringify للكائنات البسيطة (Plain Objects).

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

ابدأ الآن