جافاسكريبت - لماذا لا يوجد XOR منطقي؟


لماذا لا يوجد XOR منطقي في جافاسكريبت؟

الإجابة رقم 1

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

إذا كان لديك متغيران من النوع البولياني يمكنك تقليد العملية XOR باستخدام:

if (a != b)

مع متغيرين عشوائيين، يمكنك استخدام ! لتحويلهما إلى قيم منطقية ثم استخدام نفس الحيلة:

if (!a != !b)

هذا غامض إلى حد ما ومع ذلك بالتأكيد يستحق تعليقًا. في الواقع، يمكنك حتى استخدام عامل XOR الثنائي في هذه المرحلة، على الرغم من أن هذا سيكون ذكيًا جدًا لذوقي:

if (!a ^ !b)

الإجابة رقم 2

جافاسكريبت يحتوي على عامل XOR على مستوى البتات: ^

var nb = 5^9 // = 12

يمكنك استخدامه مع القيم البوليانية وسيعطي النتيجة كـ 0 أو 1 (والتي يمكنك تحويلها مرة أخرى إلى بوليان، على سبيل المثال result=!!(op1 ^op2)). ولكن كما قال جون، فهو مكافئ لـ result=(op1 != op2)، وهو أوضح.

الإجابة رقم 3

عملية XOR بين قيمتين منطقيتين هي ببساطة معرفة ما إذا كانتا مختلفتين، لذلك:

Boolean(a) !== Boolean(b)

الإجابة رقم 4

لا توجد عوامل منطقية حقيقية في جافاسكريبت (على الرغم من أن ! قريب جدًا من ذلك). العامل المنطقي سيأخذ فقط true أو false كقيم operands وسيعود فقط true أو false.

في جافاسكريبت، يأخذ && و|| جميع أنواع المعاملات ويعيد جميع أنواع النتائج المضحكة (مهما أدخلت فيها).

يجب على العامل المنطقي أيضًا أن يأخذ دائمًا في الاعتبار قيم كل من العاملين.

في جافاسكربت && و || يأخذان اختصارًا كسولًا و لا يقوما بتقييم العامل الثاني في حالات معينة وبالتالي تتجاهل تأثيراته الجانبية. من المستحيل إعادة إنشاء هذا السلوك باستخدام xor منطقي.

a() && b() تقوم بتقييم a() وترجع النتيجة إذا كانت خاطئة. وإلا، فإنها تقوم بتقييم b() وترجع النتيجة. لذلك، تكون النتيجة التي تم إرجاعها صحيحة إذا كانت كلتا النتيجتين صحيحتين، وخاطئة خلاف ذلك.

a() || b() يقوم بتقييم a() ويعيد النتيجة إذا كانت صحيحة. وإلا فإنه يقوم بتقييم b() ويعيد النتيجة. لذلك تكون النتيجة المعادة خاطئة إذا كانت كلتا النتيجتين خاطئتين، وصحيحة خلاف ذلك.

لذلك الفكرة العامة هي تقييم المعامل الأيسر أولاً. يتم تقييم المعامل الأيمن فقط إذا كان ذلك ضرورياً. والقيمة الأخيرة هي النتيجة. يمكن أن تكون هذه النتيجة أي شيء. كائنات، أرقام، سلاسل ... أي شيء!

هذا يجعل من الممكن كتابة أشياء مثل

image = image || new Image(); // default to a new Image

أو

src = image && image.src; // only read out src if we have an image

ولكن يمكن أيضًا استخدام قيمة الحقيقة لهذه النتيجة لتحديد ما إذا كان المشغل المنطقي "الحقيقي" سيُرجع صحيحًا أم خطأ.

هذا يجعل من الممكن كتابة أشياء مثل

if (typeof image.hasAttribute === 'function' && image.hasAttribute('src')) {

أو

if (image.hasAttribute('alt') || image.hasAttribute('title')) {

لكن عامل XOR "المنطقي" (^^) سيتعين عليه دائمًا تقييم كل من العاملين. هذا يجعله مختلفًا عن العوامل "المنطقية" الأخرى التي تقوم بتقييم العامل الثاني فقط إذا لزم الأمر. أعتقد أن هذا هو السبب في عدم وجود XOR "منطقي" في جافاسكريبت، لتجنب الالتباس.

فماذا يجب أن يحدث إذا كان كلا العاملين زائفين؟ يمكن أن يتم إرجاع كلاهما. لكن يمكن إرجاع واحد فقط. أيهما؟ الأول؟ أم الثاني؟ حدسي يخبرني بإرجاع الأول لكن عادةً ما تقوم العمليات "المنطقية" بالتقييم من اليسار إلى اليمين وإرجاع القيمة الأخيرة التي تم تقييمها. أو ربما مصفوفة تحتوي على كلا القيمتين؟

وإذا كان أحد العاملين صحيحًا والآخر خاطئًا، فيجب على العملية XOR أن ترجع العامل الصحيح. أو ربما مصفوفة تحتوي على العامل الصحيح، لجعلها متوافقة مع الحالة السابقة؟

وأخيرًا، ماذا يجب أن يحدث إذا كانت كلا العاملين صحيحتين؟ قد تتوقع شيئًا خاطئًا. لكن لا توجد نتائج خاطئة. لذلك لا يجب أن تُعيد العملية أي شيء. لذلك ربما undefined أو .. مصفوفة فارغة؟ لكن المصفوفة الفارغة لا تزال صحيحة.

باستخدام نهج المصفوفة ستنتهي إلى شروط مثل if ((a ^^b).length !== 1) {. هذا مربك جدًا.

الإجابة رقم 5

حوّل القيم إلى الشكل البوليني ثم قم بأخذ XOR على مستوى البت:

Boolean(a) ^ Boolean(b) // === 0 | 1

لاحظ أن نتيجة هذا التعبير هي رقم و ليست قيمة منطقية.

يعمل العامل XOR على مستوى البت أيضًا مع القيم غير المنطقية، لكن تذكر أن هذا عامل بتي، وليس منطقيًا. استخدام القيم غير المنطقية قد لا يسير كما تتوقع في البداية:

(5 ^ 3) === 6 // true

الإجابة رقم 6

تحويل إلى قيمة منطقية ثم تنفيذ العملية XOR كما يلي -

!!a ^ !!b

الإجابة رقم 7

هناك ... نوع من:

if( foo ? !bar : bar ) {
  ...
}

أو أسهل للقراءة:

if( ( foo && !bar ) || ( !foo && bar ) ) {
  ...
}

لماذا؟ لا أدري.

لأن مطوري جافاسكريبت اعتقدوا أنه سيكون غير ضروري لأنه يمكن التعبير عنه بواسطة عوامل منطقية أخرى موجودة ومُطبقة بالفعل.

كان بإمكانك أيضًا أن تكتفي بـ NAND وفقط، يمكنك أن تستنتج كل عملية منطقية ممكنة من ذلك.

أعتقد شخصيًا أن هناك أسبابًا تاريخية تأتي من لغات البرمجة ذات بناء جملة قائم على C، حيث حسب علمي، لا توجد عملية XOR أو على الأقل نادرة جدًا.

الإجابة رقم 8

نعم، فقط قم بما يلي. بافتراض أنك تتعامل مع القيم المنطقية booleans A و B، يمكن حساب قيمة A XOR B في JavaScript باستخدام ما يلي

var xor1 = a !== b;

السطر السابق يعادل أيضًا ما يلي

var xor2 = (!a !== !b);

شخصيًا، أفضل xor1 لأنني أحتاج لكتابة عدد أقل من الأحرف. أعتقد أن xor1 أسرع أيضًا. إنه يقوم بإجراء حسابين فقط. أما xor2 فيقوم بإجراء ثلاثة حسابات.

شرح بصري ... اقرأ الجدول أدناه (حيث 0 تعني خطأ و 1 تعني صحيح) وقارن بين العمودين الثالث والخامس.

!(A === B):

| A | B | A XOR B | A === B | !(A === B) |
------------------------------------------
| 0 | 0 |    0    |    1    |      0     |
| 0 | 1 |    1    |    0    |      1     |
| 1 | 0 |    1    |    0    |      1     |
| 1 | 1 |    0    |    1    |      0     |
------------------------------------------

استمتع.