Careful with that prototype, Eugene
Here's one that could cost you some long and puzzling debugging sessions.
What's the difference between
Foo.Bar = function() { this.number = 0; this.stuff = {}; } Foo.Bar.prototype.toString = function() { return "Bar #" + this.number + (this.stuff.id || ""); }and
Foo.Bar = function() {} Foo.Bar.prototype.number = 0; Foo.Bar.prototype.stuff = {}; Foo.Bar.prototype.toString = function() { return "Bar #" + this.number + (this.stuff.id || ""); }Well, it becomes obvious when you try the following:
var a = new Foo.Bar(); var b = new Foo.Bar(); a.number = 1; a.stuff.id = "a"; b.number = 2; b.stuff.id = "b"; alert(a.toString()); alert(b.toString());
In the first case, you'll get "Bar #1 a" and "Bar #2 b". In the second "Bar #1 b" and "Bar #2 b". The reason is that both instances of Foo.Bar have the same prototype, so they both share the same object as their "stuff" field. If you set it on any instance, it affects all of them. In the first case, a new object is created from each instance's constructor.
Using the prototype to keep the cost of constructing instances as low as possible is a good idea in general but as most powerful concepts it must be handled with care. In the next article, I'll detail the difference between the closure style of JavaScript type definition and the prototype style. This is one of the caveats to keep in mind when going the prototype way.
Now, this could very well be taken advantage of by defining a "static" blob on the prototype to simulate the concept of fields shared between instances. That would kinda work but it would be a little weird to have statics hanging off a field on instances and it would be easy to overwrite this static blob off any instance. But the best argument against that is that defining statics as members of types (i.e. constructor functions) works much better and is more natural. The only problem with the latter method is statics are hard to differentiate from instance members of the type Function.