What is it?
In JavaScript, object-oriented programming (OOP) is a programming paradigm that is based on the concept of "objects", which can contain data and code that manipulates that data, the OOP programming paradigm is fundamental to many languages and not limited to javascript alone and going forward I will be explaining the (OOP) programming paradigm using JavaScript while covering few terms like classes and instance, Inheritance, Encapsulation, Polymorphism and Abstraction with code samples demonstrating each term.
Classes and instances
Objects are created from "classes", which are templates that define the properties and behaviours of objects.
JavaScript uses prototypal inheritance, which means that objects can inherit properties and behaviours from other objects. This is different from classical inheritance, which is used in languages like Java and C++.
In JavaScript, a class is a blueprint for creating objects. It defines the properties and methods that will be available on the objects that are created from the class.
Here is an example of a simple class in JavaScript:
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
To create an object from a class, you can use the new
keyword followed by the class name. This is called instantiating the class.
// Instantiate the `Person` class
const person= new Person('Alice', 30);
The person
object is an instance of the Person
class. It has the properties and methods defined in the Person
class, as well as any additional properties or methods that you add to the object.
You can access and modify the properties of an instance using dot notation or bracket notation:
console.log(person.name(); // Output: "Alice");
person.age = 31;
console.log(person['age']); // Output: 31
You can also call the methods of an instance using dot notation:
person.greet(); // Output: `Hello, my name is Alice and I am 31 years old.
Inheritance
Inheritance is a concept in object-oriented programming that allows one class to inherit the properties and methods of another class. In JavaScript, inheritance is implemented using prototypes.
Here is an example of a base class and a derived class that inherits from the base class:
class Animal {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`Hello, I am ${this.name} the animal`);
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
bark() {
console.log('Woof woof!');
}
}
In the example above, the Dog
class is derived from the Animal
class. It inherits the name
property and the sayHello
method from the Animal
class. The Dog
class also has its own bark
method which is specific to instances of the Dog
class.
To create an instance of the Dog
class, you can use the new
keyword followed by the class name, just as you would with any other class:
const broxi = new Dog('Broxi');
You can access the inherited properties and methods using dot notation:
console.log(broxi.name); // Output: "Broxi"
broxi.sayHello(); // Output: "Hello, I am Broxi the animal"
You can also call the class-specific method using dot notation:
broxi.bark(); // Output: "Woof woof!"
Encapsulation
Encapsulation is a concept in object-oriented programming that refers to the bundling of data and methods that operate on that data within a single unit, or object. encapsulation is also used to hide the implementation details of a class from other objects and protect the internal state of an object from being modified by external code. In JavaScript, encapsulation is achieved through the use of classes and objects.
Here is an example of a class that uses encapsulation to protect the internal state of an object:
class BankAccount {
constructor(balance) {
this._balance = balance;
}
get balance() {
return this._balance;
}
set balance(amount) {
if (amount < 0) {
throw new Error('Cannot set balance to a negative amount');
}
this._balance = amount;
}
deposit(amount) {
this.balance += amount;
}
withdraw(amount) {
this.balance -= amount;
}
}
In this example, the BankAccount
class has a private property called _balance
that stores the balance of the account. The balance
getter and setter methods allow you to access and modify the balance, but they also include validation to ensure that the balance cannot be set to a negative amount.
To create an instance of the BankAccount
class, you can use the new
keyword followed by the class name:
const account = new BankAccount(1000);
You can access the balance using the balance
getter method:
console.log(account.balance); // Output: 1000
You can modify the balance using the balance
setter method, as long as you pass a valid amount:
account.balance = 500;
console.log(account.balance); // Output: 500
You can also use the deposit
and withdraw
methods to add or remove funds from the account:
account.deposit(250);
console.log(account.balance); // Output: 750
account.withdraw(100);
console.log(account.balance); // Output: 650
Polymorphism
Polymorphism is a concept in object-oriented programming that refers to the ability of a single object to take on multiple forms. In JavaScript, polymorphism is achieved through inheritance and method overriding.
Here is an example of polymorphism in JavaScript using inheritance and method overriding:
class Animal {
constructor(name) {
this.name = name;
}
makeSound() {
console.log('Some generic animal sound');
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
makeSound() {
console.log('Woof woof!');
}
}
class Cat extends Animal {
constructor(name) {
super(name);
}
makeSound() {
console.log('Meow meow!');
}
}
In this example, the Animal
class has a makeSound
method that is overridden by the Dog
and Cat
classes. This allows each class to have its own implementation of the makeSound
method, resulting in different behaviour when the method is called on an instance of each class.
To create an instance of one of the derived classes, you can use the new
keyword followed by the class name, just as you would with any other class:
const broxi = new Dog('Broxi');
const angus = new Cat('Angus');
You can call the makeSound
method on each instance to see the polymorphic behaviour:
broxi.makeSound(); // Output: "Woof woof!"
angus.makeSound(); // Output: "Meow meow!"
Abstraction
In JavaScript or any other programming language, abstraction refers to the act of representing essential features without including the background details or implementation. It allows you to focus on what the object does rather than how it does it.
There are several ways to achieve abstraction in JavaScript, including:
Functions: Functions can be used to abstract away complex logic and provide a simple interface for interacting with that logic.
Objects: Objects can be used to group related functionality together and provide a simple interface for accessing that functionality.
Classes: Classes provide a way to define objects with similar behavior and create instances of those objects. This allows developers to create reusable code and abstract away the details of object creation.
Modules: Modules allow developers to organize their code into self-contained units that can be imported and used in other parts of the application. This helps to abstract away the details of the implementation and make it easier to use and maintain the code.
Overall, abstraction is an important concept in JavaScript (and in programming in general) as it allows developers to create complex functionality in a way that is easy to use and maintain, and helps to improve the structure and organization of code.
An example of abstraction in JavaScript using functions:
function add(x, y) {
return x + y;
}
function subtract(x, y) {
return x - y;
}
function multiply(x, y) {
return x * y;
}
function divide(x, y) {
return x / y;
}
In the above example, the add
, subtract
, multiply
, and divide
functions provide a simplified interface for performing basic arithmetic operations. The implementation details of these operations are abstracted away, and the functions can be used without the user needing to know how the operations are actually performed.
An example code showing abstraction in play using objects:
const calculator = {
add(x, y) {
return x + y;
},
subtract(x, y) {
return x - y;
},
multiply(x, y) {
return x * y;
},
divide(x, y) {
return x / y;
}
};
// Use the calculator object
console.log(calculator.add(2, 3)); // 5
console.log(calculator.subtract(5, 2)); // 3
console.log(calculator.multiply(4, 2)); // 8
console.log(calculator.divide(9, 3)); // 3
In the example above, the calculator
object provides a simplified interface for performing arithmetic operations. The implementation details of these operations are encapsulated within the object, and the object's methods can be used without the user needing to know how the operations are actually performed.
Below is an example of abstraction in JavaScript using modules:
// File: math.js
export function add(x, y) {
return x + y;
}
export function subtract(x, y) {
return x - y;
}
export function multiply(x, y) {
return x * y;
}
export function divide(x, y) {
return x / y;
}
// File: main.js
import * as math from './math';
console.log(math.add(2, 3)); // 5
console.log(math.subtract(5, 2)); // 3
console.log(math.multiply(4, 2)); // 8
console.log(math.divide(9, 3)); // 3
In this example, the math
module exports a set of functions that provide a simplified interface for performing arithmetic operations. The implementation details of these operations are encapsulated within the module, and the functions can be imported and used without the user needing to know how the operations are actually performed.
Modules provide a way to organize code into self-contained units that can be imported and used in other parts of the application, which helps to improve the structure and organization of the code and abstract away the details of the implementation.
The snippet below is an example of abstraction in JavaScript using classes:
class Calculator {
add(x, y) {
return x + y;
}
subtract(x, y) {
return x - y;
}
multiply(x, y) {
return x * y;
}
divide(x, y) {
return x / y;
}
}
const calc = new Calculator();
console.log(calc.add(2, 3)); // 5
console.log(calc.subtract(5, 2)); // 3
console.log(calc.multiply(4, 2)); // 8
console.log(calc.divide(9, 3)); // 3
In the example above, the Calculator
class defines a set of methods that provide a simplified interface for performing arithmetic operations. The implementation details of these operations are encapsulated within the class, and instances of the class can be created and used without the user needing to know how the operations are actually performed.
Classes provide a way to define objects with similar behavior and create instances of those objects, which allows developers to create reusable code and abstract away the details of object creation.
Thank you for finding time to read and I hope the article did shed light on the topic for you feel free to leave questions in the comment