Team stats Project -- how to use getter

Hi,

I encountered the same problem when I am working on both projects in the “Object” section of Javascript. The error looks like this, it is always about “push”

If I take out the getter, it works but if I put it in, It just doesn’t and I really cannot see why… I checked everything. I have the same problem with the other project: meal maker.

Since the Team Stats project is shorter, below is a link to the assignment, I will ask this one:

Team Stats Project

My code:

const team = {
  players :[
    {firstName: 'Pablo',
    lastName: 'Sanchez',
    age: 11, 
  },
    {firstName: 'John',
    lastName: 'Chen', 
    age:  12, 
  },
    {firstName: 'Lily',
    lastName: 'Chan',
    age: 13
  },
  ],

  get players () {
  return this._players;
},
  
addPlayer (firstName, lastName, age) {
    let player = {
      firstName:firstName,
      lastName:lastName,
      age:age,
    };
  
    this.players.push(player);
  },
};

team.addPlayer('Steph', 'Curry', 28);
team.addPlayer('Lisa', 'Leslie', 44);
team.addPlayer('Bugs', 'Bunny', 76);
  
  
console.log(team.players);

Thank you in advance for your help. Really appreciate it!

2 Likes

here:

return this._players;

the getter returns this._players, but there is no this._players, so you get undefined

when using getters, the property is as a convention prefixed with an underscore:

example = {
   _prop = 'abc'
  get prop(){ return this._prop }
} 

now the this._prop within the getter will fetch _prop, which has abc as value

2 Likes

omg… Thank you so much!!! Everything makes much more sense now! Thanks again!!

I have one additional question. In this project, the getter for players is very simple. It is just return this._players;. However, in the other project, meal maker, one of the getter was much more specified. I do not understand why.

Please see the code below:

const menu = {
 _courses : {
  _appetizers: [],
  _mains: [],
  _desserts: [],

  get appetizers(){
   return this._appetizers;
  },
  set appetizers(appetizerInfo){
   this._appetizers.push(appetizerInfo);
  },
  get mains(){
   return this._mains;
  },

//I skipped the setters

 	get courses(){
 	return {
    appetizers: this._courses.appetizers,
    mains: this._courses.mains,
    desserts: this._courses.desserts,
   }

Thanks again!!

you are dealing with nested objects, making the getters more complicated.

the solution of meal maker does something tricky, but first lets do the simple example:

# example one
const menu = {
    courses: {
         appetizers: [],
         mains: [],
         desserts: [],
    }
}

example one is without getters and setters, to access mains we need to do:

console.log(menu.courses.mains);

now for the tricky bit:

const menu = {
    _courses : {
        _appetizers: [],
        _mains: [],
        _desserts: [],
    }, // closes courses object

    get appetizers(){
         return this._courses._appetizers; 
    }
}

now we can just do:

console.log(menu.appetizers);

this calls the getter, which access _appetizers property in _courses object

furthermore, this is very interesting:

set appetizers(appetizerInfo){
   this._appetizers.push(appetizerInfo);
  },

you now change the setter behavior, full example:

const menu = {
    _courses : {
        _appetizers: [],
        _mains: [],
        _desserts: [],

        get appetizers(){
            return this._appetizers;
        },
        set appetizers(appetizerInfo){
            this._appetizers.push(appetizerInfo);
        },
        get mains(){
            return this._mains;
        },
        get desserts(){
            return this._desserts;
        }
    },

    //I skipped the setters

    get courses(){
        return {
            appetizers: this._courses.appetizers,
            mains: this._courses.mains,
            desserts: this._courses.desserts,
        }
    }
}

menu._courses.appetizers = 'some dish'
menu._courses.appetizers = 'another dish'

console.log(menu.courses.appetizers);

now you assign to appetizers (using the setter) which will push to the array, which is different from normal assign behavior.

1 Like

I see I see. So it depends on your needs in the project, whether you need access to those properties.

Thank you so much!! I understand getter and setter much better now!

1 Like

Hey @stetim94 thank you so much! So enlightening!
But still, I really don’t understand why we move from “_appetizers” to “appetizers” and from “_players” to “players”, why we don’t stay just with one?
:fire::brain::fire:

So your question is more, why would we use getter and/or setters in general?

So many interesting answers to this question. Especially once your code base starts to grow. You might want to restrict access to a certain property and only allow access through the getter, so you can do some transformation (array to string for example) or do a check if a property has been set.

getters can also help to clarify certain aspects of your code, or certain restrictions other developers working on your code should respect

like with many things in programming, consist of two steps: learning a concept (getter in this case) and see a really useful case in a project. (getter are a bit useful here, but not that much)

The added difficulty here is that JS doesn’t enforce proper encapsulation. We can still access the property directly. Unlike other languages (java, c# and php to name a few) which do enforce proper encapsulation.

1 Like

Got the reply I was looking for:

javascript getters and setters restricted

JavaScript object properties are not private or protected. Since JavaScript objects are passed by reference, there is no way to fully prevent incorrect interactions with object properties.

One way to implement more restricted interactions with object properties is to use getter and setter methods.

Typically, the internal value is stored as a property with an identifier that matches the getter and setter method names, but begins with an underscore ( _ ).

but JavaScript still doesn’t restrict interaction. we can still access the underscore property.

And this is still different from public, protected or private properties.

1 Like

True!

Nonetheless, even with a setter method, it is still possible to directly reassign properties.

Ok, I think this goes beyond my Jedi skills now. @stetim94 do you recommend any video/reading to understand this topic? or better keep on progressing and pick the topic later on?

I would recommend continuing for now. Once you gain project experience and experience in other languages like Java and C# (with proper encapsulation), you will understand it much better :slight_smile:

For now, you grasp what is essential to know in JavaScript.

1 Like

Basically we use the _ before to inform that if shouldn’t be changed as is a variable that can cause conflicts down the production line. Ex:

let x = 'Hello';
let y = 'World';

const concatenate = (var1, var2) => {
     return  var1 + var2;
};

console.log(concatenate(x, y));  //Should  print "HelloWorld"

x = 10;

console.log(concatenate(x,y)); // Should print"10World" 

since the function was created for strings the change in x makes no sense and _ and getter/setter come in to fix this issue.
Be aware this is a very watered down example but I hope it helps.

Happy Coding!

actually, in this case using static typing would be the better solution. Given JavaScript as a language does not support this out of the box, we would have to use TypeScript. with TypeScript we can specify what type(s) the parameter(s) accept.

no? close, but not entirely. The underscore is a naming convention to tell us that the property shouldn’t be accessed directly, but instead getter (and possible setter) should be used. We can change the value of the property, that isn’t a problem.

Hi! I just finished this project and had one question. Since it regards the same project I’ll post here!

On step 6, they ask you to create a method to the team object that adds a player to the players array.

The default solution is first creating an object and then pushing it to the players object :

addPlayer (firstName, lastName, age) {   
let player = {
firstName: firstName, 
lastName: lastName, 
age: age
};
this.players.push(player);
},

But I came onto a different solution, essentially the same, but I was wondering if this might be not recommended.

 addPlayer (firstName, lastName, age) {
    this._players.push({firstName: firstName, lastName: lastName, age: age});
  },

I am using {} to make whatever the input for the push method automatically an object.

Let me know what you think! :thought_balloon:

The temporary variable (player) as in the exercise solution is redundant

however, cramming everything into a single line is not good for readability. I would put every object entry on its own line.

Some of the things I mention in my answer are just personal preference and years of experience.