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

求助:传入generateBulkInsertQueries函数后rowsx变量为何被覆盖?

问题:传入函数后rowsx变量被覆盖的原因分析

有人能解释一下,当rowsx变量传入generateBulkInsertQueries函数后为何会被覆盖吗?我期望在整个代码执行过程中,rowsx的长度始终为1。

相关代码如下:

//HELPER FUNCTIONS-------------------------------------------
var generateBulkInsertQueries = (
    data,
    dbname,
    tablename,
    colnames,
    batchSize=10
  ) => {
    if ([dbname, tablename].some((element) => element.indexOf('..') > -1))
      throw `generateInsertQueries() expected distinct db (${dbname}) and tables (${tablename})`;
    //if the colnames param is passed use it, otherwise generate colnames form the data
    if (!dbname || dbname.length < 1) throw `generateInsertQueries(): invalid dbname (${dbname})`;
    let cols = colnames ? colnames : Object.keys(data[0]); //transform keys are column names
    //transform values are inserted strings
    let values = [];
    for(let rows of splitArrayIntoChunks(data,batchSize))
    {
      let ss=rows.map(r=>`(${sqlConcatOneLine(r,cols)})`)
      values.push({outdata:`insert into [${dbname}].[dbo].[${tablename}](${cols.map((c) => `[${c}]`).join(',')}) values ${ss.join(',')}`,indata:rows});
    };
    return values
  };
  
  //demo:   let  [list,chunkSize] = [[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], 6];
  var splitArrayIntoChunks=(list,chunkSize)=>{
  list = [...Array(Math.ceil(list.length / chunkSize))].map(_ => list.splice(0,chunkSize))
  //console.log(list);
  return list
  }
  
  var sqlConcatOneLine=(row,cols)=>{
    return cols
          .map((k) => {
            let ret = "''";
            try {
              ret = "'" + row[k].toString().replace(/'/g, '').replace(/\n/g, '').replace(/\r/g, '').toString() + "'";
            } catch (e) {
              // console.log(
              //   `WARN: err inserting value (likely null) generateSQLBulkInsertQuery: ${e}`
              // );
            }
            return ret;
          })
          .join(',')
  }

//EXAMPLE OF ERROR STARTS HERE--------------------------------
(async ()=>{

//init the var
var rowsx = [{ col1: "1", col2: "2" }];
console.log({rowsxlen:rowsx.length,here:1})
var sqliq = generateBulkInsertQueries(rowsx, 'xx', 'yy', ['col1','col2'],1);

console.log({rowsxlen:rowsx.length,here:2})
if(rowsx.length!=1) console.log(`failed. rowsx.length!=1`)
else console.log(`success!!!!`)
})()

原因分析

  • 数组是引用类型:JavaScript中数组属于引用类型,当你把rowsx传入generateBulkInsertQueries函数时,传递的是数组的引用而非副本。函数内部对数组的修改会直接作用于外部的rowsx变量。
  • splice方法直接修改原数组:问题核心在splitArrayIntoChunks函数里的list.splice(0,chunkSize)语句。splice是会直接修改原数组的方法,它会从原数组中删除指定数量的元素并返回这些元素。调用该方法时,传入的rowsx数组会被直接修改,元素被移除后长度变为0。

解决方案

要避免原数组被修改,需在分割前创建原数组的副本,再对副本操作,有两种常见方式:

方式一:复制原数组后使用splice

修改splitArrayIntoChunks函数,先创建数组副本,避免修改原引用:

var splitArrayIntoChunks=(list,chunkSize)=>{
  const arrCopy = [...list]; // 用扩展运算符创建数组副本
  return [...Array(Math.ceil(arrCopy.length / chunkSize))].map(_ => arrCopy.splice(0,chunkSize))
}

方式二:使用slice方法(无原数组修改)

slice方法不会修改原数组,而是返回新子数组,用它分割更安全:

var splitArrayIntoChunks=(list,chunkSize)=>{
  const chunks = [];
  for (let i = 0; i < list.length; i += chunkSize) {
    chunks.push(list.slice(i, i + chunkSize));
  }
  return chunks;
}

修改后,外部的rowsx数组不会被函数内部操作修改,长度将保持为1。

内容的提问来源于stack exchange,提问作者Rilcon42

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 18:51:21