tags:

views:

83

answers:

5

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?

+1  A: 

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
BrunoLM
Did you read the OP's 3rd example?
Crescent Fresh
Not entirely true. The following is legal: `Circle.prototype.area()` (although you probably want to use `call` or `apply` with it.)
trinithis
True, but if it's on prototype generally it shouldn't be called like that, it might depend on some properties of the instance. Anyway thanks for point that.
BrunoLM
A: 

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.

Chris Lercher
+1  A: 

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.

bobince
+3  A: 

I would definitely go with example 2. Neither example 1 or 3 make good use of JavaScript's object-oriented features because:

  1. You duplicate method definitions in each instance.
  2. By returning a new object instead of using this, you lose the identity of the class, i.e. you can no longer do checks like a instanceof Circle.
  3. You give up the possibility of inheritance since you do not use prototypes.
casablanca
A: 

I'd like to comment 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 completely 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.

morgancodes
Regarding `this`: also read Peter Michaux' [JavaScript Widgets Without "this"](http://michaux.ca/articles/javascript-widgets-without-this)
Marcel Korpel