Why can't I use crewMember.name?

Question

In this lesson it seems intuitive to just use crewMember.name to reference the name of each crewMember. However it results in undefined, why doesn’t this work?

Solution

When using a for..in loop, the iterator is a type string (you can verify this with typeof) so they do not have the name property. For example as it iterates through the captain, crewMember = 'captain'.
Since this is a string on its own, you can log it as such. That is why `${crewMember} works correctly. However when you then want to use it to reference, the format doesn’t work using dot notation.

object.propertyName

Dot notation requires the propertyName not as a string. To use it as a string, we can utilize it in associative array notation (with square brackets). object['propertyName'].
So in our lesson, this is why you need to format it as ${spaceship.crew[crewMember].name} This way it checks spaceship and then in crew finds the crewmember and returns the name property of that crewmember.

Hope this helps, please discuss and ask further questions below.

8 Likes

This code was used in the example in this exercise: for (let crewMember in spaceship.crew) {
console.log(${crewMember}: ${spaceship.crew[crewMember].name})
};
My question is, why do you use a bracket around crewMember in the last line? It is not a two-word string, nor does it have special characters or a space.??

3 Likes

because of JS, in JS objects and associative arrays are the same, so we can just mix them:

myObj = {
  a: 3
}
console.log(myObj.a); // dot nation
console.log(myObj['a']); // associative array notation

for the dot nation (object notation if you like), we must use the same of the property, for the associative array notation, the key needs to be string.

when using a for ... in loop, the iterator (crewMember in your case) is of type string (you could use typeof to verify this), in which case we have to use the associative array notation

8 Likes

Why isn’t it possible to use

console.log(crewMate + ": " + crewMate.name);

or

console.log(crewMate + ": " + crewMate['name']);

which is much shorter and much more readable?

2 Likes

because crewMate is not in the global namespace, its a nested object.

4 Likes

I still don’t understand. Practically it crewMate.name does ouputs undefined but why? If crewMate is already a variable then crewMate.name should be working.

2 Likes

the for in loop gives the properties back as string, so crewMate will contain strings. These strings do not have a name property

11 Likes

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

In the above code, why can we call ${crewMember} without needed to specify spaceship.crew[crewMember]? Why can we not use ${crewMember.name} in the second part of the console.log() string?

5 Likes

the for in loop will give strings:

for (let crewMember in spaceship.crew) {
   console.log(crewMember, typeof crewMember)
}

these strings do not have a name property

if you want the captain, you would do:

spaceship.crew.captain

you can’t access captain directly, given its part of crew object, which in its turn is part of spaceship object

7 Likes

Why is this syntax is incorrect?:

for (let position in spaceship.crew){
console.log(position + ': ’ + spaceship.crew[position][name]);
};

Supposedly we can write the keys in bracket notation, right?

This one also returned error, but as far as I know, if the keys don’t have special characters, we can write them through dot notation:
for (let position in spaceship.crew){
console.log(position + ': ’ + spaceship.crew .position.name);
};

yes, but then the keys should be strings.

3 Likes

That makes sense. Thank you.

I still don’t get why dot notation didn’t work. Is it because dot notation can’t be used with the argument of the function?

1 Like

because using the dot syntax, you need the property name:

object.propertyName

if you have the propertyName as string, you have to use the associative array notation (with square brackets)

4 Likes

But none of my properties were strings. I’ll paste my code:

let spaceship = {
    crew: {
    captain: { 
        name: 'Lily', 
        degree: 'Computer Engineering', 
        cheerTeam() { console.log('You got this!') } 
        },
    chiefOfficer: { 
        name: 'Dan', 
        degree: 'Aerospace Engineering', 
        agree() { console.log('I agree, captain!') } 
        },
    medic: { 
        name: 'Clementine', 
        degree: 'Physics', 
        announce() { console.log(`Jets on!`) } },
    translator: {
        name: 'Shauna', 
        degree: 'Conservation Science', 
        powerFuel() { console.log('The tank is full!') } 
        }
    }
}; 

// Write your code below
for (let position in spaceship.crew){
  console.log(position + ': ' + spaceship.crew.position.name);
};

for (let position in spaceship.crew){
  console.log(spaceship.crew.position.name + ': ' + spaceship.crew.position.degree);
};

This returned ‘TypeError: Cannot read property ‘name’ of undefined’ at the dot after position unless I wrapped it with brackets.

Thank you for taking time to answer.

the for in loop gives a string:

for (let position in spaceship.crew){
   console.log(typeof position);
3 Likes

I thought that the loop had something to do but I didn’t know what. So just to be clear, then: variables on the for in loop are treated as strings, right?

the for in loop assigns the property names to the variable (position in your case).

3 Likes

I think that because dot notations looks for Keys? and keys only?

1 Like

i think that, what does that refer to? You use it, but without context its difficult to determine what you mean

1 Like

I think the reason why you have to put [position] inside bracket notations is because it is a variable and not a property right?

1 Like