1024px-Flatirons_Winter_Sunrise_edit_2

Introduction

In this mini-series we are reviewing some of the various ways you can create objects in JavaScript.

Thus far we have covered the following patterns:

  • Constructor Pattern
  • The Prototype Pattern

And we will continue to cover these patterns as well:

  • The Constructor and Prototype Pattern
  • The Object.create() Pattern

The Constructor and Prototype Pattern

The benefit of this pattern is that it combines the strenths of both the Constructor and Prototype Patterns while also removing some of their weaknesses.

For example, let’s take the following C# code snippet. This code is similar to what we’ve seen in our previous posts.

[js] using System;</p>

<p>public class Skillet
{
public string Ingredient { get; set; }
public int Quantity { get; set; }</p>

<pre><code>public Skillet() {
this.Ingredient = &amp;amp;quot;sticks of butter&amp;amp;quot;;
this.Quantity = 2;
}

public Skillet( string ingredient, int quantity )
{
this.Ingredient = ingredient;
this.Quantity = quantity;
}

public virtual void fry()
{
Console.WriteLine( &amp;amp;quot;Frying &amp;amp;quot; + this.Quantity + &amp;amp;quot; &amp;amp;quot; + this.Ingredient );
}
</code></pre>

<p>}</p>

<p>public class BaconSkillet : Skillet {
public BaconSkillet() : base() {}</p>

<pre><code>public BaconSkillet( string ingredient, int quantity ) : base( ingredient, quantity ) {}

public override void fry()
{
base.fry();
Console.WriteLine( &amp;amp;quot;Frying &amp;amp;quot; + this.Quantity + &amp;amp;quot; crispy &amp;amp;quot; + this.Ingredient );
}
</code></pre>

<p>}</p>

<p>public class Runner
{
public static void Main()
{
Skillet genericSkillet = new Skillet();
genericSkillet.fry(); //Frying 2 sticks of butter</p>

<pre><code> BaconSkillet baconSkillet = new BaconSkillet( &amp;amp;quot;bacon strips&amp;amp;quot;, 4 );
baconSkillet.fry(); //Frying 4 bacon strips /n Frying 4 crispy bacon strips
}
</code></pre>

<p>}
[/js]

https://ideone.com/IE0CK

By using both the Constructor and Prototype Patterns in JavaScript we can achieve a result that is much better than just one of the patterns by itself.

The key difference we will use in the combination technique is to store the properties on the new object instance and to define the functions off of the prototype.

[js] function Skillet( ingredient, quantity ) {
this.ingredient = ingredient || &amp;quot;sticks of butter&amp;quot;;
this.quantity = quantity || 2;
}</p>

<p>Skillet.prototype.fry = function() {
console.log( &amp;quot;Frying &amp;quot; + this.quantity + &amp;quot; &amp;quot; + this.ingredient );
};</p>

<p>var emptySkillet = new Skillet(),
eggSkillet = new Skillet( &amp;quot;eggs&amp;quot; ),
hashBrownSkillet = new Skillet( &amp;quot;hash browns&amp;quot; ),
baconSkillet = new Skillet( &amp;quot;bacon strips&amp;quot;, 3 );</p>

<p>//Inherits both ingredient and quantity from prototype
emptySkillet.fry(); //Frying 2 sticks of butter</p>

<p>eggSkillet.fry(); //Frying 2 eggs</p>

<p>hashBrownSkillet.fry(); //Frying 3 hash browns</p>

<p>baconSkillet.fry = function() {
Skillet.prototype.fry.call(this);
console.log( &amp;quot;Frying &amp;quot; + this.quantity + &amp;quot; crispy &amp;quot; + this.ingredient );
};
baconSkillet.fry(); //Frying 4 bacon strips /n Frying 4 crispy bacon strips
[/js]

//[diagram i]?

[js] //Change the fry function on the prototype
Skillet.prototype.fry = function() {
console.log( &amp;quot;Frying up a FEAST of &amp;quot; + this.quantity + &amp;quot; &amp;quot; + this.ingredient );
};</p>

<p>//Will inherit ingredient &amp;amp; quantity property and new fry function off of the prototype
emptySkillet.fry(); //Frying a FEAST of 2 sticks of butter</p>

<p>//Will inherit quantity property and new fry function off of the prototype
eggSkillet.fry(); //Frying a FEAST of 2 eggs</p>

<p>//Only inherits new fry function, because the ingredient &amp;amp; quantity properties were overridden
hashBrownSkillet.fry(); //Frying 3 crispy hash browns</p>

<p>//Still calls overriden fry() method, but it calls the updated prototype fry method
baconSkillet.fry(); //Frying a FEAST of 4 bacon strips /n Frying 4 crispy bacon strips
[/js]

//[diagram j]?

By splitting out the data from the funcitonality it allows it allows us to have

Moving Function Declarations Inside the Contructor

Despite the benfits of combining these patterns, you still might not be comfortable with defining your functions outside your constructor. As we discussed in the first artice from this series we didn’t do that because it creates a new function for each object. However, if you really want to keep all of your code closed inside your constructor you could accomplish that by using the following technique.

[js] function Skillet( ingredient, quantity ) {
this.ingredient = ingredient || &amp;quot;sticks of butter&amp;quot;;
this.quantity = quantity || 2;</p>

<pre><code>if ( typeof this.fry != &amp;amp;quot;function&amp;amp;quot; ) {
Skillet.prototype.fry = function() {
console.log( &amp;amp;quot;Frying &amp;amp;quot; + this.quantity + &amp;amp;quot; &amp;amp;quot; + this.ingredient );
};
}
</code></pre>

<p>}</p>

<p>var eggSkillet = new Skillet( &amp;quot;eggs&amp;quot; ),
baconSkillet = new Skillet( &amp;quot;bacon strips&amp;quot;, 3 );</p>

<p>//Proves that each object is using the same fry method
console.log( eggSkillet.fry === baconSkillet.fry ); //true</p>

<p>eggSkillet.fry(); //Frying 2 eggs</p>

<p>baconSkillet.fry(); //Frying 4 bacon strips
[/js]

Protect Your Constructor From The Window Again

As we showed in the first article in the series, you could protect your constructor from being called without the “new” operator. We will keep the same code from the previous section where we moved the prototype function declaration inside the constructor.

[js] function Skillet( ingredient, quantity ) {
if ( this instanceof Skillet ) {
this.ingredient = ingredient || &amp;quot;sticks of butter&amp;quot;;
this.quantity = quantity || 2;</p>

<pre><code> if ( typeof this.fry != &amp;amp;quot;function&amp;amp;quot; ) {
Skillet.prototype.fry = function() {
console.log( &amp;amp;quot;Frying &amp;amp;quot; + this.quantity + &amp;amp;quot; &amp;amp;quot; + this.ingredient );
};
}
} else {
return new Skillet( ingredient, quantity );
}
</code></pre>

<p>}</p>

<p>var eggSkillet = Skillet( &amp;quot;eggs&amp;quot; ),
baconSkillet = new Skillet( &amp;quot;bacon strips&amp;quot;, 3 );</p>

<p>//Proof that we didn’t add the ingredient property to the window by accident
console.log( typeof window.ingredient === &amp;quot;string&amp;quot; ); //false</p>

<p>eggSkillet.fry(); //Frying 2 eggs</p>

<p>baconSkillet.fry(); //Frying 4 bacon strips
[/js]

You could argue that putting all this extra logic inside of the construction takes away from it’s simplicity and I agree with you on that point. I would think that most developers would know to call the “new” operator and if they aren’t, then that should be a good learning oportunity for them.

Overloading Your Constructor

What techniques are available in JavaScript to simulate overloading constructors in C# classes? Let’s take a look at a C# example and rewrite it in a semi-equivalent JavaScript version.

[js] using System;
using System.Collections.Generic;</p>

<p>public class Ingredient
{
public string Name { get; set; }
public int Quantity { get; set; }
}</p>

<p>public class Skillet
{
public List&amp;lt;Ingredient&amp;gt; Ingredients { get; set; }</p>

<pre><code>public Skillet()
{
this.Ingredients = new List&amp;amp;lt;Ingredient&amp;amp;gt;();
this.Ingredients.Add(new Ingredient { Name = &amp;amp;quot;sticks of butter&amp;amp;quot;, Quantity = 2 } );
}

public Skillet( string ingredient, int quantity )
{
this.Ingredients.Add( new Ingredient { Name = ingredient, Quantity = quantity } );
}

public Skillet(Ingredient ingredient) : this()
{
this.Ingredients.Add(ingredient);
}

public Skillet(List&amp;amp;lt;Ingredient&amp;amp;gt; ingredients): this()
{
this.Ingredients.AddRange(ingredients);
}

public virtual void fry()
{
foreach (Ingredient ingredient in this.Ingredients)
{
Console.WriteLine(&amp;amp;quot;Frying &amp;amp;quot; + ingredient.Quantity + &amp;amp;quot; &amp;amp;quot; + ingredient.Name);
}
Console.WriteLine(string.Empty);
}
</code></pre>

<p>}</p>

<p>public class Runner
{
public static void Main()
{
Skillet genericSkillet = new Skillet();
genericSkillet.fry(); //Frying 2 sticks of butter</p>

<pre><code> Ingredient hashBrowns = new Ingredient { Name = &amp;amp;quot;hash browns&amp;amp;quot;, Quantity = 3 };
Skillet hashBrownSkillet = new Skillet(hashBrowns);
hashBrownSkillet.fry(); //Frying 2 sticks of butter n Frying 3 hash browns

List&amp;amp;lt;Ingredient&amp;amp;gt; ingredients = new List&amp;amp;lt;Ingredient&amp;amp;gt; { hashBrowns, new Ingredient { Name = &amp;amp;quot;bacon strips&amp;amp;quot;, Quantity = 4 } };
Skillet baconSkillet = new Skillet(ingredients);
baconSkillet.fry(); //Frying 2 sticks of butter n Frying 3 hash browns n Frying 4 bacon strips

Console.ReadLine();
}
</code></pre>

<p>}
[/js]

It is important to know that there isn’t the concept of overloaded methods in JavaScript like there is in C#. JavaScript doesn’t have the idea of method signatures. You can basically send however many arguments and of whatever type to a function and it will accept them. So the trick is to check the arguments that are passed in and make sure they are what you expect.

The folllowing constructor code will check to make sure the ingredient and quanity arguments indeed have values and that the ingredient is a string and the quantity is a number. If that isn’t the case, then it checks to see if it is an object and will add that to the ingredients. Lastly, it checks to see if an array is passed to the constructor and appends the array to the ingredients. As you can imagine, I could have added many more checks to in this code, but I think this is sufficient to show you what kind of code you would need to write. I utilized some of the jQuery utility methods to make some of the type checking a little easier.

[js] function Skillet( ingredient, quantity ) {
this.ingredients = [ { name: &amp;quot;sticks of butter&amp;quot;, quantity: 2 } ];</p>

<pre><code>if ( ingredient &amp;amp;amp;&amp;amp;amp; typeof ingredient === &amp;amp;quot;string&amp;amp;quot; &amp;amp;amp;&amp;amp;amp;
quantity &amp;amp;amp;&amp;amp;amp; typeof quantity === &amp;amp;quot;number&amp;amp;quot; ) {
this.ingredients.push( { name: ingredient, quantity: quantity } );
} else if ( jQuery.isPlainObject(ingredient) ) {
this.ingredients.push( ingredient );
} else if ( jQuery.isArray(ingredient) ) {
this.ingredients = this.ingredients.concat( ingredient );
} else {
//Do nothing
}

if ( typeof this.fry != &amp;amp;quot;function&amp;amp;quot; ) {
Skillet.prototype.fry = function() {
console.log( &amp;amp;quot;Frying &amp;amp;quot; + this.quantity + &amp;amp;quot; &amp;amp;quot; + this.ingredient );
};
}
</code></pre>

<p>}</p>

<p>var emptySkillet = new Skillet(),
eggSkillet = new Skillet( &amp;quot;eggs&amp;quot;, 2 ),
hashBrowns = { name: &amp;quot;bacon strips&amp;quot;, quantity: 3 },
hashBrownSkillet = new Skillet( hashBrowns ),
baconSkillet = new Skillet( [hashBrowns, { name: &amp;quot;bacon strips&amp;quot;, quantity: 4 }] );</p>

<p>emptySkillet.fry(); //</p>

<p>eggSkillet.fry(); //</p>

<p>hashBrownSkillet.fry(); //</p>

<p>baconSkillet.fry(); //Frying 4 bacon strips
[/js]

Pros of This Technique

  • A constructor that accepts parameters
  • The data for each object uses sepearte memory, so when you change one object it does not affect another object’s data
  • You reuse the same prototype function definitions across objects.
  • Since the functionality is off of the prototype you can also override that behavior as well on a per object basis.

Cons of This Technique

*