Javascript object initialization
28 Apr 2013I was about to write this post since a long time ago, when I was talking with two of my friends at work. I was reading some Javascript code that they were writing and I’ve noticed they were writing “classes” like this:
function User(name) {
return {
greeting: function() {
return 'Hello, ' + name + '!';
}
}
}
User('Ford Prefect').greeting();
Objects in Javascript are basically a map (aka hash) of keys to values. A key that maps to a function can be considered a method, and a key that maps to a primitive type is what we call a public attribute (aka instance variable). This implementation works exactly like that, when we call User
it will return a map with a key (greeting
) that points to a function. In this case name
isn’t an attribute and greeting
can access its value because in Javascript the inner functions get access to all outer variables and arguments, that’s what’s called a closure.
While I understand that this is valid Javascript and it works, I knew you can also write it like this:
function User(name) {
this.name = name;
}
User.prototype.greeting = function() {
return 'Hello, ' + this.name + '!';
}
new User('Ford Prefect').greeting();
The ones that are more seasoned to traditional object oriented languages (e.g. Java, Python, Ruby) will recognize that the first function works like an object constructor, it receives a name
parameter and stores it in an instance variable. This “class” also has a “method” in its prototype that uses that instance variable to build the user’s greeting.
This implementation has some differences in comparison with the first one:
- name is a public attribute, it can be read and changed by any code external to that object;
greeting
is added to theUser
’s prototype;- we’re using
new
to initialize the object before callinggreeting
; - any method that we add to
User
’s prototype will be available to any existing or future instance ofUser
; - the object initialization is faster and the object consumes less memory when you create lots of instances of that class.
Regarding the memory consumption bit I’ve decided to run a quick experiment to prove it. You can find the two implementations here that you’ll run with the node.js runtime and below is a graph that compares the memory consumption outputs.
With that in mind I’d strongly suggest to use the patterns that Crockford shows in his text Private Members in JavaScript, following that you’ll get the benefits of prototype when dealing with public stuff and you can mix it with closures to make some values private in your implementation.