You can’t get very far in JavaScript without dealing with objects. They’re foundational to almost every aspect of the JavaScript programming language. In fact, learning how to create objects is probably one of the first things you studied when you were starting out. With that said, in order to most effectively learn about prototypes in JavaScript, we’re going to channel our inner Jr. developer and go back to the basics.

Objects are key/value pairs. The most common way to create an object is with curly braces {} and you add properties and methods to an object using dot notation.

let animal = {}
animal.name = 'Leo'
animal.energy = 10
animal.eat = function (amount) {
  console.log(`${this.name} is eating.`)
  this.energy += amount
}
animal.sleep = function (length) {
  console.log(`${this.name} is sleeping.`)
  this.energy += length
}
animal.play = function (length) {
  console.log(`${this.name} is playing.`)
  this.energy -= length
}

Simple. Now odds are in our application we’ll need to create more than one animal. Naturally the next step for this would be to encapsulate that logic inside of a function that we can invoke whenever we needed to create a new animal. We’ll call this pattern Functional Instantiation and we’ll call the function itself a “constructor function” since it’s responsible for “constructing” a new object.

Functional Instantiation

function Animal (name, energy) {
  let animal = {}
  animal.name = name
  animal.energy = energy
  animal.eat = function (amount) {
    console.log(`${this.name} is eating.`)
    this.energy += amount
  }
  animal.sleep = function (length) {
    console.log(`${this.name} is sleeping.`)
    this.energy += length
  }
  animal.play = function (length) {
    console.log(`${this.name} is playing.`)
    this.energy -= length
  }
  return animal
}
const leo = Animal('Leo', 7)
const snoop = Animal('Snoop', 10)

"I thought this was an Advanced JavaScript course...?" - Your brain It is. We’ll get there.

Now whenever we want to create a new animal (or more broadly speaking a new “instance”), all we have to do is invoke our Animal function, passing it the animal’s name and energy level. This works great and it’s incredibly simple. However, can you spot any weaknesses with this pattern? The biggest and the one we’ll attempt to solve has to do with the three methods - eatsleep, and play. Each of those methods are not only dynamic, but they’re also completely generic. What that means is that there’s no reason to re-create those methods as we’re currently doing whenever we create a new animal. We’re just wasting memory and making each animal object bigger than it needs to be. Can you think of a solution? What if instead of re-creating those methods every time we create a new animal, we move them to their own object then we can have each animal reference that object? We can call this pattern Functional Instantiation with Shared Methods, wordy but descriptive.

Functional Instantiation with Shared Methods

const animalMethods = {
  eat(amount) {
    console.log(`${this.name} is eating.`)
    this.energy += amount
  },
  sleep(length) {
    console.log(`${this.name} is sleeping.`)
    this.energy += length
  },
  play(length) {
    console.log(`${this.name} is playing.`)
    this.energy -= length
  }
}
function Animal (name, energy) {
  let animal = {}
  animal.name = name
  animal.energy = energy
  animal.eat = animalMethods.eat
  animal.sleep = animalMethods.sleep
  animal.play = animalMethods.play
  return animal
}
const leo = Animal('Leo', 7)
const snoop = Animal('Snoop', 10)

By moving the shared methods to their own object and referencing that object inside of our Animal function, we’ve now solved the problem of memory waste and overly large animal Objects.

#javascript #programming

A Beginner’s Guide to JavaScript’s Prototype
1.30 GEEK