Please note, this is a STATIC archive of website developer.mozilla.org from 03 Nov 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

Revision 455021 of Sameness in JavaScript

  • Revision slug: Web/JavaScript/Guide/Sameness
  • Revision title: Sameness in JavaScript
  • Revision id: 455021
  • Created:
  • Creator: Sevenspade
  • Is current revision? No
  • Comment

Revision Content

ES6 has three built-in facilities for determining whether some x and some y are "the same". They are: equality or "double equals" (==), strict equality or "triple equals" (===), and Object.is. (Note that Object.is was added in ES6. Both double equals and triple equals existed prior to ES6, and their behavior remains unchanged.)

Overview

For demonstration, here are the three sameness comparisons in use:

x == y
x === y
Object.is(x, y)

Briefly, double equals will perform a type conversion when comparing two things; triple equals will do the same comparison without type conversion (by simply always returning false if the types differ); and Object.is will behave the same way as triple equals, but with special handling for NaN and -0 and +0 so that the last two are not said to be the same, while Object.is(NaN, NaN) will be true. (Comparing NaN with NaN ordinarily—i.e., using either double equals or triple equals—evaluates to false, because IEEE 754 says so.)

Do note that the distinction between these all have to do with their handling of primitives; none of them compares whether the parameters are conceptually similar in structure. For any non-primitive objects x and y which have the same structure but are distinct objects themselves, all of the above forms will evaluate to false.

For example:

let x = { value: 17 };
let y = { value: 17 };
console.log(Object.is(x, y)); // false;
console.log(x === y);         // false
console.log(x == y);          // false

Abstract equality, strict equality, and same value

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 Numbers. ES6 simply proposes to expose this algorithm through 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.

A model for understanding equality comparisons?

Prior to ES6, you might have said of double equals and triple equals that one is an "enhanced" version of the other. For example, someone might say that double equals is an extended version of triple equals, because the former does everything that the latter does, but with type conversion on its operands (e.g., so that 6 == "6"). Alternatively, someone might say that triple equals is an enhanced version of double equals, because it requires the two operands to be the same type. Which one is better depends on one's idea of which is the baseline.

However, this way of thinking about the built-in sameness operators is not a model that can be stretched to allow a place for ES6's Object.is on this "spectrum". Object.is isn't simply "looser" than double equals or "stricter" than triple equals, nor does it fit somewhere in between (i.e., being both stricter than double equals, but looser than triple equals). We can see from the sameness comparisons table below that this is due to the way that Object.is handles NaN. Notice that if Object.is(NaN, NaN) evaluated to false, we could say that it fits on the loose/strict spectrum as an even stricter form of triple equals, one that distinguishes between -0 and +0. The NaN handling means this is untrue, however. Unfortunately, Object.is simply has to be thought of in terms of its specific characteristics, rather than its looseness or strictness with regard to the equality operators.

Sameness Comparisons
x y == === Object.is
undefined undefined true true true
null null true true true
true true true true true
false false true true true
"foo" "foo" true true true
{ foo: "bar" } x true true true
0 0 true true true
+0 -0 true true false
0 false true false false
"" false true false false
"" 0 true false false
"0" 0 true false false
"17" 17 true false false
new String("foo") "foo" true false false
null undefined true false false
null false false false false
undefined false false false false
{ foo: "bar" } { foo: "bar" } false false false
new String("foo") new String("foo") false false false
0 null false false false
0 NaN false false false
"foo" NaN false false false
NaN NaN false false true

When to use Object.is versus triple equals

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

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

- (unary negation)

It's obvious that negating 0 produces -0. But the abstraction of an expression can cause -0 to creep in when you don't realize it. For example, consider:

let stoppingForce = obj.mass * -obj.velocity

If obj.velocity is 0 (or computes to 0), a -0 is introduced at that place and propogates out into stoppingForce.

Math.atan2
Math.ceil
Math.pow
Math.round
It's possible for a -0 to be introduced into an expression as a return value of these methods in some cases, even when no -0 exists as one of the parameters. E.g., using Math.pow to raise -Infinity to the power of any negative, odd exponent evaluates to -0. Refer to the documentation for the individual methods.
Math.floor
Math.max
Math.min
Math.sin
Math.sqrt
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) evalutes 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 Object.is when the signedness of zeroes 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.

Revision Source

<p>ES6 has three built-in facilities for determining whether some <var>x</var> and some <var>y</var> are "the same". They are: equality or "double equals" (<a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators" title="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators"><code>==</code></a>), strict equality or "triple equals" (<a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators" title="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators"><code>===</code></a>), and <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is"><code>Object.is</code></a>. (Note that <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is"><code>Object.is</code></a> was added in ES6. Both double equals and triple equals existed prior to ES6, and their behavior remains unchanged.)</p>
<h2 id="Overview">Overview</h2>
<p>For demonstration, here are the three sameness comparisons in use:</p>
<pre class="brush:js">
x == y</pre>
<pre class="brush:js">
x === y</pre>
<pre class="brush:js">
Object.is(x, y)</pre>
<p>Briefly, double equals will perform a type conversion when comparing two things; triple equals will do the same comparison without type conversion (by simply always returning <code>false</code> if the types differ); and <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is"><code>Object.is</code></a> will behave the same way as triple equals, but with special handling for <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN"><code>NaN</code></a> and <code>-0</code> and <code>+0</code> so that the last two are not said to be the same, while <code>Object.is(NaN, NaN)</code> will be <code>true</code>. (Comparing <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN"><code>NaN</code></a> with <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN"><code>NaN</code></a> ordinarily—i.e., using either double equals or triple equals—evaluates to <code>false</code>, because IEEE 754 says so.)</p>
<p>Do note that the distinction between these all have to do with their handling of primitives; none of them compares whether the parameters are conceptually similar in structure. For any non-primitive objects <var>x</var> and <var>y</var> which have the same structure but are distinct objects themselves, all of the above forms will evaluate to <code>false</code>.</p>
<p>For example:</p>
<pre class="brush:js">
let x = { value: 17 };
let y = { value: 17 };
console.log(Object.is(x, y)); // false;
console.log(x === y);         // false
console.log(x == y);          // false</pre>
<h2 id="Abstract_equality.2C_strict_equality.2C_and_same_value">Abstract equality, strict equality, and same value</h2>
<p>In ES5, the comparison performed by <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators" title="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators"><code>==</code></a> is described in <a href="https://ecma-international.org/ecma-262/5.1/#sec-11.9.3" title="https://ecma-international.org/ecma-262/5.1/#sec-11.9.3">Section 11.9.3, The Abstract Equality Algorithm</a>. The <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators" title="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators"><code>===</code></a> comparison is <a href="https://ecma-international.org/ecma-262/5.1/#sec-11.9.6" title="https://ecma-international.org/ecma-262/5.1/#sec-11.9.6">11.9.6, The Strict Equality Algorithm</a>. (Go look at these. They're brief and readable. Hint: read the strict equality algorithm first.) ES5 also describes, in <a href="https://ecma-international.org/ecma-262/5.1/#sec-9.12" title="https://ecma-international.org/ecma-262/5.1/#sec-9.12">Section 9.12, The SameValue Algorithm</a> 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 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number"><code>Number</code></a>s. ES6 simply proposes to expose this algorithm through <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is"><code>Object.is</code></a>.</p>
<p>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.</p>
<h2 id="A_model_for_understanding_equality_comparisons.3F">A model for understanding equality comparisons?</h2>
<p>Prior to ES6, you might have said of double equals and triple equals that one is an "enhanced" version of the other. For example, someone might say that double equals is an extended version of triple equals, because the former does everything that the latter does, but with type conversion on its operands (e.g., so that <code>6 == "6"</code>). Alternatively, someone might say that triple equals is an enhanced version of double equals, because it requires the two operands to be the same type. Which one is better depends on one's idea of which is the baseline.</p>
<p>However, this way of thinking about the built-in sameness operators is not a model that can be stretched to allow a place for ES6's <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is"><code>Object.is</code></a> on this "spectrum". <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is"><code>Object.is</code></a> isn't simply "looser" than double equals or "stricter" than triple equals, nor does it fit somewhere in between (i.e., being both stricter than double equals, but looser than triple equals). We can see from the sameness comparisons table below that this is due to the way that <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is"><code>Object.is</code></a> handles <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN"><code>NaN</code></a>. Notice that if <code>Object.is(NaN, NaN)</code> evaluated to <code>false</code>, we <em>could</em> say that it fits on the loose/strict spectrum as an even stricter form of triple equals, one that distinguishes between <code>-0</code> and <code>+0</code>. The <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN"><code>NaN</code></a> handling means this is untrue, however. Unfortunately, <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is"><code>Object.is</code></a> simply has to be thought of in terms of its specific characteristics, rather than its looseness or strictness with regard to the equality operators.</p>
<table class="standard-table">
  <caption>
    Sameness Comparisons</caption>
  <thead>
    <tr>
      <th scope="col" style="text-align: center;">x</th>
      <th scope="col" style="text-align: center;">y</th>
      <th scope="col" style="width: 10em; text-align: center;"><code>==</code></th>
      <th scope="col" style="width: 10em; text-align: center;"><code>===</code></th>
      <th scope="col" style="width: 10em; text-align: center;"><code>Object.is</code></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code>undefined</code></td>
      <td><code>undefined</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
    </tr>
    <tr>
      <td><code>null</code></td>
      <td><code>null</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
    </tr>
    <tr>
      <td><code>true</code></td>
      <td><code>true</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
    </tr>
    <tr>
      <td><code>false</code></td>
      <td><code>false</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
    </tr>
    <tr>
      <td><code>"foo"</code></td>
      <td><code>"foo"</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
    </tr>
    <tr>
      <td><code>{ foo: "bar" }</code></td>
      <td><code>x</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
    </tr>
    <tr>
      <td><code>0</code></td>
      <td><code>0</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
    </tr>
    <tr>
      <td><code>+0</code></td>
      <td><code>-0</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
    </tr>
    <tr>
      <td><code>0</code></td>
      <td><code>false</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
    </tr>
    <tr>
      <td><code>""</code></td>
      <td><code>false</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
    </tr>
    <tr>
      <td><code>""</code></td>
      <td><code>0</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
    </tr>
    <tr>
      <td><code>"0"</code></td>
      <td><code>0</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
    </tr>
    <tr>
      <td><code>"17"</code></td>
      <td><code>17</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
    </tr>
    <tr>
      <td><code>new String("foo")</code></td>
      <td><code>"foo"</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
    </tr>
    <tr>
      <td><code>null</code></td>
      <td><code>undefined</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
    </tr>
    <tr>
      <td><code>null</code></td>
      <td><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
    </tr>
    <tr>
      <td><code>undefined</code></td>
      <td><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
    </tr>
    <tr>
      <td><code>{ foo: "bar" }</code></td>
      <td><code>{ foo: "bar" }</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
    </tr>
    <tr>
      <td><code>new String("foo")</code></td>
      <td><code>new String("foo")</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
    </tr>
    <tr>
      <td><code>0</code></td>
      <td><code>null</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
    </tr>
    <tr>
      <td><code>0</code></td>
      <td><code>NaN</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
    </tr>
    <tr>
      <td><code>"foo"</code></td>
      <td><code>NaN</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
    </tr>
    <tr>
      <td><code>NaN</code></td>
      <td><code>NaN</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(255, 144, 144); text-align: center;"><code>false</code></td>
      <td style="background-color: rgb(144, 255, 144); text-align: center;"><code>true</code></td>
    </tr>
  </tbody>
</table>
<h2 id="When_to_use_Object.is_versus_triple_equals">When to use <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is"><code>Object.is</code></a> versus triple equals</h2>
<p>Aside from the way it treats <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN"><code>NaN</code></a>, generally, the only time <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is"><code>Object.is</code></a>'s special behavior towards zeroes is likely to be of interest is in the pursuit of certain metaprogramming schemes, especially regarding property descriptors when it is desirable for your work to mirror some of the characteristics of <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty"><code>Object.defineProperty</code></a>. If your use case does not require this, it is suggested to avoid <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is"><code>Object.is</code></a> and use <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators" title="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators"><code>===</code></a> instead. Even if your requirements involve having comparisons between two <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN"><code>NaN</code></a> values evaluate to <code>true</code>, generally it is easier to special-case the <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN"><code>NaN</code></a> checks (using the <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN"><code>isNaN</code></a> method available from previous versions of ECMAScript) than it is to work out how surrounding computations might affect the sign of any zeroes you encounter in your comparison.</p>
<p>Here's an inexhaustive list of built-in methods and operators that might cause a distinction between <code>-0</code> and <code>+0</code> to manifest itself in your code:</p>
<dl>
  <dt>
    <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#-_.28Unary_Negation.29" title="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators"><code>- (unary negation)</code></a></dt>
</dl>
<dl>
  <dd>
    <p>It's obvious that negating <code>0</code> produces <code>-0</code>. But the abstraction of an expression can cause <code>-0</code> to creep in when you don't realize it. For example, consider:</p>
    <pre class="brush:js">
let stoppingForce = obj.mass * -obj.velocity</pre>
    <p>If <code>obj.velocity</code> is <code>0</code> (or computes to <code>0</code>), a <code>-0</code> is introduced at that place and propogates out into <code>stoppingForce</code>.</p>
  </dd>
</dl>
<dl>
  <dt>
    <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atan2" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atan2"><code>Math.atan2</code></a></dt>
  <dt>
    <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/ceil" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/ceil"><code>Math.ceil</code></a></dt>
  <dt>
    <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/pow" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/pow"><code>Math.pow</code></a></dt>
  <dt>
    <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round"><code>Math.round</code></a></dt>
</dl>
<dl>
  <dd>
    It's possible for a <code>-0</code> to be introduced into an expression as a return value of these methods in some cases, even when no <code>-0</code> exists as one of the parameters. E.g., using <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/pow" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/pow"><code>Math.pow</code></a> to raise <code>-<a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Infinity" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Infinity">Infinity</a></code> to the power of any negative, odd exponent evaluates to <code>-0</code>. Refer to the documentation for the individual methods.</dd>
</dl>
<dl>
  <dt>
    <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor"><code>Math.floor</code></a></dt>
  <dt>
    <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max"><code>Math.max</code></a></dt>
  <dt>
    <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min"><code>Math.min</code></a></dt>
  <dt>
    <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sin" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sin"><code>Math.sin</code></a></dt>
  <dt>
    <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sqrt" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sqrt"><code>Math.sqrt</code></a></dt>
  <dt>
    <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/tan" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/tan"><code>Math.tan</code></a></dt>
</dl>
<dl>
  <dd>
    It's possible to get a <code>-0</code> return value out of these methods in some cases where a <code>-0</code> exists as one of the parameters. E.g., <code>Math.min(-0, +0)</code> evalutes to <code>-0</code>. Refer to the documentation for the individual methods.</dd>
</dl>
<dl>
  <dt>
    <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators" title="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators">~</a></code></dt>
  <dt>
    <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators" title="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators">&lt;&lt;</a></code></dt>
  <dt>
    <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators" title="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators">&gt;&gt;</a></code></dt>
  <dd>
    Each of these operators uses the ToInt32 algorithm internally. Since there is only one representation for 0 in the internal 32-bit integer type, <code>-0</code> will not survive a round trip after an inverse operation. E.g., both <code>Object.is(~~(-0), -0)</code> and <code>Object.is(-0 &lt;&lt; 2 &gt;&gt; 2, -0)</code> evaluate to <code>false</code>.</dd>
</dl>
<p>Relying on <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is"><code>Object.is</code></a> when the signedness of zeroes is not taken into account can be hazardous. Of course, when the intent is to distinguish between <code>-0</code> and <code>+0</code>, it does exactly what's desired.</p>
Revert to this revision