Constructors

Methods for instance creation (instantiation)

Let's review methods

Methods are messages that we send from Objects to other Objects. Let's start our review with looking at a familiar method of the String class. When we want to compare a String with another, regardless of case, one of our approaches is to use the toLowerCase method.

Let's say that we have a String variable named color:

if (color.toLowerCase() === "the colour out of space") {
  System.out.println("That is truly a strange color.");
}

Calling color.toLowerCase() is like saying, "Hey, color, can you give me a lowercase version of yourself?" Whether color holds the value "Purple", "purple", or "PuRpLe", it will respond "purple".

We refer to a method's response as it returning a value.


Information, Please

When a method needs additional information, we add method parameters to its definition.

Remember the split method of String? We passed it a String, indicating what we wanted to use as a delimiter to split it:

let str = "this, that, the other";
let pieces = str.split(", ");
console.log(pieces[1]); // prints "that"

This is the declaration of the split method. We say that it accepts a method parameter of type String, named separator:

String.prototype.split(separator)

If we didn't pass it the separator parameter, how would it know where to split?


John Hancock

The combination of the method name and parameter types is called its method signature. This is how JavaScript identifies which method we are calling. Also, the method signature allows JavaScript to determine whether a method is redefining another method (called overriding):

String.prototype.split(String regex)

Prototype

What is the prototype part in the middle? well JavaScript is a prototypal inheritance language. This means that when we inherit behavior from an Object we will inherit any methods that exist on the parent prototype.


Talking Back

Not all methods return something, but if they do return a response they must use the return statement.

A String is an abstraction representing a sequence of characters, so it contains an instance variable containing those characters. Lets look at how its replace method works:

String.prototype.replace(substr, newSubstr);

which we can call like this:

let str = new String("My name is Brian.");
str.replace("Brian", "Donny");
console.log(str); // prints: My name is Donny

Talking Back (continued)

String.prototype.replace(substr, newSubstr);

In order to replace a value in a String, a String looks at value and parses it looking for the specified substring (substr) and replaces it with a new substring (newSubstr).


Creating An Object

Object Oriented Programming is all about creating objects (instances of an Object) and communicating with those objects (calling methods). Objects contain instance variables that contain the state of an object, describing the object's attributes.

Let's say that we have a simple Parrot class that looks like this:

class Parrot {}

So, far when we have created an object and defined its state, we've done it something like this:

const myParrot = new Parrot();
myParrot.name = "Dewd";

Here, we've created an instance of the Parrot class named myParrot. myParrot has an instance variable named name with the value "Dewd".


A Flock of Parrots

San Francisco is just the right climate for parrots from Central/South America. Flocks of parrots that have escaped from owners or been let loose flock together on Telegraph Hill. Birds of a feather do truly flock together.

I recommend tracking down a flock sometime. They're wild (err... feral).


Creating lots of objects

Let's say we need to create a lot of parrots. There's a flock. That wouldn't be too difficult, given that our parrots only have a name right now, but if we started adding other attributes, this would become more and more difficult. We're developers, not typists. Also, it would be easy to forget to assign one or more attributes. So we can make it easier and less error prone by creating a method to create Parrot instances.


In Practice

Here's what we were doing before:

const myParrot = new Parrot();
myParrot.name = "Dewd";

Here's how we could create a method to do the same thing:

function createParrot(parrotName) {
  const p = new Parrot();
  p.name = parrotName;
  return p;
}

And here's how we would call it:

const myParrot = createParrot("Dewd");

But that still seems like a lot of work?

Luckily, there's a cleaner way. Remember that constructor we've been calling?

const p = new Parrot();

We call this a constructor because it constructs an instance of the class.


But there's no constructor in my class!

This constructor is what is known as a default constructor. If we haven't explicitly defined a constructor for our class, the runtime environment creates a constructor for us that doesn't accept any arguments and does basic instance construction. That's why we don't see the constructor in our class.

The constructor that the browser nicely creates for us if we have not explicitly declared one looks like this:

constructor() {
}

Note that it has no return statement and we call it with the convenient name constructor.


We have the technology

When we want to initialize attributes of an object, we create our own constructor that accepts parameters, just like methods that accept parameters.

Remember our createParrot method?

function createParrot(String parrotName) {
  const p = new Parrot();
  p.name = parrotName;
  return p;
}

We can (and should) move this work into the constructor for the class. Here is our Parrot class with an equivalent constructor:

class Parrot {
  constructor(parrotName) {
    this.name = parrotName; // saying this.name will create an instance variable for us
  }
}

We can construct it

Once we've created our constructor, instead of this:

const myParrot = createParrot("Dewd");

we can do this:

const myParrot = new Parrot("Dewd");

This is cleaner, more expressive, and moves the responsibility of construction to the Parrot class, where it belongs.


Now write this method

party parrot