JavaScript's class syntax was introduced in ES6 (ES2015). Previously, object-oriented programming in JavaScript was primarily achieved using functions and prototypes. However, with the introduction of the class syntax, object-oriented programming has become more intuitive and clearly articulated.
Rationale and Advantages of Using Classes
- Intuitiveness: The class syntax in JavaScript is similar to classes in other object-oriented languages, making it more familiar and easier to understand for developers.
- Reusability: Leveraging classes and inheritance can significantly enhance code reusability.
- Modularity: The structure of the code can be managed in a more organized manner.
Basic Syntax
Declaring a Class
In JavaScript, a class is declared using the class keyword.
class Person {}
Initialization Using the Constructor Method
The constructor method is a special method called when an instance of a class is created. It allows for the initial state of the instance to be set.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
In the code above, the Person class possesses two attributes: name and age. When an instance of this class is created using the new keyword, the constructor method gets invoked, and the provided name and age are set to the instance.
const JohnDoe = new Person('John Doe', 25);
console.log(JohnDoe.name); // John Doe
Method Definition
Within a class, functions can be defined as methods. These methods can be invoked on instances of the class.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
introduce() {
console.log(`My name is ${this.name}, and I am ${this.age} years old.`);
}
}
Instance Methods vs. Static Methods
- Instance Methods: Methods that are invoked on instances of the class. The
introducemethod above is an example. - Static Methods: Defined using the
statickeyword, these methods are invoked on the class itself without creating an instance.
class Person {
static populationCount() {
console.log('There are billions of humans.');
}
}
Person.populationCount(); // There are billions of humans.
The earlier defined Person class's introduce method can be called as follows:
const JohnDoe = new Person('John Doe', 25);
JohnDoe.introduce(); // My name is John Doe, and I am 25 years old.
Static method populationCount can be directly invoked using the class name without creating an instance.
Person.populationCount(); // There are billions of humans.
Inheritance and Extension
In JavaScript, inheritance in classes denotes a mechanism where attributes and methods from an existing class are passed on to a new class. This promotes code reusability and facilitates the establishment of hierarchical relationships between classes.
Understanding the Concept of Inheritance
Inheritance in JavaScript classes is implemented using the extends keyword.
class Animal {
makeSound() {
console.log('Animal sound');
}
}
class Dog extends Animal {
}
By using inheritance, the child class inherits all the attributes and methods of the parent class. In the example above, the Dog class inherits all methods and attributes from the Animal class.
Code Reusability through Inheritance
Employing inheritance allows the definition of common logic or data structures in the parent class, while only adding unique features or attributes to the child class. This reduces code duplication, enhancing development efficiency and ease of maintenance.
Method Overriding
A child class can redefine a parent class method with the same name. This is known as method overriding. The overridden method replaces the original method from the parent class.
class Animal {
makeSound() {
console.log('Animal sound');
}
}
class Dog extends Animal {
makeSound() {
console.log('Bark');
}
}
const Fido = new Dog();
Fido.makeSound(); // Bark
Invoking Parent Methods Using the Super Keyword
The super keyword allows for the invocation of a parent class's method from within a child class.
class Dog extends Animal {
makeSound() {
super.makeSound();
console.log('Bark');
}
}
const Fido = new Dog();
Fido.makeSound();
// Animal sound
// Bark
Constructor Overriding
In derived classes, it is possible to override the constructor of the base class. However, if super is not invoked within the derived class's constructor, an error will occur.
By using the super keyword in the derived class's constructor, we can call the base class's constructor. This facilitates any necessary initialization operations in the base class.
class Animal {
constructor(name) {
this.name = name;
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
}
const doggy = new Dog('doggy', 'Poodle');
console.log(doggy.name); // doggy
console.log(doggy.breed); // Poodle
Access Modifiers
We'll delve into access modifiers used in JavaScript classes to restrict access to data and methods.
Public, Private, Protected
Access modifiers determine the accessibility of class members (attributes and methods). They help in preserving the encapsulation principle of object-oriented programming by concealing the internal implementation of a class or by allowing restricted access to specific members.
- Public: By default, all members are public, meaning they can be accessed from anywhere.
- Private: Members starting with a
#symbol or an underscore (_) are private and can only be accessed within the class. - Protected: Currently, JavaScript doesn't officially support the protected access modifier. However, using the underscore (
_) convention effectively emulates protected, implying that it can be accessed within the class and its subclasses.
Use of underscore (_) and # for Private Member Variables and Methods
class Example {
_protectedMember = "Can be used like protected.";
#privateMember = "This is a private variable.";
_protectedMethod() {
console.log("This method can be utilized as if it's protected.");
}
#privateMethod() {
console.log("This is a private method.");
}
}
Getter and Setter Methods
Getter and Setter methods encapsulate the operations of accessing and modifying an object's attributes. This ensures safe access to the object's internal data or executes specific logic.
Definition and Usage of Getter and Setter Methods
class Person {
constructor(name) {
this._name = name;
}
get name() {
return this._name;
}
set name(value) {
this._name = value;
}
}
const John = new Person("John");
console.log(John.name); // John
John.name = "Jane";
console.log(John.name); // Jane
Static Members
Static members belong to the class itself and not to any instance. They are used when creating attributes or methods shared across the class.
Defining Static Variables and Methods at the Class Level
class Math {
static PI = 3.141592;
static circleArea(radius) {
return this.PI * radius * radius;
}
}
console.log(Math.PI); // 3.141592
console.log(Math.circleArea(5)); // approximately 78.5398
Differences and Applications of Static Methods and Instance Methods
Static methods are invoked at the class level and are utilized when operations unrelated to any instance's specific state are needed. On the other hand, instance methods operate based on an object's internal state, accessing or modifying the object's data.
The myriad features related to classes in JavaScript effectively assist in implementing the object-oriented programming paradigm. Leveraging these features judiciously enhances the reusability, extensibility, and maintainability of code. It is hoped that you will harness the power of these robust JavaScript class features to conduct efficient programming.