در برنامهنویسی، تصمیمگیریها معمولاً بر پایهٔ مقایسهٔ مقادیر انجام میشوند. جاوااسکریپت چندین روش برای مقایسه ارائه میدهد که هرکدام رفتار خاصی دارند. در این مقاله، تفاوتهای ظریف بین انواع مقایسهها را بررسی میکنیم.
رایجترین مقایسه در JS بررسی این است که آیا مقدار X با مقدار Y "یکسان" است یا نه. اما "یکسان بودن" در JS همیشه به معنای تطابق دقیق نیست.
عملگر === که بهعنوان مساوی دقیق (strict equality) شناخته میشود، معمولاً هم مقدار و هم نوع را بررسی میکند:
3 === 3.0; // true
"yes" === "yes"; // true
null === null; // true
42 === "42"; // false
true === 1; // false
null === undefined; // falseدر ظاهر، === نوع و مقدار را بررسی میکند و هیچ تبدیل نوعی (coercion) انجام نمیدهد. اما این عملگر در دو مورد خاص دروغ میگوید: NaN و -0.
NaN === NaN; // false
0 === -0; // trueبرای مقایسهٔ درست NaN از Number.isNaN(..) استفاده کنید، و برای -0 از Object.is(..):
Object.is(NaN, NaN); // true
Object.is(-0, 0); // falseمیتوان Object.is(..) را بهعنوان مساوی چهارگانه ==== در نظر گرفت — مقایسهای واقعاً دقیق!
مقایسهٔ اشیاء در JS بر پایهٔ هویت مرجع (reference identity) انجام میشود، نه ساختار یا محتوا:
[1, 2, 3] === [1, 2, 3]; // false
{ a: 42 } === { a: 42 }; // false
(x => x * 2) === (x => x * 2); // falseدر این مثالها، مقادیر ظاهراً یکساناند، اما چون هرکدام شیء یا تابع جدیدی هستند، مقایسهٔ آنها false میشود.
var x = [1, 2, 3];
var y = x;
y === x; // true
y === [1, 2, 3]; // falseدر اینجا، y و x به یک آرایهٔ مشترک اشاره دارند، اما مقایسه با آرایهٔ جدید شکست میخورد چون مرجع متفاوت است.
جاوااسکریپت مکانیزمی برای مقایسهٔ ساختاری اشیاء ندارد. برای چنین مقایسهای باید خودتان منطق بررسی را پیادهسازی کنید. اما این کار پیچیدهتر از آن چیزیست که به نظر میرسد — مثلاً مقایسهٔ دو تابع از نظر ساختار یا closure تقریباً غیرممکن است.
در جاوااسکریپت، مقایسهٔ مقادیر بهظاهر ساده است، اما در عمل تفاوتهای ظریفی دارد. === برای بیشتر موارد مناسب است، اما در موارد خاص مانند NaN و -0 باید از Object.is(..) یا Number.isNaN(..) استفاده کرد. برای اشیاء، فقط مقایسهٔ مرجعی انجام میشود، نه ساختاری. شناخت این تفاوتها برای نوشتن کدهای دقیق و قابلاعتماد ضروری است.