简体   繁体   中英

loop inside an array throws Uncaught TypeError: Cannot read property '1' of undefined

I am trying to make this simple loot system to work but I keep getting this TypeError and I have tried everything I could think of.

Everything is explained in the code I added below. It was working yesterday but it seems like today is no longer working...

Here is the code in the JS file:

console.info("Working!");
var items;
//here I get the json
$.getJSON('js/items.json', function(data) {
    return items = data;
});
//run the function cuz laziness to put it every time in the console
loot();

function loot() {
  //these are the drops from the mob
  const ids = [1, 2, 3, 4, 5, 6, 7];
  //define a random number to see what loot it drops
  let rand = Math.floor((Math.random() * 100) + 1);
  var loot;
  //if the chance is between 1 and 5(including them) do that
  if (rand >= 1 && rand <= 5) {
    var legends = [];
    //here I loop inside the ids constant to see what items are legendary and if they are push them to the legends array
    for (var id in ids) {
      //HERE IS THE PROBLEM I get Uncaught TypeError here and I have tried everything
      if (items[ids[id]].rarity == "Legendary") {
        legends.push(ids[id]);
      };
    };
    console.log(`legends: ${legends}`);
    //then I random the items inside legends array to get the loot
    loot = legends[Math.floor(Math.random() * legends.length)];
  };
  console.warn(`You looted a ${items[loot].name} | ${items[loot].rarity}`);
};

and here is the JSON file:

{
  "1": {
    "id": 1,
    "name": "Sword of Heaven",
    "rarity": "Legendary"
  },
  "2": {
    "id": 2,
    "name": "Wooden Sword",
    "rarity": "Common"
  },
  "3": {
    "id": 3,
    "name": "Glass of the Gods",
    "rarity": "Rare"
  },
  "4": {
    "id": 4,
    "name": "Minor HP Potion",
    "rarity": "Common"
  },
  "5": {
    "id": 5,
    "name": "The Enchiridion!",
    "rarity": "Legendary"
  },
  "6": {
    "id": 6,
    "name": "Major MP Potion",
    "rarity": "Rare"
  },
  "7": {
    "id": 7,
    "name": "Helm of the Forsaken",
    "rarity": "Rare"
  }
}

try to move your loot function into asynchronous getJson 's callback:

console.info("Working!");
var items;
//here I get the json
$.getJSON('js/items.json', function(data) {
    items = data;
    //run the function cuz laziness to put it every time in the console
    loot();
});

if you run it outside of this callback, items variable is not populated yet

if you want to use as function, move AJAX call into loot function, store result and make sure to run it only once:

function lootRun(refresh) {
  // use self in order to reach it from anonymous callback
  var self = this; 
  if (!self.items || refresh) {
    $.getJSON('js/items.json', function(data) {
      // kind of inner functional cache
      self.items = data; 
      loot(self.items);
    });
  }
  else {
    loot(self.items);
  }
}

function loot(items) {
  //these are the drops from the mob
  const ids = [1, 2, 3, 4, 5, 6, 7];
  //define a random number to see what loot it drops
  let rand = Math.floor((Math.random() * 100) + 1);
  var loot;
  //if the chance is between 1 and 5(including them) do that
  if (rand >= 1 && rand <= 5) {
    var legends = [];
    //here I loop inside the ids constant to see what items are legendary and if they are push them to the legends array
    ids.forEach(function(id) {
      //HERE IS THE PROBLEM I get Uncaught TypeError here and I have tried everything
      if (items[id].rarity == "Legendary") {
        legends.push(id);
      };
    });

    console.log(`legends: ${legends}`);
    //then I random the items inside legends array to get the loot
    loot = legends[Math.floor(Math.random() * legends.length)];
    console.warn(`You looted a ${items[loot].name} |     ${items[loot].rarity}`);
  };
};

now you can run your main loot function via lootRun , pass true to lootRun , if you want to refresh data from server

A few things to note - getJson is asynchronous, so items may be undefined. Move it into the getJson callback. Also, you're trying to get the name of an item that's undefined. You need to move the last console.log statement into the if statement so that you aren't using loot (which is undefined) to index the array.

var data = {
  "1": {
    "id": 1,
    "name": "Sword of Heaven",
    "rarity": "Legendary"
  },
  "2": {
    "id": 2,
    "name": "Wooden Sword",
    "rarity": "Common"
  },
  "3": {
    "id": 3,
    "name": "Glass of the Gods",
    "rarity": "Rare"
  },
  "4": {
    "id": 4,
    "name": "Minor HP Potion",
    "rarity": "Common"
  },
  "5": {
    "id": 5,
    "name": "The Enchiridion!",
    "rarity": "Legendary"
  },
  "6": {
    "id": 6,
    "name": "Major MP Potion",
    "rarity": "Rare"
  },
  "7": {
    "id": 7,
    "name": "Helm of the Forsaken",
    "rarity": "Rare"
  }
};

// here I get the json
$.getJSON('js/items.json', function(data) {
  loot(data);
});

function loot(items) {
  //these are the drops from the mob
  const ids = [1, 2, 3, 4, 5, 6, 7];
  //define a random number to see what loot it drops
  let rand = Math.floor((Math.random() * 100) + 1);
  var loot;
  //if the chance is between 1 and 5(including them) do that
  if (rand >= 1 && rand <= 5) {
    var legends = [];
    //here I loop inside the ids constant to see what items are legendary and if they are push them to the legends array
    ids.forEach(function(id) {
      //HERE IS THE PROBLEM I get Uncaught TypeError here and I have tried everything
      if (items[id].rarity == "Legendary") {
        legends.push(id);
      };
    });

    console.log(`legends: ${legends}`);
    //then I random the items inside legends array to get the loot
    loot = legends[Math.floor(Math.random() * legends.length)];
    console.warn(`You looted a ${items[loot].name} | ${items[loot].rarity}`);
  };
};

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