Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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();
like image 333
snitko Avatar asked Jan 07 '09 22:01

snitko


People also ask

What is the difference between adding a method inside the constructor and adding it to the prototype?

One big difference is that methods/properties added via prototype are only stored once (objects “containing” the prototype just “reference” the method/property) whereas methods/properties added in the constructor are parsed and copied for each instance created by that constructor.

What is the advantage of prototype in JavaScript?

Prototypes allow you to easily define methods to all instances of a particular object. The beauty is that the method is applied to the prototype, so it is only stored in the memory once, but every instance of the object has access to it.

Why are prototypes more efficient than other techniques for creating classes in JavaScript?

There is a clear reason why you should use prototypes when creating classes in JavaScript. They use less memory. When a method is defined using this. methodName a new copy is created every time a new object is instantiated.

Is constructor a prototype?

Every function constructor will have a prototype property, which will become the instance's [[Prototype]] when called via the new operator. ConstructorFunction. prototype.


2 Answers

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'
like image 97
Prestaul Avatar answered Nov 10 '22 01:11

Prestaul


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.

like image 41
annakata Avatar answered Nov 10 '22 01:11

annakata