如何正确访问嵌套 JSON 数据中的数组元素

10次阅读

如何正确访问嵌套 JSON 数据中的数组元素

本文详解因异步读取文件导致变量未定义,以及 json 结构含数组层级时误用点/方括号访问引发的 “cannot read properties of undefined” 错误,并提供完整、健壮的解决方案。

你遇到的错误 TypeError: Cannot read properties of undefined (reading ‘scrams’) 根源有两个关键问题:异步执行时机错误jsON 数据结构理解偏差

首先,fs.readFile() 是异步操作,其回调函数在文件读取完成之后才执行。而你在回调外部立即使用 datascrams[…][‘scrams’],此时 datascrams 仍为初始空对象 {},尚未被赋值,因此 datascrams[interaction.options.getString(‘cube’)] 返回 undefined,后续再访问 .scrams 必然报错。

其次,你的 json 结构中 “3×3” 对应的是一个数组(而非对象),其中每个元素才是包含 “scrams” 字段的对象:

{   "3x3": [     { "scrams": "R U R' U' ..." }   ] }

因此,正确路径是:data[“3×3”][0][“scrams”],而非 data[“3×3”][“scrams”] —— 缺少数组索引 [0] 会导致第二层访问失败。

✅ 正确做法是:

  1. 将逻辑完全移入 readFile 回调内(或改用 fs.promises.readFile + async/await);
  2. 解析 JSON 字符串(JSON.parse());
  3. 安全校验数据存在性(避免硬编码 [0] 导致新错误);
  4. 添加错误处理,提升鲁棒性。

以下是推荐的现代写法(使用 async/await + try/catch):

if (interaction.commandName === 'comp-scrambles') {   try {     const rawData = await fs.promises.readFile('scrambles.json', 'utf8');     const data = JSON.parse(rawData);      const cubeType = interaction.options.getString('cube');     const cubeData = data[cubeType];      if (!Array.isArray(cubeData) || cubeData.length === 0) {       return interaction.reply({ content: `❌ 未找到有效的 ${cubeType} 魔方打乱数据。`, ephemeral: true });     }      // 安全取第一个打乱(可按需扩展为随机选取)     const scram = cubeData[0].scrams;      if (typeof scram !== 'string') {       return interaction.reply({ content: `❌ 打乱数据格式异常,请检查 scrambles.json。`, ephemeral: true });     }      await interaction.reply(scram);   } catch (err) {     console.error('读取或解析 scrambles.json 失败:', err);     interaction.reply({ content: '⚠️ 服务器内部错误,请稍后重试。', ephemeral: true });   } }

? 注意事项:

  • ❌ 不要重复声明 let datascrams = {} 后又在回调里 let datascrams = rawData —— 这会创建新局部变量,无法影响外层作用域
  • ✅ 始终对 JSON.parse() 的结果做类型校验(如 Array.isArray()、?.scrams 可选链或显式 if 判断);
  • ✅ 生产环境建议将 JSON 加载逻辑抽离为独立工具函数,并配合缓存(如首次读取后存入内存),避免高频磁盘 I/O。

通过同步控制流与结构化数据验证,即可彻底规避 undefined 访问错误,让机器人稳定可靠地返回打乱序列。

text=ZqhQzanResources