diff --git a/files/en-us/web/javascript/equality_comparisons_and_sameness/index.html b/files/en-us/web/javascript/equality_comparisons_and_sameness/index.html index deb72033bc02848..3e250bd64540b29 100644 --- a/files/en-us/web/javascript/equality_comparisons_and_sameness/index.html +++ b/files/en-us/web/javascript/equality_comparisons_and_sameness/index.html @@ -27,8 +27,8 @@

JavaScript provides three different value-comparison operations:

@@ -74,7 +74,7 @@

Loose equality using ==

- Operand B + Operand B @@ -87,9 +87,10 @@

Loose equality using ==

String Boolean Object + BigInt - Operand A + Operand A Undefined true true @@ -97,6 +98,7 @@

Loose equality using ==

false false false + false Null @@ -106,6 +108,7 @@

Loose equality using ==

false false false + false Number @@ -115,6 +118,7 @@

Loose equality using ==

A === ToNumber(B) A === ToNumber(B) A == ToPrimitive(B) + ℝ(A) = ℝ(B) String @@ -124,6 +128,7 @@

Loose equality using ==

A === B ToNumber(A) === ToNumber(B) A == ToPrimitive(B) + StringToBigInt(A) === B Boolean @@ -133,6 +138,7 @@

Loose equality using ==

ToNumber(A) === ToNumber(B) A === B ToNumber(A) == ToPrimitive(B) + ToNumber(A) == B Object @@ -142,11 +148,28 @@

Loose equality using ==

ToPrimitive(A) == B ToPrimitive(A) == ToNumber(B) A === B + ToPrimitive(A) == B + + + BigInt + false + false + ℝ(A) = ℝ(B) + A === StringToBigInt(B) + A == ToNumber(B) + A == ToPrimitive(B) + A === B -

In the above table, ToNumber(A) attempts to convert its argument to a number before comparison. Its behavior is equivalent to +A (the unary + operator). ToPrimitive(A) attempts to convert its object argument to a primitive value, by attempting to invoke varying sequences of A.toString and A.valueOf methods on A.

+

In the above table:

+

Traditionally, and according to ECMAScript, all objects are loosely unequal to undefined and null. But most browsers permit a very narrow class of objects (specifically, the document.all object for any page), in some contexts, to act as if they emulate the value undefined. Loose equality is one such context: null == A and undefined == A evaluate to true if, and only if, A is an object that emulates undefined. In all other cases an object is never loosely equal to undefined or null.

@@ -193,7 +216,7 @@

Same-value-zero equality

Abstract equality, strict equality, and same value in the specification

-

In ES5, the comparison performed by == is described in Section 11.9.3, The Abstract Equality Algorithm. The === comparison is 11.9.6, The Strict Equality Algorithm. (Go look at these. They're brief and readable. Hint: read the strict equality algorithm first.) ES5 also describes, in Section 9.12, The SameValue Algorithm for use internally by the JS engine. It's largely the same as the Strict Equality Algorithm, except that 11.9.6.4 and 9.12.4 differ in handling {{jsxref("Number")}}s. ES2015 proposes to expose this algorithm through {{jsxref("Object.is")}}.

+

In ES5, the comparison performed by == is described in Section 11.9.3, The Abstract Equality Algorithm. The === comparison is 11.9.6, The Strict Equality Algorithm. (Go look at these. They're brief and readable. Hint: read the strict equality algorithm first.) ES5 also describes, in Section 9.12, The SameValue Algorithm for use internally by the JS engine. It's largely the same as the Strict Equality Algorithm, except that 11.9.6.4 and 9.12.4 differ in handling {{jsxref("Number")}}s. ES2015 proposes to expose this algorithm through {{jsxref("Object.is")}}.

We can see that with double and triple equals, with the exception of doing a type check upfront in 11.9.6.1, the Strict Equality Algorithm is a subset of the Abstract Equality Algorithm, because 11.9.6.2–7 correspond to 11.9.3.1.a–f.

@@ -427,14 +450,14 @@

A model for understandin -

When to use {{jsxref("Object.is")}} versus triple equals

+

When to use Object.is versus triple equals

-

In general, the only time {{jsxref("Object.is")}}'s special behavior towards zeros is likely to be of interest is in the pursuit of certain meta-programming schemes, especially regarding property descriptors, when it is desirable for your work to mirror some of the characteristics of {{jsxref("Object.defineProperty")}}. If your use case does not require this, it is suggested to avoid {{jsxref("Object.is")}} and use === instead. Even if your requirements involve having comparisons between two {{jsxref("NaN")}} values evaluate to true, generally it is easier to special-case the {{jsxref("NaN")}} checks (using the {{jsxref("isNaN")}} method available from previous versions of ECMAScript) than it is to work out how surrounding computations might affect the sign of any zeros you encounter in your comparison.

+

In general, the only time {{jsxref("Object.is")}}'s special behavior towards zeros is likely to be of interest is in the pursuit of certain meta-programming schemes, especially regarding property descriptors, when it is desirable for your work to mirror some of the characteristics of {{jsxref("Object.defineProperty")}}. If your use case does not require this, it is suggested to avoid {{jsxref("Object.is")}} and use === instead. Even if your requirements involve having comparisons between two {{jsxref("NaN")}} values evaluate to true, generally it is easier to special-case the {{jsxref("NaN")}} checks (using the {{jsxref("isNaN")}} method available from previous versions of ECMAScript) than it is to work out how surrounding computations might affect the sign of any zeros you encounter in your comparison.

Here's a non-exhaustive list of built-in methods and operators that might cause a distinction between -0 and +0 to manifest itself in your code:

-
- (unary negation)
+
- (unary negation)
let stoppingForce = obj.mass * -obj.velocity;
@@ -455,15 +478,15 @@

When to use {{jsxref("
{{jsxref("Math.sqrt")}}
{{jsxref("Math.tan")}}
It's possible to get a -0 return value out of these methods in some cases where a -0 exists as one of the parameters. E.g., Math.min(-0, +0) evaluates to -0. Refer to the documentation for the individual methods.
-
~
-
<<
-
>>
+
~
+
<<
+
>>
Each of these operators uses the ToInt32 algorithm internally. Since there is only one representation for 0 in the internal 32-bit integer type, -0 will not survive a round trip after an inverse operation. E.g., both Object.is(~~(-0), -0) and Object.is(-0 << 2 >> 2, -0) evaluate to false.

Relying on {{jsxref("Object.is")}} when the signedness of zeros is not taken into account can be hazardous. Of course, when the intent is to distinguish between -0 and +0, it does exactly what's desired.

-

Caveat: {{jsxref("Object.is")}} and NaN

+

Caveat: Object.is and NaN

The {{jsxref("Object.is")}} specification treats all instances of {{jsxref("NaN")}} as the same object. However, since typed arrays are available, we can have distinct instances, which don't behave identically in all contexts. For example: