4.6 抽象关系比较
a < b 中涉及的隐式强制类型转换不太引人注意,不过还是很有必要深入了解一下。
ES5 规范 11.8.5 节定义了“抽象关系比较”(abstract relational comparison),分为两个部分:比较双方都是字符串(后半部分)和其他情况(前半部分)。
该算法仅针对 a < b ,a=""> b 会被处理为 b <>
比较双方首先调用 ToPrimitive ,如果结果出现非字符串,就根据 ToNumber 规则将双方强制类型转换为数字来进行比较。
例如:
var a = [ 42 ]; var b = [ "43" ]; a < b; // true b < a; // false
前面介绍过的 -0 和 NaN 的相关规则在这里也适用。
如果比较双方都是字符串,则按字母顺序来进行比较:
var a = [ "42" ]; var b = [ "043" ]; a < b; // false
a 和 b 并没有被转换为数字,因为 ToPrimitive 返回的是字符串,所以这里比较的是 "42" 和 "043" 两个字符串,它们分别以 "4" 和 "0" 开头。因为 "0" 在字母顺序上小于 "4" ,所以最后结果为 false 。
同理:
var a = [ 4, 2 ]; var b = [ 0, 4, 3 ]; a < b; // false
a 转换为 "4, 2" ,b 转换为 "0, 4, 3" ,同样是按字母顺序进行比较。
再比如:
var a = { b: 42 }; var b = { b: 43 }; a < b; // ??
结果还是 false ,因为 a 是 [object Object] ,b 也是 [object Object] ,所以按照字母顺序 a < b 并不成立。
下面的例子就有些奇怪了:
var a = { b: 42 }; var b = { b: 43 }; a < b; // false a == b; // false a > b; // false a <= b; // true a >= b; // true
为什么 a == b 的结果不是 true ?它们的字符串值相同(同为 "[object Object]" ),按道理应该相等才对?实际上不是这样,你可以回忆一下前面讲过的对象的相等比较。
但是如果 a < b 和 a == b 结果为 false ,为什么 a <= b 和 a >= b 的结果会是 true 呢?
因为根据规范 a <= b 被处理为 b < a ,然后将结果反转。因为 b < a 的结果是 false ,所以 a <= b 的结果是 true 。
这可能与我们设想的大相径庭,即 <= 应该是“小于或者等于”。实际上 JavaScript 中 <= 是“不大于”的意思(即 !(a > b) ,处理为 !(b < a) )。同理 a >= b 处理为 b <= a 。
相等比较有严格相等,关系比较却没有“严格关系比较”(strict relational comparison)。也就是说如果要避免 a < b 中发生隐式强制类型转换,我们只能确保 a 和 b 为相同的类型,除此之外别无他法。
与 == 和 === 的完整性检查一样,我们应该在必要和安全的情况下使用强制类型转换,如:42 < "43" 。换句话说就是为了保证安全,应该对关系比较中的值进行显式强制类型转换:
var a = [ 42 ]; var b = "043"; a < b; // false -- 字符串比较! Number( a ) < Number( b ); // true -- 数字比较!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论