<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"><<</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">>></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 << 2 >> 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>