0

I have a simple object of objects:

window.abilities = {
            migrate:{
                name:"Migrate",
                description:"Move your tribe to another area; generate all new resources. Takes one time unit.",
                image:"migrate.png",
                action:"Migrate",
                unlocked:true
            },
            eradicate:{
                name:"Eradicate species",
                description:"Remove a troublesome plant or animal",
                image:"migrate.png",
                action:"Eradicate",
                unlocked:false
            }
        }

I am using a for ... in ... loop to iterate over this object and generate UI elements:

for(ability in window.abilities){
    if(ability.unlocked){
        $("#abilities").append(genAbilityCard(ability.name,ability.image,ability.description,ability.action));
    }
}

However, each ability variable is empty - it only has the key and not the properties (name, description, and so forth). These properties seem to be unenumerable - even though properties created this way should be enumerable by default!

How can I make these properties enumerable implicitly, without using Object.defineProperty or something unwieldy like that?

SPavel
  • 131
  • 5
  • 1
    Possible duplicate of [How do I loop through or enumerate a JavaScript object?](https://stackoverflow.com/questions/684672/how-do-i-loop-through-or-enumerate-a-javascript-object). This is an old and well answered question, the loop only gets you the keys. – Robert Moskal Jul 02 '17 at 16:01

2 Answers2

2

If you're able to use ES6 and the for... of loop, Alberto's answer is your best bet, and the cleanest option.

If you're limited to ES5, you can use for ... in as well. As you've found, for ... in only enumerates the keys (the property names), not the property values, but it's easy to get the property value once you know the property name:

var abilityName, ability;

for(abilityName in window.abilities){
    ability = window.abilities[abilityName];
    if(ability.unlocked){
        $("#abilities").append(genAbilityCard(ability.name,ability.image,ability.description,ability.action));
    }
}

The fact you're getting the property names means you ARE successfully enumerating the properties. Javascript is just a bit weird in how for ... in works.

PMV
  • 2,058
  • 1
  • 10
  • 15
  • I don't know what would limit me to ES5; Alberto's code worked, but thank you for going into more detail! – SPavel Jul 02 '17 at 16:14
  • @SPavel It really depends on your target platform / target browsers. IE11, for example, doesn't support most features of ES6 including `for... of`. For more details on what is supported in which environments, you can check https://kangax.github.io/compat-table/es6/ . – PMV Jul 02 '17 at 20:09
1

Try iterating by using for..of and Object.values (ES6 only):

for (const ability of Object.values(window.abilities)){
    if (ability.unlocked){
        $("#abilities").append(genAbilityCard(ability.name,ability.image,ability.description,ability.action));
    }
}
Alberto Trindade Tavares
  • 10,056
  • 5
  • 38
  • 46
  • Worked great, thanks! I couldn't get anything in the allegedly existing answer to work, but this solved it. – SPavel Jul 02 '17 at 16:13
  • Glad to help! The only caveat about that solution is that it is limited to >= ES6. If you need to work on < ES5 (no babel available, old browser, etc.), take a look at @PMV's answer – Alberto Trindade Tavares Jul 02 '17 at 16:14