JavaScript override methods - javascript

Let's say you have the below code:
function A() {
function modify() {
x = 300;
y = 400;
}
var c = new C();
}
function B() {
function modify(){
x = 3000;
y = 4000;
}
var c = new C();
}
C = function () {
var x = 10;
var y = 20;
function modify() {
x = 30;
y = 40;
};
modify();
alert("The sum is: " + (x+y));
}
Now the question is, if there is any way in which I can override the method modify from C with the methods that are in A and B. In Java you would use the super-keyword, but how can you achieve something like this in JavaScript?

Edit: It's now six years since the original answer was written and a lot has changed!
If you're using a newer version of JavaScript, possibly compiled with a tool like Babel, you can use real classes.
If you're using the class-like component constructors provided by Angular or React, you'll want to look in the docs for that framework.
If you're using ES5 and making "fake" classes by hand using prototypes, the answer below is still as right as it ever was.
JavaScript inheritance looks a bit different from Java. Here is how the native JavaScript object system looks:
// Create a class
function Vehicle(color){
this.color = color;
}
// Add an instance method
Vehicle.prototype.go = function(){
return "Underway in " + this.color;
}
// Add a second class
function Car(color){
this.color = color;
}
// And declare it is a subclass of the first
Car.prototype = new Vehicle();
// Override the instance method
Car.prototype.go = function(){
return Vehicle.prototype.go.call(this) + " car"
}
// Create some instances and see the overridden behavior.
var v = new Vehicle("blue");
v.go() // "Underway in blue"
var c = new Car("red");
c.go() // "Underway in red car"
Unfortunately this is a bit ugly and it does not include a very nice way to "super": you have to manually specify which parent classes' method you want to call. As a result, there are a variety of tools to make creating classes nicer. Try looking at Prototype.js, Backbone.js, or a similar library that includes a nicer syntax for doing OOP in js.

Since this is a top hit on Google, I'd like to give an updated answer.
Using ES6 classes makes inheritance and method overriding a lot easier:
'use strict';
class A {
speak() {
console.log("I'm A");
}
}
class B extends A {
speak() {
super.speak();
console.log("I'm B");
}
}
var a = new A();
a.speak();
// Output:
// I'm A
var b = new B();
b.speak();
// Output:
// I'm A
// I'm B
The super keyword refers to the parent class when used in the inheriting class. Also, all methods on the parent class are bound to the instance of the child, so you don't have to write super.method.apply(this);.
As for compatibility: the ES6 compatibility table shows only the most recent versions of the major players support classes (mostly). V8 browsers have had them since January of this year (Chrome and Opera), and Firefox, using the SpiderMonkey JS engine, will see classes next month with their official Firefox 45 release. On the mobile side, Android still does not support this feature, while iOS 9, release five months ago, has partial support.
Fortunately, there is Babel, a JS library for re-compiling Harmony code into ES5 code. Classes, and a lot of other cool features in ES6 can make your Javascript code a lot more readable and maintainable.

Once should avoid emulating classical OO and use prototypical OO instead. A nice utility library for prototypical OO is traits.
Rather then overwriting methods and setting up inheritance chains (one should always favour object composition over object inheritance) you should be bundling re-usable functions into traits and creating objects with those.
Live Example
var modifyA = {
modify: function() {
this.x = 300;
this.y = 400;
}
};
var modifyB = {
modify: function() {
this.x = 3000;
this.y = 4000;
}
};
C = function(trait) {
var o = Object.create(Object.prototype, Trait(trait));
o.modify();
console.log("sum : " + (o.x + o.y));
return o;
}
//C(modifyA);
C(modifyB);

modify() in your example is a private function, that won't be accessible from anywhere but within your A, B or C definition. You would need to declare it as
this.modify = function(){}
C has no reference to its parents, unless you pass it to C. If C is set up to inherit from A or B, it will inherit its public methods (not its private functions like you have modify() defined). Once C inherits methods from its parent, you can override the inherited methods.

the method modify() that you called in the last is called in global context
if you want to override modify() you first have to inherit A or B.
Maybe you're trying to do this:
In this case C inherits A
function A() {
this.modify = function() {
alert("in A");
}
}
function B() {
this.modify = function() {
alert("in B");
}
}
C = function() {
this.modify = function() {
alert("in C");
};
C.prototype.modify(); // you can call this method where you need to call modify of the parent class
}
C.prototype = new A();

Not unless you make all variables "public", i.e. make them members of the Function either directly or through the prototype property.
var C = function( ) {
this.x = 10 , this.y = 20 ;
this.modify = function( ) {
this.x = 30 , this.y = 40 ;
console.log("(!) C >> " + (this.x + this.y) ) ;
} ;
} ;
var A = function( ) {
this.modify = function( ) {
this.x = 300 , this.y = 400 ;
console.log("(!) A >> " + (this.x + this.y) ) ;
} ;
} ;
A.prototype = new C ;
var B = function( ) {
this.modify = function( ) {
this.x = 3000 , this.y = 4000 ;
console.log("(!) B >> " + (this.x + this.y) ) ;
} ;
} ;
new C( ).modify( ) ;
new A( ).modify( ) ;
new B( ).modify( ) ;
test it here
You will notice a few changes.
Most importantly the call to the supposed "super-classes" constructor is now implicit within this line:
<name>.prototype = new C ;
Both A and B will now have individually modifiable members x and y which would not be the case if we would have written ... = C instead.
Then, x, y and modify are all "public" members so that assigning a different Function to them
<name>.prototype.modify = function( ) { /* ... */ }
will "override" the original Function by that name.
Lastly, the call to modify cannot be done in the Function declaration because the implicit call to the "super-class" would then be executed again when we set the supposed "super-class" to the prototype property of the supposed "sub-classes".
But well, this is more or less how you would do this kind of thing in JavaScript.
HTH,
FK

function A() {
var c = new C();
c.modify = function(){
c.x = 123;
c.y = 333;
}
c.sum();
}
function B() {
var c = new C();
c.modify = function(){
c.x = 999;
c.y = 333;
}
c.sum();
}
C = function () {
this.x = 10;
this.y = 20;
this.modify = function() {
this.x = 30;
this.y = 40;
};
this.sum = function(){
this.modify();
console.log("The sum is: " + (this.x+this.y));
}
}
A();
B();

Related

Javascript oop dubt

I made this two classes below in the code, and I am not sure if I made it in a right oop way. Is it good that I made geometry class and vertex like two distinct classes or maybe they can be one father and child? Another problem is when I call geometry show method and it returns me undefined.
//////////////////////////////////////////
// VERTICES
//////////////////////////////////////////
function Vertex(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
}
Vertex.prototype.show = function () {
return this.x + ":" + this.y + ":" + this.z;
}
//////////////////////////////////////////
// GEOMETRY
//////////////////////////////////////////
function Geometry() {
this.vertices = [];
}
Geometry.prototype.push = function(v) {
this.vertices.push(v);
}
Geometry.prototype.show = function() {
for(var i = 0; i < this.getVertexCount(); i++){
this.vertices[i].show();// undefined!
}
}
Geometry.prototype.getVertexCount = function() {
return this.vertices.length;
}
/////TEST/////
function test() {
v = new Vertex(2,4,6);
console.log(v.show());
g = new Geometry();
g.push(v);
console.log(g.show()); //undefined
}
I am not sure if I made it in a right oop way.
Seems fine, I can't see any common mistakes.
My doubt is for geometry class that has a vertice object field inside. Is it correct or the are better way to do it?
Depends on what you need. There's nothing inherently wrong with it, but if you told us your use case we might find a different solution.
Is it good that I made geometry class and vertex like two distinct classes or maybe they can be one father and child?
No, there should not be any inheritance. There is no is-a relationship between them. They should be distinct classes, one using the other.
Another problem is when I call geometry show method and it returns me undefined.
Yes, because it doesn't return anything. All those strings that it gets from the invocation of the Vertice show() calls are thrown away. It seems like you want something like
Geometry.prototype.show = function() {
var result = "";
for (var i = 0; i < this.getVertexCount(); i++) {
if (i > 0)
result += "\n";
result += this.vertices[i].show();
}
return result; // not undefined!
}

Javascript Prototype General Enquries and Assign Id by Array Index

I am trying to learn how to work with javascripts prototype, I am only getting into it now. Please Excuse me if I ask ridiculously stupid questions
I just have a few pre-questions:
Is it worth learning? I mean it looks like a structured/clean
approach to me?
Do/should you use this with jQuery this?
is there any major problems or reason not to use it and why isn't it commonly used or am i just slow?
Actual Question:
I have the following code:
var BudgetSection = function BudgetSection(name ) {
this.id = "";
this.name = name;
this.monthlyTotal = 0.00;
this.yearlyTotal = 0.00;
this.subTotal = 0.00;
this.lineItems = [];
};
BudgetSection.prototype.calculateSubTotal = function() {
this.subTotal = ((12 * this.monthlyTotal) + this.yearlyTotal);
};
function BudgetLineItem(name) {
this.id = "";
this.name = name;
this.monthlyAmount = 0.00;
this.yearlyAmount = 0.00;
}
BudgetLineItem.prototype = {
totalAmount : function() {
var result = ((12 * this.monthlyAmount) + this.yearlyAmount);
return result;
}
};
var budgetSections = [];
section = new BudgetSection("test1");
section.lineItems.push(new BudgetLineItem('sub'));
section.lineItems.push(new BudgetLineItem('sub2'));
section.lineItems.push(new BudgetLineItem('sub3'));
budgetSections.push(section);
section = new BudgetSection("test2");
section.lineItems.push(new BudgetLineItem('sub'));
section.lineItems.push(new BudgetLineItem('sub2'));
section.lineItems.push(new BudgetLineItem('sub3'));
budgetSections.push(section);
section = new BudgetSection("test3");
section.lineItems.push(new BudgetLineItem('sub'));
section.lineItems.push(new BudgetLineItem('sub2'));
section.lineItems.push(new BudgetLineItem('sub3'));
budgetSections.push(section);
// first iterate through budgetSections
for ( var t = 0; t < budgetSections.length; t++) {
var sec = budgetSections[t];
console.log(sec);
// iterate through each section's lineItems
for (var q = 0; q< budgetSections[t].lineItems.length ; q++) {
var li = budgetSections[t].lineItems[q];
console.log(li);
}
}
the first BudgetSection "test1" is at index 0 in the budgetSections array. how can i assign the id to "section_".
And then also how can i set the id of BudgetLineItem like so: lineItemRow_<section_index><lineitem_index>
Also finally n the for loop what would be the best way to generate html?
I personally never use the new keyword if I can avoid it and do pure prototype-based programming with Object.create. Here's a simple example. I create a prototype-object called rectangle and then create an object called myRectangle which inherits from rectangle.
var rectangle = {
init: function( x, y, width, height ) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
},
move: function( x, y ) {
this.x += x;
this.y += y;
}
};
var myRectangle = Object.create( rectangle );
myRectangle.init( 0, 0, 2, 4 );
myRectangle.move( 3, 5 );
To explain in more depth what happens here, Object.create makes a new object with a specified prototype. When we access a property on an object (like init or move), it first checks the object itself. If it can't find it there, it moves up to the object's prototype and checks there. If it's not there, it checks the prototype's prototype, and keeps going up the prototype chain until it finds it.
When we call a function on an object (myRectangle.init()), this inside the function refers to that object, even if the function definition is actually on the prototype. This is called delegation - an object can delegate its responsibilities to its prototype.
A more class-like way to do this is:
function Rectangle( x, y, width, height ) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
Rectangle.prototype.move = function( x, y ) {
this.x +=x;
this.y +=y;
};
var myRectangle = new Rectangle( 0, 0, 2, 4 );
myRectangle.move( 3, 5 );
The problem is when we need to do a deeper inheritance hierarchy:
function Parent() {
/* expensive and possibly side-effect inducing initialization */
}
Parent.prototype.parentMethod = function() {};
function Child() {}
Child.prototype = new Parent();
We have to initialize a Parent object when all we really want is to set the Child prototype to an object based on Parent.prototype. Another option is:
Child.prototype = Object.create( Parent.prototype );
But now we've got this confusing, convoluted mess of prototype-based and class-based code. Personally, I like this instead:
var parent = {
parentMethod: function() {}
};
// Using underscore for stylistic reasons
var child = _.extend( Object.create( parent ), {
childMethod: function() {}
});
var instance = Object.create( child );
instance.parentMethod();
instance.childMethod();
No new keyword needed. No fake class system. "Objects inherit from objects. What could be more object-oriented than that?"
So what's the catch? Object.create is slow. If you're creating lots of objects, it's better to use new. You can still use Object.create to set up the prototype chain, but we'll have to wait a bit for browsers to optimize it enough for lots of instantiation.
Have you tried budgetSections[0].id = 'yourID';?

stoyanov javascript prototype exercises from object oriented javascript

Although I have some working experience with jQuery and JavaScript I still find it difficult to understand prototypal inheritance. Hence I have started reading Stoyan Stefanov's book entitled "Object Oriented JavaScript". However I ran into problems while solving the following exercises from the book:
Create an object called shape that has a type property and a getType method.
Define a Triangle constructor function whose prototype is shape. Objects created with Triangle should have three own properties: a, b and c representing the sides of a triangle.
Add a new method to the prototype called getPerimeter.
Test your implementation with this code:
var t = new Triangle(1, 2, 3);
t.constructor; // Triangle(a, b, c)
shape.isPrototypeOf(t); // true
t.getPerimeter(); // 6
t.getType(); // "triangle"
I have tried to solve this problem with the following code:
shape = {
type : "",
getType: function(){
return this.type;
}
};
function Triangle(a, b, c) {
}
Triangle.prototype = shape;
However it does not seem to work as expected. How would you solve this problem? Please explain it in detail. I would really like to understand prototypal inheritance.
You don't do anything with the params passed to the constructor function, probably assuming that they are just assigned to the newly-created object. The problem is, they aren't.
You should write something like this...
var shape = {
type: '',
getType: function() { return this.type; }
};
function Triangle(a, b, c) {
this.type = 'triangle';
this.a = a;
this.b = b;
this.c = c;
}
Triangle.prototype = shape;
Triangle.prototype.getPerimeter = function() {
return this.a + this.b + this.c;
};
Triangle.prototype.constructor = Triangle;
The point (why constructor is defined for prototype) is very simple: each Triangle object should know about its constructor function, but this property will be the same for each instance of Triangle. That's why it's placed it on Triangle.prototype instead.
Something like this will work:
function Shape() {
this.type = "shape";
this.getType = function(){
return this.type;
}
}
function Triangle(a,b,c){
this.type="triangle";
this.a =a;
this.b = b;
this.c = c;
}
var shape = new Shape(); //follow the requirements a bit more literally :)
Triangle.prototype = shape;
Triangle.prototype.getPerimeter = function() {
return this.a + this.b + this.c;
}
jsfiddle example: http://jsfiddle.net/TbR6q/1
Tangentially, this is an area where coffeescript is very nice and allows you to be much more clear/concise. This is the equivalent in Coffeescript.
class Shape
constructor: ->
#type = "shape"
getType : -> #type
class Triangle extends Shape
constructor: (#a,#b,#c) ->
#type="triangle"
getPerimeter: () -> #a + #b + #c
http://jsfiddle.net/qGtmX/
You're on the right track. Your code is correct. You only need to add a few more lines of code:
shape = {
type : "",
getType: function () {
return this.type;
}
};
function Triangle(a, b, c) {
this.type = "triangle";
this.a = a;
this.b = b;
this.c = c;
}
Triangle.prototype = shape;
shape.getPerimeter = function () {
return this.a + this.b + this.c;
};
To understand what's happening I suggest you read the following answers:
Object Inheritance in JavaScript
What are the downsides of defining functions on prototype this way?
JavaScript inheritance and the constructor property
For the sake of learning I would make it like this
function Shape(){
this.type = 'Shape';
this.getType = function()
{
return this.type;
}
}
var shape = new Shape();
function Triangle(a, b ,c)
{
this.type = 'triangle';
this.arguments = arguments;
}
Triangle.prototype = shape;
var triangle = new Triangle(1, 2, 3);
triangle.getType();
Triangle.prototype.getParimeter = function()
{
var perimeter = 0;
for(i = 0; i < this.arguments.length; i++){
perimeter = perimeter + this.arguments[i];
}
return perimeter;
}
console.log(triangle.getParimeter());
This is one solution (explanations on comments):
shape = {
type : "",
getType: function(){
return this.type;
}
};
function Triangle(a,b,c){
//This three variables are defined inside a closure, so in this case
//only the getPermiter function can access them
var A = a, B = b, C = c;
//The new Triangle object is crafted in the lines below as usual
this.type = "triangle";
this.getPerimeter = function(){
return A + B + C;
}
}
//Here we set the triangle prototype to point the shape object.
//So every time we call the Triangle function with the "new" operator
//the __proto__ internal property of the newly created object will be
//the shape object.
Triangle.prototype = Object.create(shape);
//The problem is that the shape object doesn't have a constructor property,
//so the shape constructor is shape.__proto__.constructor, which is the
//Object function.
//All this means that when we create a new object with the Triangle function the
//constructor property will be the Object function (shape.__proto__.constructor).
//To avoid this we must manually set the constructor to be Triangle.
Triangle.prototype.constructor = Triangle;
var t = new Triangle(1, 2, 3);
console.log(t.constructor === Triangle);
console.log(shape.isPrototypeOf(t) === true);
console.log(t.getPerimeter() === 6);
console.log(t.getType() === "triangle");

Javascript object member variable not cloning

I'm inheriting an object from the EASELJS library.
To simplify the problem, I'm reducing the code into the minimal form.
I have a class:
this.TESTProg = this.TESTProg || {};
(function() {
var _jsbutton = function(x, y, text, icon) {
p.init(x, y, text, icon);
};
var p = _jsbutton.prototype = new createjs.Container();
p.x = 0;
p.y = 0;
p.text = null;
p.icon = null;
p.init = function(x, y, text, icon) {
this.x = 0 + x;
this.y = 0 + y;
this.text = "" + text;
this.icon = null;
};
TESTProg._jsbutton = _jsbutton;
})();
Then I use it in another js object:
var buttoncancel = new SJSGame._jsbutton(
profileselConfig.cancelx, //this is defined in another jsfile:
profileselConfig.cancely,
"cancel", "_cancel.png");
console.log( buttoncancel.y ); //this gives 240
var buttoncancel2 = new SJSGame._jsbutton(
profileselConfig.cancelx,
profileselConfig.cancely - 40,
"cancel", "_cancel.png");
console.log( buttoncancel.y ); //this gives 200
console.log( buttoncancel2.y ); //this gives 200
buttoncancel2.y = 100;
console.log( buttoncancel.y ); //this now gives 200 (not changed by the second object)
console.log( buttoncancel2.y ); //this now gives 100
The config file:
var _profileselConfig = function(){
this.cancelx = 0;
this.cancely = 240;
};
profileselConfig = new _profileselConfig();
And what am i doing wrong?
I'm already using 0 + to avoid passing the reference and it's not working. What should I do now? Any suggestions? Thanks.
You should probably be calling this.init rather than p.init in your constructor.
When you call p.init, the this inside of init refers to the prototype. Thus, whenever you create an instance, your p.init call modifies the prototype for all _jsbutton objects.
That's why both buttons have the same x/y values: they both get their position from the same prototype, and the last-run constructor set the prototype values. When you set buttoncancel2.y outside of the constructor, you gave that instance its own y property, so it no longer used the shared prototype value.
If you call this.init in your constructor, then the this in init will refer to your newly-created instance. The instances will no longer use the shared prototype values for x, y, text, and icon.
Side note: "I'm already using 0 + to avoid passing the reference" -- this is not necessary, because primitive types are always copied.

Javascript prototype operator performance: saves memory, but is it faster?

I read here (Douglas Crockford) using prototype operator to add methods to Javascript classes saves also memory.
Then I read in this John Resig's article "Instantiating a function with a bunch of prototype properties is very, very, fast", but is he talking about using prototype in the standard way, or is he talking about his specific example in his article?
For example, is creating this object:
function Class1()
{
this.showMsg = function(string) { alert(string); }
}
var c = new Class1();
c.showMsg();
slower than creating this object, then?
function Class1() {}
Class1.prototype.showMsg = function(string) { alert(string); }
var c = new Class1();
c.showMsg();
P.S.
I know prototype is used to create inheritance and singleton object etc. But this question does not have anyhting to do with these subjects.
EDIT: to whom it might be interested also in performance comparison between a JS object and a JS static objet can read this answer below. Static object are definitely faster, obviously they can be usued only when you don't need more than one instance of the object.
Edit in 2021:
This question was asked in 2010 when class was not available in JS. Nowadays, class has been so optimized that there is no excuse not to use it. If you need to use new, use class. But back in 2010 you had two options when binding methods to their object constructors -- one was to bind functions inside the function constructor using this and the other was to bind them outside the constructor using prototype. #MarcoDemaio's question has very concise examples. When class was added to JS, early implementations were close in performance, but usually slower. That's not remotely true anymore. Just use class. I can think of no reason to use prototype today.
It was an interesting question, so I ran some very simple tests (I should have restarted my browsers to clear out the memory, but I didn't; take this for what it's worth). It looks like at least on Safari and Firefox, prototype runs significantly faster [edit: not 20x as stated earlier]. I'm sure a real-world test with fully-featured objects would be a better comparison. The code I ran was this (I ran the tests several times, separately):
var X,Y, x,y, i, intNow;
X = function() {};
X.prototype.message = function(s) { var mymessage = s + "";}
X.prototype.addition = function(i,j) { return (i *2 + j * 2) / 2; }
Y = function() {
this.message = function(s) { var mymessage = s + "";}
this.addition = function(i,j) { return (i *2 + j * 2) / 2; }
};
intNow = (new Date()).getTime();
for (i = 0; i < 10000000; i++) {
y = new Y();
y.message('hi');
y.addition(i,2)
}
console.log((new Date()).getTime() - intNow); //FF=5206ms; Safari=1554
intNow = (new Date()).getTime();
for (i = 0; i < 10000000; i++) {
x = new X();
x.message('hi');
x.addition(i,2)
}
console.log((new Date()).getTime() - intNow);//FF=3894ms;Safari=606
It's a real shame, because I really hate using prototype. I like my object code to be self-encapsulated, and not allowed to drift. I guess when speed matters, though, I don't have a choice. Darn.
[Edit] Many thanks to #Kevin who pointed out my previous code was wrong, giving a huge boost to the reported speed of the prototype method. After fixing, prototype is still around significantly faster, but the difference is not as enormous.
I would guess that it depends on the type of object you want to create. I ran a similar test as Andrew, but with a static object, and the static object won hands down. Here's the test:
var X, Y, Z, x, y, z;
X = function() {};
X.prototype.message = function(s) {
var mymessage = s + "";
}
X.prototype.addition = function(i, j) {
return (i * 2 + j * 2) / 2;
}
Y = function() {
this.message = function(s) {
var mymessage = s + "";
}
this.addition = function(i, j) {
return (i * 2 + j * 2) / 2;
}
};
Z = {
message: function(s) {
var mymessage = s + "";
},
addition: function(i, j) {
return (i * 2 + j * 2) / 2;
}
}
function TestPerformance() {
var closureStartDateTime = new Date();
for (var i = 0; i < 100000; i++) {
y = new Y();
y.message('hi');
y.addition(i, 2);
}
var closureEndDateTime = new Date();
var prototypeStartDateTime = new Date();
for (var i = 0; i < 100000; i++) {
x = new X();
x.message('hi');
x.addition(i, 2);
}
var prototypeEndDateTime = new Date();
var staticObjectStartDateTime = new Date();
for (var i = 0; i < 100000; i++) {
z = Z; // obviously you don't really need this
z.message('hi');
z.addition(i, 2);
}
var staticObjectEndDateTime = new Date();
var closureTime = closureEndDateTime.getTime() - closureStartDateTime.getTime();
var prototypeTime = prototypeEndDateTime.getTime() - prototypeStartDateTime.getTime();
var staticTime = staticObjectEndDateTime.getTime() - staticObjectStartDateTime.getTime();
console.log("Closure time: " + closureTime + ", prototype time: " + prototypeTime + ", static object time: " + staticTime);
}
TestPerformance();
This test is a modification of code I found at:
Link
Results:
IE6: closure time: 1062, prototype time: 766, static object time: 406
IE8: closure time: 781, prototype time: 406, static object time: 188
FF: closure time: 233, prototype time: 141, static object time: 94
Safari: closure time: 152, prototype time: 12, static object time: 6
Chrome: closure time: 13, prototype time: 8, static object time: 3
The lesson learned is that if you DON'T have a need to instantiate many different objects from the same class, then creating it as a static object wins hands down. So think carefully about what kind of class you really need.
So I decided to test this as well. I tested creation time, execution time, and memory use. I used Nodejs v0.8.12 and the mocha test framework running on a Mac Book Pro booted into Windows 7. The 'fast' results are using prototypes and the 'slow' ones are using module pattern. I created 1 million of each type of object and then accessed the 4 methods in each object. Here are the results:
c:\ABoxAbove>mocha test/test_andrew.js
Fast Allocation took:170 msec
·Fast Access took:826 msec
state[0] = First0
Free Memory:5006495744
·Slow Allocation took:999 msec
·Slow Access took:599 msec
state[0] = First0
Free Memory:4639649792
Mem diff:358248k
Mem overhead per obj:366.845952bytes
? 4 tests complete (2.6 seconds)
The code is as follows:
var assert = require("assert"), os = require('os');
function Fast (){}
Fast.prototype = {
state:"",
getState:function (){return this.state;},
setState:function (_state){this.state = _state;},
name:"",
getName:function (){return this.name;},
setName:function (_name){this.name = _name;}
};
function Slow (){
var state, name;
return{
getState:function (){return this.state;},
setState:function (_state){this.state = _state;},
getName:function (){return this.name;},
setName:function (_name){this.name = _name;}
};
}
describe('test supposed fast prototype', function(){
var count = 1000000, i, objs = [count], state = "First", name="Test";
var ts, diff, mem;
it ('should allocate a bunch of objects quickly', function (done){
ts = Date.now ();
for (i = 0; i < count; ++i){objs[i] = new Fast ();}
diff = Date.now () - ts;
console.log ("Fast Allocation took:%d msec", diff);
done ();
});
it ('should access a bunch of objects quickly', function (done){
ts = Date.now ();
for (i = 0; i < count; ++i){
objs[i].setState (state + i);
assert (objs[i].getState () === state + i, "States should be equal");
objs[i].setName (name + i);
assert (objs[i].getName () === name + i, "Names should be equal");
}
diff = Date.now() - ts;
console.log ("Fast Access took:%d msec", diff);
console.log ("state[0] = " + objs[0].getState ());
mem = os.freemem();
console.log ("Free Memory:" + mem + "\n");
done ();
});
it ('should allocate a bunch of objects slowly', function (done){
ts = Date.now ();
for (i = 0; i < count; ++i){objs[i] = Slow ();}
diff = Date.now() - ts;
console.log ("Slow Allocation took:%d msec", diff);
done ();
});
it ('should access a bunch of objects slowly', function (done){
ts = Date.now ();
for (i = 0; i < count; ++i){
objs[i].setState (state + i);
assert (objs[i].getState () === state + i, "States should be equal");
objs[i].setName (name + i);
assert (objs[i].getName () === name + i, "Names should be equal");
}
diff = Date.now() - ts;
console.log ("Slow Access took:%d msec", diff);
console.log ("state[0] = " + objs[0].getState ());
var mem2 = os.freemem();
console.log ("Free Memory:" + mem2 + "\n");
console.log ("Mem diff:" + (mem - mem2) / 1024 + "k");
console.log ("Mem overhead per obj:" + (mem - mem2) / count + 'bytes');
done ();
});
});
Conclusion: This backs up what others in this post have found. If you are constantly creating objects then the prototype mechanism is clearly faster. If your code spends most of its time accessing objects then the module pattern is faster. If you are sensitive about memory use, the prototype mechanism uses ~360 bytes less per object.
Intuitively, it seems that it would be more memory-efficient and faster to create functions on the prototype: the function's only created once, not each time a new instance is created.
However, there will be a slight performance difference when it's time to access the function. When c.showMsg is referenced, the JavaScript runtime first checks for the property on c. If it's not found, c's prototype is then checked.
So, creating the property on the instance would result in slightly faster access time - but this might only be an issue for a very deep prototype hierarchy.
We need to separate object construction and usage.
When declaring a function on a prototype, it is shared between all instances. When declaring a function in a constructor, this is recreated every time new instance is made. Given that, we need to benchmark construction and usage separately to have better results. That is what I did and want to share the results with you. This benchmark does not test for speed of construction.
function ThisFunc() {
this.value = 0;
this.increment = function(){
this.value++;
}
}
function ProtFunc() {
this.value = 0;
}
ProtFunc.prototype.increment = function (){
this.value++;
}
function ClosFunc() {
var value = 0;
return {
increment:function(){
value++;
}
};
}
var thisInstance = new ThisFunc;
var iterations = 1000000;
var intNow = (new Date()).getTime();
for (i = 0; i < iterations; i++) {
thisInstance.increment();
}
console.log(`ThisFunc: ${(new Date()).getTime() - intNow}`); // 27ms node v4.6.0
var protInstance = new ProtFunc;
intNow = (new Date()).getTime();
for (i = 0; i < iterations; i++) {
protInstance.increment();
}
console.log(`ProtFunc: ${(new Date()).getTime() - intNow}`); // 4ms node v4.6.0
var closInstance = ClosFunc();
intNow = (new Date()).getTime();
for (i = 0; i < iterations; i++) {
closInstance.increment();
}
console.log(`ClosFunc: ${(new Date()).getTime() - intNow}`); // 7ms node v4.6.0
From these results we can see that the prototype version is the fastest (4ms), but the closure version is very close (7ms). You may still need to benchmark for your particular case.
So:
We can use prototype version when we need to have every bit of performance or share functions between instances.
We can use other versions when what we want is the features they provide. (private state encapsulation, readability etc.)
PS: I used Andrew's answer as a reference. Used the same loops and notation.
I ran my own tests.
The first conclusion is, that static access is actually slower than real prototyping. Interestingly, the Version 23 of this test has a flawed prototyping (Variable X) in it, which just returns the completely overridden prototype object over and over again and when I was creating my test, this prototyping was still slower than my "real prototype" test.
Anyway, to the answer: Unless my test is flawed, it shows that real prototyping is fastest. It beats or is at least equal to the static object when ignoring instantiation. this-assignments on instantiation and private variables are both much slower. I wouldn't have guessed private variables would be this slow.
It might be of interest that I extended the prototype Object with jQuery.extend in between and it was about the same speed as the direct assignment. The extend was outside the test itself, of course. At least this is a way to circumvent writing annoying ".prototype."-Parts all the time.
High Resolution Browser Performance API Tests
None of the tests here are taking advantage of the performance API for high resolution testing so I wrote one that will show current fastest results for many different scenarios including 2 that are faster than any of the other answers on most runs.
Fasted in each category (10,000 iterations)
Property access only (~0.5ms): { __proto__: Type }
Looping object creation with property access (<3ms): Object.create(Type)
The code uses ES6 without babel transpilation to ensure accuracy. It works in current chrome. Run the test below to see the breakdown.
function profile () {
function test ( name
, define
, construct
, { index = 0
, count = 10000
, ordinals = [ 0, 1 ]
, constructPrior = false
} = {}
) {
performance.clearMarks()
performance.clearMeasures()
const symbols = { type: Symbol('type') }
const marks = (
{ __proto__: null
, start: `${name}_start`
, define: `${name}_define`
, construct: `${name}_construct`
, end: `${name}_end`
}
)
performance.mark(marks.start)
let Type = define()
performance.mark(marks.define)
let obj = constructPrior ? construct(Type) : null
do {
if(!constructPrior)
obj = construct(Type)
if(index === 0)
performance.mark(marks.construct)
const measureOrdinal = ordinals.includes(index)
if(measureOrdinal)
performance.mark(`${name}_ordinal_${index}_pre`)
obj.message('hi')
obj.addition(index, 2)
if(measureOrdinal)
performance.mark(`${name}_ordinal_${index}_post`)
} while (++index < count)
performance.mark(marks.end)
const measureMarks = Object.assign (
{ [`${name}_define`]: [ marks.start, marks.define ]
, [`${name}_construct`]: [ marks.define, marks.construct ]
, [`${name}_loop`]: [ marks.construct, marks.end ]
, [`${name}_total`]: [ marks.start, marks.end ]
}
, ordinals.reduce((reduction, i) => Object.assign(reduction, { [`${name}_ordinal_${i}`]: [ `${name}_ordinal_${i}_pre`, `${name}_ordinal_${i}_post` ] }), {})
)
Object.keys(measureMarks).forEach((key) => performance.measure(key, ...measureMarks[key]))
const measures = performance.getEntriesByType('measure').map(x => Object.assign(x, { endTime: x.startTime + x.duration }))
measures.sort((a, b) => a.endTime - b.endTime)
const durations = measures.reduce((reduction, measure) => Object.assign(reduction, { [measure.name]: measure.duration }), {})
return (
{ [symbols.type]: 'profile'
, profile: name
, duration: durations[`${name}_total`]
, durations
, measures
}
)
}
const refs = (
{ __proto__: null
, message: function(s) { var mymessage = s + '' }
, addition: function(i, j) { return (i *2 + j * 2) / 2 }
}
)
const testArgs = [
[ 'constructor'
, function define() {
return function Type () {
this.message = refs.message
this.addition = refs.addition
}
}
, function construct(Type) {
return new Type()
}
]
, [ 'prototype'
, function define() {
function Type () {
}
Type.prototype.message = refs.message
Type.prototype.addition = refs.addition
return Type
}
, function construct(Type) {
return new Type()
}
]
, [ 'Object.create'
, function define() {
return (
{ __proto__: null
, message: refs.message
, addition: refs.addition
}
)
}
, function construct(Type) {
return Object.create(Type)
}
]
, [ 'proto'
, function define() {
return (
{ __proto__: null
, message: refs.message
, addition: refs.addition
}
)
}
, function construct(Type) {
return { __proto__: Type }
}
]
]
return testArgs.reduce(
(reduction, [ name, ...args ]) => (
Object.assign( reduction
, { [name]: (
{ normal: test(name, ...args, { constructPrior: true })
, reconstruct: test(`${name}_reconstruct`, ...args, { constructPrior: false })
}
)
}
)
)
, {})
}
let profiled = profile()
const breakdown = Object.keys(profiled).reduce((reduction, name) => [ ...reduction, ...Object.keys(profiled[name]).reduce((r, type) => [ ...r, { profile: `${name}_${type}`, duration: profiled[name][type].duration } ], []) ], [])
breakdown.sort((a, b) => a.duration - b.duration)
try {
const Pre = props => React.createElement('pre', { children: JSON.stringify(props.children, null, 2) })
ReactDOM.render(React.createElement(Pre, { children: { breakdown, profiled } }), document.getElementById('profile'))
} catch(err) {
console.error(err)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="profile"></div>
I'm sure that as far as instantiating the object goes, it's way faster and also consumes less memory, no doubts about that, but I would think that the javascript engine needs to loop through all the properties of the object to determine if the property/method invoked is part of that object and if not, then go check for the prototype. I am not 100% sure about this but I'm assuming that's how it works and if so, then in SOME cases where your object has a LOT of methods added to it, instantiated only once and used heavily, then it could possibly be a little slower, but that's just a supposition I haven't tested anything.
But in the end, I would still agree that as a general rules, using prototype will be faster.
Funny thing though. It depends not that much on which type of object you create and it matters how you write an example. Likewise i ran similar test as shmuel613 who wrote a similair test as Andrew. The first test is creating a single instance of a constructor, a class and an object literal and then measures the speed of execution from the constructor's instance functions, class's prototype methods and object literal's static functions:
var Y, Z, x, y, z;
class X {
message(s) {
var mymessage = s + "";
};
addition(i, j) {
return (i * 2 + j * 2) / 2;
};
};
Y = function () {
this.message = function (s) {
var mymessage = s + "";
};
this.addition = function (i, j) {
return (i * 2 + j * 2) / 2;
};
};
Z = {
message(s) {
var mymessage = s + "";
},
addition(i, j) {
return (i * 2 + j * 2) / 2;
}
}
function TestPerformance() {
console.time("Closure time:");
y = new Y(); // create a single instance
for (var i = 0; i < 100000; i++) {
// I am comparing a single instance with the other single instances
y.message('hi');
y.addition(i, 2);
}
console.timeEnd("Closure time:");
console.time("Prototype time:");
x = new X(); // create a single instance
for (var i = 0; i < 100000; i++) {
// I am comparing a single instance with the other single instances
x.message('hi');
x.addition(i, 2);
}
console.timeEnd("Prototype time:");
console.time("Static object time:");
for (var i = 0; i < 100000; i++) {
z = Z; // obviously you don't really need this
z.message('hi');
z.addition(i, 2);
}
console.timeEnd("Static object time:");
}
TestPerformance();
The second test measures the speed of execution of creating many instances of a constructor, a class and object literals followed by executing the instance functions, prototype methods and static methods:
var Y, x, y, z;
class X {
message(s) {
var mymessage = s + "";
};
addition(i, j) {
return (i * 2 + j * 2) / 2;
};
};
Y = function () {
this.message = function (s) {
var mymessage = s + "";
};
this.addition = function (i, j) {
return (i * 2 + j * 2) / 2;
};
};
function TestPerformance() {
console.time("Closure time:");
//y = new Y()
for (var i = 0; i < 100000; i++) {
y = new Y(); // creating an instance
y.message('hi');
y.addition(i, 2);
}
console.timeEnd("Closure time:");
console.time("Prototype time:");
//x = new X();
for (var i = 0; i < 100000; i++) {
x = new X(); // creating an instance
x.message('hi');
x.addition(i, 2);
}
console.timeEnd("Prototype time:");
console.time("Static object time:");
for (var i = 0; i < 100000; i++) {
z = {
message(s) {
var mymessage = s + "";
},
addition(i, j) {
return (i * 2 + j * 2) / 2;
}
}; // creating an instance such as from factory functions
z.message('hi');
z.addition(i, 2);
}
console.timeEnd("Static object time:");
}
TestPerformance();
The lesson learned is that DON'T blindly evolve a prejudice against something without being thorough. The execution speed from instance functions of a constructor (pre ES2016 classes) and the speed from prototype methods of a class are really just as fast as the execution speed from static functions of a object. However the creation speed followed by execution speed of a constructor instance with instance functions versus the creation speed of a class instance with prototype methods versus the creation speed of object literals with static methods shows rather that classes with prototype methods are faster created and executed on Chrome, Microsoft edge, and Opera. The creation speed of an object literal with static methods is only faster at Mozilla firefox
So, creating the property on the instance would result in slightly faster access time - but this might only be an issue for a very deep prototype hierarchy.
Actually the result is different then we could expect - access time to prototyped methods is faster then accessing to the methods attached exactly to the object (FF tested).

Categories

Resources