Oop
Object-Oriented Programming (OOP) is a programming paradigm based on the concept of "objects," which can contain data and code: data in the form of fields (often known as properties or attributes), and code, in the form of procedures (often known as methods).
In JavaScript, OOP can be implemented using classes and objects, as I've described in the previous messages. However, it's important to note that JavaScript uses prototypal inheritance, which is different from the classical inheritance pattern found in many other programming languages.
Here are the main principles of OOP:
Encapsulation: Encapsulation is the bundling of data and the methods that operate on that data into a single unit, commonly referred to as an object. This restricts direct access to some of an object's components and can prevent the accidental modification of data. To achieve encapsulation in JavaScript, you use classes and the constructor keyword to bind data and methods.
class Car {
constructor(brand) {
this.carname = brand; // property
}
present() { // method
return 'I have a ' + this.carname;
}
}
Inheritance: This is a mechanism where you can to derive a class from another class for a hierarchy of classes that share a set of attributes and methods. You can use it to re-use, extend, or modify the attributes and behaviors that are defined in other classes. In JavaScript, you use the extends keyword to implement inheritance between classes.
class Model extends Car {
constructor(brand, mod) {
super(brand);
this.model = mod;
}
show() {
return this.present() + ', it is a ' + this.model;
}
}
Polymorphism: Polymorphism is a core concept in OOP that allows objects of different classes to be treated as objects of a common super class. It's the ability of different objects to respond in a unique way to the same method call. In JavaScript, polymorphism can be achieved using inheritance and method overriding. Here's an example that demonstrates polymorphism:
// A base class
class Animal {
speak() {
return 'Generic animal sound!';
}
}
// A derived class
class Dog extends Animal {
speak() {
return 'Woof!'; // This is a Dog's unique way to handle the 'speak' method
}
}
// Another derived class
class Cat extends Animal {
speak() {
return 'Meow!'; // This is a Cat's unique way to handle the 'speak' method
}
}
// A function that can work with any kind of animal
function triggerSound(animal) {
console.log(animal.speak()); // Doesn't need to know the type of animal to call the 'speak' method
}
// Creating instances
const myDog = new Dog();
const myCat = new Cat();
// The 'triggerSound' function doesn't need to know the type of animal to call the 'speak' method
triggerSound(myDog); // Outputs: Woof!
triggerSound(myCat); // Outputs: Meow!
// Here, 'triggerSound' is able to process objects of different types (Dog and Cat),
// and each type is able to respond to the 'speak' method call in its own way.
In this example, Dog and Cat both override the speak method provided by Animal, their superclass. The triggerSound function is an example of polymorphism where it can accept any object that has a speak method. It doesn't need to know whether the object is a Dog or a Cat, just that it can speak. So, when triggerSound calls speak on a Dog or Cat object, it makes the corresponding animal sound. This is polymorphism in action, where different classes have a different implementation of the same method.
Abstraction: Abstraction means hiding the complex reality while exposing only the necessary parts. It can be thought of as a form of data protection or secure data. JavaScript doesn't have traditional abstract classes, but you can achieve abstraction by using class constructors or by returning an object from a function.
Here's an example of how you might use these principles in a JavaScript program:
// Inheritance and Encapsulation
class Animal {
constructor(name) {
this.name = name; // Encapsulating properties
}
speak() { // Encapsulating method
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal { // Inheritance
speak() {
console.log(`${this.name} barks.`);
}
}
let dog = new Dog('Rex');
dog.speak(); // Output: Rex barks.
// Abstraction (not fully supported, but we can simulate)
function CreateAbstractAnimal() {
return {
abstractMethod() {
throw new Error("This is an abstract method!");
}
}
}
// Polymorphism (JavaScript's dynamic typing supports it inherently)
function doSomething(animal) {
animal.speak();
}
doSomething(new Animal('Cat')); // Output: Cat makes a noise.
doSomething(new Dog('Bulldog')); // Output: Bulldog barks.
In the example above, the Animal and Dog classes illustrate encapsulation and inheritance. The CreateAbstractAnimal function shows how you might simulate an abstract class in JavaScript, which is a part of the abstraction principle. The doSomething function is an example of polymorphism; it's a single function that can operate on any type of animal. This is possible because of JavaScript's dynamic typing system.