Hello! Today's journey ventures into the cornerstone of JavaScript's object-oriented fundamentals: Encapsulation. This concept establishes a protective barrier around an object's data, keeping it untouched by the external code ecosystem. Let's take a closer look:
- The importance of encapsulation: Delivering robust, versatile, and intuitive code.
- Private Data: How JavaScript protects certain data from external access.
- Getters and Setters: These are the tools that control data access and modification for the protection and abstraction of data.
Encapsulation fulfills a threefold role: it maintains integrity, controls data modification, and provides data abstraction — interfaces accessible to users. Think about using a cell phone — you interact with an interface without meddling with its circuits. Following this same logic, encapsulation safeguards the internal implementation while exposing safe interfaces.
Now, let's talk about Private Data: In JavaScript, due to the lack of native support, we simulate private
data by prefixing an underscore (_
) to variable names, indicating that direct access is not recommended. Let's illustrate this with a Car
class, introducing a private
attribute, _speed
:
JavaScript1class Car { 2 constructor() { 3 this._speed = 0; // private speed attribute 4 } 5}
In this class, _speed
is deemed private
— we shouldn't access it directly.
Getters and Setters are gatekeepers controlling access to private
data. In our Car
class, a getter function retrieves the _speed
attribute. In contrast, a setter function modifies it as follows:
JavaScript1class Car { 2 constructor() { 3 this._speed = 0; // Initialize speed as 0 4 } 5 6 get speed() { // Get current speed 7 return this._speed; 8 } 9 10 set speed(value) { // Update speed 11 // Speed should stay in the range 0 to 150 12 if (value < 0) { 13 this._speed = 0; 14 } else if (value > 150) { 15 this._speed = 150; 16 } else { 17 this._speed = value; 18 } 19 } 20}
These methods allow us to retrieve or set the car's speed safely.
With these concepts at hand, we can construct a Car
class that showcases encapsulation:
JavaScript1class Car { 2 constructor(model) { 3 this._model = model; // private model attribute 4 this._speed = 0; 5 } 6 7 get model() { // Getter for model 8 return this._model; 9 } 10 11 get speed() { // Getter for speed 12 return this._speed; 13 } 14 15 set speed(value) { // Setter for speed 16 // Speed should be between 0 and 150 17 this._speed = value < 0 ? 0 : (value > 150 ? 150 : value); 18 } 19}
And here is how we will use this class (note - when using get
/set
methods, we don't use parenthesis):
JavaScript1// Create a new Car instance 2let myCar = new Car("Toyota"); 3 4// `myCar.model` and `myCar.speed` call corresponding getter methods under the hood 5console.log(myCar.model); // Shows: "Toyota" 6console.log(myCar.speed); // Shows: 0 7 8// Attempt to set speed beyond its limit 9// `myCar.speed = ...` calls the setter method under the hood 10myCar.speed = 200; 11console.log(myCar.speed); // Shows: 150, speed limit is 150 12 13// Attempt to set negative speed 14myCar.speed = -10; 15console.log(myCar.speed); // Shows: 0, speed cannot be negative
The code above synergizes private
variables, along with getters and setters, encapsulating the inner workings of the Car
class.
Well done, vigilant traveler! By exploring encapsulation, you've delved deeper into JavaScript's object-oriented programming. Thanks to this lesson, your toolbelt now includes:
- An understanding of
private
data. - Knowledge of the roles of getters and setters.
Inscribe these lessons in your programming mind and continue your journey! Hands-on exercises await you — they offer practical experience and solidify your understanding of the concepts learned. Keep zooming along the path to becoming a JavaScript pro — the journey is worth it!