Monday-Wednesday: Objects, Object Constructors & Prototype Copy

How to Organize your JavaScript code

Learning to organizing your code can be a tricky part in JavaScript. The reason isn’t that JavaScript is so much more complex than other languages. On the contrary, JavaScript is a forgiving language.

In other words, you don’t have to use specific patterns and data structures in your code like in other languages. For example if you want to make a simple button, you can do it in a couple of lines of code. However as the project progresses and becomes more complex it can become hard to maintain it, unless you organize your code. Having said that JavaScript is such a flexible language that the way you organize your code is up to you.

For many developers making decisions about design patterns can be really frustrating. So in the following topics we will a few of the most common design patterns that occur in modern JavaScript code. To be more specific we will discuss some pros and cons of each pattern and will give you a chance to practice using each pattern in a project.

The design patterns we will be covering are:

  • Plain Old JavaScript Objects and Object Constructors
  • Classes
  • ES6 Modules

As you go through these patterns you will learn some important concepts in JavaScript such as:

  • closure
  • prototypes
  • IIFEs
  • … much more

Let’s get started!!

Short Review

As we have already seen there are multiple ways to define objects. However in most cases, it is best to use the object literal syntax as follows:

const myObject = {
  someProperty: 'someValue!',
  anotherProperty: 74,
  "obnoxious property": function() {
    // do stuff!
 }
}

There are also 2 ways to get information out of an object: dot notation and bracket notation.

// dot notation
myObject.someProperty // 'someValue!'

// bracket notation
myObject["obnoxious property"] // [Function]

The method that you will use depends on context. In other words, dot notation is cleaner but it has a lot of limitations. For example, myObject."obnoxious property" won’t work because that property is a string with a space in it. Likewise we can’t use dot notation when we have variables. Let’s see the following example:

const myVariable = 'someProperty'

myObject.myVariable 
// this gives us 'undefined' because it's looking for a property named 'myVariable' in our object

myObject[myVariable] 
// this is equivalent to myObject['someProperty'] and returns 'someValue!'

Learning Objectives

  • Object constructor and how to instantiate the object.
  • this keyword.
  • new keyword.
  • Constructor vs factory function.

Objects as a Design Pattern

Grouping things into objects is one of the simplest ways to organize our code.

Take these examples from a ‘tic tac toe’ game:

// first example
const playerOneName = "john"
const playerTwoName = "mary"
const playerOneMarker = "X"
const playerTwoMarker = "O"

// second example
const playerOne = {
  name: "john",
  marker: "X"
}

const playerTwo = {
  name: "mary",
  marker: "O"
}

At first glance, the first example doesn’t seem so bad and it actually takes fewer lines to write than the second example where we are using objects. However the benefits of using objects are huge.

function printName(player) {
  console.log(player.name)
}

So if we want to print each player’s name we can’t do that using the first example setup. What we would have to do instead is to remember the correct variable name and then manually console.log it:

console.log(playerOneName)
console.log(playerTwoName)

Again, this might not seem that bad. However what if we want to print the winner’s name and we don’t know the winner?

function gameOver(winner){
  console.log("Congratulations!")
  console.log(winner.name + " is the winner!")
}

Let’s consider another example. Let’s say that we are making an online shopping site with a large inventory. In this case using objects to keep track of an item’s name, price, description and other things is the only way to go. Unfortunately, in this case it isn’t efficient to type out manually the contents of our objects.

For this reason we need a cleaner way to create our objects and thus we are using the object constructors!!

Intro to Object Constructors

Object constructors are basically functions. We use them in cases where we have a specific type of object that we need to duplicate.

function Player(name, marker) {
  this.name = name
  this.marker = marker
}

We use the keyword new to call the function.

const player = new Player('paul', 'X')
console.log(player.name) // 'paul'

We can also add functions to the objects as we do with the Object Literal method.

function Player(name, marker) {
  this.name = name
  this.marker = marker
  this.sayName = function() {
    console.log(name)
  }
}

const player1 = new Player('paul', 'X');
const player2 = new Player('kevin', 'O');
player1.sayName(); // logs 'paul'
player2.sayName(); // logs 'kevin'

Additional Resources

In this section you can find a lot of helpful links to other content. This is a supplemental material for you if you want to dive deeper into some concepts.


Intro to The Prototype

Prototype is an important concept in JavaScript objects. All JavaScript objects have a prototype. In simple words, the prototype is another object that the original object inherits from, which is to say, the original object has access to all of its prototype’s methods and properties.

Learning Objectives

  • What a prototype is and how it can be used.
  • Explain how prototype chains work.
  • Prototypal inheritance.
  • How to inherit methods and properties.
  • The basic do’s and don’t’s of prototypical inheritance
  • What Object.create does.

Since this is a very important concept please make sure to really understand it before you move on.

  1. This article is a straightforward introduction and demonstration of the concept. It also covers constructors again.. good time for a review! The important bits here, once you’ve covered the basics are ‘Prototype-based inheritance’ and the ‘Prototype chain’

  2. Watch this 8-minute quick introduction to the Prototype by Net Ninja:

  1. To go a bit deeper into both the chain and inheritance spend some time with this great article. Don’t skip the exercises at the end of the article! Important note: this article makes heavy use of __proto__ which is not generally recommended. The concepts here are what we’re looking for at the moment. We will soon learn another method or two for setting the prototype.

If you’ve understood the concept of the prototype then this next section about constructors will not be confusing at all!

function Student(name, grade) {
  this.name = name
  this.grade = grade
}

Student.prototype.sayName = function() {
  console.log(this.name)
}

Student.prototype.goToProm = function() {
  // eh.. go to prom?
}

If you’re using constructors to make your objects it is best to define functions on the prototype of that object. This means that a single instance of each function will be shared between all of the Student objects. In other words, if we declare the function directly in the constructor like we did when they were first introduced that function would be duplicated every time a new Student is created.

In simple examples like this one, that wouldn’t really matter much, but in a project that is creating thousands of objects, it really can make a difference.

Recommended Method for Prototypal Inheritance

Up until now we have seen several ways of making an object inherit the prototype from another object.

Having said that, the recommended way of setting the prototype of an object is Object.create ( here is the documentation for that method.) Object.create very simply returns a new object with the specified prototype and any additional properties you want to add. For our purposes you use it like so:

function Student() {
}

Student.prototype.sayName = function() {
  console.log(this.name)
}

function SeventhGrader(name) {
  this.name = name
  this.grade = 7
}

SeventhGrader.prototype = Object.create(Student.prototype)

const peter = new SeventhGrader("peter")
peter.sayName() // console.logs "peter"
peter.grade // 7

So what happens is that after creating the constructor for SeventhGrader we set it’s prototype to a new object that has a copy of Student.prototype.

Warning: The following doesn’t work:

SeventhGrader.prototype = Student.prototype

because it will literally set SeventhGrader’s prototype to Student.prototype (i.e. not a copy), which could cause problems if you want to edit something in the future.

Let’s see another example:

function Student() {
}

Student.prototype.sayName = function() {
  console.log(this.name)
}

function SeventhGrader(name) {
  this.name = name
  this.grade = 7
}

// don't do this!!!
SeventhGrader.prototype = Student.prototype

function NinthGrader(name) {
  this.name = name
  this.grade = 9
}

// noooo! not again!
NinthGrader.prototype = Student.prototype

NinthGrader.prototype.sayName = function() {
    console.log("HAHAHAHAHAHA")
}

const peter = new SeventhGrader("peter")
peter.sayName() //uh oh! this logs "HAHAHAHAHAHA" because we edited the sayName function!

If we had used Object.create in this example then we could safely edit the NinthGrader.prototype.sayName function without changing the function for SeventhGrader as well.

Additional Resources

In this section you can find a lot of helpful links to other content. This is a supplemental material for you if you want to dive deeper into some concepts.

  • This article from Lydia Hallie and this next video from Avelx explains the Prototype concept with graphics and simple language:

Student Approved Resource

Leave a Reply