WHAT IS OOP

OOP in JAVASCRIPT

All objects in JavaScript are linked to a certain prototype object.
The prototype object contains methods and properties that all the objects that are linked to that prototype can access and use. This behavior is usually called prototypal inheritance.

We can also say that objects delegate behavior to the linked prototype object. Behaviour == Methods.

Prototypal inheritance is also called delegation because technically, objects delegate their behavior to the prototype.

CONSTRUCTOR FUNCTION AND THE NEW OPERATOR

All the constructor functions begins with a capital letter.
An arrow function will actually not work as a function constructor, that's because it doesn't have its own this keyword.

What happens when the line "new Person('Jonas', 1991);" gets executed -
1) A new empty object is created.
2) Then afterwards the function is called and in this function call the this keyword will be set to this newly created object.
3) Then this newly created object is linked to a prototype.
4) Then the object that was created in the beginning is then automatically returned from the constructor function.

PROTOTYPES

Each and every function in JavaScript automatically has a property called prototype, this includes the construtor functions too.
Prototype is an object to which the actual object's child objects are linked.
Every object that's created by a certain constructor function will get access to all the methods and properties that we define on the constructor's prototype property. (eg - Person.prototype)
Here, Person.prototype is the prototype of jonas object.
We should never create methods inside constructor functions, it is a BAD PRACTICE. Instead we define it in the constructor functions prototype object.

PROTOTYPAL INHERITANCE AND THE PROTOTYPE CHAIN

The .prototype object of the constructor function has a property called .constructor, that points back to the Person function. Person.prototype.constructor === Person

Prototype chain is very similar to scope chain.
In the prototype chain whenever JavaScript can't find a certain property or method in a certain object, it's gonna look up into the next prototype in the prototype chain and see if it can find it there.

ES6 CLASSES

Classes in JS are just syntatic-sugar over constructor function method.
Classes are just functions, that's why we have the option between class expression and class declaration.
Classes are NOT hoisted.
Classes are first-class citizens. This means that we can pass them into functions and return them from functions.
Classes are executed in strict mode.

GETTERS AND SETTERS

Basically, getters and setters allow us to call object METHODS as object PROPERTIES.
These properties are common to all the objects in JS.
We call these properties, assessor properties, while the more normal properties are called data properties.

OBJECT.CREATE()

We can use Object.create() to manually set the prototype of an object, to any other object that we want.
SYNTAX - const objectName = Object.create(objectPrototype);

INHERITANCE BETWEEN CLASSES USING CONSTRUCTOR FUNCTION

We cannot just do "student.prototype = person.prototype", because it will set the student.prototype equal to person.prototype which we do not want. (See the diagram below)

INHERITANCE BETWEEN CLASSES USING ES6 CLASSES

We can set the prototype of an object by using the "extends" keyword. Also, note the use of super() method in the example below.

INHERITANCE BETWEEN CLASSES USING ES6 CLASSES

ENCAPSULATION

Encapsulation means to keep some properties and methods private inside the class so that they are not accessible from outside of the class.
The rest of the methods are exposed as a public interface, which we can also call API.

There are 2 reasons why we need encapsulation and data privacy.
First, is to prevent code from outside of a class to accidentally manipulate our data inside the class.
The second reason is that when we expose only a small interface so a small API consisting only of a few public methods then we can change all the other internal methods with more confidence. Because in this case, we can be sure that external code does not rely on these private methods. Therefore our code will not break when we do internal changes.

A property with an "_" in front of it is private by convention.

Fields are basically properties that will be in all the instances. They will get added directly to the instances and not in their prototypes.