General Assembly Logo

JavaScript Constructors

Prerequisites

Objectives

  • Attach attributes to a new object using the constructor function
  • Recall the cost of defining methods inside a constructor function

Preparation

  1. Fork and clone this repository.
  2. Change to the new directory.
  3. Install dependencies.
  4. Create and checkout a new branch, training

Similar Objects

Now that we're using objects to solve problems, it might make sense to have a way to make multiple objects with the same kind of format - an 'object factory', designed to construct objects of a particular type.

Suppose we had the following object describing a favorite comic book hero:

const batman = {
  name: 'Bruce Wayne',
  alias: 'The Bat-man',

  usePower: function() {
    return 'Spend money and hit people';
  },
};

And now we want another object describing a different hero:

const wonderWoman = {
  name: 'Diana Prince',
  alias: 'Wonder Woman',

  usePower: function() {
    return 'Deflect bullets with bracelets';
  },
};

Why is this not a good answer?

Because copy-and-paste reuse is one of the biggest sources of errors in software development.

Lab: Model a Hero

What features do batman and wonderWoman share? Remember to think about attributes and methods when you're modeling. Also take note of what differs between them.

Make a diagram of our Hero entity based on the above objects.

Constructors

JavaScript's answer to the copy-and-paste reuse problem is constructor functions. Constructor functions:

  • Always start with a capital letter (convention)
  • Are always used with the new keyword (self-enforced)

Bad things happen when you break these rules.

Let's make a Hero constructor function. We'll make use of the function to reduce duplication in our objects, while allowing the difference to vary by only defining the differences when we construct the new object.

const usePower = function () {
  return this._power;
};

const Hero = function (name, alias, power) {
  this.name = name;
  this.alias = alias;
  this._power = power;
  this.usePower = usePower;
};

It is conventional to use a leading underscore (_) on a property name to indicate to future developers that the property is not intended for direct access or assignment. Nothing in JavaScript enforces this convention, but developers should consider any property with a leading underscore private to object (not accessible from the outside).

const is just like let, except const will not let you re-assign a value to the same name.

const foo = 'bar';
foo = 'baz'; // explode!

What does my choice of const tell you about my expectations for constructor functions?

We defined a method inside the the Hero constructor, but doing that is a Bad IdeaTM. JavaScript allows it, but don't do it. We'll see the right way to achieve a near identical and preferred result shortly.

Now, let's create wonderWoman using the constructor function instead of an object literal:

const wonderWoman = new Hero('Diana Prince',
                           'Wonder Woman',
                           'Deflect bullets with bracelets');
//=> undefined

wonderWoman;
/* => { name: 'Diana Prince',
  alias: 'Wonder Woman',
  power: 'Deflects bullets with bracelets',
  usePower: [Function] }
  */

new, a JavaScript keyword, does the following, in order:

  1. creates an empty object ({})
  2. attaches the constructor function to the object as a property
  3. invokes the constructor function as a method on the object
  4. returns the object

A new object created this way is sometimes called an 'instance' of type Hero.

Lab: Refactor Object Literals Using Constructors

Refactor the run tracker code from the previous lesson to use constructor functions instead of copying properties between object literals.

Leave the methods out for now. We'll add them back shortly.

There are no tests for this (yet), but you can still use grunt nag to lint your code and look for syntax errors.

You should have at least two constructor functions when you've finished.

  1. All content is licensed under a CC­BY­NC­SA 4.0 license.
  2. All software code is licensed under GNU GPLv3. For commercial use or alternative licensing, please contact legal@ga.co.