Office Script中array.splice意外影响两个数组的问题排查
问题排查:Office Script中临时数组修改导致原数组同步变化
我正在编写用于自动填充日历的Office Script,遇到一个问题——调用populatingIhListCountry.splice(j, 1)时,临时数组populatingIhListCountry和原数组ihListCountry的长度会同时被修改。以下是相关代码片段、控制台输出及完整函数代码,恳请帮忙排查原因:
代码片段
// Remove element from temporary list console.log('--before', ihListCountry, populatingIhListCountry); populatingIhListCountry.splice(j, 1); console.log('--after', ihListCountry, populatingIhListCountry);
控制台输出
--before (11) [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, …] (11) [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, …] --after (10) [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object] (10) [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object] --before (10) [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object] (10) [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object] --after (9) [Object, Object, Object, Object, Object, Object, Object, Object, Object] (9) [Object, Object, Object, Object, Object, Object, Object, Object, Object]
完整函数及数组初始化代码
function populateIHListCalendar( workbook: ExcelScript.Workbook, currentWorksheet: ExcelScript.Worksheet, rangeText: string[], targetRange: ExcelScript.Range, ihListCountry: socTeam[] ) { let populatingIhListCountry: socTeam[] = ihListCountry; let availabilityWorksheet: ExcelScript.Worksheet = workbook.getWorksheets()[0]; let availabilityRange: ExcelScript.Range = availabilityWorksheet.getUsedRange(); //Loop through each cells for (let i: number = 0; i < rangeText.length; i++) { let ihAvailability: boolean = false; // Refill list if it's empty if (populatingIhListCountry.length == 0) { populatingIhListCountry = ihListCountry; } let availabilityColumn: string[][] = availabilityWorksheet.getUsedRange().getColumn(i).getTexts(); let j: number = 0; let whileCycle: number = 0; while(ihAvailability === false) { // 调用函数对比IH名称与休假日历,返回该时段是否可用 ihAvailability = compareAvailabilityAndIHList(availabilityColumn, populatingIhListCountry, j); if (ihAvailability === false) { j++; if (j === populatingIhListCountry.length && whileCycle === 0) { j = 0; whileCycle = 1; } else if (j === populatingIhListCountry.length && whileCycle === 1) { populatingIhListCountry = populatingIhListCountry.concat(ihListCountry); console.log('第一轮循环结束,剩余列表中无可用IH!'); whileCycle = 2; } else if (j === populatingIhListCountry.length && whileCycle === 2) { console.log('错误!未找到可用IH!'); break; } } } if (j === populatingIhListCountry.length && whileCycle === 2) { break; } // 将IH添加到日历 let calendarTable: ExcelScript.Table = currentWorksheet.getTables()[0]; let columnRange = calendarTable.getColumn(rangeText[i]).getRange().getValues(); let k: number = 0; while (columnRange[k] != undefined && columnRange[k].toString() != "") { k++; } if (calendarTable.getColumn(rangeText[i]).getRange().getCellCount() === j) { calendarTable.addRow(); } currentWorksheet.getCell(k, calendarTable.getColumn(rangeText[i]).getIndex()).setValue(populatingIhListCountry[j].Title); // 从临时列表移除元素 console.log('--before', ihListCountry, populatingIhListCountry); populatingIhListCountry.splice(j, 1); console.log('--after', ihListCountry, populatingIhListCountry); } // IH日历生成完成 }
问题原因及解决方案
原因
在JavaScript/TypeScript中,数组属于引用类型。你直接用let populatingIhListCountry: socTeam[] = ihListCountry;赋值时,并没有创建新数组,只是让两个变量指向内存中同一个数组对象。因此对populatingIhListCountry执行splice这类修改操作时,原数组ihListCountry会同步变化。
解决方案
需要创建原数组的浅拷贝,让临时数组指向新的内存地址,具体修改如下:
1. 修改初始赋值
将:
let populatingIhListCountry: socTeam[] = ihListCountry;
改为以下任意一种方式:
- 扩展运算符(推荐):
let populatingIhListCountry: socTeam[] = [...ihListCountry]; Array.from():let populatingIhListCountry: socTeam[] = Array.from(ihListCountry);slice():let populatingIhListCountry: socTeam[] = ihListCountry.slice();
2. 修改循环内的 refill 逻辑
循环中重新填充数组时,同样需要使用拷贝:
if (populatingIhListCountry.length == 0) { populatingIhListCountry = [...ihListCountry]; // 用拷贝避免复用原数组引用 }
修改后,临时数组和原数组指向不同的对象,修改临时数组就不会再影响原数组了。
内容的提问来源于stack exchange,提问作者Jilijou
相关产品推荐
相关产品推荐

