Javascript: From Objects to Factory Functions And Modules

Written by simandebvu | Published 2020/09/02
Tech Story Tags: javascript | object-oriented-design | functional-programming | es6 | ecmascript-6 | coding | tutorial

TLDR Javascript: From Objects to Factory Functions And Modules, we have a way of organizing our Javascript code. We use the constructor to create a constructor with Javascript. Constructors look just like normal regular functions. The only difference now is that you have to instantiate them with the new keyword. This explains why this explains why we have no classes in Javascript, we did not have classes before ES6. We saw that constructors, as an optional way of organising our code, also also serve as a factory function.via the TL;DR App

Objects

An object is an abstract data type that we create to mimic real-world items. Like pen and paper! In other programming languages, these are called classes but in Javascript, we did not have classes before ES6. Don't worry we will get there real quick! Objects would have properties (attributes) like ink colour and functions like a pen object will have a write function(method).
Objects serve as an awesome way to organise your Javascript code.
Creation of objects - Objects have parents too!
Besides the normal creating of objects, there are some things that happen during the object creation. Just like how you inherited attributes from your parents, objects get their attributes from their parent. The prototype. The difference is that there is only one prototype.
And now each object will have a prototype attribute. Like all humans have blood. The prototype will simply be another object that the newly created object will be able to access.
function Player(name, symbol) {
  this.name = name
  this.symbol = symbol
}

const playerX = new Player("Shingi", "X");

// playerX will have a prototype attribute
// playerX prototype will be from the parent constructor Player.prototype
// if we create using object literal like let playerY = GamePlayer{} then playerY.prototype will be from Object.prototype
Prototypes help with Inheritance - JS does not have the traditional inheritance type that we have in other programming languages. Meaning in the example above, by updating the `Player.prototype` all instances of Player like playerX will automatically have access to Player.prototype.
Let's continue with the code above and introduce another object GoodPlayer who will inherit from Player.
// Lets add something to Player Prototype
Player.prototype.sayHi = () => { console.log("HI!") } 

Player.prototype.sayBonjour = () => { console.log("BONJOUR!") } 

function GoodPlayer() {
  this.score = 1000;
}

// Lets make GoodPlayer inherit from Player 
// To do this we will set GoodPlayer's Constructor to Players's constructor

GoodPlayer.prototype = new Player("Shingi Prime", "M");
// Yes yes ideally the parent should take no parameters. But wheres the fun in that?
// remember how we just learnt how to make objects to either inherit from Object or any CustomObject?
//Look up if you forgot!

let t = GoodPlayer();
t.sayHi(); // Will work

Prototypes help out with the prototype's chain - If the property does not exist on any of the object’s prototype in its prototype chain, then the property does not exist and undefined is returned.
The recommended way to inherit & If no constructor
GoodPlayer.prototype = Object.create(Player.prototype)
Duplicating Objects
This is for those instances or situations in which you want more of that particular thing that you would have made in JS. For example, you want to create more player objects for that awesome game that you have been working on.
Fortunately, you do not have to copy and paste each time you want a new instance of an object. We use the constructor.
function Player(name, symbol) {
  this.name = name
  this.symbol = symbol
}

const playerX = new Player("Shingi", "X");
//playerX.symbol --> Shingi
Above is how you would create a constructor with Javascript. Now have fun and duplicate your players! BUT there's a problem. Constructors look just like normal regular functions. The only difference now is that you have to instantiate them with the new keyword.
This explains why
const playerX = new Player ("Shingi", "X") // This will work.

const playerX = Player("Shingi", "X")
// This will not work.
Yes, one word can change the world. Not only is that a potential bug in the making. Constructors violate the open/closed principle which states that an API should be open for extension but not modification. These, to me, are the biggest disadvantages to constructors.

Factory Functions

So we saw that constructors, as an optional way of also organizing our code - also have their disadvantages. Factory Functions have come to the rescue! FFs serve as also a way to ditch the new keyword.
Let's keep on with our Player!
const player = (name, symbol) => {
  const sayHello = () => console.log('hello!');
  return { name, symbol, sayHello };
};

const playerX = playerFactory('shingi', 'X');

console.log(playerX.name);//shingi
Yes, you don't need to say new! And they are much simpler to get up and running that working via prototypes.
Inheritance with Factory Functions
const Player = (symbol) => {
  const showSymbol = () => console.log(`my symbol is ${symbol}`)
  return {symbol}
}

const GoodPlayer = (symbol) => {
  // lets inherit!
  const {showSymbol} = Player(symbol)
//saySymbol is the unpacked return from Player
  const doSomethingBetter = () => console.log('Something Better')
  return {showSymbol, doSomethingBetter}
}

const playerX = GoodPlayer('X');
//playerX can also showSymbol!

Factory Functions Reloaded: The Module Pattern

ES6 introduced the module pattern which helps out in a major way when it comes to private variables and namespacing. A general rule of thumb is If you want one of that thing, use a module. If you want multiple instances - use a factory function.
Well, the Modules are a super complicated thing and grab a pen and paper because we are here for a while! Okay, I'm joking!
The module is just a factory function that is immediately invoked. Meaning that you move from this
const x = (()=>{ console.log("Hey!") })()

//This will make it immeadiately run. (Immeadiately invoked)
//IIFEs (Immeadiately Invoked Function Expressions) will run instantly as they are instantly evaluated by JS
//Meaning 1.toString() will not work but (1).toString will work
// Even though 1  and (1) are both an instanceof Number

Conclusion

Both objects and factory functions are awesome ways to organize your code. Both have their good parts and bad parts. ES6 Introduced classes as a way to minimise/reduce the complexity of the prototypes that are used if you decide to use prototypes.
A module is a modification/type of a factory function.

Written by simandebvu | Full Stack Software Developer | Django | LEMP | Rails | React & Redux
Published by HackerNoon on 2020/09/02