diff options
| author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:43:23 -0500 |
|---|---|---|
| committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:43:23 -0500 |
| commit | 218934fa2ed1c702a6d3923d2aa2cc6b43c48684 (patch) | |
| tree | a9ef8ac1e1b8fe4207b6d64d3841bfb8990b6fd0 /files/zh-tw/web/javascript/equality_comparisons_and_sameness | |
| parent | 074785cea106179cb3305637055ab0a009ca74f2 (diff) | |
| download | translated-content-218934fa2ed1c702a6d3923d2aa2cc6b43c48684.tar.gz translated-content-218934fa2ed1c702a6d3923d2aa2cc6b43c48684.tar.bz2 translated-content-218934fa2ed1c702a6d3923d2aa2cc6b43c48684.zip | |
initial commit
Diffstat (limited to 'files/zh-tw/web/javascript/equality_comparisons_and_sameness')
| -rw-r--r-- | files/zh-tw/web/javascript/equality_comparisons_and_sameness/index.html | 431 |
1 files changed, 431 insertions, 0 deletions
diff --git a/files/zh-tw/web/javascript/equality_comparisons_and_sameness/index.html b/files/zh-tw/web/javascript/equality_comparisons_and_sameness/index.html new file mode 100644 index 0000000000..5821653310 --- /dev/null +++ b/files/zh-tw/web/javascript/equality_comparisons_and_sameness/index.html @@ -0,0 +1,431 @@ +--- +title: 相等比較 +slug: Web/JavaScript/Equality_comparisons_and_sameness +translation_of: Web/JavaScript/Equality_comparisons_and_sameness +--- +<div>{{jsSidebar("Intermediate")}}</div> + +<p>在 ES2015,有四個相等比較方法:</p> + +<ul> + <li>一般相等 (<code>==</code>)</li> + <li>嚴格相等 (<code style="font-weight: 700; font-style: normal;">===</code>):被用於 <code style="font-weight: 700; font-style: normal;">Array.prototype.indexOf</code>、 <code style="font-weight: 700; font-style: normal;">Array.prototype.lastIndexOf </code>和 <code style="font-weight: 700; font-style: normal;">case</code>-matching </li> + <li>零值相等:被用於 <code>%TypedArray%</code> 和 <code>ArrayBuffer</code> 建構子,以及 <code>Map</code> 和 <code>Set</code> 運算子,還有將在 ES2016 新增的 <code>String.prototype.includes。</code></li> + <li>同值相等: 用在除上面提及的所有情況。</li> +</ul> + +<p>JavaScript 提供三種不同的值比較運算操作:</p> + +<ul> + <li>嚴格相等 (或稱 "三等於"、"全等") 使用 <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Identity">===</a></li> + <li>一般相等 ("雙等於") 使用 <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Equality">==</a></li> + <li>還有 <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> (ECMAScript 2015 新加入)</li> +</ul> + +<p>要用哪個操作取決於你要哪種類型的比較。</p> + +<p>簡單來說,一般相等會將型別一致化後比較;嚴格相等則不會(也就是說若型別不同,就會回傳 fasle);<code>Object.is</code> 會和嚴格相等做同樣的事,但會將 <code>NaN</code>、<code>-0<font face="Open Sans, Arial, sans-serif"> 和 </font></code><code>+0 </code>獨立處理,因此這三個不會相等,而 <code>Object.is(NaN, NaN)</code> 則會回傳 true 。(用一般相等或嚴格相等比較兩個 <code>NaN</code> 時會回傳 <code>false</code> ,因為 IEEE 754 如此規範。) 切記,這三種判斷必須考慮原型,因為他們在設計上不被考慮為相等。對於任何非原型物件 x、y,即使他們有著相同結構,但如果是不同物件,比較就會是 false。</p> + +<h2 id="嚴格相等()">嚴格相等(<code>===</code>)</h2> + +<p>嚴格相等比較兩個值,而被比較的兩個值都不會轉換成其他型別。如果值是不同型別,就會被視為不相等。如果兩值型別相同但不是數字,若值相同,則為相等。此外,如果兩個值皆為數字,只要他們是 NaN 以外的同一值,或者 +0 和 -0,則為相等。</p> + +<pre class="brush: js">var num = 0; +var obj = new String("0"); +var str = "0"; + +console.log(num === num); // true +console.log(obj === obj); // true +console.log(str === str); // true + +console.log(num === obj); // false +console.log(num === str); // false +console.log(obj === str); // false +console.log(null === undefined); // false +console.log(obj === null); // false +console.log(obj === undefined); // false +</pre> + +<p>嚴格比較適合在絕大多數情況下使用。對於所有非數字的值,嚴格比較就如字面:一個值只相等於自己。而數字則使用稍微不同的方式:第一種情況是浮點數 0 同時為正和負,在解決某些數學問題時,<code>+0</code> 和 <code>-0 </code>是不同的,但在大部分情況下我們不需要考慮這種情境,因此嚴格比較將他們視為相同的。第二種情況是非數字,<code>NaN</code>,用來表示某些定義不明確的數學問題的解, 例如:負無窮加正無窮,嚴格比較認為 <code>NaN</code> 不等於任何值,包含他本身。(<code>(x !== x)</code>只有在 <code>x</code> 是 <code>NaN </code>時會是 <code>true</code>。)</p> + +<h2 id="一般相等()">一般相等(==)</h2> + +<p>一般相等會<em>先將</em>比較值轉換成同型別後比較。轉換後(可能一個或兩個都被轉換),接著進行的幾乎和嚴格比較(<code>===</code>)一樣。 一般相等會<em>對稱</em>: <code>A == B</code> 等同 <code>B == A</code> ,無論 <code>A</code> 和 <code>B</code> 是什麼。(除了型別轉換的順序)</p> + +<p>不同型別的一般相等運作如下表:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="row"></th> + <th colspan="7" scope="col" style="text-align: center;">比較值 B</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row"></th> + <td></td> + <td style="text-align: center;">Undefined</td> + <td style="text-align: center;">Null</td> + <td style="text-align: center;">Number</td> + <td style="text-align: center;">String</td> + <td style="text-align: center;">Boolean</td> + <td style="text-align: center;">Object</td> + </tr> + <tr> + <th colspan="1" rowspan="6" scope="row">比較值 A</th> + <td>Undefined</td> + <td style="text-align: center;"><code>true</code></td> + <td style="text-align: center;"><code>true</code></td> + <td style="text-align: center;"><code>false</code></td> + <td style="text-align: center;"><code>false</code></td> + <td style="text-align: center;"><code>false</code></td> + <td style="text-align: center;"><code>false</code></td> + </tr> + <tr> + <td>Null</td> + <td style="text-align: center;"><code>true</code></td> + <td style="text-align: center;"><code>true</code></td> + <td style="text-align: center;"><code>false</code></td> + <td style="text-align: center;"><code>false</code></td> + <td style="text-align: center;"><code>false</code></td> + <td style="text-align: center;"><code>false</code></td> + </tr> + <tr> + <td>Number</td> + <td style="text-align: center;"><code>false</code></td> + <td style="text-align: center;"><code>false</code></td> + <td style="text-align: center;"><code>A === B</code></td> + <td style="text-align: center;"><code>A === ToNumber(B)</code></td> + <td style="text-align: center;"><code>A === ToNumber(B)</code></td> + <td style="text-align: center;"><code>A == ToPrimitive(B)</code></td> + </tr> + <tr> + <td>String</td> + <td style="text-align: center;"><code>false</code></td> + <td style="text-align: center;"><code>false</code></td> + <td style="text-align: center;"><code>ToNumber(A) === B</code></td> + <td style="text-align: center;"><code>A === B</code></td> + <td style="text-align: center;"><code>ToNumber(A) === ToNumber(B)</code></td> + <td style="text-align: center;"><code>A == ToPrimitive(B)</code></td> + </tr> + <tr> + <td>Boolean</td> + <td style="text-align: center;"><code>false</code></td> + <td style="text-align: center;"><code>false</code></td> + <td style="text-align: center;"><code>ToNumber(A) === B</code></td> + <td style="text-align: center;"><code>ToNumber(A) === ToNumber(B)</code></td> + <td style="text-align: center;"><code>A === B</code></td> + <td style="text-align: center;"><code>ToNumber(A) == ToPrimitive(B)</code></td> + </tr> + <tr> + <td>Object</td> + <td style="text-align: center;"><code>false</code></td> + <td style="text-align: center;"><code>false</code></td> + <td style="text-align: center;"><code>ToPrimitive(A) == B</code></td> + <td style="text-align: center;"><code>ToPrimitive(A) == B</code></td> + <td style="text-align: center;"><code>ToPrimitive(A) == ToNumber(B)</code></td> + <td style="text-align: center;"><code>A === B</code></td> + </tr> + </tbody> +</table> + +<p>根據上表, <code>ToNumber(A)</code> 嘗試在比較前轉換成一個數字。 這等同 <code>+A</code> (單 + 運算子)。<code>ToPrimitive(A)</code> 嘗試從物件轉換成原生值,透過嘗試對 A 使用 <code>A.toString</code> 和 <code>A.valueOf</code> 方法。</p> + +<p>一般來說,根據 ECMAScript 規範,所有物件應該不等於 <code>undefined</code> 和 <code>null</code>。但大多數瀏覽器允許很小部分的物件(尤其是所有頁面的 <code>document.all</code> 物件)在某些情況下<em>當成</em> <code>undefined</code>。一般相等是其中一種:當 A 是個被<em>模擬</em> 成 <code>undefined </code>的物件<code><font face="Open Sans, Arial, sans-serif">,</font></code><code>null == A</code> 和 <code>undefined == A</code> 會是 true。而在其他情況下物件不會等同於 <code>undefined</code> 或 <code>null。</code></p> + +<pre class="brush: js">var num = 0; +var obj = new String("0"); +var str = "0"; + +console.log(num == num); // true +console.log(obj == obj); // true +console.log(str == str); // true + +console.log(num == obj); // true +console.log(num == str); // true +console.log(obj == str); // true +console.log(null == undefined); // true + +// 除了少數情況,這兩個應該是 false。 +console.log(obj == null); +console.log(obj == undefined); +</pre> + +<p>部分開發者認為最好別用一般相等。嚴格比較更容易預測,且因為不必轉型,因此效率更好。</p> + +<h2 id="同值相等">同值相等</h2> + +<p>同值相等解決了最後一個情況:比較兩個值是否<em>功能相同</em> 。(這裡用了 <a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle" title="http://en.wikipedia.org/wiki/Liskov_substitution_principle">Liskov 替換原則(英)</a> 為例)當試圖修改一個不可變的屬性:</p> + +<pre class="brush: js">// 新增一個不可變 NEGATIVE_ZERO 屬性到 Number 原型。 +Object.defineProperty(Number, "NEGATIVE_ZERO", + { value: -0, writable: false, configurable: false, enumerable: false }); + +function attemptMutation(v) +{ + Object.defineProperty(Number, "NEGATIVE_ZERO", { value: v }); +} +</pre> + +<p>當修改一個不可變屬性時, <code>Object.defineProperty</code> 會出現例外,但若沒有真的要求修改,就沒事。如果 <code>v</code> 是 <code>-0</code>,就不會有修改,也就不會有錯誤出現。但若 <code>v</code> 是 <code>+0</code>,<code>Number.NEGATIVE_ZERO</code> 不再擁有自己的不可變屬性。在內部,當一個不可變屬性被重新定義,新的值會用同值相等和原值比較。</p> + +<p><a href="/zh-TW/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> + +<h2 id="零值相等">零值相等</h2> + +<p>和同值相等一樣,但將 <code>+0</code> 和 <code>-0 </code>視為相同。</p> + +<h2 id="一般相等、嚴格相等和同值相等的規範">一般相等、嚴格相等和同值相等的規範</h2> + +<p>在 ES5,一般相等 <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators" title="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators"><code>==</code></a> 在 <a href="http://ecma-international.org/ecma-262/5.1/#sec-11.9.3" title="http://ecma-international.org/ecma-262/5.1/#sec-11.9.3">Section 11.9.3, The Abstract Equality Algorithm</a> 中規範。嚴格相等 <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators" title="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators"><code>===</code></a> 在 <a href="http://ecma-international.org/ecma-262/5.1/#sec-11.9.6" title="http://ecma-international.org/ecma-262/5.1/#sec-11.9.6">11.9.6, The Strict Equality Algorithm</a>。(可以看看,這很簡短且可讀。註:先讀嚴格相等。)ES5 也在 <a href="http://ecma-international.org/ecma-262/5.1/#sec-9.12" title="http://ecma-international.org/ecma-262/5.1/#sec-9.12">Section 9.12, The SameValue Algorithm</a> 規範 JS 引擎的行為。他幾乎和嚴格相等一樣,除了 11.9.6.4 和 9.12.4 在處理 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number">Number</a></code> 時的不同。ES2015 簡短的提出了 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is">Object.is</a>。</code></p> + +<p>我們可以發現在 11.9.6.1 中,除了 11.9.6.1 規範型別檢查,嚴格相等規範是從屬於一般相等規範,因為 11.9.6.2–7 和 11.9.3.1.a–f相應。</p> + +<h2 id="理解相等比較模型">理解相等比較模型</h2> + +<p>ES2015 以後,你或許會將雙等於和三等於解讀成是彼此的「加強版」。比如,有人或許會說雙等於是三等於的延伸版本,因為前者做的事情和後者事情一模一樣,只差在運算元的型別轉換。舉例來說,<code>6 == "6"</code> (又或者說,有人可能會講說雙等於是基底,而三等於是加強版,因為它要求兩個運算元是同型別,所以它多了一個限制。至於哪個是較好的理解模型,取決於你的觀點。</p> + +<p>儘管如此,這個思考內建相同運算子的方法,並非是延伸 ES2015 中的 <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> 方法。 <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> 不是單純地比雙等號「更寬鬆」或比三等號「更嚴謹」,也不適合將其放在兩者之間(即,比雙等號嚴謹,但較三等號寬鬆)。我們可以從下方的比較表格看到,一切是起源於 <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> 可以處理 <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> 的比較運算。要注意的是,如果 <code>Object.is(NaN, NaN)</code> 的運算結果是 <code>false</code> ,我們就可以因為它區分 <code>-0</code> 和 <code>+0</code> 的結果,使用寬鬆和嚴謹的範疇來界定它是比三等號更嚴謹的那一區段。然而,區別 <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> 的方式並不確實。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>[1,2]</code></td> + <td><code>"1,2"</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 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 <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 zeros you encounter in your comparison.</p> + +<p>Here's an in-exhaustive 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 zeros 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> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="http://dorey.github.io/JavaScript-Equality-Table/">JS Comparison Table</a></li> +</ul> |
