使用findIndex时触发TypeError: Cannot read properties of undefined的排查
问题排查:TypeError: Cannot read properties of undefined (reading 'includes')
错误场景
错误触发于以下代码行:
var nameIndex = dataFlatArr.findIndex(s => s.includes(lastName) && s.includes(firstName));
使用Sheets.Spreadsheets.Values.get批量加载数据时出现该错误,但调用普通getValues()时脚本正常运行。脚本预期找到同时包含firstName: 'Steve'和lastName: 'Jobs'的单元格(预期结果为Jobs, Steve Apple,对应列索引1)。
相关代码
主执行脚本
var firstName = 'Steve'; var lastName = 'Jobs'; var dataArr = getValues_({ spreadsheetId: fileID, sheetName: sht.getName(), start: 1, maxRow: lastRow, limit: 100000 }); var columnsArr = [1,2,3,4]; for(var i in columnsArr){ if(foundColTrigger == 'No'){ var dataFlatArr = dataArr.map(r => r[columnsArr[i]-1]); //Logger.log(dataFlatArr); var nameIndex = dataFlatArr.findIndex(s => s.includes(lastName) && s.includes(firstName)); Logger.log(nameIndex); if(nameIndex != -1){ foundColTrigger = 'Yes'; indexColumn = columnsArr[i]-1; var fullDisplayName = dataArr[nameIndex][columnsArr[i]-1]; Logger.log(fullDisplayName) } } }
批量数据加载函数
//getValues in batches of 100K rows function getValues_({ spreadsheetId, sheetName, start = 1, maxRow, limit = 100000 }) { return [...Array(Math.ceil(maxRow / limit))].flatMap((_) => { const last = start - 1 + limit; const range = `'${sheetName}'!A${start}:${last > maxRow ? maxRow : last}`; const temp = Sheets.Spreadsheets.Values.get(spreadsheetId, range).values; start += limit; return temp; }); }
表格数据示例
| Participants A | Participants B | Participants C | Participants D |
|---|---|---|---|
| Jackson, Michael | Wozniak, Steve | James, Lebron | Bonds, Barry |
| Blige, Mary J | Gates, Bill | Jordan, Michael J | McGwire, Mark |
| Carey, Mariah | Cook, Tim | Curry, Stephen | Sosa, Sammy |
| Jackson, Janet | Jobs, Mark | Durant, Kevin | Judge, Aaron |
| Houston, Whitney | Jobs, Steve Apple | Abdul-Jabbar, Kareem | Maris, Roger |
| Mercury, Freddie | Musk, Elon | Russell, Bill | Ruth, Babe |
问题原因
Sheets.Spreadsheets.Values.get返回的values数组与普通getValues()存在核心差异:当表格中存在空单元格时,API会直接跳过该单元格,不会在数组中生成对应元素;而getValues()会用空字符串""填充所有空单元格位置,保证每行数组长度一致。
这种差异导致当你通过r[columnsArr[i]-1]提取列值时,若对应位置的单元格为空,会得到undefined,调用includes()方法自然触发TypeError。
解决方案
- 方案1:修复批量加载函数,补全空单元格
修改getValues_函数,确保每行数组长度与表格列数一致,用空字符串填充缺失的单元格:
//getValues in batches of 100K rows, 补全空单元格 function getValues_({ spreadsheetId, sheetName, start = 1, maxRow, limit = 100000 }) { // 获取表格总列数,确保每行长度统一 const sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName); const columnCount = sheet.getLastColumn(); return [...Array(Math.ceil(maxRow / limit))].flatMap((_) => { const last = start - 1 + limit; const range = `'${sheetName}'!A${start}:${last > maxRow ? maxRow : last}`; const temp = Sheets.Spreadsheets.Values.get(spreadsheetId, range).values || []; // 补全每行的空单元格 const filledRows = temp.map(row => { while(row.length < columnCount) { row.push(""); } return row; }); start += limit; return filledRows; }); }
处理后dataArr结构与getValues()返回结果一致,不会出现undefined,后续includes()调用可正常执行。
- 方案2:在查找逻辑中增加空值判断
若不想修改加载函数,可在findIndex的回调中先判断目标值是否存在:
var nameIndex = dataFlatArr.findIndex(s => s && s.includes(lastName) && s.includes(firstName));
该方案更轻量,当单元格为空时会自动跳过,避免触发错误。
- 速度优化建议
- 方案1中获取列数的操作仅执行一次,不会影响批量加载的速度优势。
- 若表格列数固定(如示例中的4列),可直接将
columnCount设为固定值,省去调用getLastColumn()的开销。
内容的提问来源于stack exchange,提问作者DanCue
相关产品推荐
相关产品推荐

