JavaScript对象内数组被意外覆盖的异常问题排查
问题根源分析
1. 原对象被修改的原因
JavaScript里数组和对象都是引用类型。你代码里let currentAvailableTimesOnDate = availableTimesPerDay[bookedDate.getDate()]这行,只是把原对象里数组的引用赋值给了新变量,并不是复制出一个新数组。之后用splice修改currentAvailableTimesOnDate,本质上就是在修改原availableTimesPerDay里的数组——因为它们指向内存里同一个数组实例。
2. 同星期几日期数组同时被修改的原因
你在生成availableTimesPerDay的时候,大概率是把同一个数组实例赋值给了所有同星期几的日期键。比如可能写了类似这样的代码:
const defaultWeekdayTimes = ["10:00","10:30","11:00","11:30","12:00"]; // 假设1、8、15号都是周一 availableTimesPerDay[1] = defaultWeekdayTimes; availableTimesPerDay[8] = defaultWeekdayTimes; availableTimesPerDay[15] = defaultWeekdayTimes;
这种情况下,这几个日期对应的数组都是同一个引用,修改其中一个,其他所有指向这个数组的日期键都会跟着变。而你在codepen或控制台测试时,应该是手动为每个日期单独写了数组(比如1: ["10:00",...], 8: ["10:00",...]),每个数组都是独立实例,所以不会互相影响。
解决方案
第一步:修复availableTimesPerDay的生成逻辑
确保每个日期对应的数组都是独立的副本,不要复用同一个数组引用。可以用扩展运算符或者slice()来复制数组:
const defaultWeekdayTimes = ["10:00","10:30","11:00","11:30","12:00"]; // 每个日期都赋值数组的副本 availableTimesPerDay[1] = [...defaultWeekdayTimes]; availableTimesPerDay[8] = [...defaultWeekdayTimes]; availableTimesPerDay[15] = [...defaultWeekdayTimes];
第二步:修改函数,避免修改原对象
如果不想让原availableTimesPerDay被修改,需要先创建它的深拷贝,然后在拷贝上进行操作。因为availableTimesPerDay里的值是数组,所以要深拷贝到数组层级:
function reduceAvailableTimesBasedOnDateTime(availableTimesPerDay, bookedTimes) { // 创建深拷贝,避免修改原对象 const copiedAvailableTimes = {}; for (const dateKey in availableTimesPerDay) { copiedAvailableTimes[dateKey] = [...availableTimesPerDay[dateKey]]; } bookedTimes.forEach((bookedDateObject) => { const bookedDate = new Date(bookedDateObject.date); const dateKey = bookedDate.getDate(); const currentAvailableTimes = copiedAvailableTimes[dateKey]; if (!currentAvailableTimes) return; // 如果该日期没有可用时段,直接跳过 // 注意:toLocaleTimeString的时区问题,建议明确指定时区 const bookedTime = bookedDate.toLocaleTimeString('et', { timeZone: 'Europe/Tallinn' }); const time = bookedTime.substring(0, bookedTime.length - 3); const index = currentAvailableTimes.indexOf(time); if (index > -1) { currentAvailableTimes.splice(index, 1); } }); return copiedAvailableTimes; }
这样调用函数后,原availableTimesPerDay不会被修改,返回的是修改后的新对象。
额外优化:避免时区转换问题
你代码里用toLocaleTimeString转换时间可能存在时区偏差,建议直接从ISO字符串中提取时间部分,更可靠:
// 从"2022-12-01T11:30:00.000+02:00"提取"11:30" const time = bookedDateObject.date.slice(11, 16);
内容的提问来源于stack exchange,提问作者Banana

