Truthy، Falsy و روش‌های مقایسه‌ی مقادیر

اهداف یادگیری

  • مرور و تثبیت مفهوم Truthy و Falsy در شرط‌ها
  • درک تفاوت دقیق بین == و ===
  • آشنایی با Object.is و تفاوت آن با ===
  • توانایی انتخاب روش مناسب مقایسه در موقعیت‌های مختلف

مقدمه

در درس قبل با مفهوم Truthy و Falsy آشنا شدیم. در این درس، این مفهوم را کامل‌تر بررسی می‌کنیم و سپس وارد یکی از مهم‌ترین مباحث جاوااسکریپت می‌شویم: تفاوت بین == و ===. این تفاوت مستقیماً به Type Coercion که در درس قبل یاد گرفتیم مرتبط است.

مرور Truthy و Falsy

همان‌طور که در درس قبل دیدیم، جاوااسکریپت در شرط‌ها هر مقداری را به Boolean تبدیل می‌کند. فقط شش مقدار زیر Falsy هستند:

false
0
""
null
undefined
NaN

هر مقدار دیگری، از جمله آرایه‌ی خالی [] و شیء خالی {}، Truthy محسوب می‌شود:

if ([]) {
  console.log("اجرا می‌شود"); // چون [] یک مقدار Truthy است
}

if ({}) {
  console.log("این هم اجرا می‌شود"); // چون {} هم Truthy است
}

عملگر == (Loose Equality)

عملگر == پیش از مقایسه، در صورت متفاوت بودن نوع دو مقدار، ابتدا آن‌ها را با قوانین Type Coercion به یک نوع مشترک تبدیل می‌کند و سپس مقایسه انجام می‌شود:

console.log(5 == "5");     // true — رشته به عدد تبدیل می‌شود
console.log(0 == false);   // true — false به 0 تبدیل می‌شود
console.log(null == undefined); // true — قاعده‌ی خاص برای این دو
console.log("" == 0);      // true — رشته‌ی خالی به 0 تبدیل می‌شود

همین رفتار باعث می‌شود == گاهی نتایج غیرمنتظره و دشوار برای پیش‌بینی تولید کند.

عملگر === (Strict Equality)

عملگر === هیچ‌گونه تبدیل نوعی انجام نمی‌دهد. اگر نوع دو مقدار یکسان نباشد، بلافاصله false برمی‌گرداند:

console.log(5 === "5");    // false — نوع متفاوت است
console.log(0 === false);  // false — نوع متفاوت است
console.log(5 === 5);      // true — نوع و مقدار یکسان است

تحلیل کد

تفاوت اصلی این دو عملگر در این است که == ابتدا سعی می‌کند دو مقدار را «قابل مقایسه» کند، اما === از همان ابتدا هم نوع و هم مقدار را باهم می‌سنجد. به همین دلیل، === رفتاری کاملاً قابل پیش‌بینی دارد و == وابسته به قوانین پیچیده‌ی Type Coercion است.

Object.is چیست؟

Object.is شبیه به === عمل می‌کند، اما در دو مورد خاص رفتار متفاوتی دارد:

console.log(Object.is(NaN, NaN));   // true
console.log(NaN === NaN);            // false

console.log(Object.is(0, -0));       // false
console.log(0 === -0);               // true

در جاوااسکریپت، NaN با هیچ مقداری، حتی خودش، با === برابر نیست. اما Object.is این استثنا را در نظر می‌گیرد و NaN را با خودش برابر می‌داند. از سوی دیگر، 0 و -0 با === برابر شناخته می‌شوند، اما Object.is بین آن‌ها تفاوت قائل می‌شود.

جدول مقایسه

عملگرتبدیل نوع؟NaN با NaN0 با -0
==بلهfalsetrue
===خیرfalsetrue
Object.isخیرtruefalse

اشتباهات رایج

  • استفاده‌ی گسترده از == بدون آگاهی از قوانین Type Coercion، که می‌تواند باگ‌های پنهان ایجاد کند.
  • استفاده از === برای بررسی برابر بودن یک مقدار با NaN؛ در حالی که راه درست استفاده از Number.isNaN() یا Object.is است.
  • تصور اینکه Object.is جایگزین کاملی برای === در همه‌ی موارد است؛ درحالی‌که تفاوت آن‌ها فقط در دو مورد خاص (NaN و ۰/-۰) بروز می‌کند.

Best Practices

  • همیشه از === به‌جای == استفاده کنید، مگر در موارد بسیار خاص که مقایسه‌ی null و undefined با هم مدنظر باشد.
  • برای بررسی NaN از Number.isNaN(value) استفاده کنید، نه از مقایسه‌ی مستقیم.

ارتباط با سایر مفاهیم

مفهوم Truthy/Falsy مستقیماً روی رفتار ساختارهای شرطی مثل if تأثیر می‌گذارد، و تفاوت == و === در واقع کاربرد عملی همان قوانین Type Coercion است که در درس قبل بررسی کردیم. این مفاهیم در فصل‌های آینده، به‌ویژه در تحلیل رفتار کد و پیش‌بینی خروجی، بارها مورد استفاده قرار می‌گیرند.

جمع‌بندی

عملگر == پیش از مقایسه، مقادیر را با قوانین Type Coercion هم‌نوع می‌کند، درحالی‌که === بدون هیچ تبدیلی، نوع و مقدار را دقیقاً مقایسه می‌کند. Object.is نیز مشابه === عمل می‌کند، با دو استثنای مهم: NaN را با خودش برابر می‌داند و بین 0 و -0 تفاوت قائل می‌شود.