Table of content
Mastering JavaScript Classes: A Comprehensive Guide
November 7, 2024
Dive deep into the power of classes in JavaScript. Explore how to define classes, implement inheritance, utilize static methods and properties, and manage access control with private and protected members. This comprehensive guide will take your JavaScript object-oriented programming skills to the next level.
Deep Dive: Classes in JavaScript
JavaScript, being a prototype-based language, has traditionally used functions and prototype-based inheritance to create objects and implement inheritance. However, with the introduction of ES6 (ECMAScript 2015), JavaScript gained support for classes, which provide a more familiar and class-based object-oriented programming (OOP) syntax.
Defining a Class
The basic syntax for defining a class in JavaScript is:
class ClassName {
constructor(param1, param2, ...) {
// initializing properties
}
method1( /* parameters */ ) {
// method implementation
}
method2( /* parameters */ ) {
// method implementation
}
// more methods...
}
The class
keyword is used to define a new class. Inside the class, the constructor
method is a special method that is called when you create a new instance of the class using the new
keyword. The constructor is used to initialize the object's properties.
In addition to the constructor, you can define any number of methods within the class. These methods are available to all instances of the class.
Here's an example of a simple Person
class:
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
}
}
const john = new Person('John', 30);
john.greet(); // Output: Hello, my name is John and I'm 30 years old.
Inheritance
One of the key features of classes in JavaScript is their support for inheritance. Inheritance allows you to create new classes based on existing ones, inheriting their properties and methods.
To create a subclass that inherits from a parent class, you use the extends
keyword:
class Student extends Person {
constructor(name, age, grade) {
super(name, age);
this.grade = grade;
}
study() {
console.log(`${this.name} is studying.`);
}
}
const jane = new Student('Jane', 18, 'A');
jane.greet(); // Output: Hello, my name is Jane and I'm 18 years old.
jane.study(); // Output: Jane is studying.
In this example, the Student
class inherits from the Person
class. The Student
class has its own constructor
method that calls the constructor
of the Person
class using the super
keyword, and adds a grade
property. The Student
class also has its own study
method.
When you create a new Student
instance, it inherits all the properties and methods from the Person
class, as well as the new ones defined in the Student
class.
Static Methods and Properties
In addition to instance methods and properties (which are accessible on the object instances), classes in JavaScript also support static methods and properties. These are methods and properties that are accessible directly on the class itself, rather than on instances of the class.
class Math {
static PI = 3.14159;
static add(a, b) {
return a + b;
}
}
console.log(Math.PI); // Output: 3.14159
console.log(Math.add(2, 3)); // Output: 5
In this example, the PI
property and the add
method are both static, so they can be accessed directly on the Math
class, without creating an instance of it.
Static methods and properties are useful for providing utility functions or constants that are related to the class but don't necessarily need to be tied to a specific instance of the class.
Private and Protected Members
In addition to public members (properties and methods that are accessible from anywhere), classes in JavaScript also support private and protected members. These are members that are only accessible within the class or its subclasses, respectively.
To define a private member, you can use the #
prefix:
class BankAccount {
#balance = 0;
deposit(amount) {
this.#balance += amount;
}
withdraw(amount) {
if (amount <= this.#balance) {
this.#balance -= amount;
return true;
}
return false;
}
getBalance() {
return this.#balance;
}
}
const account = new BankAccount();
account.deposit(1000);
console.log(account.getBalance()); // Output: 1000
console.log(account.#balance); // Error: Private field '#balance' must be declared in an enclosing class
In this example, the #balance
property is private, and can only be accessed and modified through the deposit
, withdraw
, and getBalance
methods.
Protected members, on the other hand, are accessible within the class and its subclasses. To define a protected member, you can use a convention like a leading underscore (_
), although this is not enforced by the language.
class BankAccount {
_balance = 0;
deposit(amount) {
this._balance += amount;
}
withdraw(amount) {
if (amount <= this._balance) {
this._balance -= amount;
return true;
}
return false;
}
getBalance() {
return this._balance;
}
}
class CheckingAccount extends BankAccount {
withdrawFee = 5;
withdraw(amount) {
if (super.withdraw(amount + this.withdrawFee)) {
console.log(`Withdrew ${amount} with a $${this.withdrawFee} fee.`);
return true;
}
return false;
}
}
const account = new CheckingAccount();
account.deposit(1000);
account.withdraw(50); // Output: Withdrew 50 with a $5 fee.
In this example, the _balance
property is protected, and can be accessed and modified by the BankAccount
class and its subclasses, like the CheckingAccount
class.
Overall, classes in JavaScript provide a powerful way to create and manage complex object-oriented structures, with support for inheritance, static members, and access control.