Why can't I use crewMember.name?

Yes, also called String Interpolation :wink:

This reply helped in clarifying alot. Thank you very much.

Is there ever a case where you don’t know how the key value will be formatted?

In this case, we know that one of the crewMember keys is formatted as a string with a space. That requires [crewMember] instead of .crewMember.

However, what if we didn’t know how the object would be formatted? Or, if it was so large that it wasn’t feasible to check every result? Or is this simply not the case? Is there some sort of logic you would add in to check the type of each first?

Hopefully this makes sense. Thanks in advance!

the dot notation can only be used if the developer uses the property name, so if we have a variable (with a loop, parameter, or whatever other cause) you have to use square brackets (associative array notation)

1 Like

So while I’m inclined to agree that the for...in syntax is a bit clunky, I think one thing to realize about your PowerShell example is you aren’t iterating the properties of an object, you’re iterating through a list of drive objects returned by Get-Volume, so it’s not exactly apples to apples.

JS also has a for-each like syntax for iterating arrays: for...of. So to really compare apples to apples, here’s a contrived JS example of doing what you are talking about:

const drives = [
   {
     "name": "c",
     "size": "200GB"
   },
   { 
     "name": "d",
     "size": "1000GB"
   }
];
for(let drive of drives){
  console.log(`${drive.name}: ${drive.size}`);
}

In fact, if you actually wanted iterate through the properties of each drive it gets a little weird in Powershell. You can’t do foreach($prop in $drive), you have to do foreach($prop in $drive.PSObject.Properties) to get the desired behavior.

Python has a similar quirk - to iterate an object like that and get both the keys and values, you have to do for key, val in obj.items(), simply typing for item in obj will only give you the keys, much like JS.

If you really want to iterate through object and get both the key and the value, there is some functionality introduced in ES6:

Object.keys(obj) => gives you an iterable of all the keys
Object.values(obj) => gives you an iterable of all the values
Object.entries(obj) => this is the magic one - gives you an iterable of the form [key, val] for each property in the object.

In fact, these methods IMO make the for..in loop essentially obsolete :

// print all keys with for..in loop:
for(let key in obj) {
  console.log(key);
}
// print all keys with keys iterable
Object.keys(obj).forEach(key => console.log(key));

Now here’s where this gets useful - I personally much prefer the ES6 syntax versions below:

// Exercise version
for(let member in spaceship.crew){
  console.log(`${member}: ${spaceship.crew[member].name}`);
}

// ES6 version 
// Note the destructuring / array unpacking in the callback parameter, 
//   this can be tricky!!!
Object.entries(spaceship.crew).forEach(([role, member]) => {
   console.log(`${role}: ${member.name}`);
});

// Exercise solution
for(let member in spaceship.crew){
  console.log(`${spaceship.crew[member].name}: ${spaceship.crew[member].degree}`);
}

// Alternative w/ ES6 synatx - note we only need *values* here!
Object.values(spaceship.crew).forEach(member => {
   console.log(`${member.name}: ${member.degree}`);
});

crewMate.name would work the way you’re thinking if crewMate represented the individual nested objects (like captain: { name: ‘Lily’, degree: ‘Computer Engineering’ } but it’s just the string key (like ‘captain’)

crewMate is a different string each time the for…in loop runs. It starts as ‘captain’, then is ‘chief officer’, ‘medic’, etc. If you use .name on any string, it will return undefined.

That’s why you have to do spaceship.crew[crewMate].name to get the name of each crewMate. It’s using the crewMate string as a way to access the name in each nested object. Ex - the first time the for…in loop runs, you get spaceship.crew[‘captain’].name

might be a dumb question but why are we using [crewMember] to begin with? is it’s purpose to be a placeholder that also has reference for us to follow our code?

if i changed it [thisCrewContains] and apply it through the for…in, it should still work. so is it a referenced placeholder?

the iterator (crewMember or whatever you name the variable) is not a placeholder, the loop will assign the values to the iterator

oh it’s an iterator then? the process is exactly what I was thinking
by placeholder i was meaning to say a variable that is assigned a value. thanks

Thankyou… This is so helpful.

Thank you very much for such a clear explanation. I no longer had any doubt :grinning: