简体   繁体   中英

Javascript loop works the first time ran, but gives NaN the second time without logic

I'm developing a javascript game and am altering values from a JSON file through a loop. The loop however occasionally replaces the values it should alter with "NaN" and grabs a random letter from the prefix word of the array. I tried debugging the values and putting in fixed creature values, but that has made me none the wiser.

The code works THE FIRST TIME RAN in JSFiddle: https://jsfiddle.net/ezwad5mL/2/ but whenever you run it a second time, it overwrites the values in the loop with NaN and the letter. I think it's because the function random_int needs 2 values but it only inputs 1 the second time you run it, which is somehow the same value from the previous input (which it altered in the second For loop). What I don't understand is how this code doesn't reset the storedDungeon if it fires the second time.

I understand the problem I think, but I have no clue what's wrong with what I wrote and why it does okay the first time, but screws up the second time.

function random_item(items){
  return items[Math.floor(Math.random()*items.length)];
}

function random_int(min, max) {
 return Math.floor(Math.random() * (max - min)) + min;
}

var storedDungeon = []

const jsonCreatures = {
   "easy":  [
     { "name": "Scorchbird", "hp": [6,13], "prefix": ["Weak", "Small", "Young", "Wild"], 
       "damage": [1,5], "droprateCommon": [0,60], "droprateRare": [70, 90]},
     { "name": "Reanimated Corpse", "hp": [8,15], "prefix": ["Weak", "Festering"], "damage": 
       [3,5], "droprateCommon": [0,40], "droprateRare": [50, 80]}
]}

var randNumber = 2

for (let i = 0; i < randNumber; i++) {
  let randomObject = random_item(jsonCreatures.easy)
  storedDungeon.push(randomObject)
}

for (let o = 0; o < storedDungeon.length; o++) {
  storedDungeon[o].hp = random_int(storedDungeon[o].hp[0], storedDungeon[o].hp[1])
  storedDungeon[o].damage = random_int(storedDungeon[o].damage[0],storedDungeon[o].damage[1])
  storedDungeon[o].prefix = random_item(storedDungeon[o].prefix)
 }

console.log(storedDungeon)

To understand the problem we need to understand how arrays work. The following example may open your eyes to the problem.

const creatures = [
  {
    name: 'Scorchbird'
  }
]

const dungeon = []
dungeon.push(creatures[0])
dungeon[0].name = 'Reference to the object!'

console.log(creatures)
// [
//   {
//     name: 'Reference to the object!'
//   }
// ]

When we add a creature (object) to our dungeon array

dungeon.push(creatures[0])

we actually add a reference to the original object, not a copy of it.

This means that when you do

storedDungeon[o].hp = random_int(
    storedDungeon[o].hp[0],
    storedDungeon[o].hp[1]
  )

you alter the original creatures objects and their properties.

In this case the array hp: [6, 13] is replaced with a random (single!) number, for example hp: 8 And when your code runs the second time there is now hp array to do hp[0] and hp[1] , just a single number. This is why the function random_int returns NaN (not a number).

The same effect happens with the damage and with the prefix. However because prefix is a string the random_item function will return a random character in this string. That's because the characters of a string can be accessed by their index like in an array: "im a string"[1] = "m"

I think Nico Gräf's explanation is correct. To fix this, you can create a clone of the object and have it pushed to the storedDungeon .

storedDungeon.push({...randomObject})

Please note that spread syntax doesn't deep clone your object. So it only works to the first level of the object, which should be fine with your current design.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM