为何向数组添加日期会覆盖原有元素?附月末日期生成需求
JavaScript Date数组元素被覆盖问题修复与月末日期生成优化
问题根源
- Date对象的引用特性:JavaScript中
Date是引用类型,targetDate = datesArr[i]只是将数组中已有Date对象的引用赋值给变量,后续调用targetDate.setDate()会直接修改原对象,导致数组中之前的元素被覆盖。 - deltaOfDays函数逻辑错误:
- 函数内
numberOfDays未初始化,直接使用numberOfDays =+ ...会导致值为NaN - 循环第一次迭代就直接
return,未按durationOfMonths要求累加天数 - 数组
shift/push操作无实际作用,因循环提前终止
- 函数内
解决方案
1. 避免引用修改:操作Date副本
每次处理数组中的日期时,通过new Date(existingDate)创建原对象的副本,修改副本不会影响数组中已有的元素。
2. 简化月末日期计算:利用原生Date API
手动计算月份天数易出错(如闰年2月、不同月份天数差异),直接用Date的setMonth和setDate方法即可精准获取前n个月的月末:
- 将日期设为
0会自动回退到上月最后一天 - 结合
setMonth直接调整月份,无需手动计算天数
修正后的完整代码
// 生成包含指定月末日期及之前11个对应频率月末日期的数组 let datesArr = []; const initialDate = new Date(2022, 03, 30); // 2022-04-30 const period = 12; const durationOfMonths = 1; // 每月一次,设为3则为每季度 // 初始化第一个元素,创建副本避免后续修改影响原对象 datesArr[0] = new Date(initialDate); // 循环生成剩余11个日期 for (let i = 0; i < period - 1; i++) { const currentDate = datesArr[i]; // 创建当前日期的副本,确保修改不影响原数组元素 const prevMonthEnd = new Date(currentDate); // 调整月份为前durationOfMonths个月 prevMonthEnd.setMonth(prevMonthEnd.getMonth() - durationOfMonths); // 设置为当月最后一天:日期设为0会自动回退到上月最后一天 prevMonthEnd.setDate(0); datesArr.push(prevMonthEnd); } console.log(datesArr); // 输出示例:[2022-04-30T00:00:00.000Z, 2022-03-31T00:00:00.000Z, ..., 2021-05-31T00:00:00.000Z]
关键改动说明
- 创建Date副本:每次处理时用
new Date(currentDate)生成独立对象,彻底避免引用修改导致的元素覆盖问题 - 简化日期计算:利用原生API直接获取月末日期,规避了闰年、月份天数差异等边界问题
- 调整循环次数:数组已初始化第一个元素,只需循环
period - 1次即可生成12个目标元素
保留deltaOfDays函数的修复版本(若需特定逻辑)
如果必须保留原函数逻辑,需修复其计算错误:
function deltaOfDays(targetDate, durationOfMonths) { const daysPerMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; // 闰年判断逻辑 const isLeapYear = (year) => (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; let totalDays = 0; let currentMonth = targetDate.getMonth(); let currentYear = targetDate.getFullYear(); for (let i = 0; i < durationOfMonths; i++) { currentMonth--; // 月份越界时调整年份 if (currentMonth < 0) { currentMonth = 11; currentYear--; } // 累加天数,闰年2月额外加1天 let days = daysPerMonth[currentMonth]; if (currentMonth === 1 && isLeapYear(currentYear)) days += 1; totalDays += days; } return totalDays; }
主逻辑中需配合副本使用:
// ... 初始化部分 ... for (let i = 0; i < period - 1; i++){ const targetDate = new Date(datesArr[i]); // 创建副本 const numberOfDays = deltaOfDays(targetDate, durationOfMonths); const newMonthEndDate = new Date(targetDate); newMonthEndDate.setDate(newMonthEndDate.getDate() - numberOfDays); datesArr.push(newMonthEndDate); }
内容的提问来源于stack exchange,提问作者devTokyo90
相关产品推荐
相关产品推荐

