JS数组循环赋值触发cannot set property of undefined错误
尝试将axios响应返回的CSV格式列表数据存入对象:第一行作为表头存入cols数组,其余数据存入rows数组。接收到的原始数据字段均已定义,解析后控制台打印内容完全正常。循环加载rows元素时,第一组元素可正常存储,但循环变量i=2时触发报错:cannot set property of undefined (setting 0)。
为方便复现问题,以下使用修改后的模拟数据替代真实axios返回内容
let response = {data:'"A","B"\n"C","D"\n"E","F"'} // 实际为await axios(URL)的返回值 let raw = response.data.split(/\r?\n/); let data = { cols:[], rows:[] // 已尝试过rows:[[]]、rows:[{v:[]}]等声明方式 } for (let i in raw) { raw[i] = raw[i].split(","); for(let j in raw[i]){ raw[i][j] = raw[i][j].replace(/"/g, '') if (i==0) data.cols[j]=raw[i][j] else{ data.rows[i-1][j]=raw[i][j] // 如果rows存对象则写为data.rows[i-1].v[j] //console.log(i+'->'+data.rows[i-1]) } } } return data
已做过的排查尝试:
- 已尝试将
rows声明为二维数组,错误未解决 - IDE鼠标悬停查看对象属性时提示
rows (property) : never[],cols属性存在相同的类型提示
报错核心是你从未给data.rows的对应索引位置初始化过数组/对象。
声明rows: []时,它只是长度为0的空数组,data.rows[0]、data.rows[1]这些位置本身是undefined,直接给undefined的属性赋值就会触发该报错。之前尝试的rows:[[]]只初始化了第0位的数组,循环到i=2时要访问data.rows[1],这个位置仍是undefined,所以依然会报错。
IDE提示never[]是因为TS类型推断时发现初始化的是空数组,没有指定内部元素类型,会默认推断为永远不会有元素的never[]类型。
在给data.rows[i-1]的索引赋值前,先判断对应位置是否存在,不存在就先初始化空数组,TS环境下可以给数组明确类型避免推断错误:
// TS环境保留类型声明,纯JS环境可去掉类型定义 let data: {cols: string[], rows: string[][]} = { cols:[], rows:[] } for (let i in raw) { raw[i] = raw[i].split(","); // 非表头行先初始化rows对应位置的数组 if (i !== '0') { data.rows[Number(i)-1] = [] } for(let j in raw[i]){ raw[i][j] = raw[i][j].replace(/"/g, '') if (i==0) { data.cols[j]=raw[i][j] } else { data.rows[Number(i)-1][j]=raw[i][j] } } }
如果需要rows存储带v字段的对象,把初始化逻辑改成data.rows[Number(i)-1] = {v: []},赋值时对应写data.rows[Number(i)-1].v[j] = raw[i][j]即可。
注意:
for...in遍历拿到的索引是字符串类型,做数值计算时最好显式转成Number,避免隐式类型转换带来的意外问题。
内容的提问来源于stack exchange,提问作者Mohammed Tausif Raza Khan

