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

Discord.js读取undefined的name属性触发TypeError报错排查

报错根因

触发TypeError: Cannot read properties of undefined (reading 'name')是因为代码中用于定位Scammere数组元素的index变量值越界,访问jsonData.Scammere[index]时返回了undefined,再读取name属性就会抛出该错误,具体逻辑漏洞如下:

  • 查找玩家索引的for循环逻辑错误:遍历过程中只要当前元素和目标玩家名不匹配,就会把index覆盖为jsonData.Scammere.length + 1,哪怕之前已经匹配到正确索引,也会被后续遍历的非匹配项覆盖;而JS数组索引从0开始计数,数组长度+1必然是超出数组范围的无效索引。
  • 新增玩家条目后未更新index值:当判定为新玩家执行push操作后,没有将index设置为新元素对应的索引,后续读取元素时会定位到错误位置。
  • 持久化逻辑存在缺陷:用require()加载JSON文件时Node.js会缓存模块,对jsonData的修改不会自动写入本地test.json,进程重启后数据会丢失;同时node-localstorage的键名拼接多了空格、未处理空值转NaN的问题,会导致计数逻辑异常。
修复步骤
  1. 移除重复的遍历逻辑,直接用数组原生findIndex方法一次性获取目标玩家索引,避免手动写循环出现变量覆盖问题,未找到匹配项时findIndex会返回-1,可直接用来判断是否为新玩家。
  2. 新玩家条目push进数组后,手动将index设置为新元素的索引(即数组长度-1)。
  3. 改用fs模块读写JSON文件,替换原有require加载JSON的方式,保证数据修改能持久化到本地。
  4. 修正localStorage键名拼接逻辑,增加空值判断,避免出现NaN的计数错误。
  5. 提前把当前操作的玩家对象存为单独变量,避免重复写jsonData.Scammere[index]的冗余代码,也减少索引写错的概率。
修复后完整代码
const fs = require('fs');
const path = require('path');
const { LocalStorage } = require('node-localstorage');
const localStorage = new LocalStorage('./scratch');

// 读写Scammer数据的工具函数
function getScammerData() {
  const file = path.join(__dirname, 'test.json');
  return JSON.parse(fs.readFileSync(file, 'utf8'));
}
function saveScammerData(data) {
  const file = path.join(__dirname, 'test.json');
  fs.writeFileSync(file, JSON.stringify(data, null, 2), 'utf8');
}

module.exports = {
  name: 'addscammer',
  description: '添加诈骗者记录指令',
  execute(message, args, Discord) {
    if (!args[0]) return message.reply('Du skal skrive personens ingame navn');
    const inputName = args[0].toString();
    const targetName = inputName.toUpperCase();

    // 权限校验
    const hasPerm = message.member.roles.cache.has('850790004275019796') || message.member.roles.cache.has('850790306915942400');
    if (!hasPerm) return message.reply('你没有使用该指令的权限');

    const scammerData = getScammerData();
    // 直接查找目标索引
    const targetIndex = scammerData.Scammere.findIndex(item => item.name.toUpperCase() === targetName);
    const isNewPlayer = targetIndex === -1;
    let operateIndex = targetIndex;

    if (isNewPlayer) {
      // 新增条目
      scammerData.Scammere.push({
        name: inputName,
        timesScamed: 1,
        timesTrusted: 0
      });
      // 新元素索引为数组长度减1
      operateIndex = scammerData.Scammere.length - 1;
    } else {
      // 更新已有条目计数
      const storeKey = `storedScams_${scammerData.Scammere[operateIndex].name}`;
      const storedVal = localStorage.getItem(storeKey);
      const baseCount = storedVal ? parseInt(storedVal) : scammerData.Scammere[operateIndex].timesScamed;
      scammerData.Scammere[operateIndex].timesScamed = baseCount + 1;
      localStorage.setItem(storeKey, scammerData.Scammere[operateIndex].timesScamed.toString());
    }

    // 持久化到JSON文件
    saveScammerData(scammerData);
    const currentPlayer = scammerData.Scammere[operateIndex];

    setTimeout(() => {
      let hexColor = '#000';
      let status = 'scammer';

      if (!isNewPlayer) {
        if (currentPlayer.timesScamed > currentPlayer.timesTrusted) {
          hexColor = '#ff0000';
          status = 'Scammer';
        } else {
          hexColor = '#43eb34';
          status = 'Trusted';
        }
      } else {
        hexColor = '#c4c4c4';
        status = 'Måske';
      }

      const embed = new Discord.MessageEmbed()
        .setColor(hexColor)
        .setTitle(`Data om: ${currentPlayer.name}`)
        .setAuthor({
          name: currentPlayer.name,
          iconURL: `https://minotar.net/avatar/${currentPlayer.name}/128.png`,
          url: 'https://discord.js.org'
        })
        .setThumbnail(`https://mc-heads.net/body/${currentPlayer.name}/128.png`)
        .addFields(
          { name: 'Status', value: status },
          { name: 'Scammet', value: currentPlayer.timesScamed.toString() },
          { name: 'Trusted', value: currentPlayer.timesTrusted.toString() }
        );

      message.channel.send({ embeds: [embed] });
    }, 500);
  }
}
注意事项
  • 原有JSON文件的字段名是Scammere,后续读写时注意拼写一致,不要漏写末尾的e。
  • 数组访问前建议增加非空判断,比如if(!currentPlayer) return message.reply('数据读取异常'),可以避免后续迭代时再出现同类undefined报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 20:06:24