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)
71: ES6 Classes
If you've been following along, you know that JavaScript is fundamentally based on prototypes. But let's be honest: writing prototype methods manually can feel clunky and visually messy. That's why ES6 gave us class. Now, it's important to realize that classes are mostly "syntactic sugar." They don't introduce a brand new object-oriented model to the language; they just give us a much cleaner way to write the prototype patterns we're already using.
Defining the blueprint for a SmartLight
Let's build something concrete. Imagine we're writing a system for a smart home. We need a way to create multiple light bulbs, each with its own state. Instead of creating a factory function, I'm going to use a class.
class SmartLight {
constructor(roomName, brightness = 100) {
this.roomName = roomName;
this.brightness = brightness;
this.isOn = false;
}
}
const kitchenLight = new SmartLight('Kitchen');
const bedroomLight = new SmartLight('Bedroom', 50);
console.log(kitchenLight.roomName); // 'Kitchen'
The constructor is where the magic happens. It's the special method that runs the moment you call new SmartLight(). I've set a default value for brightness just in case we don't provide one—it's a small touch that makes the class much more flexible.
Adding behavior with methods
A light that can't actually turn on or off isn't very useful. In a class, we don't need to put our methods inside the constructor. We just define them directly in the class body.
class SmartLight {
constructor(roomName, brightness = 100) {
this.roomName = roomName;
this.brightness = brightness;
this.isOn = false;
}
turnOn() {
this.isOn = true;
console.log(`The ${this.roomName} light is now on.`);
}
turnOff() {
this.isOn = false;
console.log(`The ${this.roomName} light is now off.`);
}
}
Fixing a common 'this' mistake
Here is where I usually trip up when I'm coding quickly. I wanted to add a toggle method to flip the light's state. I wrote it like this:
toggle() {
isOn = !isOn;
console.log(`Toggled light to ${isOn}`);
}
When I ran this, it crashed with a ReferenceError: isOn is not defined. Why? Because I forgot that inside a class method, you must use the this keyword to access the instance's properties. JavaScript doesn't automatically know that isOn refers to the property on the current object; it thinks I'm looking for a global variable named isOn.
Here is the corrected version:
toggle() {
this.isOn = !this.isOn;
console.log(`Toggled light to ${this.isOn}`);
}
Specializing our light with inheritance
Now, let's say we want a fancy light that can change colors. We don't want to rewrite the turnOn and turnOff logic. This is where extends comes in. We can create a child class that inherits everything from SmartLight but adds its own specific features.
class ColorLight extends SmartLight {
constructor(roomName, brightness = 100, color = 'white') {
// super() calls the constructor of the parent class (SmartLight)
super(roomName, brightness);
this.color = color;
}
changeColor(newColor) {
this.color = newColor;
console.log(`The ${this.roomName} light is now ${this.color}.`);
}
}
const livingRoomLight = new ColorLight('Living Room', 80, 'blue');
livingRoomLight.turnOn(); // Inherited from SmartLight
livingRoomLight.changeColor('red'); // Specific to ColorLight
Notice the super() call. If you're extending a class and adding a constructor, you have to call super() before you touch this. It tells JavaScript to run the parent's setup logic first, ensuring the object is properly initialized before the child class adds its own custom properties.
📋 Practical Task
Build a SmartThermostat with Temperature Limits
Your task is to create a class system for a smart home thermostat. Follow these requirements:
- Create a class called
SmartThermostat. - The
constructorshould accept aroomNameand aninitialTemp. - Add a method
setTemperature(newTemp)that updates the temperature and logs the change. - Create a child class called
AdvancedThermostatthat extendsSmartThermostat. - The
AdvancedThermostatshould have amaxTempproperty (set in its constructor). - Override the
setTemperaturemethod inAdvancedThermostatso that it refuses to set the temperature ifnewTempexceedsmaxTemp, logging a warning instead.
There are no comments for now.