When to Use Object.is for Precise Value Comparisons in JavaScript
What is Object.is?
In JavaScript, Object.is
is a method that determines whether two values are strictly equal. It's a more precise comparison method compared to the standard equality operators (==
and ===
).
How is it different from ===
?
- Object.is
Similar to===
but with stricter handling of zeros andNaN
:Object.is(-0, +0)
returnsfalse
(unlike===
which returnstrue
).Object.is(NaN, NaN)
returnstrue
(unlike===
which returnsfalse
).
- === (Strict Equality)
Performs a type check and value check. It treats positive and negative zero (+0
and-0
) as equal, but considersNaN
(Not a Number) not equal to itself.
Comparison | === (Strict Equality) | Object.is |
---|---|---|
-0 === +0 | true | false |
NaN === NaN | false | true |
When to use Object.is
?
Use Object.is
when you need a very strict equality check, especially when dealing with zeros or NaN
values and want to avoid potential type coercion issues that can occur with ===
.
Example
const num1 = -0;
const num2 = +0;
console.log(num1 === num2); // true (might be surprising)
console.log(Object.is(num1, num2)); // false (more accurate)
const nan1 = NaN;
const nan2 = NaN;
console.log(nan1 === nan2); // false
console.log(Object.is(nan1, nan2)); // true
- It's generally recommended for situations where you need a more predictable equality check, particularly when working with zeros and
NaN
. Object.is
is not a part of the core JavaScript language; it's a method defined on the built-inObject
object.
Checking for exact equality of floating-point numbers
function areFloatingPointEqual(num1, num2) {
// Handle cases where either number is NaN (Not a Number)
if (isNaN(num1) || isNaN(num2)) {
return Object.is(num1, num2);
}
// Use Object.is for strict comparison, avoiding potential rounding errors
return Object.is(+num1, +num2); // Convert to numbers explicitly
}
const a = 0.1 + 0.2;
const b = 0.3;
console.log(a === b); // Might be false due to floating-point precision issues
console.log(Object.is(a, b)); // Also false
console.log(areFloatingPointEqual(a, b)); // More reliable check (false)
Comparing object references
const obj1 = {};
const obj2 = {};
console.log(obj1 === obj2); // false (different object references)
console.log(Object.is(obj1, obj2)); // false
// Even if objects have the same properties, they're not the same object
const obj3 = { name: "Alice" };
const obj4 = { name: "Alice" };
console.log(obj3 === obj4); // false
console.log(Object.is(obj3, obj4)); // false
const str1 = "10";
const num1 = 10;
console.log(str1 === num1); // true (implicit type coercion)
console.log(Object.is(str1, num1)); // false (strict check)
const bool1 = true;
const str2 = "true";
console.log(bool1 === str2); // false (different types)
console.log(Object.is(bool1, str2)); // false
Strict Equality Operator (===)
- However, be aware of its behavior with zeros and
NaN
:-0 === +0
returnstrue
.NaN === NaN
returnsfalse
.
- In most cases, the strict equality operator (
===
) is sufficient for general comparison tasks. It performs both type and value checks, making it suitable for most comparisons.
Custom Comparison Functions
- This allows you to define specific rules for handling different data types or edge cases.
- If you need more control over the comparison logic, write a custom function.
function compareFloats(num1, num2, tolerance = 0.0001) {
return Math.abs(num1 - num2) < tolerance;
}
const a = 0.1 + 0.2;
const b = 0.3;
console.log(compareFloats(a, b)); // Could be true depending on tolerance
Lodash's isEqual Function (if using a library)
- Be mindful of potential library size and dependency considerations.
- These functions can handle complex data structures like objects and arrays more comprehensively.
- If you're already using a library like Lodash, it might provide a helper function like
isEqual
for deep comparisons.
- For more complex comparisons or handling edge cases, consider custom functions or appropriate library functions.
- For general equality checks,
===
usually suffices. - If strict equality checks with the specific handling of zeros and
NaN
fromObject.is
are crucial, it's the recommended choice.