Reputation: 4278
Im look at Addy Osmani's chapter on the constructor pattern: http://addyosmani.com/resources/essentialjsdesignpatterns/book/#constructorpatternjavascript and I came across the following:
function Car( model, year, miles ) {
this.model = model;
this.year = year;
this.miles = miles;
this.toString = function () {
return this.model + " has done " + this.miles + " miles";
};
}
// Usage:
// We can create new instances of the car
var civic = new Car( "Honda Civic", 2009, 20000 );
var mondeo = new Car( "Ford Mondeo", 2010, 5000 );
// and then open our browser console to view the
// output of the toString() method being called on
// these objects
console.log( civic.toString() );
console.log( mondeo.toString() );
He said this was not a great thing to do with regards to the this.toString function as it isn't very optimal and isn't shared between all instances of the car type. But he doesn't explain what exactly this means and why it's a bad thing. He recommends to do the following:
function Car( model, year, miles ) {
this.model = model;
this.year = year;
this.miles = miles;
}
// Note here that we are using Object.prototype.newMethod rather than
// Object.prototype so as to avoid redefining the prototype object
Car.prototype.toString = function () {
return this.model + " has done " + this.miles + " miles";
};
// Usage:
var civic = new Car( "Honda Civic", 2009, 20000 );
var mondeo = new Car( "Ford Mondeo", 2010, 5000 );
console.log( civic.toString() );
console.log( mondeo.toString() );
Can someone explain why using the prototype object to add in this functionality is optimal/better?
Upvotes: 5
Views: 154
Reputation: 413712
Functions (well, more generally, properties) on the prototype object are shared by all instances. That single "toString" function will remain just one solitary object no matter how many "Car" instances are made. When you do the assignment in the constructor, a new function object is created for each one.
Obviously, if each instance needs a property that may vary from those of other instances, then you need a per-instance property.
Upvotes: 6
Reputation: 8189
A typical rule of thumb for me is to set properties that are specific to a given instance such as name, color, etc in the constructor and define functions that a "class" should share as a function on the prototype.
There are also performance ramifications of defining functions on the prototype vs on the constructor. When you define a function on the constructor, each time you use the constructor you are redefining the function again and again...
http://jsperf.com/prototype-vs-instance-functions
You wouldn't want something like name
on the prototype because if you went in and changed Car.prototype.name
, then you'd change the name for all new instances of Car
.
Hope that helps!
Upvotes: 2
Reputation: 12027
Functions on the prototype are shared between every instance. This means that this is the exact same function for every instances, not an identical copy.
If you define the function in the constructor instead, each instance has to create its own version of the function, and then own it for itself. That means if you have 100 instances, you have 100 copies of the function in memory. It also means that updating the function is not fun at all, you would have to do it on every instance.
If the function is in the prototype, updating it in the prototype means every instance now use the updated code (because they all use the same, shared, function)
For example:
function Car( model, year, miles ) {
this.model = model;
this.year = year;
this.miles = miles;
}
Car.prototype.toString = function () {
return this.model + " has done " + this.miles + " miles";
};
var civic = new Car( "Honda Civic", 2009, 20000 );
console.log( civic.toString() );
Car.prototype.toString = function () {
return this.model + " has done " + (this.miles * 1.60934) + " kilometers";
};
console.log( civic.toString() );
Note how I did not need to change the civic
instance, it uses the new code and display the distance in kilometers.
Upvotes: 2
Reputation: 35793
When the function is inside the constructor it will be created for every new instance of the 'class'. So each Car
object you create will have it's own toString
function taking up extra memory.
If you add the toString
via the prototype, it will only exist once and each of the Car
objects you create will use this same function.
It also tidies up the constructor code to only include what is relevant to creating the object.
Upvotes: 2
Reputation: 9811
Everytime u run new Car
JS parser executes code in constructor, which mean u are creating another
this.toString = function () {
return this.model + " has done " + this.miles + " miles";
};
With prototype
approach there is always only one copy of toString()
.
Upvotes: 1