You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 07:15:00