Why can't I use crewMember.name?

 > for(let members in spaceship.crew) {
     spaceship.crew[members].cheerTeam();
   }
   You got this!
   WhooHaa
   BEEER
   what the heck
<- undefined

The last undefined we can ignore. That’s the console responding that it’s done carrying out the code we passed it.

Lesson here is be sure the function/method you’re calling isn’t doing the logging, too, else if you log the call it will be the undefined returned by console.log().

Corrected code from above post
spaceship = {
  crew: {
    captain: {
      name: 'Lily',
      degree: 'Computer Engineering',
      cheerTeam() { 
        console.log('You got this!')
      }
    },
    'chief officer': {
      name: 'Dan',
      degree: 'Aerospace Engineering',
      cheerTeam() {
        console.log('WhooHaa')
      },
      agree() {
        console.log('I agree, captain!')
      }
    },
    medic: {
      name: 'Clementine',
      degree: 'Physics',
      cheerTeam() {
        console.log('BEEER')
      },
      announce() {
        console.log('Jets on!')
      }
    },
    translator: {
      name: 'Shauna',
      degree: 'Conservation Science',
      cheerTeam() {
        console.log('what the heck')
      },
      powerFuel() {
        console.log('The tank is full')
      }
    }
  }
}
6 Likes

I’m not sure if I follow this explanation. I understand the question. It’s quite abstract. You would think that if console.log({crewMember}`)` references to every member (every element in crew), then digging down 1 level to for example a name of such a member would be `console.log(`{crewMember.name}).

You’re simply digging down from that placeholder/variable crewMember. Doesn’t work though. Anyone can explain why?

crewMember in this example is a variable, so must be subscripted to access it.

spaceship.crew[crewMember].name

Cconsider,


outer = {
  inner: {
    one: {
      name: "One"
    },
    two: {
      name: "Two"
    },
    three: {
      name: "Three"
    }
  }
}
for (let member in outer.inner) {
  console.log(member.name);
  console.log(outer.inner[member].name)
}
undefined
One
undefined
Two
undefined
Three
7 Likes

Thank you. I’m still trying to find the pattern here.

So calling crewMember (an object) you can do directly and calling a value string (crewMember.name) you have to do from the root, describing the entire path?

Or is the difference that you can refer to crewMember because it’s the variable you set in this for in loop and anything other than the variable itself has to have its entire path declared?

1 Like

Since we are using a variable to hook each inner property, it has to be subscripted (cannot use dot notation). We cannot access only the subscript, so,

[subscript].name

will not work. That means we need the object that it is a subscript of, hence the full identifier.

We could simplify it by creating a stand alone reference…

let crew = spaceship.crew;
for (let member in crew) {
    console.log(crew[member].name);
}

To keep that temporary object from taking up memory, we can clear it by setting it to ‘null’

crew = null;

We could not do this if we declared it with const, hence I used let.

5 Likes

so i was wondering what s the point of making the variable in the for in loop. like couldnt i have just put no variable instead of specEd, maybe im not getting the significance of the variable in this for in loop…

for(let specEd in spaceship.crew){
console.log(${spaceship.crew[specEd].name}: ${spaceship.crew[specEd].degree})
}

like why doesnt this work?
for(let specEd in spaceship.crew){
console.log(${spaceship.crew.name}: ${spaceship.crew.degree})
}

crew contains multiple members, if you just do spaceship.crew.name, how is javascript suppose to know of which crew member you want the name? That is why we use the loop

lets say we want the captains name, we get:

spaceship.crew.captain.name

by using a loop, we can replace captain with a variable to print the name of every crew member
except

3 Likes

…with a subscripted variable… (so as not to mislead)

6 Likes

It sounds like associative array notation should work all the time, and dot notation some of the time. That leads to two related questions:

  1. Why use dot notation at all, when new key-value pairs containing strings might be added later?
  2. (This might be a case-in-point for question 1) Why does ${spaceship[crew][crewMember][name]} give me syntax errors?

Thanks!

1 Like
${spaceship[crew][crewMember][name]}

will not work, but

${spaceship['crew'][crewMember]['name']}

will (notice the quotation marks). Bracket notation for objects is normally formatted with quotation marks.

So, spaceship.crew[crewMember].name and spaceship['crew'][crewMember]['name'] are the same thing.

What I currently do not understand, and cannot help with, is why crewMember is called without quotation marks. The explanations on this page suggest it’s something to do with for…in loops returning strings instead of objects but I am frankly struggling to parse much that’s being said here beyond that.

1 Like

Oh wait. Since this is a different kind of for loop, crewMember is an iterator variable, but just not a numerical one, right?

So we can write this in a more similar style to a normal for loop, as

for(let i in spaceship.crew) {
 console.log(`${i}: ${spaceship.crew[i].name}`);
}

We tell the loop ‘I want to iterate through every item at the level immediately below spaceship.crew’, and then we can access the result using spaceship.crew[i], the same as we would using a regular for loop if we were dealing with an array instead of an object.

I guess we don’t need to do i++ to iterate through a for…in loop like we do a regular for loop, because for…in always tells the program to loop through everything at that level within the object, and then stop.

Is that correct?

Thinking about (and formatting) it this way clarifies a little more to me why we have to format property names and variable names differently from each other in this exercise.

5 Likes

Very strange…I’v never had to use this before. ${crewMember.name} I thought would work for sure.

for (let crewMember in spaceship.crew) { console.log({crewMember}: {spaceship.crew[crewMember].name}) };

I don’t get why crewMember is a string, if it has let before it…telling me that it’s a variable/parameter? How would I know that?

its a variable holding a string value. When we declare a variable we let we can perfectly give it a string value:

let example = 'hello world'

that is what the for ... in loop does as well, but then for every element in the object

1 Like

Hello there,
I was trying to log the list of properties of each one of the crew’s member

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

It logs

captain:[object Object]
chief officer:[object Object]
medic:[object Object]
translator:[object Object]

But if I use
console.log( spaceship.crew[member] );
instead, then it works well to print each crew’s member properties

If I write

for (let member in spaceship.crew) {
  console.log( `\n ${member}:${spaceship.crew[member]}`);
  console.log( spaceship.crew[member] );
}

will print

captain:[object Object]
{ name: ‘Lily’,
degree: ‘Computer Engineering’,
cheerTeam: [Function: cheerTeam] }

chief officer:[object Object]
{ name: ‘Dan’,
degree: ‘Aerospace Engineering’,
agree: [Function: agree] }

medic:[object Object]
{ name: ‘Clementine’,
degree: ‘Physics’,
announce: [Function: announce] }

translator:[object Object]
{ name: ‘Shauna’,
degree: ‘Conservation Science’,
powerFuel: [Function: powerFuel] }

It seems the problem appears when trying to concatenate strings to the object,
does this mean that a whole object cannot be “transformed” into a multi-lined string as it’s the case for numbers and arrays?

Just to confirm if I understand correctly. Only if the iterator variable is of type string, should you use the brackets in console.log(${crewMember}: ${spacecraft.crew**[crewMember]**.name})

Is the iterator in een for…in loop always of type string or can it be an integer (e.g. index number of an array)? And if so, how would that effect the console.log in this case?

still seems to give string:

obj = {1: 2}
for (a in obj){
  console.log(typeof a, obj[a])
}

the comparison doesn’t seem to be strict, and we can’t have a integer and string key of the same value:

obj = {1: 2}
obj["1"] = 2
console.log(obj)

as mentioned in the documention under Why Use for…in?, for in should not be used on arrays.

Thanks for the clarification!

Why can’t we use (${spaceship.crew[crewMember]}) in the first for loop instead of only using (${crewMember})? Aren’t they supposed to be indicating the same thing?

If not why can’t we just use ${[crewMember].name} in the second loop instead of ${spaceship.crew[crewMember].name}?

for (let crewMember in spaceship.crew) {
  console.log(`${crewMember}: ${spaceship.crew[crewMember].name}`)
};

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

2 Likes

Can someone tell me why this option doesn’t work? Am I missing something?

// Write your code below
for (let crewMember in spaceship.crew) {
console.log(${crewMember}: ${spaceship.crew[crewMember].name})
};

PS I included backticks in the console statement.