Classes, prototype: Object-Oriented JavaScript

In this tutorial, we will learn class, prototype, and object-oriented JavaScript with the help of a simple example.

Okay, Let's Discuss What exactly we do in development?

  1. save data (store data).
  2. apply the functionality on data (run code).

Easy! So Why development is hard? There are lots of challenges in development some of them are -

  1. how to save millions of data?
  2. what about special privileges (like admin access)?
  3. Where is the functionality when I need it?
  4. How do we make sure the functionality is only used on the right data?
  5. How to add functionality ( new features)?
  6. AND AND How to make code efficient and performant?

With the help of OOP we are able to solve all these challenges! but what is OOP?

According to Wikipedia OOP is

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 attributes or properties), and code, in the form of procedures (often known as methods).!

Okay, let's learn and OOP in JavaScript with the help of a simple example. we are going to make a web app for a class of students to keep a record of their scores.

What data and functionality do we need for our app? does it depend on your business logic?

Okay for now in our app data we can take student names, roll numbers, and scores. In functionality, we can make a functionality that increments the score of students.

Okay we decided the data and functionality But what would be the best way to store this data and functionality together in one place?

Objects: with the help of objects we can store data and code(functions).

Cool now we decided data and functionality on data and we can store them so let's do it.

     let student1 = {
        name : "Vivek",
        rollnumber : "101",
        score : 0,
        incrementScore : function (score){
            score++;
        }
    }

Creating student2 using 'dot notation

     let student2 = {}; // creating an empty object 

    student2.name = "Gauri"; //assigning property using dot 
    student2.rollnumber = 102;
    student2.score = 0;
    student2.incrementScore = function(){
        student2.score++;
    }

Creating studet3 using Object.create()

    let student3 = Object.create(null);
    student3.name = "Ravindra";
    student3.rollnumber = 103;
    student3.score = 0;
    student3.incrementScore = function(){
        student3.score++;
    }

What alternative techniques do we have for creating objects? How you are going to make millions of users on our app? Aren't we repeating our code again and again for making new students?

what do we do if we want to repeat some code again and again? Obs, we use functions !! So Instead of creating objects by hand we can generate objects using function and return.

Solution 1 - Generating objects using a functions

     function studentCreator(name, rollnumber, score){
        const newStudent = {}; // create a new student

        newStudent.name = name; // assign property
        newStudent.rollnumber = rollnumber;
        newStudent.score = score;

        newStudent.incrementScore = function(){
            this.score++;   
        }

        return newStudent;  // return created object 
    }

    let student4 = studentCreator("Deepak", 104, 0);
    let student5 = studentCreator("Tinu", 105, 0);

    student4.incrementScore();

Problem with solution 1

Each time we create a new user we make space in our computer's memory for all our data and functions. But our functions are just copies. Not memory-efficient :(

Is there a better way? what about storing all useful functions (that apply to every object ) in a single place?

So we can store all useful functions in a single object and link this object to all new creating object

But how to make this link? ( proto property)

All objects have a proto property by default. Which defaults to linking to a big object - Object.prototype full of (somewhat) useful functions. This property can be modified by explicitly stating that it should refer to another prototype. We can modify this property using Object.create() method.

Solution 2: Using the prototype chain

     function studentCreator(name, rollnumber, score){
       /* creating new student and modifying 
           __proto__ property by passing another object in  argument */
        let newStudent = Object.create(UsefulFunctionStore);  
        newStudent.name = name;
        newStudent.rollnumber = rollnumber;
        newStudent.score = score;
        return newStudent;
    }

    let UsefulFunctionStore = {
        incrementScore: function(){
            this.score++;
        },
        nameChane: function(newName){
            this.name = newName;
        },  
       login: function(){
           console.log(`${this.name} successfully logged in !}`);
       }
    } 
    let student6 = studentCreator("tinu", "106", 0);
    student6.incrementScore();
    student6.nameChane("Tinu");

Problem with solution 2

whenever we call the studentCreator (constructor) function to generate an object we always create an object and return it.

Introduction to new keyword

Whenever we call studentCreator function to generate an object we always create an object and return it and a new keyword automates these two things

  1. create a new student object
  2. return new student object

Problem with new keyword

  1. But now new is automatically creating a new object then how we are going to refer to an auto-created object?
  2. and when we create an object we link our UsefulFunctionStore object but now how we are going to link it?

To understand this we have to understand the prototype

Statement: functions are both objects and functions. let's understand this by an example

     function addTwo(number){
         return number + 2;
     }
     addTwo.storeSomething = 5;
     console.log(addTwo.prototype); // {}  where is prototype object is ?
     console.log(addTwo.storeSomething); // 5

So All functions have a default property on their object version, ’prototype’, which is itself an object - to replace our UsefullFunctionStore object.

So with new keyword:

  1. we refer to our auto created object with this keyword
  2. and we replace our UsefulFunctionStore object with studentCreator.prototype object

Solution 3 - Using new keyword

    function StudentCreator(name, rollnumber, score){
        this.name = name;
        this.rollnumber = rollnumber;
        this.score = score;
    }

    StudentCreator.prototype.incrementScore = function(){
        this.score++;
    }

    StudentCreator.prototype.nameChange = 
    function(newName){
        this.name = newName;
    }

    let student7 = new StudentCreator("dinesh", 107, 0);
    student7.incrementScore();
    student7.nameChange("Dinesh");

NOTE 1: just to know when we call a function whether we have to use the new keyword or not. If we have to use the new keyword before calling the function. We make the first letter of the function name capital.

NOTE 2: As you can see this new keyword is completely different from c++ and java programming language

NOTE 3: when calling the StudenCreator function it creates an object and assigns some properties to the newly created object and returns the object because of that similar to other programming languages we call this function constructor function.

Problem with solution 3 (Introduction to class keyword):

In our newly created object, we are writing our shared methods separately from our object. (in StudentCreatoor.prototype object); So can we do it in JavaScript as well? yes with the help of class keyword we can do this

So we can see a class in javaScript is just a 'Syntactic Sugar' that allows putting our methods and property together

Solution 4: using class keyword

     class StudentCreator {
        constructor(name, rollnumber, score){
            this.name = name;
            this.rollnumber = rollnumber;
            this.score = score;
        }
        incrementScore(){
            this.score++;
        }
        nameChane(newName){
            this.name = newName;
        }
    }
    let student8 = new StudentCreator("maleena", 108, 0);
    student8.nameChane("Maleena");
    student8.incrementScore();

Wrapping Up

In javaScript to store data and code, we can use objects, and to create objects, again and again, we can use functions and with help of a prototype, we can save space.

As we can clearly see javaScript is not an OOP language as it performs prototyping in the background.

A big thanks to Frontend Masters I learned everything related to web development from Frontend Master courses.

Thanks For Reading my first Blog :)