如何动态命名和创建子对象属性?

Posted

技术标签:

【中文标题】如何动态命名和创建子对象属性?【英文标题】:How to dynamically name & create sub-object properties? 【发布时间】:2020-10-24 18:19:15 【问题描述】:

我有一个对象,稍后我将其写入 JSON 进行存储。这个特殊的项目是为我正在制作的 rpg-bot 生成敌人。我有一个关于敌人统计数据的“动物寓言”,我正在尝试生成多个敌人以进入遭遇战。

这是现在的代码 sn-p:

SpawnEncounter(message, [0, 2, 5, 1], characterInfoJSON, userID, ServerPrefix)

function SpawnEncounter(message, EnemiesIndicies, InfoFile, user, ServerPrefix) 
    // bestiary is a json containing monster statistics.  their keys are numbers
    let bestiary = JSON.parse(fs.readFileSync("./bestiary.json", "utf8"));

    let encounterIntro = [];

    InfoFile[user].CurrentEncounter = ;
    InfoFile[user].CurrentEncounter.Target = 0;
    InfoFile[user].CurrentEncounter.Enemies = ;
    
    // EnemiesIndecies is an array of keys, referring to specific monsters in the bestiary
    for (const item in EnemiesIndicies) 
        // Copy the monster stats into one enemy in the encounter
        InfoFile[user].CurrentEncounter.Enemies[item] = bestiary[EnemiesIndicies[item]];

        // Add a Modifiers object to the enemy
        InfoFile[user].CurrentEncounter.Enemies[item].Modifiers = 
            StrMod: 0,
            DefMod: 0,
            AttackSpeedMod: 0,
            ACMod: 0,
            DmgMod: 0,
            CritMod: 0
        
        // push the name of the enemy to the list of all enemies that will spawn
        encounterIntro.push(bestiary[EnemiesIndicies[item]].Name);
    

    // store the encounter once complete
    fs.writeFile("./playerinfo.json", JSON.stringify(InfoFile), (err) => 
        if (err) console.log(err)
    );

    // display the new encounter
    let LastEnemy = encounterIntro.pop()

    if (encounterIntro.length === 0) 
        message.channel.send(`All of a sudden, a $LastEnemy appears!\nTo attack it, use \`\`$ServerPrefixattack\`\``);
    
    else if (encounterIntro.length >= 1) 
        message.channel.send(`All of a sudden, a $encounterIntro.join(", ") and a $LastEnemy appears!\nTo attack it, use \`\`$ServerPrefixattack\`\``);
    

我希望创建的是这样的:


   MyID: 
      CurrentEncounter: 
         Target: 0
         Enemies: 
            0: insert enemy 0's stats + modifiers,
            1: insert enemy 2's stats + modifiers,
            2: insert enemy 5's stats + modifiers,
            3: insert enemy 1's stats + modifiers
         
      
   

我意识到这已经被大大简化了,但我希望它能够理解这一点。

我的问题是,每次我运行这个程序并产生一个遭遇时,它总是说应该出现的敌人都被称为“未定义”。

我在写入 JSON 后检查了它,对象的结构是正确的,直到 Enemies。它显示有一个归于 Enemies 的对象,但它是空的。里面什么都没有。

这告诉我,我在生成敌人或将信息分配给敌人属性的方式上有问题,但我无法确定。更糟糕的是,没有错误消息可以关闭。这一定意味着我的语法是正确的,但它没有提取动物寓言信息,或者它没有正确编写它......

谁能告诉我哪里出了问题,或者更好:提出一个更好的解决方案?

【问题讨论】:

【参考方案1】:
for (const item in EnemiesIndicies) 
    // Copy the monster stats into one enemy in the encounter
    InfoFile[user].CurrentEncounter.Enemies[item] = bestiary[EnemiesIndicies[item]];

    // Add a Modifiers object to the enemy
    InfoFile[user].CurrentEncounter.Enemies[item].Modifiers = 
        StrMod: 0,
        DefMod: 0,
        AttackSpeedMod: 0,
        ACMod: 0,
        DmgMod: 0,
        CritMod: 0
    ;
  
    // push the name of the enemy to the list of all enemies that will spawn
    encounterIntro.push(bestiary[EnemiesIndicies[item]].Name);

您正在使用 For->In 循环...该循环的每次迭代,“item”都是与 EnemiesIndicies 数组不同的值...它不是数组中当前项的索引。当你这样做时:

InfoFile[user].CurrentEncounter.Enemies[item] = bestiary[EnemiesIndicies[item]];

和:

encounterIntro.push(bestiary[EnemiesIndicies[item]].Name);

您正在使用 item 作为 EnemiesIndicies 中的索引...很有可能作为 EnemiesIndicies 中存储的值之一的 item 的值超出了数组的条目数...因此它不是有效索引......即使它是一个有效的索引,它也不是值本身的索引......它所写的唯一方法是:EnemiesIndicies[0] 为 0,EnemiesIndicies[1] 为 1,和 EnemiesIndicies[2] 是 2,等等......

考虑使用标准的 for 循环:

let item = 0;
for (item = 0; item < EnemiesIndicies.length; item++) 
    // Copy the monster stats into one enemy in the encounter
    InfoFile[user].CurrentEncounter.Enemies[item] = bestiary[EnemiesIndicies[item]];
        
    // Add a Modifiers object to the enemy
    InfoFile[user].CurrentEncounter.Enemies[item].Modifiers = 
        StrMod: 0,
        DefMod: 0,
        AttackSpeedMod: 0,
        ACMod: 0,
        DmgMod: 0,
        CritMod: 0
    ;
          
    // push the name of the enemy to the list of all enemies that will spawn
    encounterIntro.push(bestiary[EnemiesIndicies[item]].Name);

这样做... item 始终是 EnemiesIndicies 中值的索引。

【讨论】:

不幸的是,这并没有做到。我复制了你的建议来替换我的 for-in 循环,它仍然说“突然间,出现了一个未定义的内容!” 它仍在应用正确的结构,但它没有向 Enemies 写入任何内容。 在循环中,做一个console.log(item); console.log(EnemiesIndicies[item]); console.log(bestiary[EnemiesIndicies[item]]);看看会返回什么...确保您确实传递了您认为自己的数据... 我刚刚完成了您建议的控制台日志,但没有任何内容打印到控制台...【参考方案2】:

事实证明,在一种情况下,当我调用 SpawnEncounter() 时,我只是将 EnemiesIncdecies 作为一个数字而不是一个数字数组传入(即使数组中只有一个数字)。传入一个数字数组后,问题自行解决,代码现在可以正常工作了。

【讨论】:

讽刺谁会想到两个括号(“[ ]”)会导致长达一个月的问题!

以上是关于如何动态命名和创建子对象属性?的主要内容,如果未能解决你的问题,请参考以下文章

类命名空间与对象实例的命名空间和下面向对象的组合用法

python基础 13 类命名空间于对象实例的命名空间,组合方法

类命名空间与对象实例的命名空间

类命名空间与对象实例的命名空间 and 面向对象的组合用法

类和对象的命名空间

面向对象编程二