我们从数学中了学习到很多比较运算符

  • 大于/小于:a > b, a < b,

  • 大于等于/小于等于:a >= b, a <= b,

  • 相等检查写作 a == b(请注意是两个等于号 ==,一个等于号 a = b 表示赋值)。

  • 不等于在数学里的符号是 ≠,在 JavaScript 里是用一个惊叹号来写的:a != b。

返回的是布尔值

就像所有其他操作符一样,比较返回一个值。值是布尔类型的值。

  • true:表示“是”,“正确”,“真的”。

  • false:表示“否”,“错误”,“假的”。

例如:

  1. alert( 2 > 1 ); // true (正确的)
  2. alert( 2 == 1 ); // false (错误的)
  3. alert( 2 != 1 ); // true (正确的)

一个比较结果可以分配给一个变量,就像任何值一样:

字符串比较

要查看一个字符串是否大于另一个字符串,就使用所谓的“字典”或“词典”顺序。

换句话说,字符串是逐字母进行比较的。

例如:

  1. alert( 'Z' > 'A' ); // true
  2. alert( 'Glow' > 'Glee' ); // true
  3. alert( 'Bee' > 'Be' ); // true

比较两个字符串的算法很简单:

  1. 比较两个字符串的第一个字符。

  2. 如果第一个字符大(或小)的话,第一个字符串就比第二个大(或小)。结束比较。

  3. 否则,如果第一个字符相等,那么就按照同样的方式比较第二个字符。

  4. 重复直到比较到字符串结束。

  5. 如果两个字符串到最后一个字符也是相等的,那么两个字符串就相等。否则,长的那个字符串比短的大。

在上面的例子里,’Z’ > ‘A’ 的比较在第一步就能得到答案。

字符串 “Glow” 和 “Glee” 的比较是一个一个字符的:

  1. G 等于 G。

  2. l 等于 l。

  3. o 比 e 要大。在这里停止了,第一个字符串比第二个大。

⚠️不是真的字典顺序,而是 Unicode 顺序

上面给出的比较算法大致相当于在图书字典或电话簿中使用的比较算法。但这并不是完全一样的。

例如,大小写是区分的。大写字母“A”不等于小写的“a”。哪一个更大?实际上,小写的“a”更大。为什么?因为小写字符在内部编码表(Unicode)中有更大的索引。我们将在《字符串》章节的中回到具体的细节和结果。

不同类型的比较

当比较值属于不同类型时,它们被转换成数字。

例如:

  1. alert( '2' > 1 ); // true, string '2' becomes a number 2
  2. alert( '01' == 1 ); // true, string '01' becomes a number 1

对于布尔值,true 变成 1 false 变成 0:

  1. alert( true == 1 ); // true
  2. alert( false == 0 ); // true

⚠️有趣的结果

在同一时间,有可能:

  • 两个值相等。

  • 其中一个转换成布尔值是 true,而另一个转换成布尔值是 false。

例如:

```javascript let a = 0; alert( Boolean(a) ); // false

let b = “0”; alert( Boolean(b) ); // true

alert(a == b); // true!

  1. >
  2. > JavaScript 的角度来看,这是很正常的。一个平等检查使用数字转换进行转换(因此 "0" 变成了 0),而布尔值的转换是另一套规则。
  3. <a name="q7matx"></a>
  4. ## 严格相等
  5. 普通的相等检查 == 有一个问题。不能区分 0 false
  6. ```javascript
  7. alert( 0 == false ); // true

空字符串也是一样的:

  1. alert( '' == false ); // true

这是因为使用相等运算符 == 后,不同类型的操作数被转换成了数字。空字符串,像 false 一样,变成了 0。

那么我们怎么区分 0 和 false 呢?

一个严格相等运算符 === 检查相等时,不会发生类型转换。

也就是说,如果 a 和 b 是不同类型的,那么 a === b 的结果就会返回 false。

我们试下:

  1. alert( 0 === false ); // false, because the types are different

当然也有“严格非相等”运算符 !==,对应 !=。

严格相等运算符写起来更长,但能清楚地说明做了什么,并且留下了更少的错误空间。

null 和 undefined 的比较

我们来看些边缘情况。

当 null 和 undefiend 在一起比较的时候,会发生非直觉的结果。

这两个值用严格相等运算符 === 比较,是 false。因为两者属于不同的类型。

  1. alert( null === undefined ); // false

这两个值用相等运算符 == 比较,结果是 true,这是一个特殊的规则。同时, null 和 undefined 和其他值比较的结果都是 false。

  1. alert( null == undefined ); // true

对于算术和其他比较运算符 < > <= >=

null/undefined 会转换为数值:null 变成 0,而 undefined 变成 NaN。

现在让我们看看当我们应用这些规则时发生的有趣的事情。更重要的是,如何不落入这些特性的陷阱。

奇怪的结果

我们来比较下 null 和 0 的结果:

  1. alert( null > 0 ); // (1) false
  2. alert( null == 0 ); // (2) false
  3. alert( null >= 0 ); // (3) true

是的,从数学上来说这很奇怪。最后的结果表明“null大于或等于零”。上面的一个比较肯定是正确的,但它们都是假的。

原因是,相等运算符 == 和其他比较运算符 > < >= <= 工作方式有些不一样。比较运算符会把 null 转换为数值,因此当成 0 对待了。这就是为什么(3) null >= 0 是 true 的原因,而(1) null > 0 是 false 了。

另一方面,对于 undefinednull 来说,相等检查 == 在规范中是这样定义的:不发生类型转换,只彼此相等,不与其他任何值相等。这就是为什么 (2) 处 null == 0 结果为 false 的原因。

无与伦比的 undefined

undefined 就不应该参与比较运算:

  1. alert( undefined > 0 ); // false (1)
  2. alert( undefined < 0 ); // false (2)
  3. alert( undefined == 0 ); // false (3)

为什么它不喜欢零?总是 false!

我们得到了这些结果,因为:

  • 比较 (1) 和 (2) 返回 false 是因为 undefined 转换成了 NaN。NaN 是个特殊的值,不等于任何值。

  • 相等检查 (3) 返回 false,因为 undefined 仅与 null 比较为 true,与其他值比较均为 false。

逃避问题

为什么我们要观察这些例子?我们应该一直记住这些特性吗?好吧,其实不是。实际上,随着时间的推移,这些棘手的事情会逐渐变得熟悉起来,但是有一种可靠的方法可以避免任何问题。

除了在严格相等运算符 === 的情况下,任何在比较 null/undefiend 的场景都要小心。

不要在一个变量值在可能等于 null/undefined 的情况下使用比较运算符 >= > < <=,除非你明白你到底在做什么。如果一个变量可以有这样的值,那么就分别检查它们。

总结

  • 比较运算符会返回一个逻辑值。

  • 字符串比较时,是按照“字典”顺序一个字符一个字符进行比较的。

  • 当比较不同类型的值时,它们会被转换成数字(排除了严格相等运算符检查)。

  • 仅 null 与 undefined 的相等比较 == 结果为 true,和其他任意值比较的结果都是 false。

  • 如果一个变量的可能值是 null/undefined 的话,使用比较运算符 > 或 < 的时候一定要小心。对 null/undefiend 分开检查是个好主意。

(完)


📄 文档信息

🕘 更新时间:2020/02/08
🔗 原文链接:https://javascript.info/comparison
🤟 特别感谢:@tys1998(tys1998)