返回介绍

第一部分 类型和语法

第二部分 异步和性能

4.6 抽象关系比较

发布于 2023-05-24 16:38:21 字数 2202 浏览 0 评论 0 收藏 0

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文