Patterns for enforcing “new”

Recently I was looking around for a book on JavaScript Patterns. I decided to give the JavaScript Patterns by Stoyan Stefanov a try. If you have been looking for a book on Javascript Patterns, I highly recommend this book.

In the 3rd chapter, Literals and Constructors, I noticed this section on “Patterns for enforcing new” with the following entry:

When your constructor has something like this.member and you invoke the constructor without new, you’re actually creating a new property of the global object called member and accessible through window.member or simply member. This behavior is highly undesirable, because you know you should always strive for keeping the global namespace clean.

Take a look at the following code:


function Person(name) {
this.personName = name || "John";
}

var tammy = new Person("tammy");
console.log(typeof tammy); // Object
console.log(tammy instanceof Person); // true
console.log(tammy.personName); // tammy
console.log(window.personName); // undefined

var jason = Person("jason");
console.log(typeof jason); // undefined
console.log(jason instanceof Person); // false
console.log(window.personName); // jason


Eek! Thats not what I expected at all. So how can we force this to always create a new Object each time, regardless of whether or not the Object (“function”) has been called with new?

Solutions

There are a couple of solutions. We can either, change the scope of the internal variable to something other than “this” OR we can always force a “new” on the object.

Use “that”

If we change the function to create a new object called “that” and then assign personName to the new object, we can make sure that the global namespace isn’t polluted.


function Person(name) {
var that = {};
that.personName = name || "John";

return that;
}

var tammy = new Person("tammy");
console.log(typeof tammy); // Object
console.log(tammy instanceof Person); // false
console.log(tammy.personName); // tammy
console.log(window.personName); // undefined

var jason = Person("jason");
console.log(typeof jason); // Object
console.log(jason instanceof Person); // false
console.log(jason.personName); // jason
console.log(window.personName); // undefined


Well, that is much better. However, if we check whether or not “jason” or “tammy” are actually people we see that both fail. So while this gets us to the point of not polluting the global namespace we aren’t creating actual “people”.

Force “new”

We can actually check to see if “this” is an instance of Person, if not, returning a “new Person”.


function Person(name) {
if (!(this instanceof Person)){
return new Person(name);
}

this.personName = name || "John";

}

var tammy = new Person("tammy");
console.log(typeof tammy); // Object
console.log(tammy instanceof Person); // true
console.log(tammy.personName); // tammy
console.log(window.personName); // undefined

var jason = Person("jason");
console.log(typeof jason); // Object
console.log(jason instanceof Person); // true
console.log(jason.personName); // jason
console.log(window.personName); // undefined


Much better, now we actually have true instances of “Person”.

The good news in all of this is that in ECMAScript5 strict mode, this no longer applies. As the “this” reference will no longer point to the global namespace.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>