10 things Paul Irish learned from the jQuery source
Tags: webdevelopment, programming. By lucb1e on 2012-06-09 23:28:14 +0100
I got very annoyed by the arrogance of Mr. jQuery Board Member which some people seem to love... I thought I would get a great talk about 10 awesome things jQuery does that hardly anyone knows about. Instead this is an hour-long video full of 'stuff's and 'awesome's with like 0.1% content.
This post will be telling you all useful stuff he said, only without pretending every word that I say is awesome just because I said it.
The video
http://paulirish.com/2010/10-things-i-learned-from-the-jquery-source/
The useful stuff
jQuery has parenthesis all around it:
(function(window, document, undefined) {
jQuery source;
})(this, document);
This can be simplified down to:
function() { code }();
Which does the same. The reason that there are parenthesis around
function(){code} is because it tells whoever reads the code right at the top: This is going to execute immediately. You could have used an exclamation mark in front of it too (but not behind it), it all works.
Then the arguments: Since it's called outside any DOM element or function,
this will return the window. Document just gets passed document, and undefined will be skipped to make it an undefined variable.
The window and document arguments are to make minifying work better. If you would use
document.getElementById("something"); a lot, now the minifier will make it:
(function(A,B,C){B.getElementById("something");});
instead of the long "document" you had before. Another small advantage is that when you use B here, it will first look if there is a variable in the local scope (within the function) which has that name. After that it looks at the global scope (if there is a global variable with that name), where it would find document. But since you passed it as an argument, it finds it right at first when it looks for the local scope (arguments are local of course). This is only a very slight performance increase though, there is no need to to this just for this reason, it's only a nice side effect.
Then the undefined argument is to ensure that
if (varname == undefined) does what you think it does. Because (according to him, I can't get it to work like this) if you would do:
undefined = true;
if (varname === undefined) alert("It's undefined!");
it will alert that it is defined, because varname is not true. To prevent the jQuery library from getting messed up if someone, for some mind-boggling reason, does this, the undefined argument is now a local variable which is really undefined.
The next thing Paul complains about is how setInterval is so very nasty. When you do
setInterval("func();", 10); it will call func() every 10 milliseconds, even if the func takes more than 10ms to execute. This can indeed cause unwanted effects, but for what I've used it for, this is just what I want it to do (and I wouldn't know how else to do it).
To make it wait 10ms between each run of the function you can simply make your own 'delayed loop'. I actually did this when I didn't know setInterval existed:
function run() {
//Code you want to run
setTimeout("run();", 10);
}
This will of course run itself, and only after it ran it will set the timeout to do it again. Effectively pausing 10ms between each run, instead of running every 10ms.
jQuery.noConflict() prevents itself from conflicting with other libraries which use the dollar sign as well. The way it does this is simple: Right at first, before it binds $ to the jQuery library, it will make a backup of whatever the dollar sign currently is. Then at noConflict, it will just set back the backup.
<script>
$ = function() { alert("Call me!"); }
</script>
<script src=jQuery.js>
jQuery(); //Will call jQuery
$(); //This will now call jQuery, while we are trying to spawn an alert
$.noConflict(); //puts back the backup of $ to $
$(); //Now it will spawn the alert again, while...
jQuery(); //...still works to use jQuery
</script>
jQuery.props is used as a dictionary to look stuff up. This is a part of the source:
jQuery.props = { "for": "htmlFor", "class": "className" };
So if you are not so smart, jQuery tries to guess some property names for you. The only place this is used really is in .attr(), which is used by many other functions though. So if you try $(elem).attr("class"), it will actually call $(elem).attr("className"). I feel this is a bit nooby, but it fits with the library's idea: it saves time.
You can add your own shortcuts by using:
$.props["w"] = "width";
Now when you try this, it will alert the width:
alert($(elem).attr("w"));
$(elem).fadeIn("speed") makes an element fade in with a certain speed. There are by default three speeds: fast, slow and the default. He complains that you will doubt what the default is, it might be "normal" or "regular", but both (or even passing no argument) works just fine. You can extend the available speeds with your own variables if you want though:
$.fx.speeds["veryslow"] = 1200;
You can change the default like so:
$.fx.speeds._default = //yourvalue
(Actually he says that you can make it run twice as slow in MSIE6 and 7 to prevent a jerky animation, but I think this is pretty obvious to everyone and also very undesirable--the speed will suddenly change by 100% depending on which browser you use.)
$().ready(function() { executed when the DOM is ready! });
What this does is attach an eventListener in decent browsers to be executed when the DOM is ready. It also adds itself to document.onLoad as a fallback, just in case. It runs only once though, when it's already called it simply won't execute anymore.
In MSIE it has a special treatment, which does another thing next to adding itself to document.onLoad. This was invented by Diego Perini and is a little hack: In MSIE the <html> tag has a property called doScroll which is supposed to return a boolean saying whether the element would be scrollable, pretending that the content would be large enough to need a scrollbar. Though when the DOM isn't ready yet, this function will raise an exception. So what jQuery does is simply look every millisecond whether doScroll still raises an exception. If it doesn't, it'll run the document.ready event.
Then somewhere between 24 minutes and 32 minutes he copies a method from jQuery to make his own shorthand function... I don't really see the sense of doing this, but he has an apparent fetish for cornify, so if you have that too I recommend you watch it. Hmm this will probably make people wanna watch what I mean. Just don't, it's not worth your time. If you want to do what he did but a little more sane, just find some code in jQuery and copy it over, then modify it a bit and call it.
Note how at 33:10 he dual-licenced the code both under copyright law and the WTFPL licence. So first he copied a part of jQuery (which is licenced as open-source under MIT, BSD, and GPL), then tries to put copyright on (which is legally impossible for all lines that aren't his), and then adds another licence stating that the code is in the public domain. If anyone can come up with anything legally even more impossible, let me know. Of course he meant it as a joke, but it's just so stupid I can't help but use his joke as a joke.
$("#id").find("tag.thing") is faster than
$("#id tag.thing") because if you do it all in one string instead of attach the
.find(), it takes a bit longer to find out what you actually passed it. jQuery checks if you passed an #id only, and if you didn't it goes into Sizzle.
$(":password") gets all password fields. It's a synonym for
$("*:password"). All it really does is check every element in the DOM for:
element.type == "password".
Let me repeat that: every single element in the DOM. Also your divs, which can't be passwords. So do your CPU a favor and use
$("input:password"). That'll speed it up by a lot. Same goes for all other
:selectors.
For JSON parsing, jQuery first checks for native support by the browser. If the browser supports it, it'll just use it. If not, it'll eval it.
The jQuery
.unique function is only capable of sorting and removing duplicates of elements. Why not strings and/or numbers? Well it's simply an alias for Sizzle's function
uniqueSort. Sizzle uses it internally, and I guess the jQuery writers were like, oh well whynot make this a jquery feature too. It's in there already anyway.
Here is code by which you can redefine/upgrade the unique function: http://paulirish.com/2010/duck-punching-with-jquery/ (See example 2)
With
$.support{} you can see what kind of browser we're dealing with; whether a certain feature works or not. The way this works is, jQuery creates a div element and places this HTML in it:
" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>"
Then, it fills the support object:
support = {
hrefNormalized: ( a.getAttribute("href") === "/a" ),
getSetAttribute: div.className !== "t"
};
(It has a lot more items and comments in it than this, but it's just to show you what it does.)
After running this you can simply use
$.support.hrefNormalized in an expression.
His video: 53 minutes and 40 seconds.
This post, read by the Average American Adult: 7 minutes and 20 seconds.