prototype

OOProgramming

Encapsulation: we group related variable and functions together adn this way we can reduce the complexity, now we can reuse these objects in different parts of a program or in different programs.

Abstraction: We hide the details and show only the essentials that required this techinque reduces complexity and also isolates the impact of changes in the code.

Inheritance: We can eliminate redundant code

Polymorphism: We can make each object method work differently


##Factory Function##
Factory Function is a function which returns an object
function createCircle(radius) {
return {
radius,
draw: function() {
console.log('draw');
}
};
}

const circle = createCircle(1); // here the Factory function returns a new object
circle.draw(); // draw

##Constructor Function##
function Circle(radius){
this.radius = radius;
this.draw = function (){
console.log('draw');
}
}
const circle2 = new Circle(1); // the new keyword will create an empty object and then Circle function will be called and using this it will create properties to that object. if you don't use the new keyword and just call the function, then it will create the properties on the global object called window.

##Primitives##
Numbers, String, Boolean, Symbol, undefined, null
##Objects##
Objects, Arrays, Functions

Primitives are copied by their value
Objects are copied by their reference

##private properties and private methods##
function Circle(radius){
this.radius = radius;
let defaultLocation = {x:0, y:0}; //making this a private prop with let keyword
let computeOptimumLocation = function(factor) { // private method
//...
}
this.draw = function() {
this.computeOptimumLocation(0.1);
console.log('draw');
};
}

###in closures the parent functions variables will stay even after completions of the closure function.

##getters and setters in objects##
Object.defineProperty(this, 'name', {
get: function() {
return name;
},
set: function(value) {
name = value;
}
});

circle.name = 'naresh';

Prototype is the concept of inheritance in javascript
basically every object has property called prototype where you can add methods and properties to it. And when you create other objects from this object the newly created object will auntomatically inherit the property of the parent. but not by including in its own property but instead it uses from it's parent prototype properties and methods. The way it works is when you call a particular method on an object it first looks at it's own properties to see if it's there if it's not there then it will look at it's parent and if it's find it there then it will execute it. so this way the objects are much ligter and doesn't carry all this methods with it.

For example if you carried a thousand objects, you won't have to include all of those methods. it's automatically available to you by prototype inheritance.

#### prototype ####

var Employee = {
  company: 'xyz'
}
var emp1 = Object.create(Employee);
delete emp1.company
console.log(emp1.company); // xyz

The output would be xyz. Here, emp1 object has company as its prototype property. The delete operator doesn't delete prototype property.

emp1 object doesn't have company as its own property. You can test it console.log(emp1.hasOwnProperty('company')); //output : false. However, we can delete the company property directly from theEmployee object using delete Employee.company. Or, we can also delete the emp1 object using the __proto__ property delete emp1.__proto__.company.


## Objec.freeze ##
Don't allow user to add any property on the object

let profile = { name: 'naresh' };
profile.age = '25' // don't allow the user to add/remove properties like this

solution
let profile = { name: 'naresh' };
Object.freeze(profile); // will not allow to add/remove or even change the existing properties
profile.age = 3;
console.log(profile); // will not have the age.

## Objec.seal ## // doesn't allow to add/remove prop but can update existing properties

## Object.defineProperty ##
we can define readonly properties in objects even you can have getters and setters.

let profile = { name: 'naresh' };
Object.defineProperty( profile, 'age', {
value: 3,
writable: false,
get: function() {
return name;
},
set: function(value) {
name = value;
}
});

##Call(), Apply() and Bind() methods##
------------------------------------------------
Call(), Apply() and Bind() methods can come in handy when setting the “this” value.
these are Function.prototype properties.

* “this” always refers to an object.
* “this” refers to an object which calls the function it contains.
* In the global context “this” refers to either window object or is undefined if the ‘strict mode’ is used.

var car = {
    registrationNumber: "GA12345",
    brand: "Toyota",

    displayDetails: function(){
        console.log(this.registrationNumber + " " + this.brand);
    }
}
The above will work perfectly fine as long as we use it this way:

car.displayDetails(); // GA12345 Toyota
But what if we want to borrow a method?

var myCarDetails =  car.displayDetails;
myCarDetails();
Well, this won’t work as the “this” will be now assigned to the global context which doesn’t have neither the registrationNumber nor the brand property.

The bind() Method
For such cases we can use the ECMAScript 5 bind() method of the Function.prototype property. This means bind() can be used by every single function.

var myCarDetails = car.displayDetails.bind(car);
myCarDetails(); // GA12345 Toyota
The bind() method creates a new function where “this” refers to the parameter in the parenthesis in the above case “car”. This way the bind() method enables calling a function with a specified “this” value.

What if we would like to pass a parameter to the displayDetails function? We can use the bind method again. The following argument of the bind() method will provide an argument to the function bind() is called on.

Let me rewrite the car object:

var car = {
    registrationNumber: "GA12345",
    brand: "Toyota",

    displayDetails: function(ownerName){
        console.log(ownerName + ", this is your car: " + this.registrationNumber + " " + this.brand);
    }
}
Example of passing arguments with bind():

var myCarDetails = car.displayDetails.bind(car, "Vivian"); // Vivian, this is your car: GA12345 Toyota
call() and apply() methods
Similar but slightly different usage provide the call() and apply() methods which also belong to the Function.prototype property.


# This time there is a car object without the displayDetails function, which is located in the global context.

var car = {
    registrationNumber: "GA12345",
    brand: "Toyota"
}

function displayDetails(ownerName) {
    console.log(ownerName + ", this is your car: " + this.registrationNumber + " " + this.brand);
}
We can use the apply() function:

displayDetails.apply(car, ["Vivian"]); // Vivian, this is your car: GA12345 Toyota
Or

displayDetails.call(car, "Vivian"); // Vivian, this is your car: GA12345 Toyota
Note that when using the apply() function the parameter must be placed in an array. Call() accepts both an array of parameters and a parameter itself. Both are great tools for borrowing functions in JavaScript.

bind(), call() and apply() functions can make your life easier when you need to set the value of ‘this’.