JavaScript OOP Tutorial
Overview
JavaScript supports Object-Oriented Programming (OOP) principles through its prototype-based architecture. This tutorial will cover key concepts such as classes, objects, data abstraction, data encapsulation, polymorphism, and inheritance, providing step-by-step examples for each.
Four Pillars of Object-Oriented Programming
OOP languages adhere to four primary principles:
- Encapsulation: Combining data and methods within objects to ensure data security.
- Inheritance: Allowing classes to inherit properties and methods from parent classes, promoting code reuse and enabling method overriding.
- Polymorphism: Using the same function in different forms to reduce repetition and enhance code utility.
- Abstraction: Hiding complex implementation details to simplify usage.
Is JavaScript Object-Oriented?
To determine if JavaScript is object-oriented, we need to understand the difference between OOP and prototype-based programming.
- Object-Oriented Programming (OOP): Involves creating classes and instances (objects) from these classes.
- Prototype-Based Programming: Involves deriving objects from existing objects.
According to MDN Docs, prototypes allow JavaScript objects to inherit features from one another. JavaScript primarily employs prototype-based programming, and the class
keyword is syntactic sugar over prototypes, giving it an OOP-like appearance.
Creating Objects in JavaScript
In JavaScript, everything is an object. Arrays, functions, and even primitive values extend the functionality from prototype objects. Here are three ways to create objects:
Using an Object Literal
javascript
const student = {
first_name: 'Mary',
last_name: 'Green',
display_full_name: function() {
return `${this.first_name} ${this.last_name}`;
}
};
console.log(student.display_full_name()); // Output: Mary Green
Using an Object Constructor
javascript
function Student(first_name, last_name) {
this.first_name = first_name;
this.last_name = last_name;
this.display_full_name = function() {
return `${first_name} ${last_name}`;
};
}
const student1 = new Student("Mary", "Green");
const student2 = new Student("Lary", "Smith");
console.log(student2.display_full_name()); // Output: Lary Smith
Using Object.create()
Method
javascript
const student = {
first_name: 'Mary',
last_name: 'Green',
display_full_name: function() {
return `${this.first_name} ${this.last_name}`;
}
};
const student1 = Object.create(student);
student1.last_name = "Smith";
console.log(student1.display_full_name()); // Output: Mary Smith
No Traditional Classes in JavaScript
JavaScript is prototype-based and does not have traditional classes. The class
keyword introduced in ES6 is syntactic sugar for prototype-based inheritance.
Class and Object
Definition:
- Class: A blueprint for creating objects (instances). It encapsulates data for the object.
- Object: An instance of a class. It contains properties and methods defined by its class.
Example:
Using ES6 syntax, we can define a class and create objects from it.
javascript
class Student {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
displayFullName() {
return `${this.firstName} ${this.lastName}`;
}
}
// Creating instances of the Student class
const student1 = new Student('Mary', 'Green');
const student2 = new Student('Lary', 'Smith');
console.log(student1.displayFullName()); // Output: Mary Green
console.log(student2.displayFullName()); // Output: Lary Smith
Data Abstraction
Definition:
- Data Abstraction: The concept of hiding the complex implementation details and showing only the necessary features of an object.
Example:
Using private fields (introduced in ES2022) to hide internal details.
javascript
class Rectangle {
#width;
#height;
constructor(width, height) {
this.#width = width;
this.#height = height;
}
getArea() {
return this.#width * this.#height;
}
}
const rectangle = new Rectangle(10, 20);
console.log(rectangle.getArea()); // Output: 200
console.log(rectangle.width); // Output: undefined
Another Example of Data Abstraction:
class Bank{ #balance; //private variable constructor(pincode) { this.pincode = pincode; this.#balance = 10000; } credit(_amount) { if(this.login()) { this.#balance += _amount; } else { console.log('Invalid pincode'); } } debit(_amount) { if(this.login()) { if(this.#balance<_amount) { console.log('Insufficient balance'); return; } this.#balance -= _amount; } else { console.log('Invalid pincode'); } } login() { if(this.pincode===1234) { return true; } else { return false; } } get balance() { if(this.login()) { return this.#balance; } else { console.log('Invalid pincode'); } }}
const obj = new Bank(12345);obj.credit(5000);obj.debit(2000);console.log(obj.balance);
Data Encapsulation
Definition:
- Data Encapsulation: The bundling of data with methods that operate on that data. It restricts direct access to some of an object's components.
Example:
Encapsulating data using getter and setter methods.
javascript
class Circle {
constructor(radius) {
this._radius = radius;
}
get radius() {
return this._radius;
}
set radius(newRadius) {
if (newRadius > 0) {
this._radius = newRadius;
} else {
console.error('Radius must be positive');
}
}
getArea() {
return Math.PI * this._radius * this._radius;
}
}
const circle = new Circle(5);
console.log(circle.getArea()); // Output: 78.53981633974483
circle.radius = 10;
console.log(circle.getArea()); // Output: 314.1592653589793
circle.radius = -5; // Output: Radius must be positive
Polymorphism
Definition:
- Polymorphism: Poly means many and morphism means form, it provide same name method and operator to be used for multiple functionality. The ability to present the same interface for different data types. In JavaScript, this is often achieved through method overriding and interface implementation.
Example:
Overriding methods in derived classes.
javascriptclass Animal { makeSound() {
console.log('Some generic sound');
}
}
class Dog extends Animal {
makeSound() {
console.log('Bark');
}
}
class Cat extends Animal {
makeSound() {
console.log('Meow');
}
}
const animals = [new Dog(), new Cat(), new Animal()];
animals.forEach(animal => {
animal.makeSound(); // Output: Bark, Meow, Some generic sound
});
Inheritance
Definition:
- Inheritance: A mechanism where a new class inherits properties and methods from an existing class.
Example:
Creating a base class and extending it.
javascriptclass Vehicle { constructor(brand) {
this.brand = brand;
}
start() {
console.log(`${this.brand} is starting.`);
}
}
class Car extends Vehicle {
constructor(brand, model) {
super(brand);
this.model = model;
}
start() {
super.start();
console.log(`${this.brand} ${this.model} is ready to go.`);
}
}
const myCar = new Car('Toyota', 'Corolla');
myCar.start();
// Output:
// Toyota is starting.
// Toyota Corolla is ready to go.
Complete Tutorial Steps
Define a Class:
- Use the
class
keyword to define a class. - Add a constructor to initialize object properties.
- Define methods within the class.
- Use the
Create Objects:
- Use the
new
keyword to create instances of the class. - Access properties and methods using the dot notation.
- Use the
Implement Data Abstraction:
- Hide internal details using private fields.
- Provide public methods to interact with the hidden data.
Encapsulate Data:
- Use getter and setter methods to control access to properties.
- Validate data within setters to enforce rules.
Achieve Polymorphism:
- Override methods in derived classes to change behavior.
- Use the same method name in different contexts.
Apply Inheritance:
- Use the
extends
keyword to create a subclass. - Call the superclass constructor with
super
. - Override methods and add new ones in the subclass.
POST Answer of Questions and ASK to Doubt