15

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?

  • I think your first code example will not work since project does not leave the scope. To use inheritance in JS you use prototyping. The first example is not meant to extend project, so reusability might be limited. – Aitch Feb 13 '15 at 21:37
  • Yeah I accidentally put the project declaration inside the function. Updated. – JDillon522 Feb 13 '15 at 21:40
  • same here. first example is static, second is object oriented. – Aitch Feb 13 '15 at 21:44
  • 1
    If you are using only ONE instance of object, then there is no reason whatsoever to use prototypal definition. And what you seem to need - is a module format - there is lot of options for that, see: addyosmani.com/writing-modular-js – c69 Feb 13 '15 at 22:47
  • 1
    First one for singleton pattern The second one for non-singleton (when 1 class can have many objects) – Kokizzu Feb 17 '15 at 9:02
6
+50

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.

| improve this answer | |
  • This is a partially epicly awesome answer! Can you edit it and go into further detail comparing and contrasting the two methods? Your first two paragraphs confuse me on which design method you're referring to. Your exercise is excellent! I never gave much thought to the power of prototyping like that. Can you also give a semi detailed case use example of when to use each method? Thanks again, this is great. – JDillon522 Feb 17 '15 at 14:09
  • @JDillon522 Glad to hear that. I will try to update it in the next hours! – 53777A Feb 17 '15 at 16:00
  • @JDillon522 Just did a quick update. Hope it will be more clear this time. – 53777A Feb 17 '15 at 18:21
  • @JDillon522 A little bit more about your sample snippets ... – 53777A Feb 18 '15 at 9:24
  • Nice singleton example. So I used this in the silly prototype example because this refers to its own properties, including its methods. I dont learn the best from reading about code, but more from looking at code. (MDN's bit on it, Object Playground (amazing), and a few others). Can you point to something that explains what you mean about "this takes priority over prototype"? I'd like to look into it more. – JDillon522 Feb 18 '15 at 13:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.