Tell us what’s happening:
I’m having trouble understanding the instructions, explanation and example code.
The explanation states “These are classically called getters and setters.” What does classically mean in this context?
Can someone please elaborate on: “You can obtain values from an object and set the value of a property within an object.” What does it mean to obtain values from an object and set the value of a property?
What is an object’s private variable and what/who is the user?
I think I understand what a constructor is - this is just a way to create an object, right?
Regarding the this keyword - not sure I understand what it is. I don’t recall this being covered in prior lessons. I searched but couldn’t locate the lesson. Can someone please provide a link to the lesson that covers this?
The instructions state: “Notice the syntax used to invoke the getter and setter. They do not even look like functions.” Although I’ve read the word many times, I’m still not clear on what syntax means in JS. What does it mean to invoke the getter and setter? What does it mean to look like a function? Are they, or are they not functions (i.e. get and set)?
This instructions state: “This is the power of a getter and a setter. You are creating an API for another user, who can get the correct result regardless of which one you track.” What does the word this refer to, in the context of its sentence - meaning what exactly is the power of a getter and setter? What is an API? Who is another user? and who in fact is the first user (since in order for there to be another user there must be a first user)? What does which one you track refer to - specifically one of what?
What does it mean to be “abstracting implementation details from the user.” (Again - who is the user? And user of what?)
Sorry for the detailed questions. But it would be helpful to me if anyone is able to offer clear and concise explanations, and/or provide links to info that would help me understand better what all this means.
Thanks so much!
Your code so far
// Only change code below this line
// Only change code above this line
const thermos = new Thermostat(76); // Setting in Fahrenheit scale
let temp = thermos.temperature; // 24.44 in Celsius
thermos.temperature = 26;
temp = thermos.temperature; // 26 in Celsius
Your browser information:
User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36.
Challenge: Use getters and setters to Control Access to an Object
First off, these are all good questions. I’ll try to help.
Let’s do this…
“Classically” here means as in class-based object oriented terminology. You may have heard that JavaScript is a prototype-based language. Essentially, what this means is that objects in JavaScript can be created based upon other existing objects. In a class-based language, objects are created from Class templates/definitions. Prior to ES6, JavaScript didn’t have the language keywords to define objects in a way that was familiar to programmers coming from a class-based language. In class based languages, like Java and C#, programmers of those languages are familiar with using “getters” and “setters” to control access to properties (getters) or to control modification of properties (setters). What that sentence is trying to convey is that if you are familiar with those concepts from a class-based language, what the lesson describes is similar.
You can read more about the theory of getters/setters on the Wikipedia page for Mutator method. Take a look at that, but if it gets too “deep” and you don’t feel it’s helping don’t worry about. A lot of these concepts just click if you stick with them for a bit in practice. You can always come back for a formal understanding at a later time when things start to fall into place.
You should already be somewhat familiar with properties as they related to objects in JavaScript from the Basic JavaScript lessons in the curriculum. If you don’t feel comfortable with that, you should double back to those lessons to review.
For example, if I have an object book:
let book = {
name: 'Code Complete',
author: 'Steve McConnell',
pages: 0
};
If I want to obtain the value of the name property of my book object so that I could log it to the console for example, I would just reference that property using book.name like so:
console.log(book.name)
If I wanted to set the value of the pages property of the book object, I would use a reference to that property, book.pages , on the left hand side of an assignment operator (=) like so:
book.pages = 960;
I’m guessing that will make sense to you and that you were just getting hung up on the terminology.
The term user in this context refers to the user of the object or more specifically the programmer writing the code using the object.
The term private variable in this context (and in object oriented programming terminology in general) means a property of an object that can only be accessed/manipulated internally by the object itself, no external access to it is allowed/provided.
For example, in my book object example above, all of the book object’s properties would be considered “public” properties—that’s because anyone using the object (i.e. the “user”) can access and change the values of those properties by referencing them (e.g. console.log(book.name);) or assigning values to them (e.g. book.pages = 960;)
You have to do something special in JavaScript to truly make properties private to an object. With the features available in ES6 that’s where setters and getters help with this.
Almost. The term constructor in object oriented terminology simply means a special function that runs when creating an object. You can think of the constructor as the “blueprint” that is followed for creating the object when using the new keyword to create an object.
Fully understanding the this keyword is fundamental to understanding working with objects in JavaScript. There’s a lot to learn when it comes to this, but just take it a little at a time.
Back up and go through the Object Oriented Programming section of the JavaScript Algorithms and Data Structures Certification curriculum for a refresher. The specific lesson that introduces this is: Make Code More Reusable with the this Keyword
You may want to spend some time with this useful resource: ObjectPlayground.com Watch the video there, take some notes, play with the code. Repeat a few times to make it sink in.
I leave you with that for now, but will try to get back to your other questions in a bit.
The term syntax is used to reference the formal structure of a programming language. What makes a statement valid in any programming language? If a statement written in code follows the “syntax rules” of the language, it is valid.
The same can be said about regular language like English, French, Spanish, etc. I could say “I the book read good was.” but you’d probably be confused and that’s because I didn’t follow the syntactical grammar rules for writing in English. When I do that and instead say, “The book I read was good,” you would now have a better chance of understanding me.
The same applies in programming. If you do not follow the syntax rules of a programming language, like JavaScript, the JavaScript engine will not understand your code and will throw errors, which is the compiler/engine’s way of saying, “I don’t understand this code.”
So basically, that instruction quote is just referencing that getters and setters do not use the same syntax rules as functions. For example, function declarations typically begin with the keyword function whereas setters and getters do not. They have their own syntax rules and use the keywords get and set when defining them.
Technically, getters and setters are a type of function. The subtle difference is in the intention of what the code is doing with getters and setters, in terms of encapsulation and hiding details from the user of the object. Which you’ll need to learn about and what is referenced in your next questions…
This is referring to the concept conveyed in sentence just before that in the instructions, the one that starts with “Note:” The “power” it is referring to is the control you are taking inside the class by ensuring that internally the temperature is stored as a Celsius value even though the user is using a Fahrenheit value when setting it. Admittedly this is not the best example of the power/control getters and setters provide, but it is trying to be simple enough to get that concept across.
The phrase abstracting implementation details from the user essentially means that you are hiding some complexity details from the user. If you, for instance, forced the user to perform the calculation from Fahrenheit to Celsius before passing the value to the constructor function, then you would be pushing that complexity over to the user, who would then be responsible for ensuring they had the calculation code correct and who would have to do the calculation every time they wanted to create a Thermostat object.
(and remember user above means the user of, or programmer using, your object)
Here are some additional resource you can work through to better understand these concepts:
@robertgroves, thank you for detailed and clear explanations. I appreciate your taking the time to address my questions. I’ll review your answers and check out the links you provided. Feeling totally overwhelmed at this point but I’ll try to break it into smaller pieces.
I have to say that this whole ES6 section seems totally out of place compared with the rest of the curriculum. It’s like trying to learn to fly a 737 when I haven’t even figured out how to fly a kite.
However I did not understand most of the information. I still don’t quite understand what this exercise is about or where to begin.
A few specific issues:
regarding:
How do getters and setters prevent a private variable from being accessed externally? Why does it matter whether or not they can be accessed externally?
Why do we need to use a constructor?
I’m still not clear on the this keyword.
regarding
This is the power of a getter and a setter. You are creating an API for another user, who can get the correct result regardless of which one you track.”
I’m still not clear on the power of a getter and a setter in the context of this exercise. Why do we need a getter and a setter - why can’t we just use another way of obtaining values from an object and setting the values of object properties?
What is an API? Why do we need to create an API? What is the one you track?
I’m not clear on what’s happening in the example code and how it relates to the challenge.
Technically, you don’t have to use getters/setters. They are syntactic sugar. They make things a little more convenient. Although some would argue that they can complicate things as well. You need to learn about them because you will most likely see them in other code. But for your own personal use, you can avoid them if you like.
ES6: Use class Syntax to Define a Constructor Function
ES6: Use getters and setters to Control Access to an Object
… are meant to show you the new class syntax that was introduced to JavaScript in ES6. It’s just a different way to create objects and their properties.
If you aren’t familiar with Object Oriented Programming (OOP) and/or do not have knowledge of different class-based OOP languages, all of this may be conceptually confusing. In order to fully understand it, you would need to get a better foundation of OOP concepts.
Maybe start by pausing the ES6 lessons and skip them until you complete the Object Oriented Programming lessons that come in a few modules. Also, the last two “additional resources you can work through” links that I provided (in my previous reply) may help you if you want to try and understand OOP concepts better.
It may be enough (right now anyway) to just know that all these two lessons are showing you is a different way of creating an object (that eventually you should become familiar with because you will see it in other code and have to understand it).
You could go on writing JavaScript creating objects and implementing OOP concepts in JavaScript and never use the ES6 syntax/language features (that’s actually what JavaScript programmers did before ES6). Those features were added to make things seem more familiar to programmers coming from other languages that had a class-based object oriented model.
It probably is better to say that getters and setters allow the developer creating the object to control what is allowed when accessing the object’s data.
For instance, you can add logic in your setter function to manipulate or verify the value being set and to prevent the wrong thing from happening which could introduce a bug later in the program. You cannot do that with assignment to a normal property (i.e. one that does not use a getter or setter).
Constructors provide you a way to bundle up creation of an object so that it can be reused over and over without having to replicate the same code whenever you need to create an object of the same type.
There is a lot to know about the this keyword, but I’ll try to boil it down to handful of bullet points:
You can think of the this keyword as a special variable in that it is always available in JavaScript program
The value the this keyword refers to is different depending on the current context when executing your JavaScript code
See for yourself, open Dev Tools and in the console type this and hit enter—you’ll see it is set to the global window object
…but it isn’t always set to that. JavaScript changes it’s value depending on what happens during execution of your code. This fact is what makes the this keyword in JavaScript confusing if you don’t know all the rules that go into setting the value of this.
When you call a function that is a property of an object (or a “method” as it’s called), the value of this is set to the current object that you called the method on.
This fact is what allows you to use this inside of your methods to refer to properties of the current object
There are ways you can force what value this is set to, but you don’t really need to know about those right now (unless you want to, then look up: Function.prototype.apply, Function.prototype.call, Function.prototype.bind).
If you don’t fully understand the reason behind it now, don’t worry about that for now. It will hopefully click later after you learn more about object oriented programming.
For now all you need to know is the how, meaning how to create a constructor, setter, and getter (like it is showing you in the lessons). Think of it like knowing how to start a car does not mean you have to know the reasons why turning the key in the ignition makes the car start.
API stands for Application Programming Interface. APIs are created to provide a well defined interface to a system or object. This makes them easy to use because you do not have to write all of the code to do the thing you want/need to do when interacting with a system/object.
Think of why you create a function, you wrap a bunch of lines of code up in a reusable “package” (so to speak) so that you don’t have to deal with writing that code over and over every time you need to do what it is those lines of code do. If you did have to rewrite them, it would allow you to possibly make mistakes every time you re-wrote them.
You can think of an API as a collection of functions (like an object with a bunch of methods that it provides) which allow you to do things that have been wrapped up into a package of code to make it easily reusable and less error prone.
The full context for that is in the lesson where it says:
Note: When you implement this, you will track the temperature inside the class in one scale, either Fahrenheit or Celsius.
This is the power of a getter and a setter. You are creating an API for another user, who can get the correct result regardless of which one you track.
So, in the Note it mentions that you will track the temperature as either Fahrenheit or Celsius (whichever you choose). The “one you track” refers to the choice you made, either Fahrenheit or Celsius.
Essentially, the class you are creating accepts a Fahrenheit temperature value when it is created and will give back that temperature in Celsius. Internally, (in the code you write for the class), you can store that value as Fahrenheit or Celsius. You’ll have to implement the logic differently depending on your choice:
If you choose to keep the temperature value as Fahrenheit and store it inside your class:
Your setter can just store the value provided, but…
…you’ll have to perform the conversion to Celsius in your getter method before returning the value
If you choose to convert the temperature value to Celsius and store it inside your class:
Your setter will need to perform the F to C calculation before it stores the value internally
Your getter function can just return the internally stored value (since it was already converted when it was set)
At the suggestion of another FCC member, I did exactly that a while back. About halfway through the ES6 lessons, I went ahead and went through the OOP lessons, as well as the regex, debugging, basic data structures and basic algorithm scripting.
It seems the ES6 lessons should really come after those others. It’s a mystery as to why it is where it is in the curriculum.
I have no prior programming experience in any other language, so all this is new to me. It almost seems like prior JS programming experience, or prior experience in another object oriented language, is necessary to be able to understand the ES6 lessons.
Thanks for the additional explanations. Unfortunately I’m not really absorbing much of it. I just keep reading stuff over and over again…
I’ll go back and review the MDN information you referenced. However it seems like a whole lot of information to know and understand (i.e. an overwhelming amount of info), in order to do one lesson, and so it seems like maybe they should break this down into a whole bunch of smaller lessons to give students the background to be able to understand and complete the challenge.
@Sharad823 it sounds like you’re going to have a hard time breaking through it on your own, I’m sure you will if you keep at it and practice the lessons (looking things up and really trying to absorb the details). However, it sounds to me like you could really use a mentor to get you through your sticking point. Have you checked your area for a freeCodeCamp local study group?
I am still unclear about how we create a private variable in JS. What is the something special that we do, to create a private variable? Are getters and setters making the variables private?
Also unclear on this
So if getters and setters are a type of function, then (to me, at least) it would follow logically that as a function, they would use the syntax rules of functions. But yet they do not. This seems arbitrary and therefore confusing.
Local study groups are independently organized and run meetups held by individual Camper volunteers (not directly affiliated with freeCodeCamp directly).
There is a local study group directory but I don’t think it gets updated any longer. That being said, there are groups listed in there that still meet up. If you can’t find anything in the directory near you, your best bet is to search for “freeCodeCamp local study group LOCATION” where LOCATION should be replaced with wherever you are located.
Also, it doesn’t have to be a fCC study group. Find other local JavaScript related groups by searching on Google, Meetup, Facebook, etc. and ask if anyone is willing to help you out in a mentor - mentee relationship for learning JavaScript.
There are also websites out there (some paid, some free) that allow you to find a coding mentor. Like codementor.com and codingcoach.io. (I cannot endorse either of those because I never used them so due diligence should be performed).
For classes, there is a way to create private variables (officially, they are referred to as private fields), but not all browsers support them yet. This is a brand new feature that has been working its way through the proposal process for a while now. The way you create a private field is:
class X {
#foo = 10;
method() {
console.log(this.#foo)
}
}
You add the pound sign before the variable. This will prevent you from accessing #foo from the object you’ve instantiated (you can only access it from methods within the class):
const obj = new X();
console.log(obj.#foo); // This will throw an error
I believe some of the transpilers will accept private class fields and fix the code so it can be used on browsers that don’t implement it yet.
As far as creating private variables the traditional way, you use the power of closures. The gist of it is that you create a function with your private variables and then return an object composed of methods that access and manipulate those private variables. Rather than give you a long example, here’s someone who has done that already:
No getters and setters are not making private variables/properties. The ES6 syntax does not allow private variables, or at least it cannot enforce that; you’d have to agree to a convention. Some JavaScript programmers use the convention of naming a property beginning with and underscore to mean that it should be treated as a private property and not modified outside of the Class code.
You’d have to use the plain constructor function (meaning not use the Class syntax and just do it the way it’s described in the Object Oriented Programming section of the curriculum) to actually create objects with private properties.
Here’s an example:
Let’s say we need to create an object that allows us to get a number count from it. We can tell where to start counting from (it should use zero by default if we don’t specify a number) and every time we get the count value it is incremented by 1.
If we do this the ES6 way we might define something like this:
class Counter {
// The constructor accepts a number for the starting value to count from.
// It defaults to start from 1 if no number is passed.
constructor(startingValue = 1) {
this._currentValue = startingValue - 1;
}
// Getter for the current value of the counter
get count() {
this._currentValue += 1;
return this._currentValue;
}
// NOTE: Not creating a setter here because the user of
// objects created by this class should not be able to modify
// the count value. Only the internal workings of this class
// code that I'm writing should do that.
}
// To use the class above to create a counter object, we do:
var myCounter = new Counter(10); // Create a counter that will count starting at 10
// Now I'll do some log my counter values to the console a few times:
console.log(myCounter.count); // Output is: 10
console.log(myCounter.count); // Output is: 11
console.log(myCounter.count); // Output is: 12
// You see above that myCounter.count will give back an increasing count value
// everytime it is referenced. That's good, as this is what we wanted!
Now as the developer of the class above I don’t really want users of my Counter class, (users meaning the programmers creating objects with it—me or anyone else), to modify the object’s _currentValue value. With current ES6 syntax there is no way to enforce “private”, so instead I have to rely on a convention that I hope all programmers using my class will also follow. That is why I named the property starting with an underscore: _currentValue. This is just a convention though, JavaScript won’t throw an error. A programmer could do this, (continuing from the program above):
myCounter._currentValue = 100;
// Oh no! Someone did not follow the convention mentioned above and has
// modified the internal count value.
// Now instead of the next count value being 13, it will be 100 instead.
console.log(myCounter.count); // Output is: 100
console.log(myCounter.count); // Output is: 101
console.log(myCounter.count); // Output is: 102
In the above example, we tried to make a nice counter class, but since we couldn’t make _currentValue private it allowed a user of our class to do something wrong, modify the internal state of our class (in this case the _currentValue value).
Now if we really want to have a private member we need to skip using the nice ES6 syntax to create a class and just use the regular JavaScript constructor function way. Something like this:
function BetterCounter(startingValue = 1) {
// This is our private variable. It's private because the object being returned
// by this constructor function will not have a direct reference to it.
let currentValue= startingValue - 1;
// The countUp function will have access to curretValue because of the way scoping
// works in JavaScript, inner functions have access to the enclosing/outer functions
// objects (i.e. variables/functions).
function countUp() {
currentValue += 1;
return currentValue;
}
// The counterObj variable is being assigned a literal object that has one
// property named count which is assigned the countUp function. This will
// give users of this object the ability to call countUp by using
// objectName.count().
let counterObj = {
count: countUp
}
return counterObj;
}
// To use the constructor function above to create a counter object, we do:
var myNewCounter = new BetterCounter(10); // Create a counter that will start at 10
// Now I'll do some log my counter values to the console a few times:
console.log(myNewCounter.count()); // Output is: 10
console.log(myNewCounter.count()); // Output is: 11
console.log(myNewCounter.count()); // Output is: 12
With the code above, there is no way for the user of objects created from the BetterCounter constructor function to modify the internal state (the currentValue property).
myNewCounter.currentValue = 100;
// Even though someone tried to manipulate the current count value they won't be
// successful. The above assignment does create a new property named currentValue on
// the myNewCounter object, but it is not the same one used internally. There is no
// way to externally access the internal currentValue state of the count method.
console.log(myNewCounter.count()); // Output is: 13
console.log(myNewCounter.count()); // Output is: 14
console.log(myNewCounter.count()); // Output is: 15
The above shows that the currentValue in this case is truly private and inaccessible by users of the objects created by the BetterCounter class.
If it is confusing to you then please just forget when I said about getters and setters technically being a type of function. I can see where that is confusing.
Instead, consider them their own stand-alone thing not quite a function and not quite a property. They have their own syntax and behavior.
So, even though inside an ES6 class definition they kind of look like functions and outside of the class definition when you’re referencing them on an object, they look like a property reference—just know that they have their own definition syntax and their own behavior. Similar, but different.
If you consider them their own stand-alone “thing” that you have to learn about. Maybe that will make it easier, or at least less confusing.
You may also want to give https://exercism.io/ a try. You’re not formally paired up with a mentor, meaning that you cannot directly send questions to a mentor. The mentors do look at your code that you submit as solutions to the problems given and then they provide feedback. So you could work the JavaScript lessons until it gets to the point of the OOP stuff, and then just submit your code with comments stating where you’re confused and the mentor looking at your stuff should help you out.