In the JavaScript the same thing you can do in many different ways.
Consider the examples:
1:
function Circle(radius) {
return {
"r" : radius,
"area" : function(){
return Circle.pi * this.r * this.r;
}
}
}
Circle.pi = 3.14159;
var a = Circle(10);
alert(a.area());
2:
function Circle(radius) {
this.r = radius;
}
Circle.pi = 3.14159;
Circle.prototype.area = function(){
return Circle.pi * this.r * this.r;
}
var a = new Circle(10);
alert(a.area());
The second is better than first because we dont define the same function area for any instance of the Circle.
But lets consider 3:
function Circle(radius) {
return {
"r" : radius,
"area" : Circle.area
}
}
Circle.pi = 3.14159;
Circle.area = function(){
return Circle.pi * this.r * this.r;
}
var a = Circle(10);
alert(a.area());
Is there any reason to prefer second style instead of third? Or I misunderstood something at all?
In the JavaScript the same thing you can do in many different ways.
Consider the examples:
1:
function Circle(radius) {
return {
"r" : radius,
"area" : function(){
return Circle.pi * this.r * this.r;
}
}
}
Circle.pi = 3.14159;
var a = Circle(10);
alert(a.area());
2:
function Circle(radius) {
this.r = radius;
}
Circle.pi = 3.14159;
Circle.prototype.area = function(){
return Circle.pi * this.r * this.r;
}
var a = new Circle(10);
alert(a.area());
The second is better than first because we dont define the same function area for any instance of the Circle.
But lets consider 3:
function Circle(radius) {
return {
"r" : radius,
"area" : Circle.area
}
}
Circle.pi = 3.14159;
Circle.area = function(){
return Circle.pi * this.r * this.r;
}
var a = Circle(10);
alert(a.area());
Is there any reason to prefer second style instead of third? Or I misunderstood something at all?
Share Improve this question asked Aug 28, 2010 at 20:31 DanDan 3071 gold badge3 silver badges6 bronze badges 3-
You know about the availability of
Math.PI
, don't you? – Marcel Korpel Commented Aug 28, 2010 at 21:08 - 1 possible duplicate of Object oriented javascript with prototypes vs closures – Marcel Korpel Commented Aug 28, 2010 at 21:13
- I've made some benchmarks like here blogs.msdn./b/kristoffer/archive/2007/02/13/…. The result - the 3rd style just between 1st and 2nd :) Thx for all answers and ments, I've learnt a lot. – Dan Commented Aug 28, 2010 at 22:38
5 Answers
Reset to default 4I would definitely go with example 2. Neither example 1 or 3 make good use of JavaScript's object-oriented features because:
- You duplicate method definitions in each instance.
- By returning a new object instead of using
this
, you lose the identity of the class, i.e. you can no longer do checks likea instanceof Circle
. - You give up the possibility of inheritance since you do not use prototypes.
Is there any reason to prefer second style instead of third?
The third style is still wasting a small amount of space in order to store the association between the name area
and the area function.
Also because you are returning a new Object
from the {...}
literal, instanceof Circle
won't work.
The second is better than first because we dont define the same function area for any instance of the Circle.
Indeed, but it can sometimes be useful to define a new copy of each method—a copy that, thanks to closures, can know what object it is bound to. With traditional prototyping you only get the this
context which is set from the object the caller retrieved it from, rather than bound to a particular object. The first way avoids the problems of this
-retention in things like event handlers, at the price of some loss of efficiency.
The difference between Circle.prototype.area
and Circle.area
is that one is only accessible with a instance of the class.
Circle.prototype.area = function(){};
Circle.area // wrong
(new Circle()).area // ok (you need a Circle object)
and
Circle.area = function(){};
Circle.area // ok (you don't need the object, its static)
(new Circle()).area // wrong
The problem with example 2 is, that when you accidentally forget to use the new
operator when creating the object, and just call var a = Circle(10);
(which is fine for the 3rd example, but not for the 2nd), then your constructor creates big trouble:
this.r = radius;
Since you didn't use new
, this
will be assigned the global object, so the constructor really sets the global variable r
!
So I would strongly prefer example 3.
I'd like to ment on "The second is better than first because we dont define the same function area for any instance of the Circle." In practice, this may be such a negligable advantage as to be totally insignificant. I tend to favor syntax and human-friendly code over efficiency, unless performance is noticably affected. I've been pletely ignoring the Prototype feature of javascript and also avoiding the use of "this", basically using technique #1. It's working just fine for me. I find avoiding "this" prevents a lot of confusion about just what "this" refers to. It's perfectly possible to create inheritance-type structures without "prototype". You simple create a superclass object, and override whichever methods you want. Douglas Crockford has written pretty extensively on numerous different ways to do inheritance in javascript.
I will agree with casablanca above that being able to test for type using "instanceof" is a nice advantage of returning "this". Perhaps I'll take another look at "protype" and "this" on a future project. For now, though, I'm getting along just fine without them.