aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/web/javascript/equality_comparisons_and_sameness/index.html
blob: c9e1e5ae7118d3cd2b0c86a60c03c6a2b11b3bf2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
---
title: JavaScript 中的相等性判断
slug: Web/JavaScript/Equality_comparisons_and_sameness
tags:
  - JavaScr
  - 严格相等
  - 同值相等
  - 比较
  - 相等
  - 零值相等
  - 非严格相等
translation_of: Web/JavaScript/Equality_comparisons_and_sameness
---
<div>{{jsSidebar("Intermediate")}}</div>

<p>ES2015中有四种相等算法:</p>

<ul>
 <li>抽象(非严格)相等比较 (<code>==</code>)</li>
 <li>严格相等比较 (<code>===</code>): 用于  <code>Array.prototype.indexOf</code><code>Array.prototype.lastIndexOf</code>, 和 <code>case</code>-matching</li>
 <li>同值零: 用于 <code>%TypedArray%</code> 和 <code>ArrayBuffer </code>构造函数、以及<code>Map</code><code>Set</code>操作, 并将用于 ES2016/ES7 中的<code>String.prototype.includes </code></li>
 <li>同值: 用于所有其他地方</li>
</ul>

<p>JavaScript提供三种不同的值比较操作:</p>

<ul>
 <li>严格相等比较 (也被称作"strict equality", "identity", "triple equals"),使用 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Identity">===</a> ,</li>
 <li>抽象相等比较 ("loose equality","double equals") ,使用 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Equality">==</a></li>
 <li>以及 <a href="https://developer.mozilla.org/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/ ES6 新特性)</li>
</ul>

<p>选择使用哪个操作取决于你需要什么样的比较。</p>

<p>简而言之,在比较两件事情时,双等号将执行类型转换; 三等号将进行相同的比较,而不进行类型转换 (如果类型不同, 只是总会返回 false );  而Object.is的行为方式与三等号相同,但是对于NaN和-0和+0进行特殊处理,所以最后两个不相同,而Object.is(NaN,NaN)将为 <code>true</code>。(通常使用双等号或三等号将NaN与NaN进行比较,结果为false,因为IEEE 754如是说.) 请注意,所有这些之间的区别都与其处理原语有关; 这三个运算符的原语中,没有一个会比较两个变量是否结构上概念类似。对于任意两个不同的非原始对象,即便他们有相同的结构, 以上三个运算符都会计算得到 false 。</p>

<h2 id="严格相等">严格相等 <code>===</code></h2>

<p>全等操作符比较两个值是否相等,两个被比较的值在比较前都不进行隐式转换。如果两个被比较的值具有不同的类型,这两个值是不全等的。否则,如果两个被比较的值类型相同,值也相同,并且都不是 number 类型时,两个值全等。最后,如果两个值都是 number 类型,当两个都不是 NaN,并且数值相同,或是两个值分别为 +0 和 -0 时,两个值被认为是全等的。</p>

<pre class="brush: js">var num = 0;
var obj = new String("0");
var str = "0";
var b = false;

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 是不分正负的。区分 +0 和 -0 在解决一些特定的数学问题时是必要的,但是大部分情况下我们并不用关心。全等操作符认为这两个值是全等的。第二个情况是,浮点数包含了 NaN 值,用来表示某些定义不明确的数学问题的解,例如:正无穷加负无穷。全等操作符认为 NaN 与其他任何值都不全等,包括它自己。(等式 <code>(x !== x)</code> 成立的唯一情况是 x 的值为 NaN)</p>

<h2 id="非严格相等">非严格相等 <code>==</code></h2>

<p>相等操作符比较两个值是否相等,在比较前将两个被比较的值转换为相同类型。在转换后(等式的一边或两边都可能被转换),最终的比较方式等同于全等操作符 === 的比较方式。 相等操作符满足交换律。</p>

<p>相等操作符对于不同类型的值,进行的比较如下图所示:</p>

<table class="standard-table">
 <thead>
  <tr>
   <th scope="row"></th>
   <th colspan="7" scope="col">被比较值 B</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <th scope="row"></th>
   <td></td>
   <td>Undefined</td>
   <td>Null</td>
   <td>Number</td>
   <td>String</td>
   <td>Boolean</td>
   <td>Object</td>
  </tr>
  <tr>
   <th colspan="1" rowspan="6" scope="row">被比较值 A</th>
   <td>Undefined</td>
   <td><code>true</code></td>
   <td><code>true</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>IsFalsy(B)</code></td>
  </tr>
  <tr>
   <td>Null</td>
   <td><code>true</code></td>
   <td><code>true</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>IsFalsy(B)</code></td>
  </tr>
  <tr>
   <td>Number</td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>A === B</code></td>
   <td><code>A === ToNumber(B)</code></td>
   <td><code>A=== ToNumber(B) </code></td>
   <td><code>A== ToPrimitive(B)</code></td>
  </tr>
  <tr>
   <td>String</td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>ToNumber(A) === B</code></td>
   <td><code>A === B</code></td>
   <td><code>ToNumber(A) === ToNumber(B)</code></td>
   <td><code>ToPrimitive(B) == A</code></td>
  </tr>
  <tr>
   <td>Boolean</td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>ToNumber(A) === B</code></td>
   <td><code>ToNumber(A) === ToNumber(B)</code></td>
   <td><code>A === B</code></td>
   <td><code>ToNumber(A) == ToPrimitive(B)</code></td>
  </tr>
  <tr>
   <td>Object</td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>ToPrimitive(A) == B</code></td>
   <td><code>ToPrimitive(A) == B</code></td>
   <td><code>ToPrimitive(A) == ToNumber(B)</code></td>
   <td>
    <p><code>A === B</code></p>
   </td>
  </tr>
 </tbody>
</table>

<p>在上面的表格中,<code>ToNumber(A)</code> 尝试在比较前将参数 A 转换为数字,这与 +A(单目运算符+)的效果相同。<code>ToPrimitive(A)</code>通过尝试调用 A 的<code>A.toString()</code> 和 <code>A.valueOf()</code> 方法,将参数 A 转换为原始值(Primitive)。</p>

<p>一般而言,根据 ECMAScript 规范,所有的对象都与 <code>undefined </code><code>null </code>不相等。但是大部分浏览器允许非常窄的一类对象(即,所有页面中的 <code>document.all </code>对象),在某些情况下,充当效仿 <code>undefined </code>的角色。相等操作符就是在这样的一个背景下。因此,<code>IsFalsy(A) </code>方法的值为 <code>true </code>,当且仅当 <code>A </code>效仿 <code>undefined</code>。在其他所有情况下,一个对象都不会等于 <code>undefined </code><code>null</code></p>

<pre class="brush: js">var num = 0;
var obj = new String("0");
var str = "0";
var b = false;

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

// both false, except in rare cases
console.log(obj == null);
console.log(obj == undefined);
</pre>

<p>有些开发者认为,最好永远都不要使用相等操作符。全等操作符的结果更容易预测,并且因为没有隐式转换,全等比较的操作会更快。</p>

<h2 id="同值相等">同值相等</h2>

<p>同值相等解决了最后一个用例:确定两个值是否在任何情况下功能上是相同的。(这个用例演示了<a href="http://zh.wikipedia.org/zh-cn/%E9%87%8C%E6%B0%8F%E6%9B%BF%E6%8D%A2%E5%8E%9F%E5%88%99">里氏替换原则</a>的实例。)当试图对不可变(immutable)属性修改时发生出现的情况:</p>

<pre class="brush: js">// 向 Nmuber 构造函数添加一个不可变的属性 NEGATIVE_ZERO
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> 在试图修改不可变属性时,如果这个属性确实被修改了则会抛出异常,反之什么都不会发生。例如如果 v 是 -0 ,那么没有发生任何变化,所以也不会抛出任何异常。但如果 v 是 +0 ,则会抛出异常。不可变属性和新设定的值使用 same-value 相等比较。</p>

<p>同值相等由 <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>

<h2 id="零值相等">零值相等</h2>

<p>与同值相等类似,不过会认为 +0 与 -0 相等。</p>

<h2 id="规范中的相等、严格相等以及同值相等">规范中的相等、严格相等以及同值相等</h2>

<p>在 ES5 中, <a href="https://developer.mozilla.org/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="https://developer.mozilla.org/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 也提供了 same-value 相等, <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 在处理数字上的不同外,它基本和严格相等算法相同。ES6 简单地通过  <a href="https://developer.mozilla.org/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>我们可以看到,使用双等或三等时,除了 11.9.6.1 类型检查,严格相等算法是相等算法的子集因为 11.9.6.2–7 对应 11.9.3.1.a–f。</p>

<h2 id="理解相等比较的模型">理解相等比较的模型</h2>

<p>在 ES2015 以前,你可能会说双等和三等是“扩展”的关系。比如有人会说双等是三等的扩展版,因为他处理三等所做的,还做了类型转换。例如 6 == "6" 。反之另一些人可能会说三等是双等的扩展,因为他还要求两个参数的类型相同,所以增加了更多的限制。怎样理解取决于你怎样看待这个问题。</p>

<p>但是这种比较的方式没办法把 ES2015 的 <a href="https://developer.mozilla.org/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="https://developer.mozilla.org/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="https://developer.mozilla.org/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="https://developer.mozilla.org/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="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN"><code>NaN</code></a> 的处理表明,这是不对的。 <a href="https://developer.mozilla.org/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>

<table class="standard-table">
 <caption>判等</caption>
 <thead>
  <tr>
   <th scope="col">x</th>
   <th scope="col">y</th>
   <th scope="col"><code>==</code></th>
   <th scope="col"><code>===</code></th>
   <th scope="col"><code>Object.is</code></th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td><code>undefined</code></td>
   <td><code>undefined</code></td>
   <td><code>true</code></td>
   <td><code>true</code></td>
   <td><code>true</code></td>
  </tr>
  <tr>
   <td><code>null</code></td>
   <td><code>null</code></td>
   <td><code>true</code></td>
   <td><code>true</code></td>
   <td><code>true</code></td>
  </tr>
  <tr>
   <td><code>true</code></td>
   <td><code>true</code></td>
   <td><code>true</code></td>
   <td><code>true</code></td>
   <td><code>true</code></td>
  </tr>
  <tr>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>true</code></td>
   <td><code>true</code></td>
   <td><code>true</code></td>
  </tr>
  <tr>
   <td><code>"foo"</code></td>
   <td><code>"foo"</code></td>
   <td><code>true</code></td>
   <td><code>true</code></td>
   <td><code>true</code></td>
  </tr>
  <tr>
   <td><code>0</code></td>
   <td><code>0</code></td>
   <td><code>true</code></td>
   <td><code>true</code></td>
   <td><code>true</code></td>
  </tr>
  <tr>
   <td><code>+0</code></td>
   <td><code>-0</code></td>
   <td><code>true</code></td>
   <td><code>true</code></td>
   <td><code>false</code></td>
  </tr>
  <tr>
   <td><code>0</code></td>
   <td><code>false</code></td>
   <td><code>true</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
  </tr>
  <tr>
   <td><code>""</code></td>
   <td><code>false</code></td>
   <td><code>true</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
  </tr>
  <tr>
   <td><code>""</code></td>
   <td><code>0</code></td>
   <td><code>true</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
  </tr>
  <tr>
   <td><code>"0"</code></td>
   <td><code>0</code></td>
   <td><code>true</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
  </tr>
  <tr>
   <td><code>"17"</code></td>
   <td><code>17</code></td>
   <td><code>true</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
  </tr>
  <tr>
   <td><code>[1,2]</code></td>
   <td><code>"1,2"</code></td>
   <td><code>true</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
  </tr>
  <tr>
   <td><code>new String("foo")</code></td>
   <td><code>"foo"</code></td>
   <td><code>true</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
  </tr>
  <tr>
   <td><code>null</code></td>
   <td><code>undefined</code></td>
   <td><code>true</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
  </tr>
  <tr>
   <td><code>null</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
  </tr>
  <tr>
   <td><code>undefined</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
  </tr>
  <tr>
   <td><code>{ foo: "bar" }</code></td>
   <td><code>{ foo: "bar" }</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
  </tr>
  <tr>
   <td><code>new String("foo")</code></td>
   <td><code>new String("foo")</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
  </tr>
  <tr>
   <td><code>0</code></td>
   <td><code>null</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
  </tr>
  <tr>
   <td><code>0</code></td>
   <td><code>NaN</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
  </tr>
  <tr>
   <td><code>"foo"</code></td>
   <td><code>NaN</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
  </tr>
  <tr>
   <td><code>NaN</code></td>
   <td><code>NaN</code></td>
   <td><code>false</code></td>
   <td><code>false</code></td>
   <td><code>true</code></td>
  </tr>
 </tbody>
</table>

<h2 id="什么时候使用_Object.is_或是三等">什么时候使用 <a href="https://developer.mozilla.org/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> 或是三等</h2>

<p>总的来说,除了对待<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN"><code>NaN</code></a>的方式,<a href="https://developer.mozilla.org/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>唯一让人感兴趣的,是当你需要一些元编程方案时,它对待0的特殊方式,特别是关于属性描述器,即你的工作需要去镜像<a href="https://developer.mozilla.org/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>的一些特性时。如果你的工作不需要这些,那你应该避免使用<a href="https://developer.mozilla.org/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="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators" title="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators"><code>===</code></a>来代替。即使你需要比较两个<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN"><code>NaN</code></a>使其结果为<code>true</code>,总的来说编写使用<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN"><code>NaN</code></a> 检查的特例函数(用旧版本ECMAScript的<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN"><code>isNaN方法</code></a>)也会比想出一些计算方法让<a href="https://developer.mozilla.org/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>不影响不同符号的0的比较更容易些。</p>

<p>这里是一个会区别对待-0和+0的内置方法和操作符不完全列表:</p>

<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#-_.28Unary_Negation.29" title="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators"><code>- (一元负)</code></a></p>

<dl>
 <dd>
 <p>显而易见,对<code>0一元负操作得到</code><code>-0</code>。但表达式的抽象化可能在你没有意识到得情况下导致-0延续传播。例如当考虑下例时:</p>

 <pre class="brush:js  language-js"><code class="language-js">let stoppingForce = obj.mass * -obj.velocity</code></pre>

 <p>如果<code>obj.velocity</code><code>0</code> (或计算结果为<code>0</code>), <code>一个-0</code>就在上处产生并被赋值为<code>stoppingForce的值</code>.</p>
 </dd>
</dl>

<dl>
 <dt><a href="https://developer.mozilla.org/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="https://developer.mozilla.org/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="https://developer.mozilla.org/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="https://developer.mozilla.org/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>即使传入的参数中没有-0,这些方法的返回值都有可能是-0。例如当用 <a href="https://developer.mozilla.org/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>计算<code>-<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Infinity" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Infinity">Infinity</a></code>的任何负奇指数的幂都会得到<code>-0</code>。详情请参见这些方法各自的文档。</dd>
</dl>

<dl>
 <dt><a href="https://developer.mozilla.org/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="https://developer.mozilla.org/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="https://developer.mozilla.org/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="https://developer.mozilla.org/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="https://developer.mozilla.org/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="https://developer.mozilla.org/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>当传入参数中有-0时,这些方法也可能返回-0。例如, <code>Math.min(-0, +0)</code> 得出 <code>-0</code>。详情请参见这些方法各自的文档。</dd>
</dl>

<dl>
 <dt><code><a href="https://developer.mozilla.org/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="https://developer.mozilla.org/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="https://developer.mozilla.org/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>这些操作符内部都使用了ToInt32算法。因为内部32位整数类型只有一个0(没有符号区别),-0的符号在反操作后并不会保留下来。例如<code>Object.is(~~(-0), -0)</code><code>Object.is(-0 &lt;&lt; 2 &gt;&gt; 2, -0)</code> <code>都会得到false</code>.</dd>
</dl>

<p>在未考虑0的符号的情况下依赖于<a href="https://developer.mozilla.org/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><code>是危险的。当然,如果本意就是区分-0和+0的话,</code><a href="https://developer.mozilla.org/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><code>能按照期望完成工作。</code></p>

<h2 id="参考">参考</h2>

<ul>
 <li><a href="http://dorey.github.io/JavaScript-Equality-Table/">JS比较表</a></li>
</ul>