jQuery's latest stab at competence



Some things never change. I see lots of blog posts with statements
like "jQuery was always super fast, but just look at these graphs!"
Never mind that the graphs have no units.

John Resig has been fumbling, bumbling and stumbling around browser
scripting for three years now (according to his Website, the release
was on jQuery's 3rd anniversary.) Why are so many people willing to
wait out his painfully slow learning process?

I saw one post by a developer who had to downgrade due to
incompatibility with some worthless plug-in. He stated that he would
*love* to use the new (super super fast?) jQuery, but he can't because
he is married to the "great" plug-in.

And what is "Sizzle?" John Resig suddenly discovered
document.evaluate? He's years behind on an unattainable goal (writing
the perfect JS library that satisfies the needs of every project and
every user.) Near as I can tell, he has never written a competent
script in his life (or written anything useful on the subject.)

So what do we have here?

Five seconds in, this line sticks out like a sore thumb:

if ( typeof text !== "object" && text != null )

The first comparison does not need to be strict. The second
comparison is obviously a waste of time. Who knows what the
intentions are as there are no comments for the containing method
(also called "text.") Looks like a symptom of jQuery's botched
design, which relies on all sorts of ill-advised method "overloading."

for ( var name in options )
elem.style[ name ] = old[ name ];

Wouldn't you hate to be a jQuery developer? Good luck debugging apps
that use other scripts.

Now here's a low-level function that needs to be as efficient as
possible:

css: function( elem, name, force ) {
if ( name == "width" || name == "height" ) {
var val, props = { position: "absolute", visibility: "hidden",
display:"block" }, which = name == "width" ? [ "Left", "Right" ] :
[ "Top", "Bottom" ];


Sure, why not create these objects every time through? Super fast
that.



function getWH() {
val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
var padding = 0, border = 0;
jQuery.each( which, function() {

So much for efficiency. This guy has learned nothing.

padding += parseFloat(jQuery.curCSS( elem, "padding" + this,
true)) || 0;
border += parseFloat(jQuery.curCSS( elem, "border" + this +
"Width", true)) || 0;
});
val -= Math.round(padding + border);

Rounding?! Box model differences?

}

if ( jQuery(elem).is(":visible") )

So much for common sense. Even the MooTools team figured out that
this is a stupid idea.

getWH();
else
jQuery.swap( elem, props, getWH );

That's the method with the unfiltered for-in loop.

return Math.max(0, val);

Whatever.

}

return jQuery.curCSS( elem, name, force );

So if it is not height or width, call some other function.

},

Here it is:

curCSS: function( elem, name, force ) {
var ret, style = elem.style;

// We need to handle opacity special in IE
if ( name == "opacity" && !jQuery.support.opacity ) {
ret = jQuery.attr( style, "opacity" );

As I mentioned a year earlier, the "attr" method is a God-awful mess.
Resig actually agreed IIRC (his only concession in the face of dozens
of obvious mistakes.) Yet, here we are a year later calling it to get
the opacity style.


return ret == "" ?
"1" :
ret;

return ret || '1';


}

// Make sure we're using the right name for getting the float value
if ( name.match( /float/i ) )

Match?!

name = styleFloat;



if ( !force && style && style[ name ] )
ret = style[ name ];

else if ( defaultView.getComputedStyle ) {


If that looks odd (did to me), "defaultView" is created earlier:

defaultView = document.defaultView || {},

Yes, he is actually storing a reference to the mother of all host
objects. Do this in FF or the like:

window.alert(document.defaultView == window)

Granted, IE doesn't have this property (at least not in the released
versions.) Maybe newer versions of IE won't leak memory at all, but
then again, they might have document.defaultView pointing to the
window object, which would cause any element with an ID to leak
listeners attached through jQuery (not to mention the document object,
images, links, child nodes of the document, their child nodes, etc.)

For example, if you attach a listener to the first image in the
document, you would create this circular reference:

[image]->[wrapped listener]->[variable object]->[window]->[document]->
[images]->[image]

What a nightmare. Never preserve a reference to the window object (or
global object) in a closure (certainly not in code that attaches
listeners!)

// Only "float" is needed here
if ( name.match( /float/i ) )

Apparently he hasn't gotten to the "T" section of the manual yet
(test.)

name = "float";

name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();

var computedStyle = defaultView.getComputedStyle( elem, null );

if ( computedStyle )
ret = computedStyle.getPropertyValue( name );

The getPropertyValue method is broken in some older browsers. I
wouldn't expect the jQuery team to be aware of the need to test for
this as they seem to have their hands full with the latest versions of
IE, FF and Safari (do they even claim to support anything else?)

// We should always get a number back from opacity

A string actually.

if ( name == "opacity" && ret == "" )
ret = "1";

} else if ( elem.currentStyle ) {

Slow. How many years until the authors learn to use efficient
patterns?

var camelCase = name.replace(/\-(\w)/g, function(all, letter){
return letter.toUpperCase();
});

Another function created and discarded to be created again next time.
I get the feeling that no significant time or thought was put into any
of this.

ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];

That's just stupid. The "camel-ized" version is what works.


// From the awesome hack by Dean Edwards
// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291

Actually, I know this sucks. I admit I have used it when writing
general-purpose scripts, but it required some modification. Of
course, it would be better if application developers avoided
situations that required such hacks (but that would be less than
"awesome" wouldn't it?) Another reason why scripts without context
are generally a bad idea.

// If we're not dealing with a regular pixel number
// but a number that has a weird ending, we need to convert it to
pixels
if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
// Remember the original values
var left = style.left, rsLeft = elem.runtimeStyle.left;

// Put in the new values to get a computed value out
elem.runtimeStyle.left = elem.currentStyle.left;
style.left = ret || 0;
ret = style.pixelLeft + "px";

// Revert the changed values
style.left = left;
elem.runtimeStyle.left = rsLeft;
}
}

return ret;
},

jQuery.offset = {
initialize: function() {
if ( this.initialized ) return;

Ugh.

var body = document.body, container = document.createElement('div'),
innerDiv, checkDiv, table, td, rules, prop, bodyMarginTop =
body.style.marginTop,
html = '<div style="position:absolute;top:0;left:0;margin:0;border:
5px solid #000;padding:0;width:1px;height:1px;"><div></div></
div><table style="position:absolute;top:0;left:0;margin:0;border:5px
solid #000;padding:0;width:1px;height:1px;" cellpadding="0"
cellspacing="0"><tr><td></td></tr></table>';

rules = { position: 'absolute', top: 0, left: 0, margin: 0, border:
0, width: '1px', height: '1px', visibility: 'hidden' };
for ( prop in rules ) container.style[prop] = rules[prop];

container.innerHTML = html;
body.insertBefore(container, body.firstChild);
innerDiv = container.firstChild, checkDiv = innerDiv.firstChild, td
= innerDiv.nextSibling.firstChild.firstChild;

this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
this.doesAddBorderForTableAndCells = (td.offsetTop === 5);

innerDiv.style.overflow = 'hidden', innerDiv.style.position =
'relative';
this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop ===
-5);

body.style.marginTop = '1px';
this.doesNotIncludeMarginInBodyOffset = (body.offsetTop === 0);
body.style.marginTop = bodyMarginTop;

body.removeChild(container);
this.initialized = true;

Well, I suppose imitation is a form of flattery. Still, it's a pretty
poor imitation.

},

bodyOffset: function(body) {
jQuery.offset.initialized || jQuery.offset.initialize();

Arrrrrghhhhhhhhh! (See above and don't write code like this.)

var top = body.offsetTop, left = body.offsetLeft;
if ( jQuery.offset.doesNotIncludeMarginInBodyOffset )
top += parseInt( jQuery.curCSS(body, 'marginTop', true), 10 ) ||
0,
left += parseInt( jQuery.curCSS(body, 'marginLeft', true), 10 ) ||
0;

parseInt?

return { top: top, left: left };
}

The rest of the offset code is more of the same (confused and
inefficient.) This is the hardest function to write and one that
virtually nobody needs. At least this version isn't infested with
browser sniffing like the previous attempts. If they keep at it, they
may one day come up with a solution to a problem that doesn't need to
be solved in the first place.

if ( document.documentElement["getBoundingClientRect"] )

Why bracket notation? Is it sloppiness or ignorance? And as we all
know by now, this is a terrible way to detect a host method.
Apparently John Resig does not read this group, except when jQuery is
panned periodically (even then, he doesn't seem to grasp what he is
reading.)

From the FX code, which has always been awful:

// Simple function for setting a style value
update: function(){
if ( this.options.step )
this.options.step.call( this.elem, this.now, this );

(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );

// Set display property to block for height/width animations
if ( ( this.prop == "height" || this.prop == "width" ) &&
this.elem.style )
this.elem.style.display = "block";
},

This is the function that is called on each "step" of the animation.
Look at that last bit. Not the logic (which is disturbing enough),
but the placement. I've got animation code from before the turn of
the century that is light years ahead of this. Well, he's learning.
It's a process. Wait a few more years and this will really be the
ultimate script for everything.

// Either scroll[Width/Height] or offset[Width/Height], whichever is
greater
Math.max(
document.documentElement["client" + name],
document.body["scroll" + name], document.documentElement["scroll"
+ name],
document.body["offset" + name], document.documentElement["offset"
+ name]
) :

Comment seems confused. Logic is ludicrous.

// elem is actually elem.style ... set the style

I really hate that.

// IE uses filters for opacity
if ( !jQuery.support.opacity && name == "opacity" ) {
if ( set ) {
// IE has trouble with opacity if it does not have layout
// Force it by setting the zoom level
elem.zoom = 1;

// Set the alpha filter to set the opacity
elem.filter = (elem.filter || "").replace( /alpha\([^)]*\)/, "" )
+
(parseInt( value ) + '' == "NaN" ? "" : "alpha(opacity=" + value
* 100 + ")");
}

return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?
(parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100) +
'':
"";
}

I think it is quite clear at this point that they can't do *anything*
right. This is the worst thing I have seen since MooTools. So the
answer to the "jQuery vs. MooTools" question is obviously neither.
Either will allow neophytes to delude themselves (and their clients)
into thinking they can write cross-browser widgets and applications.
The prevailing opinion seems to be that what follows is a maintenance-
free utopia with armies of eager support representatives waiting to
solve any problems that may arise. This opinion has been formed
because the authors of these scripts repeatedly make such assertions
in their blogs, leading lots of clueless people to parrot them as
facts (see the Ajaxian site for lots of examples.)

These people are marketers, not programmers. They aren't doing this
to be good samaritans either (never mind that their scripts are
free.) This is all about selling their books, which aren't worth a
plugged nickel. Save your time, money and aggravation and forget that
jQuery exists.
.



Relevant Pages

  • Re: JS strangeness
    ... Cheap shot #1. ... JS scripts, or in the HTML. ... a - DOMContentLoaded - event on the document (assuming the browser ... The relationship is that Mozilla employs the author of jQuery, ...
    (comp.lang.javascript)
  • Re: jQuery and autosuggest and more
    ... jQuery, which version of jQuery UI and what browser/configuration? ... using a dodgy stack of scripts like jQuery UI is a very ... This is a rare case where browser usage statistics can be taken at ... "Opera Mini has limited support for JavaScript. ...
    (comp.lang.javascript)
  • Re: jQuerys latest stab at competence
    ... *love* to use the new (super super fast?) jQuery, ... general-purpose scripts, ... Apparently John Resig does not read this group, ...
    (comp.lang.javascript)
  • Re: book - jQuery
    ... what jQuery is to a bad program written in ...  And it is full of browser sniffing, ... Matter of taste, if you ask me. ... scripts) everywhere I go. ...
    (comp.lang.javascript)
  • Re: how work .animate
    ... opacity: 0.6}).end. ... is possible to have 2nd opacity with no use of .animate? ... others:if I use opacity: toggle" I have for just a moment image with ... You appear to be using jQuery. ...
    (comp.lang.javascript)