关系操作符

​ 关系操作符执行比较两个值的操作,包括小于(<)、大于(>)、小于等于()和大于等于(>=), 用法跟数学课上学的一样。这几个操作符都返回布尔值,如下所示:

 let result1 = 5 > 3; // true
 let result2 = 5 < 3; // false

​ 与 ECMAScript 中的其他操作符一样,在将它们应用到不同数据类型时也会发生类型转换和其他行为

	- 如果操作数都是数值,则执行数值比较。
	- 如果操作数都是字符串,则逐个比较字符串中对应字符的**编码**。
	- 如果有任一操作数是数值,则将另一个操作数转换为**数值**,执行**数值比较**。
	- 如果有任一操作数是对象,则调用其 valueOf()方法,取得结果后再根据前面的规则执行比较。 如果没有 valueOf()操作符,则调用 toString()方法,取得结果后再根据前面的规则执行比较。
	- 如果有任一操作数是布尔值,则将其转换为数值再执行比较。

​ 在使用关系操作符比较两个字符串时,会发生一个有趣的现象。很多人认为小于意味着“字母顺序 靠前”,而大于意味着“字母顺序靠后”,实际上不是这么回事。对字符串而言,关系操作符会比较字符 串中对应字符的编码,而这些编码是数值。比较完之后,会返回布尔值。问题的关键在于,大写字母的 编码都小于小写字母的编码,因此以下这种情况就会发生:

 let result = "Brick" < "alphabet"; // true

​ 在这里,字符串”Brick”被认为小于字符串”alphabet”,因为字母 B 的编码是 66,字母 a 的编码 是 97。要得到确实按字母顺序比较的结果,就必须把两者都转换为相同的大小写形式(全大写或全小写), 然后再比较:

let result = "Brick".toLowerCase() < "alphabet".toLowerCase(); // false

​ 将两个操作数都转换为小写,就能保证按照字母表顺序判定”alphabet”在”Brick”前头。

​ 另一个奇怪的现象是在比较两个数值字符串的时候,比如下面这个例子:

let result = "23" < "3"; // true

​ 这里在比较字符串”23”和”3”时返回 true。因为两个操作数都是字符串,所以会逐个比较它们的 字符编码(字符”2”的编码是 50,而字符”3”的编码是 51)。不过,如果有一个操作数是数值,那么比较的结果就对了:

let result = "23" < 3; // false

​ 因为这次会将字符串”23”转换为数值 23,然后再跟 3 比较,结果当然对了。只要是数值和字符串比较,字符串就会先被转换为数值,然后进行数值比较。对于数值字符串而言,这样能保证结果正确。 但如果字符串不能转换成数值呢?比如下面这个例子:

let result = "a" < 3; // 因为"a"会转换为NaN,所以结果是false

​ 因为字符”a”不能转换成任何有意义的数值,所以只能转换为 NaN。这里有一个规则,即任何关系操作符在涉及比较 NaN 时都返回 false。这样一来,下面的例子有趣了:

let result1 = NaN < 3;  // false
let result2 = NaN >= 3; // false

​ 在大多数比较的场景中,如果一个值不小于另一个值,那就一定大于或等于它。但在比较 NaN 时, 无论是小于还是大于等于,比较的结果都会返回 false。