Re: Why should I eschew prototype.js?
- From: "Richard Cornford" <Richard@xxxxxxxxxxxxxxxxxxx>
- Date: Tue, 13 Nov 2007 00:45:57 -0000
nolo contendere wrote:
I've recently begun playing with prototype.js as well as
scriptaculous, and found both very helpful in developing
web pages with lots of pop. Modal boxes, SlideUp/Down,
calendars, etc.
I've also recently ramped up my lurking and participation
in this newsgroup. There are some who advocate using prototype,
Here?
and others who are adamantly opposed to it. Are there any
concrete reasons why I should NOT use it?
Lots, but I don't have time to go through all of them right now. However, one good illustration is the least you deserve.
Take this code form the latest (1.6.0) version of Prototype.js:-
| var Hash = Class.create(Enumerable, (function() {
| if (function() {
| var i = 0, Test = function(value) { this.key = value };
| Test.prototype.key = 'foo';
| for (var property in new Test('bar')) i++;
| return i > 1;
| }()) {
| function each(iterator) {
| var cache = [];
| for (var key in this._object) {
| var value = this._object[key];
| if (cache.include(key)) continue;
| cache.push(key);
| var pair = [key, value];
| pair.key = key;
| pair.value = value;
| iterator(pair);
| }
| }
| } else {
| function each(iterator) {
| for (var key in this._object) {
| var value = this._object[key], pair = [key, value];
| pair.key = key;
| pair.value = value;
| iterator(pair);
| }
| }
| }
| ...
- What this appears to represent is the conditional creation of a function based upon (rather complex) test. But in ECMAScript terms this is actually one big syntax error, because inside each of the BlockStatement branches of the - if-else - there are what appear to be function declarations, and BlockStatemen may only contain Statements (not FunctionDeclarations (FunctionDeclarations and Statements being the two distinct syntactic units from which ECMAScript Programs and function bodies are constructed)).
Obviously if the 3 or 4 browsers with which Prototype.js 'works' actually generated a syntax error that fact would have been noticed, so what is happening? The first part of the answer is that JavaScript(tm) has a non-standard syntax extension that is a FunctionStatement, which (being a Statement) may appear inside a BlockStatement and can be conditionally evaluated. ECMAScript allows for such extensions, though they usually must be avoided when creating cross-browser code. The second part of the answer is that JScript (and many other ECMAScript implementations, including Opera's) are tolerant enough to unconditionally treat these out of context 'FunctionDeclarations' as FunctionDeclarations. But because FunctionDeclarations are processed during variable instantiation, before any actual code execution, in these environments the effect of the above is the equivalent of:-
var Hash = Class.create(Enumerable, (function() {
function each(iterator) {
for (var key in this._object) {
var value = this._object[key], pair = [key, value];
pair.key = key;
pair.value = value;
iterator(pair);
}
}
function each(iterator) {
var cache = [];
for (var key in this._object) {
var value = this._object[key];
if (cache.include(key)) continue;
cache.push(key);
var pair = [key, value];
pair.key = key;
pair.value = value;
iterator(pair);
}
}
if (function() {
var i = 0, Test = function(value) { this.key = value };
Test.prototype.key = 'foo';
for (var property in new Test('bar')) i++;
return i > 1;
}()) {
} else {
}
...
- Where the first - each - FunctionDeclaration results in the creation of a function object and the assignment of a reference to that function to the 'each' property of the variable object, and then the second - each - FunctionDeclaration - results in the creation of a second function object which is then assigned to the 'each' property of the variable object, replacing the first. So in these environments it is the second FunctionDeclaration that defines 'each', unconditionally, and the - if-else - statement is effectively empty, making its execution worthless.
Now if this code 'works' at all it 'works' mostly by coincidence as it is relying on a non-standard extension wherever the - if-else - is effective, and where the FunctionDeclaration are unconditionally acted upon the result must only 'work' due to the order in which the two declarations appear.
Of course the conditional creation of function objects is trivial in javascript in a way that fully conforms with the ECMAScript specification, and so in a way that can be expected to be fully cross-browser and consistently executed in ECMA 262 3rd Ed. implementing environments. Such code would be something like:-
var Hash = Class.create(Enumerable, (function() {
var each;
if (function() {
var i = 0, Test = function(value) { this.key = value };
Test.prototype.key = 'foo';
for (var property in new Test('bar')) i++;
return i > 1;
}()) {
each = function (iterator) {
var cache = [];
for (var key in this._object) {
var value = this._object[key];
if (cache.include(key)) continue;
cache.push(key);
var pair = [key, value];
pair.key = key;
pair.value = value;
iterator(pair);
}
}
} else {
each = function (iterator) {
for (var key in this._object) {
var value = this._object[key], pair = [key, value];
pair.key = key;
pair.value = value;
iterator(pair);
}
}
}
...
- replacing the 'syntax error' FunctionDeclaration with Expression Statements where a Function Expression is assigned to an Identifier. The result is fully ECMAScript standard and so will 'work' consistently in all past, present and future ECMA 262 3rd Ed. conforming implementations.
It is simply the case that anyone knowing javascript would have written the original code in this final form. So would not be writing code that functioned purely by coincidence but instead they would be programming.
The problem with the way this sort of ignorance of javascript results in code that only works by coincidence is highlighted by browsers like Opera. Opera currently acts like JScript, and unconditionally acts on the FunctionDeclarations out of their (otherwise syntax error) context but while Opera has an ECMA 262 conforming javascript implementation, they also aim to emulate JavaScript(tm), and so may introduce JavaScript(tm)'s FunctionStatement extension at any moment. And so code that works by coincidence because of the order of the 'FunctionDeclarations' may find itself suddenly conditionally evaluating FunctionStatements with any next version of Opera, and what these branches do in that versions of Opera may be totally inappropriate.
The Prototype.js approach results in code that cannot be expected to work in any more browsers than those in which it has been demonstrated to 'work', and so cannot even be expected to 'work' with the future versions of that those browsers. This cannot be a viable approach to creating cross-browser code, and it does not.
That is quite a bit of writing in order to demonstrate that the authors of Prototype.js don't know javascript. Similar demonstrations are possible for bad design, ridiculous inefficiencies, avoidable bad practices and much else besides, but I don't have time right now so you will have to look them up in the archive.
Is it inefficient?
The code itself is about a quarter as efficient as it could be, but certain aspects of the design promote its extremely inefficient use, so examples you will see are often orders of magnitude worse than that. Fast computers mitigate that problem, but you would find systems created with Prototype.js become unacceptably sluggish at much lower levels of complexity.
It seems that today's computers have sufficient processing
power to overcome most slowly implemented solutions in
javascript.
Maybe, but that doesn't stop my boss continually wanting the client-side code our web applications to run faster. He maintains that they are easier to sell when they are fast, and then that they are easier to sell if they have ever more bells and whistles. Obviously those are contradictory demands.
And the benefits of being able to inject such
a wide variety of effects into a page (to me) far
outweigh any harm.
At least for as long as you avoid understanding how those effects work, and so how trivial they are to create for yourself.
Richard.
.
- Follow-Ups:
- Re: Why should I eschew prototype.js?
- From: nolo contendere
- Re: Why should I eschew prototype.js?
- References:
- Why should I eschew prototype.js?
- From: nolo contendere
- Why should I eschew prototype.js?
- Prev by Date: open source JavaScript debugger that I can port to a new browser
- Next by Date: Re: form serialization (Code Worth Recommending Project)
- Previous by thread: Re: Why should I eschew prototype.js?
- Next by thread: Re: Why should I eschew prototype.js?
- Index(es):
Relevant Pages
|