Declaring JavaScript Object Method in Constructor Function VS. in Prototype

Declaring javascript object method in constructor function vs. in prototype

For the example you give, you should use the prototype approach. In general, it depends. The main advantage of the first approach (initializing methods in the constructor) is that you can take advantage of closures by making use of local variables defined within the constructor in your methods. These variables are not directly accessible outside the constructor function so are effectively "private", meaning your API is cleaner than if these variable were instead defined as properties of the object. Some general rules of thumb:

  • If your methods do not use local variables defined in your constructor (your example doesn't), then use the prototype approach.
  • If you're creating lots of Dogs, use the prototype approach. This way, all "instances" (i.e. objects created by the Dog constructor) will share one set of functions, whereas the constructor way, a new set of functions is created every time the Dog constructor is called, using more memory.
  • If you're creating a small number of Dogs and find that using local, "private" variables in your constructor improves your code, this may be the better approach. Use your judgment and do some benchmarks if performance or memory consumption are major concerns.

It is possible to use a hybrid approach whereby only methods that need access to local private constructor variables are defined in the constructor while other methods are assigned to the prototype.

For example, the code below uses a local variable in the constructor to keep track of the number of times this dog has barked while keeping the actual number private, so the barking-related methods are defined inside the constructor. Tail wagging does not require access to the number of barks, therefore that method can be defined on the prototype.

var Dog = function(name) {    this.name = name;
var barkCount = 0;
this.bark = function() { barkCount++; alert(this.name + " bark"); };
this.getBarkCount = function() { alert(this.name + " has barked " + barkCount + " times"); };};
Dog.prototype.wagTail = function() { alert(this.name + " wagging tail");};
var dog = new Dog("Dave");dog.bark();dog.bark();dog.getBarkCount();dog.wagTail();

Functions inside constructor vs prototype

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

    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

JavaScript: Constructor vs Prototype

The differences between 2 approaches (using Object.create() and constructor invocation) are:

The creation:

  • Object.create(somePrototype) creates a new object making the somePrototype it's prototype;
  • new someConstructor() creates an object using constructor invocation. The prototype of the obj2 is a simple object: new Object()

The properties inheritance:

  • obj1 inherits the property speak, which is a function. If this property changes in the somePrototype object, this will affect any objects created with Object.create(somePrototype) which inherit it.

    Object.keys(obj1) will return [], because the object has no own properties.
  • obj2 contains an own property speak. Modifying this property on a single instance won't affect any other instances created using new someConstructor().

    Object.keys(obj2) will return ['speak'] as its listed property.

The constructor:

  • obj1.constructor === Object is true
  • obj2.constructor === someConstructor is true

Hoisting:

  • someConstructor is hoisted to the top of scope it was created. So it can be used before the function declaration.
  • And sure somePrototype is not hoisted with the object literal, so should be used after setting up the value.

Check this interesting post about constructor property.

Trying to understand the difference between prototype and constructor in JavaScript

It is pretty hard to wrap your mind around this concept if you are used to the ease of extending objects in other OOP languages, but I'll do my best to explain the uses of those and what is what. I am going to assume you are familiar with other OOP languages. Correct me if I'm wrong.

All functions have the prototype Function(). They are inheriting all base functionality from Function like toString() and valueOf().

Then there is a constructor. That is what you use to initialize an object with.

p = new Foo();

So in this case we have two things.

  • A function Foo with Function as prototype(Foo)
  • A Function object with Foo() as constructor(p)

(following me yet?)

The Foo() constructor can override some base functionality of the Function constructor or leave it as it is and make good use of it.

If you are familiar with OOP principles, The prototype is the base class, the constructor your current class. In OOP the above would be class Foo extends Function

You can also start inheritance with this entire setup of prototype and constructor making more complex objects as you go whilst sharing functionality.

For example this:

// Make an object initialiser extending Function. In OOP `class Foo extends Function`

function Foo(bar) {
this.baz = bar;
}
Foo.prototype.append = function(what) {
this.baz += " " + what;
};
Foo.prototype.get() {
return this.baz
}

Now lets say we want different ways to get baz out of there. One for console logging and one for putting it on the title bar.
We could make a big thing about our class Foo, but we don't do that, because we need to do wholly different things with the new classes that are made for different implementations. The only thing they need to share are the baz item and the setters and getters.

So we need to extend it to use an OOP term. In OOO this would be the desired end result class Title extends Foo(){}. So lets take a look at how to get there.

function Title(what) {
this.message = what;
}

At this point the Title function looks like this:

  • prototype Function
  • constructor Title

So, to make it extends Foo we need to change the prototype.

Title.prototype = new Foo();
  • prototype Foo
  • constructor Foo

This is done by initializing a new Foo() object against the prototype.
Now its basically a Foo object called Title. That is not what we want because now we can't access the message part in Title.
We can make it properly extend Foo() by resetting the constructor to Title

Title.prototype.constructor = Title;
  • prototype Foo
  • Constructor Title

Now we are faced with one more problem. The constructor of Foo doesn't get initialized so we end up with an undefined this.baz

To resolve that we need to call the parent. In Java you would do that with super(vars), in PHP $parent->__construct($vars).

In Javascript we have to modify the Title class constructor to call the constructor of the parent object.

So the Title class constructor would become

function Title(what) {
Foo.call(this,what);
this.message = what;
}

By using the Function object property Foo inherited we can initialize the Foo object in the Title object.

And now you have a properly inherited object.

So instead of using a keyword like extend like other OOP languages it uses prototype and constructor.

Setting methods through prototype object or in constructor, difference?

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'

Defining methods via prototype vs using this in the constructor - really a performance difference?

See http://jsperf.com/prototype-vs-this

Declaring your methods via the prototype is faster, but whether or not this is relevant is debatable.

If you have a performance bottleneck in your app it is unlikely to be this, unless you happen to be instantiating 10000+ objects on every step of some arbitrary animation, for example.

If performance is a serious concern, and you'd like to micro-optimise, then I would suggest declaring via prototype. Otherwise, just use the pattern that makes most sense to you.

I'll add that, in JavaScript, there is a convention of prefixing properties that are intended to be seen as private with an underscore (e.g. _process()). Most developers will understand and avoid these properties, unless they're willing to forgo the social contract, but in that case you might as well not cater to them. What I mean to say is that: you probably don't really need true private variables...

Declaring properties in Prototype vs. Constructor function? Pros and Cons?

You have a few things mixed up. This is common when trying to understand javascript from an OO perspective, because it's not a very good fit. Maybe this will help a little:

This is just a function that (when called with new) returns an object:

function Parent() {
// create a new object and call it this
this.name = "jeff";
}

The object it returns is created fresh every time and that object is what this is referencing. So each time you run it, it makes an object, gives that object a name parameter set to jeff and retuns. It's easier to see if use a dynamic property:

function Parent() {    console.log("creating a new object and a new value")    this.value = Math.floor(Math.random()* 100000); }  var child1 = new Parent(); console.log("child1: ", child1)
var child2 = new Parent(); console.log("child2: ", child2)

Why do we add methods using the prototype property of the constructor function?

In your second example you recreate the logName function every time you create a new instance of MyExample. If you use the MyExample's prototype then one logName method is shared across all instances of the MyExample object and context is passed around automatically.

The prototype also allows you to add a new method at a later point that can be accessed by already-existing objects of that type or globally modify a method for all objects of a type.

This question touches on the same topic if you would like more information, Advantages of using prototype, vs defining methods straight in the constructor?

Adding prototype methods outside vs inside of constructor function

tl;dr: The prototype should be initialized outside the constructor.


The prototype object is something that should be initialized/created only once. Changing it inside the constructor means that every time a new instance is created, the prototype is changed one way or the other.

That kind of defeats the purpose of prototypes because they should be setup ones and shared across all instances (to "save" memory).

It's not so evident for Shape, but it becomes more evident for Circle:

function Shape() {    Shape.prototype.duplicate = function() {        console.log('Duplicate');    }}
function Circle() { Circle.prototype = Object.create(Shape.prototype);}
var c1 = new Circle();var c2 = new Circle();
console.log( Object.getPrototypeOf(c1) === Object.getPrototypeOf(c2), ':-O every Circle instance has its own prototype');
c1.duplicate();// can't even call `c1.duplicate` because // `Circle.prototype = Object.create(Shape.prototype);` happens // *after* the first instance was created

Assigning prototype methods *inside* the constructor function - why not?

Functionally, are there any drawbacks to structuring my code this way?
Will adding a prototypical method to a prototype object inside the
constructor function's body (i.e. before the constructor function's
expression statement closes) cause unexpected scoping issues?

Yes, there are drawbacks and unexpected scoping issues.

  1. Assigning the prototype over and over to a locally defined function, both repeats that assignment and creates a new function object each time. The earlier assignments will be garbage collected since they are no longer referenced, but it's unnecessary work in both runtime execution of the constructor and in terms of garbage collection compared to the second code block.

  2. There are unexpected scoping issues in some circumstances. See the Counter example at the end of my answer for an explicit example. If you refer to a local variable of the constructor from the prototype method, then your first example creates a potentially nasty bug in your code.

There are some other (more minor) differences. Your first scheme prohibits the use of the prototype outside the constructor as in:

Filter.prototype.checkProduct.apply(someFilterLikeObject, ...)

And, of course, if someone used:

Object.create(Filter.prototype) 

without running the Filter constructor, that would also create a different result which is probably not as likely since it's reasonable to expect that something that uses the Filter prototype should run the Filter constructor in order to achieve expected results.


From a run-time performance point of view (performance of calling methods on the object), you would be better off with this:

var Filter = function( category, value ){
this.category = category;
this.value = value;

// product is a JSON object
this.checkProduct = function( product ){
// run some checks
return is_match;
}

};

There are some Javascript "experts" who claim that the memory savings of using the prototype is no longer needed (I watched a video lecture about that a few days ago) so it's time to start using the better performance of methods directly on the object rather than the prototype. I don't know if I'm ready to advocate that myself yet, but it was an interesting point to think about.


The biggest disadvantage of your first method I can think of is that it's really, really easy to make a nasty programming mistake. If you happen to think you can take advantage of the fact that the prototype method can now see local variables of the constructor, you will quickly shoot yourself in the foot as soon as you have more than one instance of your object. Imagine this circumstance:

var Counter = function(initialValue){
var value = initialValue;

// product is a JSON object
Counter.prototype.get = function() {
return value++;
}

};

var c1 = new Counter(0);
var c2 = new Counter(10);
console.log(c1.get()); // outputs 10, should output 0

Demonstration of the problem: http://jsfiddle.net/jfriend00/c7natr3d/

This is because, while it looks like the get method forms a closure and has access to the instance variables that are local variables of the constructor, it doesn't work that way in practice. Because all instances share the same prototype object, each new instance of the Counter object creates a new instance of the get function (which has access to the constructor local variables of the just created instance) and assigns it to the prototype, so now all instances have a get method that accesses the local variables of the constructor of the last instance created. It's a programming disaster as this is likely never what was intended and could easily be a head scratcher to figure out what went wrong and why.



Related Topics



Leave a reply



Submit