Functions inside the constructor and prototype

I know there are similar questions like this one, but I want to see if these answers remain valid when optimized in the new Javascript engines.

In my opinion, the greatest advantage in defining functions inside the constructor is that you can easily avoid having to know the meaning of the 'this' keyword:

var Person = function() { var self = this; self.firstName = null; self.lastName = null; self.fullName = function() { return self.firstName + self.lastName; }; }; 

This approach is recommended by Knockout Management 'this' . This is a big advantage, especially when the code is modified by many developers, because it is very easy to understand and use.

Another approach would be to use a prototype object:

 var Person = function() { this.firstName = null; this.lastName = null; }; Person.prototype.fullName = function() { return this.firstName + this.lastName; }; 

In this case, there are performance advantages, since object objects will be created once. However, the main problem I am facing is that it would be difficult to process the 'this' keyword. The above example is very simple, but if you have event handlers for all calls, jQuery calls each (), methods called from different contexts, etc., this is easy to mess up.

Of course, if you understand how 'this' works and know how the method is called, you should not have many problems. However, in my experience, this takes time, and it is error prone, especially when the code is created by many developers.

I know that new JS engines, such as V8, apply optimizations to cases where you declare functions inside the constructor, creating hidden classes: How does the V8 engine work? .

So my question is that, given these optimizations made by the new JS machines and the complexity of processing the 'this' keyword, does it make sense to use a prototype approach? What would I lose using the approach of putting everything inside the constructor?

UPDATE 1:

I just made a micro benchmark in Chrome (version 42). I create 1M objects with functions inside the constructor and functions in the prototype. This is a very simple object with two variables and three functions, and the results look like this:

 Functions inside constructor: 1.91 seconds Functions in prototype: 1.10 seconds 

It seems that even with those optimizations in the V8, it is still 73% faster. However, it was a micro benchmark. Not sure if this will be a big difference in real applications.

UPDATE 2:

I also looked at memory consumption, and there are big differences. For functions inside constructors:

 Shallow size: 64,000,120 Retained size: 336,001,128 

For prototype functions:

 Shallow size: 40,000,000 Retained size: 40,000,000 

Either optimization with a hidden class is not so good, or I missed something. I use monomorphic code (constructors without arguments) as suggested by V8, but not sure if I am doing something wrong.

UPDATE 3:

Here is the link of the test I did if someone can point out something is wrong: http://jsperf.com/dg-constructor-vs-prototype

+8
javascript
source share
3 answers

I am doing a quick test. If you declare a function in the constructor, two object instances have different function instances even after optimization. However, with the prototype, you only have one instance of the function that explains the difference in performance.

  var Person = function () { var self = this; self.firstName = null; self.lastName = null; self.fullName = function () { return self.firstName + self.lastName; }; }; Person.prototype.fullName2 = function () { return this.firstName + this.lastName; }; var a = new Person(); var b = new Person(); console.log(a.fullName == b.fullName); // returns false console.log(a.fullName2 == b.fullName2); // returns true 
+4
source share

I used a slightly different approach, which in IMO has the advantage of clarity, and also avoids re-creating member functions every time the constructor is called:

  • define class member functions as module level functions outside the constructor
  • explicitly assign functions to the class instance in the constructor

For example:

 // Constructor for MyClass function MyClass(a, b){ // set properties of the instance from constructor arguments this.a = a; this.b = b; // assign the report function as a member of this instance this.report = Report; } // Report function is defined at the module level, // but used by assigning it to an instance variable // within the constructor. function Report(){ console.log( "a=" + this.a, "b=" + this.b); } 

There will be only one instance of a member function that is used by all instances of the same class - as in the case of assigning a function to class.prototype.function - so this approach is efficient and has these additional advantages, IMO:

  1. The constructor explicitly includes declarations of all methods of the class, instead of adding methods to the prototype outside the constructor.
  2. The constructor code is less cluttered and easier to understand than if the full function definition were encoded in the constructor.
  3. Since the method is defined at the module level, it is created before the module is executed, so the class can be referenced in the code that precedes the constructor declaration. This is not the case when class.prototype.function is assigned, which must be executed before the constructor is called.

Using:

 // Create instances of my class var inst1 = new MyClass( "as", "df"); var inst2 = new MyClass( "gh", "jk"); // Report the instances inst1.report(); inst2.report(); // Class and method declarations follow below here... 

Are there any drawbacks to this approach?

0
source share

As @Ersin Basaran mentioned, the function created inside the constructor is unique for each instance of the object, unlike when it is created using the prototype, it makes it the same for each instance of the object.

However, after introducing classes in ES6 (ECMAScript2015), if you use a class to create a method instead of using the constructor function and create this method outside the constructor (but inside the class), it will be the same for each object, for example, as when using a prototype.

Here is an example of creating the fullName() method:

 class Person { constructor () { var self = this; self.firstName = null; self.lastName = null; } fullName () { return self.firstName + self.lastName; } } Person.prototype.fullName2 = function () { return this.firstName + this.lastName; }; var a = new Person(); var b = new Person(); console.log(a.fullName == b.fullName); // returns true console.log(a.fullName2 == b.fullName2); // returns true 

Hope this helps.

0
source share

All Articles