# Constructor in JS

## What is Constructor?

A constructor is a special type of `function` that is used to initialize an object when it is created. There are two types of constructors in Javascript based on syntax. The first one defined as a `function` and the second one defined via a constructor method in the `class`. In both cases, we use the `new` keyword to create a new instance of the object.

## Object Constructor Function

Default constructor in JavaScript. It existed before the introduction of the ES6 specification, i.e. before the introduction of `classes`, and of course it still exists and is used.

We use the following convention when creating a constructor:

1. When creating the name of a constructor function, we should start with a capital first letter.
    
2. We should use the `new` operator to call the created constructor.
    

Example:

```javascript
function Player() {
    this.nickname = 'Rambo',
    this.level = 1
}
```

We have created a constructor function called `Player`, for now without any parameters inside the parentheses. Additionally, inside the constructor, we assigned the `nickname` and `level` properties to the word `this`. And we have assigned default values for these properties (`Rambo`, `1`). The `this` keyword is an object that specifies a context (in this case the `Player()` context), and is used to refer to that context and assign values to its properties.

Constructor usage example:

```javascript
const newPlayer = new Player();
console.log(newPlayer); // Output: {nickname: 'Rambo', level: 1}
```

In the above example, a new instance of the `Player` object was created using the `new` operator, and we also assigned it to the `newPlayer` constant. The value of `newPlayer` is the same as `Player` because we did not pass any new values to the function constructor.

Now let's try to pass the data when calling a new instance of the function constructor. For this purpose, we must specify the parameters when creating the constructor.

```javascript
// Creating constructor function with two parameters
function Player(nicknameParam, levelParam) {
    this.nickname = nicknameParam,
    this.level = levelParam
}
const newPlayer = new Player('Terminator', 70);
console.log(newPlayer); // Output: {nickname: 'Terminator', level: 70}
```

In this example, we invoked a new instance of the constructor with two new arguments (`Terminator`, `70`) that were assigned to the `nickname` and `level` properties from the context of the `Player` object. These values were returned when `newPlayer` was called.  
Why are these values returned even though we don't see the `return` declaration there? Because the `return` declaration is added at the end by JavaScript, when the `new` operator is used and a new instance of the object is invoked.

```javascript
function Player(nicknameParam, levelParam) {
    // this = {}; <- creating empty object for context
    this.nickname = nicknameParam,
    this.level = levelParam
    // return this;
}
```

Therefore, it is important to use the `new` operator when creating a new object. Without it, JS will read the call as a `function` without a `return` declaration and return `undefined`.

```javascript
function Player(nicknameParam, levelParam) {
    this.nickname = nicknameParam,
    this.level = levelParam
    // no return statement
}
const newPlayer = Player('Terminator', 70);
console.log(newPlayer); // Output: undefined
```

## Class constructor

In the ES6 specification (ECMAScript 2015), `classes` were introduced into the JacaScript syntax, and it is possible now to use a constructor within them.  
Like `function constructor`, `class constructor` is a special method for configuring new objects, but now integrated into the class structure. This makes the syntax clearer and the constructor can e.g. access and use class features such as inheritance using the `super` keyword.

Below is the same example we already know, but using `class`:

```javascript
class Player {
    constructor(nicknameParam, levelParam) {
        this.nickname = nicknameParam;
        this.level = levelParam;
    }
}
const newPlayer = new Player('Terminator', 70);
console.log(newPlayer); // Output: {nickname: 'Terminator', level: 70}
```

Above we used the `classPlayer` and in it we defined a `constructor` with parameters and properties. Notice that now the constructor is created using the `constructor` keyword. To create a new instance of class, or more specifically the constructor of the `Player` class, we still use the `new` operator, and in this case we even have to, because JS requires it. If we do not do this, we will receive an error.

It is possible to omit the constructor when creating a class if we do not use any additional object initialization.

```javascript
class Player {
   nickname = 'Rambo';
   level = 1;
}
const newPlayer = new Player();
console.log(newPlayer); // Output: {nickname: 'Rambo', level: 1}
```

## Inheritance

As mentioned earlier, in ES6 classes introduce the possibility of inheritance, i.e. the ability to take over the entire functionality of the parent `class` and the possibility of adding additional classes.

For better understanding, I will explain it with an example:

```javascript
class PlayerInfo {
    constructor(nicknameParam, levelParam) {
        this.nickname = nicknameParam;
        this.level = levelParam;
    }

    getPlayerInfo() {
        return `Your character ${this.nickname} has level ${this.level}.`
    }
}
const newPlayerInfo = new PlayerInfo('Terminator', 70);
console.log(newPlayerInfo.getPlayerInfo()); 
// Output: Your character Terminator has level 70.
```

We have created a base `class` that takes two parameters `nicknameParam`, `levelParam` and has a `getPlayerInfo` function that returns text.

Now let's try to create another one that will inherit from the `PlayerInfo` class:

```javascript
class PlayerFullInfo extends PlayerInfo {
    constructor(nicknameParam, levelParam, activeSubscribtionParam) {
        super(nicknameParam, levelParam);    
        this.activeSubscribtion = activeSubscribtionParam;
    }
    getPlayerInfo() {
        const subsctibtion = this.activeSubscribtion ? 'active' : 'inactive';
        return `Your character ${this.nickname} has level ${this.level} 
        and your subscribtion is ${subsctibtion}.`;
    }
}
const newPlayerFullInfo = new PlayerFullInfo('Rambo', 20, true);
console.log(newPlayerFullInfo);
// Output: {nickname: 'Rambo', level: 20, activeSubscribtion: true}
console.log(newPlayerFullInfo.getPlayerInfo());
// Output: Your character Rambo has level 20 and your subscribtion is 
// active.
```

When creating a new `PlayerFullInfo` class, we used the `extends` keyword to indicate which class we will inherit from.  
Then we used the `super` keyword in the constructor properties to call the code from the constructor of the class we are extending. Additionally, we created the `getPlayerInfo()` method which, although it has the same name as in the `PlayerInfo` class, is overwritten and returned when `newPlayerFullInfo.getPlayerInfo()` is called.

## Why do we need a constructor?

By using a constructor function, you can easily create multiple objects with the same properties and behavior without having to manually set them for each object. We also gain benefits such as: encapsulation, inheritance, so our code becomes more reusable, consistent and easier to maintain.
