[quoted text, click to view] "Igor Tandetnik" <itandetnik@mvps.org> wrote in message
news:uZpbV$DpGHA.4116@TK2MSFTNGP03.phx.gbl...
> Dhruba Bandopadhyay <dhruba.bandopadhyay@hotmail.com> wrote:
> > I have came across 3 different ways of creating a structure or class.
> >
> > 1. Class as a function way
> >
> > // Class Constructor
> > function Timer(Source) {
> >
> > // Class Properties
> > this.timerID = 0;
> > this.tStart = null;
> >
> > // Class Methods
> > this.UpdateTimer = function() {
> > };
> > }
>
> It's better to define a method like this:
>
> function Timer() {...}
> Timer.prototype.UpdateTimer = function() {...};
>
> This way the function is created only once. In your original code, an
> instance of the function object is created anew every time an instance
> of Timer is created.
>
> > 2. Class.create & prototype way
> >
> > var WindowDelegate = Class.create();
>
> I've never seen this syntax. In IE, it produces an error " 'Class' is
> undefined".
>
> > 3. Declare as a var way
> >
> > var myObserver = {
> > variable: null,
> > anotherVariable: 33
> > stringVariable: 'asdf',
> > aFunction: function(a, b) {
> > }
> > }
> >
> > I assume #3 is just a object/structure instance rather than a class
> > definition.
> >
> > Has anyone came across #1 way?
>
> All major JavaScript libraries I know of do it this way. See e.g.
>
http://dojotoolkit.org/ >
> > What are the differences between these
> > 3 ways?
>
> Well, #2 does not work. #1 has a nice encapsulated syntax, constructors
> with parameters - you can almost pretend you are working in an object
> oriented language. #3 is useful for a quick one-off object, but this
> approach does not lend itself to reuse. Also, an object created with #1
> can be tested with instanceof operator:
>
> var timer = new Timer(0);
> if (timer instanceof Timer) {...};
>
> #3 also does not allow one to use prototype property to create a method
> just once: you have to define it every time you create an instance,
> which adds performance overhead. One can work around it like this, but
> it's not as clear as #1:
>
> function Timer_UpdateTimer() {...};
> function makeTimer(source) {
> var timer = {};
>
> // Class Properties
> timer.timerID = 0;
> timer.tStart = null;
>
> // Class Methods
> timer.UpdateTimer = Timer_UpdateTimer;
> }
> var timer = makeTimer(0);
>
>
> Almost everything you can do with #1 you can also do with #3, but I feel
> #1 syntax is cleaner. The two things you can only achieve with #1 are
> support for instanceof, and inheritance (in JavaScript, you can arrange
> for one class to "inherit" from another, several levels deep; multiple
> inheritance is not really supported, but there are techniques to fake
> it).
>
> > And what is the proper way to define a class?
>
> #1.
There are ultimately two 'proper' ways to define a class as you have already
touched on. To clarify:-
Option A.
function MyClass(value)
{
var x = 0, y = 0 //private class level variables
this.a = value // public member
function fnPrivateStuff() // private functions
{
...
}
this.publicStuff = function() // public method
{
...
}
}
This approach provides much stronger encapsulation (x,y for example can only
be referenced from a function defined inside the class) it is therefore more
suited to large complex objects. However as pointed out instances of this
type are more expensive to create so may not be the best choice if a large
number are to be created. A more important point IMO is that implementing a
design that incoporates generalised and specialised classes (inheritance) is
awkward in this approach.
Option B
function MyClass(value)
{
this.x = 0; this.y = 0
this.a = value
}
MyClass.prototype.fnPrivateStuff = function()
{
}
MyClass.prototype.publicStuff = function()
{
}
MyClass.prototype.publicStuff2 = function()
{
}
This approach has much weaker encapsulation. In fact it has no
encapsulation at all. The distinction between public and private members
would have to rely on conventions such as the use of a preceeding underscore
in member names. Creating a large number of instances of this class is
cheaper since the created instance only needs to carry the value the member
variables not the functions. This approach's biggest strength is in
implementing specialisation of general classes:-
function MyDerivedClass(value1, value2)
{
MyClass.call(this, value1) //Base class constructor
this.b = value2
}
MyDerivedClass.prototype = new MyClass()
MyDerivedClass.prototype.somePublicMethod = function()
{
}
MyDerivedClass.prototype.publicStuff2 = function() // override
{
}
On thing often missed in the prototype approach is that default values for
non-function members can also be defined. This further reduces the cost of
creating instances of these classes where member values are only actually
created when a new value is assigned to them. The MyClass above can look
like this:-
function MyClass(value)
{
this.a = value
}
MyClass.prototype.x = 0
MyClass.prototype.y = 0
HTH,
Anthony