JavaScript 中的日期比较:如何避免踩坑并加速代码
\n\n想象一下:你正在编写一个在线商店,需要检查商品折扣是否已过期。或者你在制作一个任务日历,需要筛选出今天的活动。又或者你在收集分析数据——"显示过去一周的所有订单"。在这些场景中,你都需要比较两个日期。看起来很简单,对吧?但 JavaScript 一如既往地准备给你带来惊喜。
\n\nStack Overflow 上关于 "Compare two dates with JavaScript" 的问题获得了数千次浏览——这并非偶然。即使是经验丰富的开发者,也常常在处理日期时遇到一些不明显的特性而犯错。在本文中,我们不仅会展示如何比较两个日期,还会分析哪种方法更快、哪种更安全。开始吧!
\n\n为什么简单的日期比较行不通?
\n\n我们先从新手常犯的经典错误开始。假设我们有两个日期:
\n\nlet date1 = new Date('2024-03-15');\nlet date2 = new Date('2024-03-20');\n\nconsole.log(date1 < date2); // true\nconsole.log(date1 > date2); // false\nconsole.log(date1 == date2); // false\n\n\n使用 < 和 > 运算符时一切正常。JavaScript 会将 Date 对象转换为数字(毫秒)并进行比较。但 == 运算符(以及严格等于 ===)的行为则不同。它比较的是对象的引用,而不是它们的值。两个不同的日期就是两个不同的对象,因此 == 总是返回 false,即使这两个日期精确到毫秒也完全相同。
这是第一个陷阱。由此得出的教训是:永远不要使用 == 或 === 来比较日期。只能使用 <、>、<=、>= 或专门的方法。
getTime() 方法:日期比较的黄金标准
\n\n最可靠且性能最高的方法是使用 getTime()。它返回自 1970 年 1 月 1 日(Unix 纪元)以来经过的毫秒数。而 JavaScript 非常擅长比较数字:
let date1 = new Date('2024-03-15T10:00:00');\nlet date2 = new Date('2024-03-15T10:00:00');\nlet date3 = new Date('2024-03-20T10:00:00');\n\nconsole.log(date1.getTime() === date2.getTime()); // true\nconsole.log(date1.getTime() < date3.getTime()); // true\nconsole.log(date1.getTime() > date3.getTime()); // false\n\n\n为什么这很高效?因为 getTime() 是一个非常轻量级的操作。它只是返回 Date 对象内部已经存储的数值。无需解析,无需额外计算。仅仅是一个数字。
让我们来测量一下性能。以下是在浏览器控制台中进行的一个小测试:
\n\nlet date1 = new Date('2024-01-01');\nlet date2 = new Date('2024-12-31');\n\nconsole.time('getTime');\nfor (let i = 0; i < 1000000; i++) {\n date1.getTime() < date2.getTime();\n}\nconsole.timeEnd('getTime');\n// 结果:在现代浏览器中约 5-10 毫秒\n\n\n一百万次比较在 10 毫秒内完成——这是一个非常棒的结果。相比之下,其他方法可能会慢 2-3 倍。
\n\n使用 valueOf() 比较日期
\n\nvalueOf() 方法做的事情与 getTime() 相同——返回日期的数值表示。但有一个细微差别:当使用比较运算符(<、> 等)时,JavaScript 会隐式调用 Date 对象的 valueOf()。也就是说,下面这段代码:
let date1 = new Date('2024-03-15');\nlet date2 = new Date('2024-03-20');\nconsole.log(date1 < date2);\n\n\n实际上是这样工作的:
\n\nconsole.log(date1.valueOf() < date2.valueOf());\n\n\n因此,对于简单的 < 和 > 比较,可以直接使用 Date 对象。但对于精确的相等性比较(===),这行不通,这时就需要使用 getTime() 或 va