Question

I've spent a good bit of time developing simple widgets for projects in the following way:

var project = project || {};

(function() {

  project.elements = {
    prop1: val1,
    prop2: val2
  }

  project.method1 = function(val) {
    // Do this
  }

  project.method2 = function(val) {
    // Do that
  }

  project.init = function() {
    project.method1(project.elements.prop1)
    project.method2(project.elements.prop2)
  }
})()

project.init();

But I've started to change my format to the following:

function Project() {
  this.elements = {
    prop1: val1,
    prop2: val2
  }

  this.method_one(this.elements.prop1);
  this.method_two(this.elements.prop2);
}

Project.prototype.method_one = function (val) {
  // 
};

Project.prototype.method_two = function (val) {
  //
};

new Project();

Granted, these are silly examples so dont get wrapped around the axel. But what is the functional difference and when should I pick one or the other?

Was it helpful?

Solution

The first difference can be summarized as: this refers to the Instance of the class. prototype refers to Definition.

Let's say we have the following class:

var Flight = function ( number ) { this.number = number; };

So here we are attaching this.number to every instance of the class, and it makes sense because every Flight should have their own flight number.

var flightOne = new Flight( "ABC" );
var flightTwo = new Flight( "XYZ" );

In contrast, prototype defines a single property that can be accessed by all of the instances.

Now if we want to get the flight number, we can simply write the following snippet and all of our instances will get a Reference to this newly prototyped object.

Flight.prototype.getNumber = function () { return this.number; };

The second difference is about the way that JavaScript searches for a property of an object. When you are looking for Object.whatever, JavaScript goes all the way up to the main Object object (the object that everything else has inherited from), and as soon as it finds a match it will return or call it.

But that only happens for the prototyped properties. So if you have somewhere in the higher tiers this.whatever, JavaScript won't consider it as a match and will continue the search.

Let's see how it happens in reality.

First note that [almost] everything are Objects in JavaScript. Try this:

typeof null

Now let's see what is inside an Object (note the Uppercase O and . in the end). In Google Chrome's Developer Tools when you enter the . you will get a list of available properties inside that specific object.

Object.

Now do the same thing for Function:

Function.

You may notice the name method. Just go and fire it up and let's see what happens:

Object.name
Function.name

Now let's create a function:

var myFunc = function () {};

And let's see if we got the name method here as well:

myFunc.name

You should get an empty string, but that's okay. You should not get an Error or Exception.

Now let's add something to that god-like Object and see if we get it in other places as well?

Object.prototype.test = "Okay!";

And there you go:

Object.prototype.test
Function.prototype.test
myFunc.prototype.test

In all cases you should see "Okay!".

Regarding the pros and cons of each method you can consider prototyping as a "more-efficient" way of doing things, since it keeps a reference on every instance rather copying the whole property in each object. On the other hand it's an example of Tightly Coupling which is a big no-no until you can really justify the reason. this is quite more complicated since it's relevant to context. You can find a lot of good resources for free in the internet.

That all said, both ways are just language tools and it really depends to you and the problem you're trying to solve to pick what fits better.

If you need to have a property to be relevant to every instance of a class, then use this. If you need to have a property to function the same on every instance, then use prototype.

Update

Regarding your sample snippets, the first one is an example of Singleton, so it makes sense to use this within object body. You can also improve your example by making it modular like this (and you don't need to always use this as well).

/* Assuming it will run in a web browser */
(function (window) {
    window.myApp = {
        ...
    }
})( window );

/* And in other pages ... */
(function (myApp) {
    myApp.Module = {
        ...
    }
})( myApp );

/* And if you prefer Encapsulation */
(function (myApp) {
    myApp.Module = {
         "foo": "Foo",
         "bar": function ( string ) {
             return string;
         },
         return {
             "foor": foo,
             "bar": bar
         }
    }
})( myApp );

Your second snippet doesn't make that much sense because first you are using this and later you are trying to hack it with prototype, which doesn't work because this takes priority over prototype. I'm not sure what were your expectations from that piece of code and how it was working, but I highly recommend you to refactor it.

Update

To elaborate on this taking precedence on prototype I can show you an example and tell you how it can be explained, but I don't have any external resource to back it up.

The example is very simple:

var myClass = function () { this.foo = "Foo"; };
myClass.prototype.foo = "nice try!";
myClass.prototype.bar = "Bar";

var obj = new myClass;
obj.foo;     // Still contains "Foo" ...
obj.bar;     // Contains "Bar" as expected

The explanation is, as we know, this is relevant to the context. So it won't come to existence until the context is ready. When context is ready? When the new instance is being created! You should guess the rest now! It means that even though there is a prototype definition, but this makes more sense to take precedence because it's all about the new instance being created at that moment.

Licensed under: CC-BY-SA with attribution
scroll top