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

Discord.js挖矿Bot开发:数组push元素无效返回undefined问题

Discord机器人挖矿掉落功能异常排查

问题现象

开发支持资源挖矿玩法的Discord机器人时遇到逻辑异常:控制台可正常打印掉落的物品对象,但物品无法被推入droppedItems数组,最终无法将数组映射为字符串输出。

  • 预期结果:返回由掉落物品对象组成的数组,每个对象包含name、amount、category三个属性
  • 实际结果:函数最终返回undefined
  • 已尝试无效方案:给push操作加await、将数组声明为常量等微调操作
  • 初始疑问:是否是数组定义在循环外部导致异常

问题代码

module.exports.addItem = async (client, user, item, amount, interaction) => {
    if(!client instanceof Client) throw new Error("Client is not an instance of Discord.js Client");
    if(!user instanceof User) throw new Error("User is not an instance of Discord.js User");
    if(!item) throw new Error("Item is not defined");
    if(!amount) throw new Error("Amount is not defined");
    if(typeof amount !== "number") throw new Error("Amount is not a number");
    if(!interaction) throw new Error("Interaction is not defined");
    if(!interaction instanceof Interaction) throw new Error("Interaction is not an instance of Discord.js Interaction");

    const userFound = await client.database.user.findOne({ userID: user.id });
    if(!userFound) return interaction.followUp({ content: `You haven't started your journey yet!` });

    const itemFound = userFound.inventory.find(i => i.name === item.name);
        if(!itemFound) {
            await client.database.user.findOneAndUpdate(
                {
                    userID: user.id,
                }, {
                    userID: user.id,
                    $push: {
                        inventory: {
                            name: item.name,
                            amount,
                            category: item.category
                        }
                    }
                } , {
                    upsert: true,
            });
        } else {
            await client.database.user.findOneAndUpdate(
                {
                    userID: user.id,
                }, {
                    userID: user.id,
                    $pull: {
                        inventory: {
                            name: item.name
                        }
                    } 
                } , {
                    upsert: true,
            });
                
            await client.database.user.findOneAndUpdate(
                {
                    userID: user.id,
                }, {
                    userID: user.id,
                    $push: {
                       inventory: {
                            name: item.name,
                            amount: item.amount + amount,
                            category: item.category
                        }
                    }
                } , {
            upsert: true,
        });
    }
    return { name: item.name, amount, category: item.category };
}

module.exports.dropItem = async (client, user, category, interaction) => {
    if(!client instanceof Client) throw new Error("Client is not an instance of Discord.js Client");
    if(!user instanceof User) throw new Error("User is not an instance of Discord.js User");
    if(!category) throw new Error("Category is not defined");
    if(typeof category !== "string") throw new Error("Category is not a string");

    let droppedItems = [];
    
    for (const item of client.items) {
        for(let i = 0; i < client.items.length; i++) {
            if(!client.items[i].category === category) return;
        }

        const dropAmount = Math.floor((Math.random() * 3) + 1);
        const dropChance = Math.floor(Math.random() * 100);
        if(dropChance > item.dropChance) return;

        const itemDropped = await this.addItem(client, user, item, dropAmount, interaction)
        console.log(itemDropped); // This logs the item correctly

        droppedItems.push(itemDropped);
    }

    return droppedItems; // This always returns "undefined"
}

问题根因

和数组定义位置无关,是代码里的逻辑错误导致函数提前终止、调用失效,具体问题如下:

  1. 提前return终止整个函数:两处错误的return是返回undefined的核心原因
    • 内层多余的for循环中,只要遍历到任意一个物品分类和目标分类不符,就直接执行return终止整个dropItem函数,根本走不到后续返回数组的逻辑
    • 掉落概率判断处,只要当前物品概率判定未掉落,就直接return终止函数,应该用continue跳过当前物品的循环,而不是退出整个函数
  2. 类型校验写法失效:所有!xxx instanceof Class的写法存在运算符优先级错误,!优先级高于instanceof,实际执行逻辑是(!xxx) instanceof Class,永远返回false,所有参数校验完全不生效
  3. 方法调用指向错误:CommonJS模块下直接用this.addItem调用会出现指向问题,this不指向当前导出对象,会导致addItem调用失败
  4. 物品数量计算错误:更新已有物品库存时,错误使用了基础配置物品的item.amount(基础物品配置不存在该字段,值为undefined),应该用查询到的用户库存中对应物品的itemFound.amount + 新增数量计算
  5. 冗余循环逻辑:外层已经在遍历所有物品,内层再写一层for循环遍历所有物品检查分类完全多余,直接判断当前遍历到的item.category是否匹配目标分类即可

修复后核心逻辑参考

// 先单独定义方法,避免this指向问题
const addItem = async (client, user, item, amount, interaction) => {
    // 修复instanceof校验写法,加括号改变优先级
    if(!(client instanceof Client)) throw new Error("Client is not an instance of Discord.js Client");
    if(!(user instanceof User)) throw new Error("User is not an instance of Discord.js User");
    if(!item) throw new Error("Item is not defined");
    if(!amount) throw new Error("Amount is not defined");
    if(typeof amount !== "number") throw new Error("Amount is not a number");
    if(!interaction) throw new Error("Interaction is not defined");
    if(!(interaction instanceof Interaction)) throw new Error("Interaction is not an instance of Discord.js Interaction");

    const userFound = await client.database.user.findOne({ userID: user.id });
    if(!userFound) return interaction.followUp({ content: `You haven't started your journey yet!` });

    const itemFound = userFound.inventory.find(i => i.name === item.name);
        if(!itemFound) {
            await client.database.user.findOneAndUpdate(
                { userID: user.id },
                {
                    $push: {
                        inventory: { name: item.name, amount, category: item.category }
                    }
                },
                { upsert: true }
            );
        } else {
            await client.database.user.findOneAndUpdate(
                { userID: user.id },
                { $pull: { inventory: { name: item.name } } },
                { upsert: true }
            );
                
            await client.database.user.findOneAndUpdate(
                { userID: user.id },
                {
                    $push: {
                       inventory: {
                            name: item.name,
                            amount: itemFound.amount + amount, // 修复数量取值
                            category: item.category
                        }
                    }
                },
                { upsert: true }
            );
    }
    return { name: item.name, amount, category: item.category };
}

const dropItem = async (client, user, category, interaction) => {
    // 修复instanceof校验
    if(!(client instanceof Client)) throw new Error("Client is not an instance of Discord.js Client");
    if(!(user instanceof User)) throw new Error("User is not an instance of Discord.js User");
    if(!category) throw new Error("Category is not defined");
    if(typeof category !== "string") throw new Error("Category is not a string");

    const droppedItems = [];
    
    for (const item of client.items) {
        // 删除冗余内层循环,直接判断当前物品分类,不匹配就跳过当前循环
        if(item.category !== category) continue;

        const dropAmount = Math.floor((Math.random() * 3) + 1);
        const dropChance = Math.floor(Math.random() * 100);
        // 未掉落就跳过当前物品,不要return退出整个函数
        if(dropChance > item.dropChance) continue;

        // 直接调用定义好的addItem,不用this
        const itemDropped = await addItem(client, user, item, dropAmount, interaction)
        console.log(itemDropped);
        droppedItems.push(itemDropped);
    }

    return droppedItems;
}

// 最后统一导出
module.exports = { addItem, dropItem }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 13:39:19