Javascript: From Objects to Factory Functions And Modules | Hacker Noon

Author profile picture

@simandebvuShingirayi Innocent Mandebvu

Full Stack Software Developer | Django | LEMP | Rails | React & Redux

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.

Author profile picture

Read my stories

Full Stack Software Developer | Django | LEMP | Rails | React & Redux

Tags

The Noonification banner

Subscribe to get your daily round-up of top tech stories!

read original article here