如何修复JS中Cannot read properties of undefined (reading '0')错误
Discord.js /script命令选择菜单 TypeError 错误修复
错误信息
TypeError: Cannot read properties of undefined (reading '0')
问题场景
开发Discord机器人的/script命令时,调用API测试触发上述错误。代码尝试通过const value = interaction.values[0];获取选择菜单的值,但用户选择选项后无法发送对应数据。
核心问题分析
- 错误根源:初始的Slash Command交互对象中不存在
values属性,该属性仅在用户触发选择菜单点击事件时才会生成。代码在发送选择菜单后立即读取interaction.values,必然抛出undefined错误。 - 重复回复冲突:即便获取到值,重复调用
interaction.reply()会报错,因为同一交互只能回复一次,后续操作需使用update()或followUp()。 - SQL注入风险:直接将用户ID拼接进SQL语句,存在注入漏洞。
- 异步回调混乱:使用回调方式处理SQL查询,导致代码嵌套复杂且无法正确捕获异步错误。
修复后的完整代码
const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder } = require('discord.js'); function makeid(length) { var result = ''; var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; var charactersLength = characters.length; for (var i = 0; i < length; i++) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); } return result; } module.exports = { data: new SlashCommandBuilder() .setName('script') .setDescription('รับสคริป'), execute: async (interaction, con, log, client, config) => { log(`[LOG Command] ${interaction.user.username}, use command getscript`, "green"); const menu = new ActionRowBuilder().addComponents( new StringSelectMenuBuilder() .setCustomId("SCRIPT_SELECT") .addOptions( { label: "BloxFruit", description: "script BloxFruit ", value: "BF", emoji: "🍎" }, { label: "City Thiland", description: "script City Thiland 2", value: "CTTH", emoji: "🏙" } ) ); try { // 参数化查询防SQL注入 const [results] = await con.promise().query( `SELECT userkey, discord_id, Blacklisted FROM bloxfruit WHERE discord_id = ?`, [interaction.user.id] ); if (!results[0]) { await interaction.reply({ embeds: [ new EmbedBuilder() .setColor("#FF0000") .setTitle('**"WET HUB" | ᴡʜɪᴛᴇʟɪsᴛ ᴍᴀɴᴀɢᴇʀ**') .setDescription("คุณไม่มีไวริสนะคะ กรุณาก่อนใช้ด้วยค่ะ") .setTimestamp() ], ephemeral: true }); return; } if (results[0].Blacklisted === "True") { await interaction.reply({ embeds: [ new EmbedBuilder() .setColor("#FF0000") .setTitle('**WET HUB | ᴡʜɪᴛᴇʟɪsᴛ ᴍᴀɴᴀɢᴇʀ**') .setDescription("คุณอยู่ในบัญชีดำนะคะ") .setTimestamp() ], ephemeral: true }); return; } const key = results[0].userkey; const discord_id = results[0].discord_id; // 发送选择菜单 await interaction.reply({ content: "请选择你需要的脚本:", ephemeral: true, components: [menu] }); // 监听选择菜单交互,仅响应命令发起者 const filter = i => i.customId === 'SCRIPT_SELECT' && i.user.id === interaction.user.id; const collector = interaction.channel.createMessageComponentCollector({ filter, time: 60000 }); collector.on('collect', async i => { const value = i.values[0]; let embed; switch (value) { case "BF": case "CTTH": embed = new EmbedBuilder() .setColor("00FF46") .setTitle('**WET HUB | ᴡʜɪᴛᴇʟɪsᴛ ᴍᴀɴᴀɢᴇʀ**') .setDescription(`\`\`\`lua getgenv().Key = "${key}" getgenv().DiscordId = "${discord_id}" loadstring(game:HttpGet("https://raw.githubusercontent.com/Galiverking/CheckPointWT/main/check-lua.lua"))() \`\`\``) .setTimestamp(); break; default: embed = new EmbedBuilder() .setColor("#FF0000") .setTitle('错误') .setDescription("无效的选择"); } // 更新原消息,替换为脚本内容并移除菜单 await i.update({ content: "", embeds: [embed], components: [] }); collector.stop(); }); // 超时处理 collector.on('end', collected => { if (collected.size === 0) { interaction.editReply({ content: "选择超时,请重新执行命令。", components: [] }).catch(console.error); } }); } catch (err) { console.error("数据库查询错误:", err); await interaction.reply({ content: "执行命令时发生错误,请稍后重试。", ephemeral: true }); } } };
关键修复说明
- 交互监听逻辑:使用
MessageComponentCollector监听用户的选择菜单点击事件,仅在用户触发交互时读取i.values[0],彻底解决undefined错误。 - SQL注入防护:采用参数化查询方式,避免直接拼接用户输入,杜绝SQL注入风险。
- 异步处理优化:将SQL查询改为Promise化调用,配合try/catch捕获异常,代码结构更清晰且错误处理更完善。
- 消息操作修正:使用
i.update()更新原消息,避免重复回复的冲突问题。 - 超时与权限控制:添加60秒交互超时,同时限制仅命令发起者可操作选择菜单,提升安全性。
- 代码清理:移除未使用的变量和导入,修正选择菜单CustomId的拼写错误。
内容的提问来源于stack exchange,提问作者GaliverKing
相关产品推荐
相关产品推荐

