Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript Object-Oriented JavaScript Getters and Setters Getters

WHY GETTERS?

i am totally confused here why do we need to use getters at all let alone setters? i am so used to guil hernardez so i find it difficult coping with new instructors

Encapsulation

4 Answers

I can totally understand why 'getters' seem superfluous right now. If it helps, here are two quick real-world cases for a 'getter':

1: Creating properties which contain logic

Imagine a Person class with firstName and lastName properties, where we will frequently be accessing the full name as the firstName and lastName separated by a space. With a 'getter', that logic can live on the class itself and the interpolated value can be accessed like a normal property:

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  }
};

const richMan = new Person("Jeff", "Bezos");
richMan.fullName; // "Jeff Bezos"
richMan.firstName = "Jeffrey";
richMan.fullName; // "Jeffrey Bezos"

Remember, properties/values are, methods/functions do. Without get, fullName would need to be accessed by calling the function richMan.fullName(). For anyone using your class, the interface for accessing the fullName is much more intuitive with a 'getter'. It's as if we'd included a this.fullName property in the constructor, but (as you see above) it will automatically update when a dependent property is updated. Had richman.fullName been instantiated in the constructor, every time richMan.firstName changed we'd also need to update richMan.fullName.

2: Creating immutable values

This is a bit different from what you've seen in the lesson, but consider the following:

class ClassicalPerson {
  constructor(name) {
    this.name = name;
  }
  greet() {
    return `Hi, I'm ${this.name}!`;
  }
};

const jim = new ClassicalPerson("Jim");

jim.name; // "Jim";
jim.greet(); // "Hi, I'm Jim!"
jim.name = "Bob";
jim.name; // "Bob"
jim.greet(); // "Hi, I'm Bob!"

const FunctionalPerson = name => ({
  get name() { // getter
    return name;
  },
  greet() {
    return `Hi, I'm ${name}!`;
  }
});

const mike = FunctionalPerson("Mike");

mike.name; // "Mike";
mike.greet(); // "Hi, I'm Mike!"
mike.name = "Harry"; // fails
mike.name; // "Mike";
mike.greet(); // "Hi, I'm Mike!"

Note how in both instances the name is accessed just like a property - .name. The big difference is that it cannot be set like a property when it's a getter. In other words, the name "Mike" lives within mike, it is read and accessed through name and greet, but it cannot be changed after the initial function call. This sort of control over the object can help prevent major bugs while behaving just like a normal property.

I hope this helps!

Steven Parker
Steven Parker
231,269 Points

Wow, that's rather tricky, since the "name" in FunctionalPerson isn't an object property at all, but a function parameter. If I redefine it without the getter but with an expanded greet method it does this:

const FunctionalPerson = name => ({
  greet() {
    return `Hi, I'm ${name}! (or am I ${this.name}?)`;
  }
});

const mike = FunctionalPerson("Mike");
mike.name = "Harry";
mike.greet(); // "Hi, I'm Mike! (or am I Harry?)"

What really surprised me was that before I made any changes, I tried dumping mike out in the JavaScript console, and it included this property: name: (...) (not name: "Harry" or name: "Mike")!

Steven Parker I'm sorry, I meant to clarify, not add further 'trickiness'! I was using a different pattern which I'll try to briefly explain for whomever it may help:

My example FunctionalPerson was a factory function which:

  • returns a new object
  • does not use the generic object (populated with this)
  • is called like a normal function (const person = Person("John"))

Whereas a class or constructor function:

  • populates an object within the context of where it's called (by using this)
  • must be called with the 'new' operator (const person = new Person("John")) to create a new context and prevent all kinds of bugs! (Using the class syntax prevents calling without the 'new' keyword for this reason.)

Your example FunctionalPerson effectively mixes the two approaches, which must be avoided by developers since a JavaScript engine won't catch it (it's a 'gotcha').

I hope this is clearer, I didn't mean to throw a spanner in the works! My apologies.

Edit: shortened for clarity

Steven Parker
Steven Parker
231,269 Points

Getters (and setters) allow your object to have custom code internally, but to operate from the outside just as if they were ordinary properties. You don't actually need them, as you can do similar things with methods, but the syntax for using them will be different.

Being able to access them just like properties can be quite convenient, once you get used to them.

Daoud Merchant, I don't think that I understand the need (or preference) of a getter in the first example.

Am I not getting the same result as in your code block with the getter if I do this:

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.fullName = `${firstName} ${LastName}`: // defining the fullName in the constructor method
  }
 // get fullName() {
 //   return `${this.firstName} ${this.lastName}`;
 // }
};

const richMan = new Person("Jeff", "Bezos");
richMan.fullName; // "Jeff Bezos"
richMan.firstName = "Jeffrey";
richMan.fullName; // "Jeffrey Bezos"

What is the benefit of using the getter over what I did above?

Steven Parker
Steven Parker
231,269 Points

The obvious difference is you did not define a getter for firstName.
If you do, you will still be able to read it, but not change it.

I'm afraid you won't get the same result, because this.fullName is assigned the values from the constructor call ("Jeff" and "Bezos"), and therefore does not update itself when either firstName or lastName are changed (it contains values which were set and need to be reset manually rather than logic which recalculates a value every time the property is accessed (and the function is called).

Have you tried this out in the console? When I do I get:

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.fullName = `${firstName} ${lastName}`; // defining the fullName in the constructor method
  }
};

const richMan = new Person("Jeff", "Bezos");
richMan.fullName; // "Jeff Bezos"
richMan.firstName = "Jeffrey";
richMan.fullName; // "Jeff Bezos" (does not update!)

Let me know if it's still unclear.

Thanks Steven Parker and Daoud Merchant. I think I understand it a little better now re the updating itself part (watched some extra YT videos of it as well).