OOP: From Pseudo-classical class instantiation to Class instantiation
Tags: javascript, oop
Published: 2020-10-24 20:52:02

In this post, we will discuss how we can create objects in JavaScript. We will explore the traditional approach using **Pseudo-classical class instantiation** and will end with **Class instantiation** introduced in **ECMAScript 6**.

### Introduction to objects

Objects are key/value pairs to store information about an entity that we can to represent in our code. You can create an object using the curly braces `{}`, and you can add properties and methods using the **dot notation**.

```js
let employee = {};

// Properties
employee.name = 'Diego';
employee.position = 'Software Engineer';

// Methods
employee.program = function () {
  console.log(`${this.name} is programming!`);
};

employee.program(); // Result: Diego is programming!
```

### Functional instantiation

To create multiple objects we can use a **constructor function**. A **constructor function** encapsulates an object creation and it allows you to create multiple instances of the same object structure. 

Creating a constructor function to instantiate new objects follows the **functional instantiation** pattern.

```js
function Employee(name, position) {
  let employee = {};
  employee.name = name;
  employee.position = position;

  employee.program = function() {
    console.log(`${this.name} is programming!`);
  };

  return employee;
}

const employeeDiego = Employee('Diego', 'Software Engineer');
const employeeJuan = Employee('Juan', 'Sofware Architect');
```

### Functional instantiation with shared methods

Every time that we are creating a new instance of the Employee object we are creating, in memory, something like this:

```js
const employeeDiego = {
  name: 'Diego',
  position: 'Software Engineer',
  program: [Function],
};

const employeeJuan = {
  name: 'Juan',
  position: 'Software Architect',
  program: [Function],
};
```

We can observe that we are creating two objects that share the same functionality (`program`). If we are creating two objects we probably didn't see the memory impact, but if we are creating thousands of objects we are wasting memory to store every time the same functionality. To avoid this problem we can use **functional instantiation with shared methods**. 

```js
const employeeMethods = {
  program: function() {
    console.log(`${this.name} is programming!`);
  }
};

function Employee(name, position) {
  let employee = {};
  employee.name = name;
  employee.position = position;
  employee.program = employeeMethods.program;

  return employee;
}

const employeeDiego = Employee('Diego', 'Software Engineer');
const employeeJuan = Employee('Juan', 'Sofware Architect');
```

With this improvement we will creating, in memory, something like this:

```js
const employeeDiego = {
  name: 'Diego',
  position: 'Software Engineer',
  program: [Function: program],
};

const employeeJuan = {
  name: 'Juan',
  position: 'Software Architect',
  program: [Function: program],
};
```

In JS objects are passed as reference, so we only have created a single object that encapsulates the `program` function, and every instance of the `Employee` object access the same function in memory.

**Object.create**

We can improve our constructor function using `Object.create`.

```js
const employeeMethods = {
  program: function() {
    console.log(`${this.name} is progamming`);
  }
};

function Employee(name, position) {
  let employee = Object.create(employeeMethods);
  employee.name = name;
  employee.position = position;

  return employee;
}

const employeeDiego = Employee('Diego', 'Software Engineer');
const employeeJuan = Employee('Juan', 'Sofware Architect');
```

With this improvement, every time we create a new instance of the `Employee` object we will have, in memory, something like this:

```js
const employeeDiego = {
  name: 'Diego',
  position: 'Software Engineer',
};

const employeeJuan = {
  name: 'Juan',
  position: 'Software Architect',
};
```

If the created objects don't have the `program` method, how will it be possible to invoke it? Every time we invoke `employee.program()` will fail because the created object doesn't have that method. But we use `Object.create(employeeMethods)`, so every time we invoke the `program` method it will look it in the parent object (`employeeMethods`).

### Prototypal instantiation

In JavaScript, every function has a `prototype` property that references an object. This property allows us to share methods across all instances of a function.

```js
function Employee(name, position) {
  let employee = Object.create(employeeMethods);
  employee.name = name;
  employee.position = position;

  return employee;
}

console.log(Employee.prototype); // Employee {} 
```

So, we can use the `prototype` property to share the `program` function across all instances instead of using a separate `object`.

```js
function Employee(name, position) {
  let employee = Object.create(Employee.prototype);
  employee.name = name;
  employee.position = position;
}

Employee.prototype.program = function () {
  console.log(`${this.name} is programming`);
};

const employeeDiego = Employee('Diego', 'Software Engineer');
```

With this improvement, every time we create a new instance of the `Employee` object we will have, in memory, something like this:

```js
const employeeDiego = {
  name:  'Diego',
  position: 'Software Engineer',
};
```

And the `Employee.prototype` will look like:

```js
{
  program: [Function]
}
```

### Pseudo-classical class instantiation

Currently, we are using the `Object.create()` function to create a new object based on the prototype of a parent object, and then we `return` that created object. With the `new` keyword, we can merge the `Object.create()` and `return` functionality. The created object is called `this`.

```js
function Employee(name, position) {
  this.name = name;
  this.position = position;
}

Employee.prototype.program = function () {
  console.log(`${this.name} is programming`);
};

const employeeDiego = new Employee('Diego', 'Software Engineer');
```

This pattern is called **pseudo-classical class instantiation**. When we use the `new` keyword we are invoking the function constructor. If we don't add the `new` keyword, the function won't create the object and it will return `undefined`. 

### Class instantiation

With ECMAScript 6 a `class` keyword was added. The `class` keyword was introduced to create classes in popular OOP programming languages like Java, but it works as the **pseudoclassical class instantiation**.

```js
class Employee {
  constructor(name, position) {
    this.name = name;
    this.position = position;
  }

  program() {
    console.log(`${this.name} is programming!`);
  }
}

const employeeDiego = new Employee('Diego', 'Software Engineer');
```

*****

<span>Photo by <a href="https://unsplash.com/@aznbokchoy?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Lucas Benjamin</a> on <a href="https://unsplash.com/s/photos/abstract?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span>