JavaScript
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
73: Getters and Setters in Classes
I see this all the time when I'm reviewing code from developers moving into JavaScript: they treat getters and setters as just another way to name their methods. They'll create a class and write methods like getName() and setName(value), thinking they are following a "best practice" from other languages like Java. While that works, it's not actually using JavaScript's built-in getter and setter functionality. It's just writing regular methods.
Thinking getters and setters are just methods with "get" in the name
If you're manually calling a function to get a value, you aren't using a JavaScript getter. Look at this snippet. This is the "manual" way that many people default to:
class SmartLight {
constructor(brightness) {
this._brightness = brightness;
}
// This is just a method, NOT a JS getter
getBrightness() {
return `${this._brightness}%`;
}
// This is just a method, NOT a JS setter
setBrightness(value) {
if (value < 0 || value > 100) {
console.error("Brightness must be between 0 and 100");
return;
}
this._brightness = value;
}
}
const light = new SmartLight(50);
console.log(light.getBrightness()); // We have to call it as a function
light.setBrightness(75); // We have to call it as a function
This approach is clunky. From the perspective of the person using your class, they have to remember that brightness isn't a property—it's a set of functions. It breaks the intuition of how objects usually work in JavaScript.
Using the get and set keywords to treat methods like properties
JavaScript allows us to define "accessor properties." By using the get and set keywords, we can execute logic behind the scenes while the outside world thinks they are just accessing a simple variable. This is the real power of getters and setters.
class SmartLight {
constructor(brightness) {
this._brightness = brightness;
}
// Now it's a getter!
get brightness() {
return `${this._brightness}%`;
}
// Now it's a setter!
set brightness(value) {
if (value < 0 || value > 100) {
console.error("Brightness must be between 0 and 100");
} else {
this._brightness = value;
}
}
}
const light = new SmartLight(50);
// Notice: No parentheses! It looks like a property.
console.log(light.brightness); // "50%"
// Notice: We use the assignment operator (=), not a function call.
light.brightness = 75;
console.log(light.brightness); // "75%"
light.brightness = 150; // "Brightness must be between 0 and 100"
Do you see the difference? The API is much cleaner. The user of the SmartLight class doesn't need to care that there is validation logic happening under the hood; they just assign a value to brightness.
Now, here is a critical warning that will save you hours of debugging: Never name the internal property the same as the getter/setter.
In my example, I used this._brightness (with an underscore) inside the setter, while the setter itself is named brightness. If I had written this.brightness = value inside the setter, the setter would call itself, which would call itself, and so on, until you hit a "Maximum call stack size exceeded" error. The underscore is a convention in the JS community to signal, "Hey, this is a private-ish variable, don't touch it directly from outside the class."
- Use
getwhen you want to format a value or calculate a property on the fly. - Use
setwhen you need to validate data before it's saved to the object. - Always use a different internal name (like
_variable) to avoid infinite recursion.
📋 Practical Task
Build a Temperature Converter Class
Create a class called Thermostat. The class should store the temperature internally in Celsius, but provide a way to interact with it in Fahrenheit.
- The constructor should accept an initial temperature in Celsius and store it in a property called
_celsius. - Create a getter called
fahrenheitthat converts the internal Celsius value to Fahrenheit (Formula:(Celsius * 9/5) + 32) and returns it. - Create a setter called
fahrenheitthat takes a Fahrenheit value, converts it back to Celsius (Formula:(Fahrenheit - 32) * 5/9), and updates the internal_celsiusproperty. - Add a safety check in the setter: if the Fahrenheit value provided is below -459.67 (absolute zero), log an error message and do not update the temperature.
Test your code: Instantiate the class with 25 degrees Celsius. Log the fahrenheit property to ensure it's 77. Then, set fahrenheit to 100 and log the internal _celsius to see if it updated correctly.
There are no comments for now.