OOPs (Object Oriented Programming in Js)

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.

Normal Objects

Here we are repeating objects

const athlet1 = {
    name: "Muruga",
    weapon: "Vel",
    attack : function() {
        return `attack with: ${athlet1.weapon}`
    }
}        
const athlet2 = {
    name: "Thor",
    weapon: "Hammer",
    attack : function() {
        return `attack with: ${athlet2.weapon}`
    }
}
//Above Code is repeating

console.log( athlet1.attack() )
console.log( athlet2.attack() )

FACTORY FUNCTION - (function that create objects)

Instead of copy pasting above code, we can reuse in factory function. We avoid repeated code.

function createAthlet(name, weapon) {
    return {
        name : name,
        weapon : weapon,
        attack : function(){
            return `attack with: ${weapon}`
        }
    }
}
const muruga = createAthlet("Muruga", "Vel");
console.log( muruga.attack() )

const thor = createAthlet("Thor", "Hammer");
console.log( thor.attack() ) 

Taking the generic method object outside of the function (seperately)

In Above code the methods like attack will be same (Generic) to all. But this is going to copy on each createAthlet() function call.

For this luckly in Javascript, we can use "Prototypal inheritance"

//Now this is not generic
const genericFn = {
    attack : function(){
        return `attack with: ${this.weapon}`
    }
}

function createAthlet(name, weapon) {
    return {
        name : name,
        weapon : weapon,
    }
}

const muruga = createAthlet("Muruga", "Vel");
muruga.attack = genericFn.attack; //It places the method function, inside muruga object
console.log( muruga.attack() );

const thor = createAthlet("Thor", "Hammer");  
thor.attack = genericFn.attack;
console.log( thor.attack() );

Object.create()

The Object.create() static method creates a new object, using an existing object as the prototype of the newly created object.

const genericFn = {
    attack : function(){
        return `attack with: ${this.weapon}`
    }
}
//Object.create() - will create a link between these two blocks of code (It creates a prototype chain __proto__)

function createAthlet(name, weapon) {

    let newGenericFn = Object.create( genericFn ); //Creating a copy of the genericFn Object.
    // Object.create() creates "prototypal inheritance"

    //Adding properties inside the newly copied Object.
    newGenericFn.name = name;
    newGenericFn.weapon = weapon;

    return newGenericFn;

}

const muruga = createAthlet("Muruga", "Vel");
console.log( muruga.attack() );

const thor = createAthlet("Thor", "Hammer");
console.log( thor.attack() );

CONSTRUCTOR FUNCTION

However you wont see the Object.create() in most code bases.

'this' in Constructor function - Executes the constructor function with the given arguments, binding newInstance as the this context

function CreateAthlet(name, weapon) {
    this.name  = name;
    this.weapon = weapon;
}

const muruga = new CreateAthlet("Muruga", "Vel"); 
console.log( muruga ); //prints object

const thor = new CreateAthlet("Thor", "Hammer");
console.log( thor );
*/
/* Note: As a rule, all constructor functions should start with a capital letter to let other programmers know that you need to call the function with new keyword. */

FUNCTION CONSTRUCTOR

const CreateAthlet = new Function(
    'name', 
    'weapon',
    `this.name = name; this.weapon = weapon`,    
)

const keerthi_k = new CreateAthlet("K Keerthi", 'Badminton Bat');

const shinChan = new CreateAthlet("Shin Chan", 'Speech and Activity');

console.log(keerthi_k);
console.log(shinChan);

Using the "prototype" Property

Sometimes you want to add new properties (or methods) to all existing objects of a given type.

Sometimes you want to add new properties (or methods) to an object constructor.

The JavaScript prototype property allows you to add new properties to object constructors:
<p> id="demo"> </p>
-----------------------------------------
function Person(first, last, age, eye) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.eyeColor = eye;
}

Person.prototype.nationality = "English";

const myFather = new Person("John", "Doe", 50, "blue");
document.getElementById("demo").innerHTML =
"The nationality of my father is " + myFather.nationality; 
function Elf(name, weapon) {
    this.name = name;
    this.weapon = weapon;
    console.log('this', this)
}

Elf.prototype.attack = function() {
    return 'attack with' + this.weapon
}

const peter = new Elf('Peter', 'stones');
console.log(peter.attack());

const sam = new Elf('Sam', 'fire');
console.log(sam.attack());

console.log(peter.__proto__); //the prototype of peter constructor function