Object Oriented Programming in JavaScript

In this blog, we take an in-depth look at JavaScript, a prototype-based procedural language that incorporates functional and object-oriented programming paradigms. We also explore how JavaScript uses the concepts of classes, objects, encapsulation, and inheritance, and learn about ES6 classes, function scope, closures, and prototypal inheritance.

GraphQL has a role beyond API Query Language- being the backbone of application Integration
background Coditation

Object Oriented Programming in JavaScript

JavaScript is a Prototype-based programming paradigm. It is not an OOP language. But it has support for it. It has the class keyword, which is just a syntactic sugar over prototypes. We actually create prototypes in javascript, and not classes. The class keyword is there to make javascript look like an OOP language.
Javascript uses objects and follows the principles of OOP, but it does this using pure functions, which is a property of the functional programming paradigm (FP). JavaScript follows both OOP and FP and is actually a procedural language.
Note:
JavaScript is not an object-oriented language. Neither is it completely a functional language. JavaScript is a prototype-based procedural language. It supports both functional and object-oriented patterns of programming.
There are four rules or main pillars of Object-oriented programming language. This defines how the data and actions associated with the data; are organized using code.

  • Classes
  • Objects
  • Encapsulations
  • Polymorphism
Classes in JavaScript

JavaScript is a prototype-based language, and it doesn't have classes in it. We define the templates for objects using constructor functions or prototypes.
But JavaScript does have support for the class keyword.

ES6 Classes

Let's look at the ES6 way of defining classes, using the class keyword and then we'll see how classes were defined traditionally.


//Defining the class
class Student{ 
  constructor(firstName, lastName) { 
  this.firstName = firstName,
  this.lastName = lastName
  getName = function() { 
    return '${firstName} ${lastName}' 
  }
}

// Creating instances using the "new" keyword
const student1 = new Student("Deep", "Singh"); 
const student2 = new Student("Rohan", "Roy");

This way, we create a class using the class keyword. Define constructor function and all the other data functions inside the class declaration function. Then we create instances for this class using the new keyword.

Traditional Way of Class Simulation

This is how classes were defined before JavaScript started supporting the class keyword. That is before ES6 came up.


function Student(firstName, lastName){ 
 this.firstName = firstName 
 this.lastName = lastName 
}
Student.prototype.getName = function() { 
  return '${this.firstName} ${this.lastName}' 
}
const student1 = new Student("Mary", "Green");
const student2 = new Student("Lary", "Smith"); ;
console.log(studentl.getName()); 
console.log(student2.firstName);

Object

An object is a data structure containing properties and methods. Consider a student. A student will have characteristics like name, roll number, and class, and he will perform an action, let's say, giving an exam. In object-oriented programming, these characteristics are called data variables. These actions are called data methods.

We create a class called Student and then create instances of this class. These instances are called Objects. Hence, an object is a real instance of a class. Class is nothing but a prototype/blueprint.

Object can be created in two ways in JavaScript:

  1. Using an Object Literal

//Defining object
let students = {
  first_name: 'Manish',
  last_name: 'Dube', 
  
  //method 
  getStudentDetail : function() { 
   return ("The name of the student is ${person.first_name}      ${person.last_name}")
  }


  //object within object :
  address : {
    address_linel: 'SK Road',
    address_line2: 'Powai',
    pincode: '400092',
    city: 'Mumbai',
    state: 'Maharashtra'
  }
}
console. log(person.getStudentDetail());
console.log(person.address.city);


Output : 
Manish Dube
Mumbai

  1. Using an Object Constructor: 

// using a constructor
function students(first_name, last_name) { 
  this.first_name = first_name; 
  this.last_name = last_name;
}
//creating new instances of person object 
let student1 = new students('Manish', 'Dube'); 
let student2 = new students('Michal', 'Mishra'); 

console.log(studentl.first_name);
console.log(`${student2.first_name} ${student2.last_name}`);


Output:
Manish
Michal Mishra

Encapsulation

Encapsulation puts the data variables and the data functions together inside a box. Encapsulation ensures that data can only be accessed using the data functions defined inside the class, and abstraction ensures that no one outside this encapsulated box can access it.
But, we already saw that there is no actual concept of classes in JavaScript. So, JavaScript implements encapsulation using two ways: Function Scope and Closures.
Let's discuss both of them with examples.

Function Scope

When we define a variable or a function inside the function, we can only access it from inside and not from outside the function. This can be one way of implementing abstraction. Look at the example below.


function printUserEmail() {
  const email= "abc@gmail.com";
  console.log("Access Email from inside: ", email);
}
// Calling the function which internally defines the email
printUserEmail(); 
// Trying to access email from outside the function which defines it 
console.log("Access Email from outside: ", email);

Output: 

The output for this code snippet says the right message when accessed from inside but throws an error when accessed from outside. Hence, the message is encapsulated.

Closures

We can create a function inside a function, and the inner function will be able to access the local variable defined inside the outer function. This is called closure.

Note: A closure is created every time a function is declared.


function sendEmail() {
   const email = "abc@gmail.com"
 
  const printEmail = function() {
     console.log("Accessing Email from inside: ", email);
  }
  printEmail();
}
// Calling the function which internally defines the message
sendEmail();

// Trying to access message from outside the function which defines it
console.log("Accessing Email from outside: ", email);

Output:

Again, the output says that creating a closure helps encapsulate and restrict the data access only to inside the function.

Inheritance

JavaScript lets objects inherit properties from parent objects or any other objects. It uses the concept of prototypal inheritance.

Prototype

JavaScript is a prototype-based language. The objects created here can inherit the properties and methods from other objects or their parent ones.

Let's create an object and console it.

We only defined the property name, age & mobile  to the user Object, but we can see a lot of other methods. We didn't define them! These methods are inherited from the parent object, i.e., the prototype for the object data structure. When we create the object user Object, we basically inherit all the properties object data structure.

In our next blog, we compare and contrast asynchronous programming in Dart and JavaScript, discussing their similarities and differences.

Hi, I am Manish Dube. I am a Javascript & Flutter developer with over 6 years of experience in software development. In my free time, I enjoy playing outdoor games and staying up-to-date with the latest developments in the tech industry.

Want to receive update about our upcoming podcast?

Thanks for joining our newsletter.
Oops! Something went wrong.

Latest Articles

Implementing feature flags for controlled rollouts and experimentation in production

Discover how feature flags can revolutionize your software deployment strategy in this comprehensive guide. Learn to implement everything from basic toggles to sophisticated experimentation platforms with practical code examples in Java, JavaScript, and Node.js. The post covers essential implementation patterns, best practices for flag management, and real-world architectures that have helped companies like Spotify reduce deployment risks by 80%. Whether you're looking to enable controlled rollouts, A/B testing, or zero-downtime migrations, this guide provides the technical foundation you need to build robust feature flagging systems.

time
12
 min read

Implementing incremental data processing using Databricks Delta Lake's change data feed

Discover how to implement efficient incremental data processing with Databricks Delta Lake's Change Data Feed. This comprehensive guide walks through enabling CDF, reading change data, and building robust processing pipelines that only handle modified data. Learn advanced patterns for schema evolution, large data volumes, and exactly-once processing, plus real-world applications including real-time analytics dashboards and data quality monitoring. Perfect for data engineers looking to optimize resource usage and processing time.

time
12
 min read

Implementing custom embeddings in LlamaIndex for domain-specific information retrieval

Discover how to dramatically improve search relevance in specialized domains by implementing custom embeddings in LlamaIndex. This comprehensive guide walks through four practical approaches—from fine-tuning existing models to creating knowledge-enhanced embeddings—with real-world code examples. Learn how domain-specific embeddings can boost precision by 30-45% compared to general-purpose models, as demonstrated in a legal tech case study where search precision jumped from 67% to 89%.

time
15
 min read