news 2026/10/7 16:24:08

现代 JavaScript 教程实战:用 Date 自动校准特性一行代码获取任意月份的最后一天

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
现代 JavaScript 教程实战:用 Date 自动校准特性一行代码获取任意月份的最后一天
  • 文档
  • 教程
  • 前端

【免费下载链接】zh.javascript.info

现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。

项目地址:https://gitcode.com/gh_mirrors/zh/zh.javascript.info
点击查看免费下载

本篇文章基于《现代 JavaScript 教程》(zh.javascript.info)日期和时间章节下的配套练习题“某月的最后一天?”,完整讲解getLastDayOfMonth(year, month)的实现思路、底层原理与测试验证。读完本文,你将掌握new Date(year, month, date)构造器的参数规则、Date对象"自动校准"(Autocorrection)这一关键特性,并学会用"下个月的第 0 天"这一技巧一行代码求出任意月份(含闰年二月)的天数,同时通过仓库内的 Mocha 测试用例验证结果正确性。

任务背景:为什么"某月最后一天"是个值得研究的题目

在 5-last-day-of-month/task.md 中给出了这样一道练习题:

写一个函数getLastDayOfMonth(year, month)返回month月的最后一天。有时候是 30,有时是 31,甚至在二月的时候会是 28/29。

参数约定如下:

  • year—— 四位数的年份,比如 2012;
  • month—— 月份,从 0 到 11(与 JavaScript 的Date月份约定一致,0 代表一月)。

示例要求:getLastDayOfMonth(2012, 1) = 29(2012 年是闰年,二月的最后一天是 29 日)。

这道题的"难点"在于:不同月份的天数不同(30/31),而且二月还要受闰年规则影响(28 或 29)。如果手写分支判断,需要维护一张月份天数表,还要额外实现闰年判定逻辑(year % 4 === 0 && year % 100 !== 0 || year % 400 === 0),既繁琐又容易出错。而Date对象本身就内置了完整的日历算法,可以优雅地解决这个问题。

前置知识:new Date(year, month, date) 的构造规则

要理解解法,必须先回顾 日期和时间 中关于构造函数的关键约定:

new Date(year, month, date, hours, minutes, seconds, ms)使用当前时区中的给定组件创建日期,只有前两个参数是必须的:

  • year应该是四位数。为了兼容性,也接受 2 位数,并将其视为19xx(例如98与1998相同),但强烈建议始终使用 4 位数;
  • month计数从0(一月)开始,到11(十二月)结束——这是 JavaScript 初学者最容易踩的坑;
  • date是当月的具体某一天,如果缺失,则为默认值1;
  • 如果hours/minutes/seconds/ms缺失,则均为默认值0。

例如new Date(2011, 0, 1)表示 2011 年 1 月 1 日 00:00:00。访问日期组件时,getMonth()同样返回从 0 到 11 的月份,getDate()返回当月的具体日期(从 1 到 31)。

核心原理:Date 的自动校准(Autocorrection)

解法能够一行完成,依赖的是Date对象一个非常方便的特性——自动校准:

我们可以设置超范围的数值,它会自动校准。超出范围的日期组件将会被自动分配。

仓库文档中给出了两个典型例子:

let date = new Date(2013, 0, 32); // 32 Jan 2013 ?!? alert(date); // ……是 1st Feb 2013!

日期组件越界时会被自动进位。反过来,设置 0 甚至负值同样有效:

let date = new Date(2016, 0, 2); // 2016 年 1 月 2 日 date.setDate(1); // 设置为当月的第一天 alert( date ); date.setDate(0); // 天数最小可以设置为 1,所以这里设置的是上一月的最后一天 alert( date ); // 31 Dec 2015

正是因为"第 0 天"会被自动校准为"上个月的最后一天",我们才能用构造器直接求出目标月份的天数,而完全不必关心这个月到底是 28、29、30 还是 31 天——闰年逻辑全部由引擎内置的日历算法处理。

标准解法:下个月的第 0 天

仓库中的官方解答位于 5-last-day-of-month/solution.md,核心思路是:用下个月(month + 1)创建日期,但将天数(day)传为 0:

function getLastDayOfMonth(year, month) { let date = new Date(year, month + 1, 0); return date.getDate(); } alert( getLastDayOfMonth(2012, 0) ); // 31 alert( getLastDayOfMonth(2012, 1) ); // 29 alert( getLastDayOfMonth(2013, 1) ); // 28

逐行拆解:

  1. new Date(year, month + 1, 0):先构造"下个月"的日期对象;
  2. 天数传0:通常日期从 1 开始,但从技术上讲我们可以传递任何数字,日期会自动进行调整。因此当我们传递0时,它的意思是"一个月的第一天的前一天",换句话说——"上个月的最后一天";
  3. date.getDate():取出这一天是几号,即目标月份的最后一天。

对照任务示例验证:getLastDayOfMonth(2012, 1)中month = 1表示二月,new Date(2012, 2, 0)即"2012 年 3 月 0 日"被自动校准为 2012 年 2 月 29 日(2012 是闰年),getDate()返回 29,完全符合题目要求。

仓库中的独立实现文件 5-last-day-of-month/_js.view/solution.js 与上述解答完全一致,可直接复制运行:

function getLastDayOfMonth(year, month) { let date = new Date(year, month + 1, 0); return date.getDate(); }

测试验证:仓库内置的 Mocha 用例

该练习目录下还带有配套的测试文件 5-last-day-of-month/_js.view/test.js,使用 Mocha +assert对三个典型场景做了断言:

describe("getLastDayOfMonth", function() { it("last day of 01.01.2012 - 31", function() { assert.equal(getLastDayOfMonth(2012, 0), 31); }); it("last day of 01.02.2012 - 29 (leap year)", function() { assert.equal(getLastDayOfMonth(2012, 1), 29); }); it("last day of 01.02.2013 - 28", function() { assert.equal(getLastDayOfMonth(2013, 1), 28); }); });

三个用例分别覆盖了:

调用含义期望结果覆盖场景
getLastDayOfMonth(2012, 0)2012 年 1 月3131 天的大月
getLastDayOfMonth(2012, 1)2012 年 2 月29闰年二月
getLastDayOfMonth(2013, 1)2013 年 2 月28平年二月

可以看到,测试刻意选择了"相邻年份的同一月份",以此证明解法对闰年判定(28/29)的处理是自动且正确的,无需任何手写的闰年分支。

延伸思考:这个技巧还能用在哪儿

"第 0 天 / 自动校准"并不是一个孤立的小技巧,它是Date对象最通用的能力之一,在本教程的其他练习中同样有体现:

  • 计算 N 天前的日期:配套练习 4-get-date-ago/solution.md 中,通过date.setDate(date.getDate() - days)处理跨月甚至跨年的减法,例如从 2015 年 1 月 2 日减去 2 天得到 2014 年 12 月 31 日、减去 365 天得到 2014 年 1 月 2 日,日期自动校准帮你处理了所有边界;
  • 构造指定日期:如 1-new-date/task.md 所示,用new Date(2012, 1, 20, 3, 12)创建当地时区的 "Feb 20, 2012, 3:12am";
  • 日期加减运算:date.setDate(date.getDate() + 2)在 2016 年 2 月 28 日上加两天,自动得到 3 月 1 日(闰年)——日期和时间 文档中的"自动校准"小节对此有完整阐述;
  • 获取当月剩余天数、判断某月天数、生成日历组件等前端常见需求,都可以复用"下个月第 0 天"这一模式。

小结

要点结论
构造器规则new Date(year, month, date)中month从 0 开始,date缺省为 1
自动校准超出范围(含 0 和负值)的日期组件会被引擎自动进位/借位
核心技巧new Date(year, month + 1, 0)即"下个月的第 0 天"= 本月的最后一天
最终实现getLastDayOfMonth(year, month)仅需两行:构造 +getDate()
正确性保证仓库配套 test.js 验证了 31 天大月、闰年二月 29 日、平年二月 28 日三种情形

这道题完美诠释了 JavaScriptDate对象"内置日历算法 + 自动校准"的设计哲学:与其手写月份天数和闰年判断,不如把日历计算交给引擎,让代码更短、更不易出错。这一模式在日期处理的各类实战场景中都可以直接复用。

  • 文档
  • 教程
  • 前端

【免费下载链接】zh.javascript.info

现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。

项目地址:https://gitcode.com/gh_mirrors/zh/zh.javascript.info
点击查看免费下载
上一篇:Pigsty pg_monitor 角色深度解析:PostgreSQL 集群监控 Exporter 的自动化部署与基础设施注册
下一篇:Carbon Language 设计原则 p001280 解读:所有 API 都是库 API——把内置类型做成库类型的设计与实现

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 16:22:33

体育研究生论文写到emo,这个AI让我提前两周交稿✅

体育研究生写论文有多emo?白天带训练队、上训练课、做体质测试,晚上拖着酸痛的身体坐到电脑前,面对一个字没动的论文,真的会想转行。 体育学研究生的论文是"文理双修"——既要做实验(训练干预、体质测试、生…

作者头像 李华
网站建设 2026/10/7 16:21:53

eFuse与MCU协同实现工业电源路径保护:从原理到实战

做嵌入式项目,尤其是工业控制这一类,电源永远是最容易出幺蛾子的环节。前阵子帮客户调一套24V供电的控制器,现场反馈了一个很刁钻的问题:某一路负载在热插拔的瞬间,整个控制器会出现偶发性重启,十次里能撞上…

作者头像 李华
网站建设 2026/10/7 16:20:01

六行业实战拆解:如何把WorkBuddy从玩具变成生产力工具

提到 WorkBuddy,很多人第一反应是"又一个 AI 助手",然后打开界面问几个问题、让它写几段内容,就放回角落吃灰了。但把最近的搜索热词翻一遍,你会发现情况远不止这么简单:有人在到处找"从入门到精通&quo…

作者头像 李华