Setting methods through prototype object or in constructor, difference? [duplicate]

Could you explain the difference between setting methods in the constructor and through prototype object? The following code shows these two ways of setting the methods - say_hello and say_bye both work fine:

function MessageClass() {
  this.say_bye = function() { alert('see ya'); };
}

MessageClass.prototype.say_hello = function() { alert('hello'); };

x = new MessageClass();
x.say_hello();
x.say_bye();

Solution 1:

foxxtrot and annakata are both correct, but I'll throw in my 2 cents.

If you use the prototype then each instance of the "MessageClass" is really referencing the same functions. The functions exist in memory only once and are used for all instances. If you declare the methods in the constructor (or otherwise add it to a specific instance) rather than the prototype then a new function is created for each instance of MessageClass.

That being said, there is probably not any noticeable performance difference for most cases and it is unlikely that you will see a memory usage difference either. I would go with the prototype method unless you have a compelling reason to do otherwise. The only reason I can thing that you might want to declare a method in the constructor is if you need a closure. For example, if you have event handlers or you wanted to simulate private properties with getters/setters you might do:

function MessageClass() {
    var self = this;
    this.clickHander = function(e) { self.someoneClickedMe = true; };

    var _private = 0;
    this.getPrivate = function() { return _private; };
    this.setPrivate = function(val) { _private = val; };
}

EDIT: Because there has been discussion about how this effects objects extended by another object with functions assigned in the constructor I'm adding a bit more detail. I might use the term "class" to simplify the discussion, but it is important to note that js does not support classes (that doesn't mean we can't do good OO development) or we would not be discussing this issue.

Most javascript libraries call the constructor on the base class and the sub class. (e.g. Prototype.js's Object.extend) This means that methods assigned in the constructor of each will be available on the resulting objects. However, if you are extending objects yourself there can be unexpected consequences.

If I take the MessageClass above and extend it:

function ErrorMessageClass() {}
ErrorMessageClass.prototype = new MessageClass();

errorMsg = new ErrorMessageClass();

Then errorMsg will have a getPrivate and setPrivate method on it, but they may not behave as you would expect. Because those functions were scoped when they were assigned (i.e. at "ErrorMessageClass.prototype = new MessageClass()" not only are the get/setPrivate methods shared, the _private variable gets shared across all instances of ErrorMessageClass as well. This essentially makes _private a static property for ErrorMessageClass. For example:

var errorA = new ErrorMessageClass();
var errorB = new ErrorMessageClass();
errorA.setPrivate('A');
console.log(errorA.getPrivate()); // prints 'A'
console.log(errorB.getPrivate()); // prints 'A'
errorB.setPrivate('B');
console.log(errorA.getPrivate()); // prints 'B'

Likewise with the clickHandler function and someoneClickedMe property:

errorA.clickHandler();
console.log(errorA.someoneClickedMe); // prints 'true'
console.log(errorB.someoneClickedMe); // prints 'true'

However, change those function definitions to use this._private:

this.getPrivate = function() { return this._private; };
this.setPrivate = function(val) { this._private = val; };

and behavior of instances of ErrorMessageClass becomes more of what you would expect:

errorA.setPrivate('A');
errorB.setPrivate('B');
console.log(errorA.getPrivate()); // prints 'A'
console.log(errorB.getPrivate()); // prints 'B'

Solution 2:

If you bind methods by prototype JS only has to do it once and binds to an object class (which makes it elligible for OO JS extensions).

If you do the binding within the "class" function, JS has to do the work of creating and assigning for each and every instance.