views:

126

answers:

3

What are the technical reasons for using .prototype instead of declaring functions and members inside the object itself. It is easiest to explain with code examples.

What are the advantages of using:

RobsObject = function(data){
    this.instanceID = data.instanceID;
    this._formButton = document.getElementById('formSubmit_' + this.instanceID);
    if(this._formButton)
    {
        //set a click listener that
        //points to this._onSubmit, this._onSuccess, and this.onFailure
    }
};

RobsObject.prototype = {
    _onSubmit: function(type, args)
    {
        //make an ajax call
    },

    _onSuccess: function(type, args)
    {
        //display data on the page
    },

    _onFailure: function(type, args)
    {
        //show an alert of some kind
    },
};

As oppose to declaring your functions inside of the Object like:

RobsObject = function(data){
    this.instanceID = data.instanceID;
    this._formButton = document.getElementById('formSubmit_' + this.instanceID);
    if(this._formButton)
    {
        //set a click listener that
        //points to this._onSubmit, this._onSuccess, and this.onFailure
    }

    this._onSubmit = function(type, args)
    {
        //make an ajax call
    }

    this._onSuccess = function(type, args)
    {
        //display data on the page
    }

    this._onFailure = function(type, args)
    {
        //show an alert of some kind
    }
};

Thanks.

Edit: As many of you have pointed out my functions in the second code snippet should have 'this' in front of them in order to be public. So I added it. Just a mistake on my part.

+10  A: 

Everything declared in a constructor function's prototype is shared by all instances of that constructor function. If you define functions in the constructor function, then each instance gets its own copy of the function, which wastes memory (and could potentially cause problems if you compare properties between two instances later).

Also, in your example the functions declared in the constructor function are private to the scope of the function. They cannot be called as member methods on instances. For that you would need to assign them to properties of the object:

MyObject = functon() {
  // ...

  this.myMethod = function() {
    // ...
  };
}

Douglas Crockford has a good write-up of prototypical inheritance that is definitely worth checking out: Prototypical Inheritance in JavaScript.

UPDATE: Brief Prototype Summary

When you create a new object using a constructor function, the value of the function's prototype property is assigned as the new object's prototype object. (Yes, the names are confusing!) This is a lot like assigning a superclass in a class-based language (but not quite! Read Crockford's page!)

// MyObject constructor function:
MyObject = function() {
  this.a = 1;
}

// Define an object to use as a prototype.
var thePrototype = { b: 2 };

// Assign thePrototype as the prototype object for new instances of MyObject.
MyObject.prototype = thePrototype;

// Create an instance of MyObject.
var x = new MyObject();
// Everything in thePrototype is available to x.
console.log(x.b);

// x's prototype is a reference to thePrototype, so updating it affects x.
thePrototype.c = 3;
console.log(x.c);

// Setting properties on x always sets them *on x*, even if the property is
//  defined on the prototype:
x.b = 0;
y = new MyObject();
console.log(x.b);
console.log(y.b);
Annabelle
Thanks for the link and the info. If I understand your answer, would it be correct to say that .prototype properties/functions act similar to static functions in other languages?
Rob Lund
No, they act more like superclasses in a class-based language. If you want a static property or function, simply assign it to a property of the constructor: `MyObject = function() { /* ... / } MyObject.StaticMethod = function() { / ... */ };`
Annabelle
Oh, ok, that makes sense.
Rob Lund
+2  A: 

The answer is memory. If you put the members inside of the object itself, then EVERY instance of that object will contain (in memory) all members. If you use prototype, on the other hand, it only exists once, and all instances will access those members as if they were their own.

Gabriel McAdams
A: 

In the first case, an object constructed with new RobsObject() has the functions _onSubmit(), _onSuccess() as it's properties. They are so-called the public functions of the object.

In the second case, those functions are not properties of new RobsObject(). However, they would be visible to any of the 'public' functions (there aren't any, in your case). In effect, they are the private functions.

However, if you wrote your second snippet this way...

RobsObject = function(data){
    this.instanceID = data.instanceID;
    this._formButton = document.getElementById('formSubmit_' + this.instanceID);
    if(this._formButton)
    {
        //set a click listener that
        //points to this._onSubmit, this._onSuccess, and this.onFailure
    }

    this._onSubmit = function(type, args)
    {
        //make an ajax call
    }

    this._onSuccess = function(type, args)
    {
        //display data on the page
    }

    this._onFailure = function(type, args)
    {
        //show an alert of some kind
    }
};

the result is the same.

An important difference between these two conventions is that in the first method, you can't define private functions that can be shared between many public functions like you do in the second method. The Object literal used to define the prototype does not form closures like a function body.

For example,

function MyConstructor() {
    var myPrivate = function() {
    }

    this.myPublic1 = function() {
        myPrivate();
    }

    this.myPublic2 = function() {
        myPrivate();
    }

}

myPrivate() is a function that is visible to both public functions.

Chetan Sastry
The result of your first example is not actually the same as if you used a prototype object. Methods declared within the constructor consume additional memory and processing time for each instance of the object. The upside, however, is in your first example, the methods would have access to private methods (as declared in your 2nd example). Methods on the prototype would not.
Annabelle
Hmm. I see. Consequently, I think object creation would also be slightly slower in addition to extra memory if there is a large constructor function - because it needs to run every time a object is created.
Chetan Sastry
Yep. That said, if you really really want to typical private/public semantics, that's the only way to do it.
Annabelle