Object Oriented Programming
Object-Oriented Programming is a programming paradigm that enables you to model and structure your code using objects and classes. JavaScript is not a full-fledged OOP language, but you can still leverage OOP's core principles to write cleaner and more maintainable code. There are four main pillars of Object-Oriented Programming:
Abstraction
Abstraction means hiding the complex implementation details and exposing only what is necessary. Even though JavaScript lacks interfaces or abstract classes, we can still achieve abstraction through other means.
One effective approach for implementing abstraction is to expose only the necessary methods and then, through this exposed method, invoke the private methods of the class. This strategy effectively conceals the underlying complexities, which is a fundamental aspect of abstraction.
class Auth {
constructor() {}
#validate() {
// Private method
}
#sendOnboardingEmail() {
// Private method
}
// Public method that calls private methods
signUp() {
this.#validate();
// Execute signUp functionality
this.#sendOnboardingEmail();
}
}
const auth = new Auth();
// Calls the public method, which, in turn, calls private methods
auth.signUp();
Encapsulation
When you search the internet for information about Abstraction and Encapsulation, you will likely come across numerous articles that sometimes present conflicting ideas. In my understanding, although abstraction and encapsulation are different concepts, they often complement each other. In the code block above, private accessors are utilized, enabling controlled access to the class, aligning with the principles of Encapsulation. Encapsulation promotes the idea of bundling data and the functions that operate on that data into a single, self-contained package. This encapsulated entity can control how the data is accessed, modified, or interacted with.
Even though Encapsulation is an OOP concept, it can be implemented without the use of classes and objects by utilizing Closures. A closure is a mechanism that enables an inner function to access the variables and parameters of its outer function, even after the outer function has completed its execution. Closures achieve encapsulation by packaging the actual code (the body of the function) along with the variables and parameters that the function can access during its execution. The exclusive method for accessing the encapsulated data is through the function.
function createCounter() {
let count = 0; // This variable is encapsulated within the closure.
function increment() {
count++; // The inner function can access the 'count' variable.
console.log(count)
}
return increment; // Return the inner function (closure).
}
const counter = createCounter();
Inheritance
When a class acquires the members and behaviors of its parent class, it is known as Inheritance. Inheritance provides code reusability and encourages modular design by breaking down a complex system into smaller, manageable components. When you need to make changes or updates to shared functionality, you can do so in the base class. These changes automatically apply to all derived classes, reducing maintenance efforts and ensuring consistency throughout your codebase.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`Hello, my name is ${this.name}, and I am ${this.age} years old.`);
}
}
// Create a derived class Student that inherits from Person
class Student extends Person {
constructor(name, age, studentId) {
super(name, age); // Call the parent class constructor using super
this.studentId = studentId;
}
study(subject) {
console.log(`${this.name} with student ID ${this.studentId} is studying ${subject}.`);
}
}
// Create instances of Person and Student
const person1 = new Person('Alice', 30);
const student1 = new Student('Bob', 25, '12345');
// Use the inherited methods
person1.sayHello();
student1.sayHello();
student1.study('Math');
Polymorphism
The term 'polymorphism' means having many forms. The concept of polymorphism enables us to perform different operations in various scenarios. In object-oriented programming languages such as C#, polymorphism is achieved through the use of interfaces and abstract classes, as well as through the use of virtual methods and overriding in inheritance. While JavaScript does not provide comprehensive support for polymorphism, we can still achieve it.
Polymorphism can be attained by using inheritance and by overriding the base class. You do not need to explicitly indicate that a method is being overridden since JavaScript uses a prototype-based inheritance model, and method overriding is accomplished simply by defining a method with the same name in a subclass. The new method in the subclass effectively replaces the method with the same name in the base class, allowing you to perform different actions in different scenarios, which aligns with the concept of polymorphism
class Transport {
constructor() {}
drive() {
console.log("Driving...");
}
fly() {
console.log("Flying...");
}
}
// Create a derived class Car that inherits from Transport
class Car extends Transport {
constructor() {
super();
}
// Overrides it's base implementation
fly() {
console.log("I am a car, I cannot fly");
}
}
const audi = new Car();
audi.fly();
Song of the day : Agalloch - Hawthorne Passage
Top comments (13)
From my personal experience in corporations and startups alike, using Javascript OOP on the frontend usually creates an unintentional mess of polymorphism. OOP is great, but it has it's uses, just like functional programming.
My understanding is, that you web development can greatly benefit from using OO principles. But currently I do not see much support for this idea.
Thank you for sharing your thoughts! I appreciate your perspective. I kind of agree with you that there is not much support for OOP on the frontend in the web dev world. However, there's always Angular and the older version of React, which implement OOP principles very well. Even on the backend, I have been able to write clean, modular code using Node.js.
Maybe you like to try out DML. I wrote this library to build fully reactive frontends.
DML does not force to use OOP, but it creates some prerequisites to write OOP code:
DOM elements are already objects, so there is not much to do for for the standard HTML-elements. But with DML, you can extend this concept to self generated objects, that are generated the same way as standard elements. Think of an image carousel, a complex input element or any UI-element, that contains more than one DOM element. On the DML homepage (which was generated using DML), there is this funny jell yfish-menue. This can be generated using one single line of code, all interactions fully encapsulated the a class.
The DML homepage is pretty fast, though the code is not much optimizes (no bundler used). Please do your own performance checks to see, if this could be an option for your projects. I´m just about to release a new version, but the core will be very similar, so it´s worth a try.
Thank you for the in-depth explanation. Your initial comment is much clearer to me now. I will definitely check out this library.
do you think oop is enough?
Hey Helina, thank you for your comment! Could you please elaborate on your question? Are you referring to its suitability for specific tasks, or do you have a particular concern about its limitations?
what im mean is that there are other programming paradigms, but the oop is the most famous so my question is, do i have to learn other paradigms besides oop or is it enough
In my opinion, once you are comfortable with OOP, you can start looking into functional programming, but it is not a necessity; however, it is always good to know. I have read that many features in the React ecosystem, such as state management in Redux, leverage functional programming principles.
If you look at the 2004 paper The Structure and Interpretation of the Computer Science Curriculum the educators involved found that students typically had an easier time starting with functional programming and then transitioning to class-based object-oriented programming.
Given my personal experience I have no trouble accepting that, given the amount of unlearning I had to do when moving from OO to FP (and beyond). This group of researchers eventually had to concede that a scheme-like language isn't ideal for all students which is why they created Pyret. And in their most recent efforts they don't focus on either FP or OO but on data: A Data-Centric Introduction to Computing (without falling back into structured programming; they also elaborate where Python falls short for their purposes).
James Coplien jokes that JavaScript is the only object-oriented language because the code actually manipulates objects directly while all the mainstream class-oriented languages only create objects via classes. In class-oriented languages an instance has a lifetime membership with its class and in most cases that membership significantly impacts its behaviour.
In JavaScript an object tracks its
constructor
but other than that aclass
is just a template for creating objects. After creation an individual object can be augmented in any number of ways (Monkey Patching) blurring its relationship to the creating class.From that view the term
object
is unfortunate. “Tables are the main (in fact, the only) data structuring mechanism in Lua, and a powerful one.”.I think I finally “get” JS objects
Taylor Hunt ・ May 30
Once plain JavaScript objects are simply viewed as key-value data containers and “functions are objects” is accepted as a convenience feature the Function-Oriented nature of JS emerges, especially when one considers its Scheme-y past.
Granted JavaScript is said to support object-oriented, imperative, and declarative (e.g. functional programming) styles but there are trade-offs to be considered.
The notion of a performance budget is something you would typically expect with embedded products, not necessarily something application-level developers would have to concern themselves with. Given the engineering behind products like TurboFan JavaScript is already faster than it has any right to be but it can't compare to native (though Static Hermes may change that).
Classes also interfere with tree-shaking. For this reason libraries like RxJS which started out as class-heavy ports of the C#/Java originals, now minimize their use of classes and limit the methods on those that remain to the absolute, bare minimum.
Keep in mind that today's mobile devices vary wildly in their performance characteristics and capabilities; so while the flagship devices keep improving, the average, commodity devices really aren't.
When faced with a similar reality with regards to gaming consoles in 2009 the gaming industry started moving from OO to Data-Oriented Design and embracing the Entities, Components, Systems (ECS) approach.
Note that often the contention that imperative or OO programming is “easier” is a result of the familiarity heuristic; subjectively we perceive whatever we already know (e.g. learned first) as “easier”—just because something is different doesn't mean it's difficult.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.