Comparisons in JavaScript – From === to Object.is and the Difference Between Primitives and References

Comparing values is essential for decision-making in JavaScript programs. This article explores the nuances of strict equality (===), identity vs structural comparison, and special cases like NaN and -0. It also explains how object and function comparisons work and why JavaScript doesn’t support structural equality natively. Understanding these distinctions is key to writing reliable code.

comparisonstrict-equalityObject.isreference-value

~2 دقیقه مطالعه · آخرین به‌روزرسانی ۳۰ مهر ۱۴۰۴

Introduction


In programming, comparisons help us make decisions. JavaScript offers several mechanisms for comparing values, each with its own behavior. This article explores the subtleties of equality and identity in JS.


Equal…ish


The most common comparison asks: “Is value X the same as value Y?” But in JS, “same” can mean different things depending on context. The === operator, known as strict equality, checks both value and type — without coercion:


3 === 3.0;       // true
"yes" === "yes"; // true
42 === "42";     // false
true === 1;      // false
null === undefined; // false

While === avoids type coercion, it has quirks — especially with NaN and -0.


Comparing NaN and -0


NaN === NaN; // false
0 === -0;    // true

To compare these values accurately, use:


Number.isNaN(NaN);       // true
Object.is(-0, 0);        // false
Object.is(NaN, NaN);     // true

Object.is(..) is like a “quadruple-equals” — a truly strict comparison that doesn’t lie.


Comparing Objects and Functions


Object comparisons in JS use reference identity, not structure or content:


[1, 2, 3] === [1, 2, 3]; // false
{ a: 42 } === { a: 42 }; // false
(x => x * 2) === (x => x * 2); // false

Even if two objects look identical, they are different if they are separate instances.


Reference Identity in Practice


var x = [1, 2, 3];
var y = x;
y === x; // true
y === [1, 2, 3]; // false

x and y point to the same array, so they are equal. But comparing to a new array fails, even if the contents match.


Structural Equality? Not in JS


JavaScript does not provide built-in structural equality for objects. You must implement it manually — and it’s complex. For example, comparing two functions structurally is nearly impossible due to closures and context.


Conclusion


Comparisons in JavaScript are nuanced. === works well for most cases, but for special values like NaN and -0, use Object.is(..) or Number.isNaN(..). For objects and functions, JS compares references, not structure. Understanding these distinctions helps you write more accurate and predictable code.


نوشته و پژوهش‌شده توسط دکتر شاهین صیامی

مقالات مرتبط

Coercive Conditional Comparison and Prototypal Classes in JavaScript – Understanding Implicit Logic and Legacy Inheritance Patterns

This article explores two advanced topics from Appendix A of You Don’t Know JS Yet: how JavaScript performs coercive comparisons in conditional expressions, and how prototypal class patterns were used before ES6 introduced the class keyword. Through practical examples, it clarifies how implicit boolean logic works and how prototype chains enable behavior delegation.

ادامه

Value vs Reference and the Many Forms of Function Definitions

Value vs Reference and the Many Forms of Function Definitions

ادامه

Prototypes in JavaScript – Delegation, Prototype Chains, and Dynamic this Behavior

Prototypes in JavaScript provide a mechanism for property delegation between objects. This article explains how prototype chains work, how to create linked objects using Object.create, and how property access and assignment behave in relation to delegation. It also explores how the dynamic nature of this enables prototype-based method reuse across multiple objects.

ادامه

Closure and this in JavaScript – Scope Memory and Dynamic Execution Context

Closure and this are two foundational and often misunderstood concepts in JavaScript. This article defines closure as a function’s ability to remember variables from its outer scope, and explains how this refers to the dynamic execution context of a function call. Through practical examples, it clarifies the difference between static scope and dynamic context.

ادامه

Iteration in JavaScript – The Iterator Pattern, Built-in Iterables, and Standard Data Consumption

Iteration is a foundational pattern for processing data in JavaScript. This article explores the iterator protocol, how to consume iterators using for..of loops and the spread operator, the distinction between iterators and iterables, and how built-in structures like arrays, strings, maps, and sets support standardized iteration. It also shows how to customize iteration for your own data structures.

ادامه

Modules in JavaScript – From Classic Patterns to ES Modules and Structural Differences

Modules in JavaScript, like classes, are designed to group data and behavior into logical units. This article explores the classic module pattern using factory functions, compares it to class-based design, and introduces ES Modules (ESM) introduced in ES6. It explains how modules are defined, exported, imported, and instantiated, and highlights the differences in structure and usage.

ادامه