۶ ژوئیه ۲۰۲۳

مقایسه ها

عملگرهای مقایسه ای زیادی را از ریاضی می شناسیم.

در جاوااسکریپت آن ها را مانند شکل زیر می نویسم:

  • بزرگ تر / کوچک تر: a > b، a < b.
  • بزرگ تر / کوچک تر یا مساوی: a >= b، a <= b.
  • برابر یا مساوی: a == b، توجه کنید که علامت مساوی دوتایی (double equlity) == به معنای تست برابری است، در حالی که یک مساوی a = b مقدار سمت راست را در متغیر سمت چپ می ریزد.(asign).
  • نابرابری: در ریاضی علامت نابرابری است، اما در جاوااسکریپت به صورت a != b نوشته می‌شود.

در این مقاله ما بیشتر درباره تفاوت انواع مقایسه ها، چطور جاوااسکریپت آنها را انجام می دهد، به همراه رفتارهای عجیب و مهم این زبان.

در انتها شما می توانید به راحتی از از مشکلات مربوط به علامت ها دوری کنید.

‌نتیجه یک boolean است

تمام عملگرهای مقایسه ای یک مقدار از نوع boolean برمی گردانند:

  • true – به معنای “بله” و “درست” است.
  • false – به معنای “نه” و “غلط” است.

برای مثال:‌

alert( 2 > 1 );  // true (درست)
alert( 2 == 1 ); // false (غلط)
alert( 2 != 1 ); // true (درست)

نتیجه یک مقایسه می تواند داخل یک متغیر ذخیره شود، دقیقا مانند هر مقدار دیگری:

let result = 5 > 4; // assign the result of the comparison
alert( result ); // true

مقایسه رشته ها (string)

برای این که متوجه شموی که آیا یک رشته بزرگ تر از رشته ی دیگر هست یا نه، جاوااسکریپت از یک مفهوم به نام “dictionary” یا “lexicographical order” استفاده می کند.

به عبارت دیگر، رشته ها حرف به حرف با یکدیگر مقایسه می شوند.

برای مثال:

alert( 'Z' > 'A' ); // true
alert( 'Glow' > 'Glee' ); // true
alert( 'Bee' > 'Be' ); // true

الگوریتمی که برای مقایسه دو رشته استفاده می شود بسیار ساده است:

  1. اولین کاراکتر هر دو رشته را با هم مقایسه کن.
  2. اگر اولین کاراکتر رشته اول بزرگ تر (یا کوچک تر) از اولین حرف رشته دیگر بود، آنگاه رشته اول بزرگ تر ( یا کوچک تر) از رشته دوم است و الگوریتم به پایان می رسد.
  3. در غیر این صورت، اگر هر دو کاراکتر مانند هم بودند، حرف دوم رشته ها را به روش مرحله قبل با هم مقایسه می کند.
  4. این عمل را تا پایان یکی از رشته ها ادامه می دهد.
  5. اگر هر دو رشته با هم به پایان برسند، در آن صورت آن ها مساوی هستند. در غیر این صورت، رشته بزرگتر بزرگ تر است.

در مثال بالا، مقایسه 'Z' > 'A' در اولین مرحله به نتیجه می رسد.

درحالی که رشته های 'Glow' و 'Glee' حرف به حرف با هم مقایسه می شوند:

  1. G دقیقا مانند G است.
  2. l دقیقا مانند l است.
  3. o از e بزرگ تر است. الگوریتم در این جا به پایان می رسد و نتیجه می گیرد که رشته اول بزرگ تر است.
از نظر تکنیکی بر اساس یک دیکشنری عمل نمی کند ولی کد های یونی (unicode) آن مرتب شده اند.

ترتیب و ارزشی که در الگوریتم مقایسه بالا به هر حرف داده می شود، تقریبا مانند دیکشنری ها یا کتاب های تلفن است، اما نه دقیقا مشابه آن ها.

برای مثال، بزرگ یا کوچکیه حروف اهمیت دارند. حرف "A" بزرگ با حرف "a" کوچک برابر نیست. حتما می پرسید کدام یک بزرگ تر است؟ جواب حرف "a" کوچک است. چرا؟ به دلیل اینکه حرف “a” کوچک دارای شماره بزرگتری در جدول encoding ٔداخلی خود جاوااسکریپت دارد. (Unicode). ما بعدا در فصل رشته ها به این موضوع مفصل می پردازیم. رشته‌ها.

مقایسه انواع متفاوت داده با یکدیگر

وقتی که مقادیر با نوع های متفاوت را در جاوااسکریپت با یکدیگر مقایسه می کنید، جاوااسکریپت مقادیر را به نوع داده Number تبدیل می کند.

برای مثال:

alert( '2' > 1 ); // true، رشته '2' به عدد 2 تبدیل می شود.
alert( '01' == 1 ); // true، رشته '01' به عدد 1 تبدیل می شود.

برای مقادیر از نوع true boolean به 1 و false به 0 تبدیل می شود.

برای مثال:

alert( true == 1 ); // true
alert( false == 0 ); // true
یک اتفاق جالب

این امکان وجود دارد که همزمان:

  • دو مقدار با هم مساوی باشند.
  • یکی از آن ها در نوع false boolean است و دیگری true.

برای مثال:

let a = 0;
alert( Boolean(a) ); // false

let b = "0";
alert( Boolean(b) ); // true

alert(a == b); // true!

از نظر جاوااسکریپت، این تنیجه کاملا عادی است. علامت برابری (equality) = مقادیر را به number تبدیل کرده و سپس آن ها را با یکدیگر مقایسه می کند.(به همین دلیل "0" به 0 تبدیل می شود.) اما تبدیل آن ها به صورت جداگانه به Boolean از قانون های دیگری استفاده می کند.

برابری سختگیرانه

یک علامت مقایسه برابری معمولی == یک مشکل دارد. این عملگر بین 0 و false تفاوتی قائل نمی شود:

alert( 0 == false ); // true

دقیقا همین اتفاق برای یک رشته خالی هم می افتد:

alert( '' == false ); // true

دلیل این اتفاق این است که مقادیر با نوع های متفاوت به نوع number توسط عملگر == تبدیل می شوند و یک رشته خالی دقیقا مانند مقدار false به صفر تبدیل می شود.

سوال اینجاست که ما چطور می توانیم بین false و 0 تفاوت ایجاد کنیم؟

عملگر مقایسه برابری سخت گیرانه (strict equality operator) === برابری را بدون تبدیل به نوع number انجام می دهد.

به عبارت دیگر، اگر نوع متغیر های a و b با یکدیگر متفاوت باشد، در این صورت عملیات a === b بالافاصله مقدار false را برمی گرداند و عمل تغییر نوع داده را انجام نمی دهد.

بیاید امتحان کنیم:

alert( 0 === false ); // false، به خاطر اینکه نوع آن ها با یکدیگر متفاوت است.

یک علامت “مقایسه نابرابری سختگیرانه” (strict non-equality operator) !== هم وجود دارد در کنار عملگر مقایسه نابرابری !=.

نوع سختگیرانه این عملگرها در زمان نوشتن کمی طولانی تر می شوند، اما به وضوح مشخص می کند که چه اتفاقی در پشت پرده در حال افتادن است و احتمال خطا را کاهش می دهد.

مقایسه با مقادیر null و undefined

در زمان مقایسه مقادیر متفاوت با null و undefined یک رفتار غیر قابل پیش بینی اتفاق می افتد.

در زمان استفاده از عملگر برابری سختگیرانه ===

این دو مقدار با یکدیگر نا برابرند به دلیل اینکه از دو نوع متفاوت هستند.

alert( null === undefined ); // false
در زمان استفاده از عملگر برابری غیر سختگیرانه ==

یک قانون خاص وجود دارد. تنها این دو با هم برابرند و نه با هیچ مقدار دیگری

alert( null == undefined ); // true
برای ریاضی و دیگر مقایسه ها < > <= >=

null/undefined به عدد تبدیل می شوند: null تبدیل به 0 می شود در حالی که undefined به NaN.

حال بگذارید چند اتفاق با مزه و جالب که با اعمال این قانون ها می افتند را ببینیم. و مهم تر از همه ببینیم که چگونه داخل این تله ها نیفتیم.

نتایج عجیب: 0 در مقابل null

مقایسه مقدار null با صفر:

alert( null > 0 );  // (1) false
alert( null == 0 ); // (2) false
alert( null >= 0 ); // (3) true

از نظر ریاضی، این ۳ عبارت با هم هم خوانی ندارند. عبارت آخر مشخص می کند که "null بزرگ تر یا مساوی 0" است، پس منتطقا یکی از دو عبارت اول باید true باشند درحالی که هر دو false هستند.

دلیل این اتفاق این است که عملگر == و > < >= <= متفاوت با یکدیگر عمل می کنند. علامت های مقایسه ای مقدار null را به یک عدد تبدیل می کنند، و با آن مانند عدد 0 رفتار می کنند. به همین دلیل عبارت (۳) true است و عبارت (۱) false.

از طرفی ، عملگر == مقادیر undefined و null را با هم برابر و نابرابر با هر مقدار دیگری در نظر می گیرد، به همین دلیل عبارت شماره (۲) false است.

undefiend غیرقابل مقایسه

مقدار undefined نباید با دیگر مقادیر مقایسه شود:

alert( undefined > 0 ); // false (1)
alert( undefined < 0 ); // false (2)
alert( undefined == 0 ); // false (3)

به نظر شما چرا undefiend انقدر از صفر بدش می آید که در تمام حالات false برمی گرداند!

دلیل این نتایج:

  • در عبارت شماره (1) و (2) مقدار undefined به مقدار NaN تبدیل می شود که یک نوع خاص از number ها است که در تمام مقایسه ها false برمی گرداند.
  • در عبارت (3) عملگر ==، false برمی گرداند زیرا undefined تنها برابر null بوده و نابرابر با هر مقدار دیگری.

اجتناب از مشکلات

چرا ما این مثال ها را بررسی کردیم؟ آیا ما این رفتار های عجیب را باید همیشه به خاطر داشته باشیم؟ در حقیقت نیازی به این موضوع نیست. زیرا در گذر زمان و به صورت تدریجی این رفتار های برای شما آشنا می شوند، اما یک راه حل کاربردی و مطمئن برای دوری از این مشکلات وجود دارد:

  • با احتیاط و ملاحظه از undefined/null در مقایسه های خود استفاده کنید به جزء زمانی که از عملگر === استفاده می کنید.
  • از علامت های مقایسه ای >= > < <= برای مقایسه مقادیری که ممکن از undefined/null شوند استفاده نکنید مگر اینکه واقعا متوجه عواقب کارهای خود هستید. اگر متغیری می تواند این مقادیر را داشته باشد، آن ها را به صورت جداگانه بررسی کنید.

خلاصه

  • عملگرهای مقایسه یک مقدار boolean را برمی گردانند.
  • رشته ها به صورت حرف به حرف با توجه به ترتیب حروف در “دیکشنری” با هم مقایسه می شوند.
  • وقتی که مقادیری با نوع های متفاوت با یکدیگر مقایسه می شوند، به نوع number تبدیل می شوند (بدون در نظر گرفتن حالت استفاده از عملگر === ).
  • مقادیری null و undefined با یکدیگر برابر == و با هر مقدار دیگری نابرابرند.
  • زمانی که از علامت ها > یا < برای مقایسه متغیر هایی که می توانند مقدار null/undefined داشته باشند استفاده می کنید، مراقب باشید. بررسی برای مقارید null/undefined به صورت جداگانه کار بسیار پسندیده ای است.

تمارین

اهمیت: 5

نتیجه نهایی عبارت های زیر چیست؟

5 > 4
"apple" > "pineapple"
"2" > "12"
undefined == null
undefined === null
null == "\n0\n"
null === +"\n0\n"
5 > 4 → true
"apple" > "pineapple" → false
"2" > "12" → true
undefined == null → true
undefined === null → false
null == "\n0\n" → false
null === +"\n0\n" → false

بعضی از دلایل:

  1. true، نیاز به توضیح نداره.
  2. false، بر اساس مقایسه لغت نامه ای که "a" کوچک تر از "p" است.
  3. دوباره مانند مثال قبل در مقایسه لغت نامه ای حرف اول "2" بزرگ تر از حرف اول عبارت دیگر "1" است.
  4. مقادیر null و undefined تنها برابر یکدیگرند.
  5. برابری سختگیرانه، سختگیرانه است. به دلیل تفاوت در نوع داده پاسخ false است.
  6. مانند مثال شماره (4)، null تنها برابر undefined است.
  7. برابری سختگیرانه برای دو داده از دو نوع متفاوت.
نقشه آموزش

نظرات

قبل از نظر دادن این را بخوانید…
  • اگر پیشنهادی برای بهبود ترجمه دارید - لطفا یک ایشوی گیت‌هاب یا یک پول‌ریکوئست به جای کامنت‌گذاشتن باز کنید.
  • اگر چیزی را در مقاله متوجه نمی‌شوید – به دقت توضیح دهید.
  • برای قراردادن یک خط از کد، از تگ <code> استفاده کنید، برای چندین خط – کد را درون تگ <pre> قرار دهید، برای بیش از ده خط کد – از یک جعبهٔ شنی استفاده کنید. (plnkr، jsbin، codepen…)