Advantages of using prototype, vs defining methods straight in the constructor?

JavascriptOopPrototype

Javascript Problem Overview


I am wondering if there are any advantages of using any of these over the other, and which way should I go?

Constructor approach:

var Class = function () {
   
    this.calc = function (a, b) {
        return a + b;
    };
   
};

Prototype approach:

var Class = function () {};

Class.prototype.calc = function (a, b) {
    return a + b;
};

I don't like that, using the prototype, method definitions are separated from the class, and I'm not aware if there is any specific reason I should use this over just the first approach.

Also, is there any benefit of using a function literal to define a "class", over just function definition:

var Class = function () {};

vs

function Class () {};

Thanks!

Javascript Solutions


Solution 1 - Javascript

Methods that inherit via the prototype chain can be changed universally for all instances, for example:

function Class () {}
Class.prototype.calc = function (a, b) {
    return a + b;
}

// Create 2 instances:
var ins1 = new Class(),
    ins2 = new Class();

// Test the calc method:
console.log(ins1.calc(1,1), ins2.calc(1,1));
// -> 2, 2

// Change the prototype method
Class.prototype.calc = function () {
    var args = Array.prototype.slice.apply(arguments),
        res = 0, c;

    while (c = args.shift())
        res += c;

    return res; 
}

// Test the calc method:
console.log(ins1.calc(1,1,1), ins2.calc(1,1,1));
// -> 3, 3

Notice how changing the method applied to both instances? This is because ins1 and ins2 share the same calc() function. In order to do this with public methods created during construction, you'd have to assign the new method to each instance that has been created, which is an awkward task. This is because ins1 and ins2 would have their own, individually created calc() functions.

Another side effect of creating methods inside the constructor is poorer performance. Each method has to be created every time the constructor function runs. Methods on the prototype chain are created once and then "inherited" by each instance. On the flip side of the coin, public methods have access to "private" variables, which isn't possible with inherited methods.

As for your function Class() {} vs var Class = function () {} question, the former is "hoisted" to the top of the current scope before execution. For the latter, the variable declaration is hoisted, but not the assignment. For example:

// Error, fn is called before the function is assigned!
fn();
var fn = function () { alert("test!"); } 

// Works as expected: the fn2 declaration is hoisted above the call
fn2();
function fn2() { alert("test!"); }

Solution 2 - Javascript

The advantage of the prototype approach is efficiency. There is one calc() function object shared between all Class objects (by which I mean objects created by calling the Class constructor). The other way (assigning methods within the constructor) creates a new function object for every Class object, using more memory and taking more processing time when calling the Class constructor. However, this approach does have an advantage: the calc() method has access to local variables within the constructor, which you can use to your advantage:

function Class() {
    var calcCallCount = 0;

    this.calc = function (a, b) {
        ++calcCallCount;
        alert("Calc called " + calcCallCount + " times");
        return a + b;
    };
};

Regarding var Class = function() {...} versus function Class() {...}, I generally prefer the latter is because it means the function has a name, which can be useful when debugging. The other difference is that the latter version (a function declaration) is hoisted, meaning that it is available everywhere within the scope in which it is defined, not just after the definition. However, some people prefer to use the former (a function expression) everywhere.

Solution 3 - Javascript

var YourClass = function(){
  var privateField = "somevalue";
  this.publicField = "somevalue";
  this.instanceMethod1 = function(){
     //you may access both private and public field from here:
     //in order to access public field, you must use "this":
     alert(privateField + "; " + this.publicField);
  };
}

YourClass.prototype.instanceMethod2 = function(){
  //you may access only public field 2 from this method, but not private fields:
  alert(this.publicField);
  //error: drawaback of prototype methods:
  alert(privateField);  
};

Advantages of prototype methods:

  1. When you define methods via prototype, they are shared among all YourClass instances. As a result the total size of such instances is < than if you define methods in constructor; There are tests that show how method definition via prototype decrease the total size of html page and as a result a speed of its loading.

  2. another advantage of methods, defined via prototype - is when you use inherited classes, you may override such methods and in the overriden method of the derived class you may invoke the method of base class with the same name, but with methods defined in constructor, you cannot do this.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLeoView Question on Stackoverflow
Solution 1 - JavascriptAndy EView Answer on Stackoverflow
Solution 2 - JavascriptTim DownView Answer on Stackoverflow
Solution 3 - JavascriptAlexandrView Answer on Stackoverflow