Fork jQuery! Introducing ukQuery…
July 26, 2011 § 2 Comments
At Mint Digital we’re always looking for the best tools out there to make our work more streamlined. We use Ruby on Rails to create a solid backend, GitHub for version control, and jQuery as our Javascript framework.
Having come from a company where we mostly used Dojo, I find the latter tool is sometimes quite confusing to work with.
Making jQuery better – ukQuery
To make it easier to work with jQuery, I decided to fork jQuery and create my own custom version. I started with an important spelling correction; colour is now spelled in UK English. So every styling on the CSS ‘color’ property via ukQuery can be done with the ‘colour’ property as well.
$("a").css("colour", "red");
To make the UK jQuery experience complete, you can only use the ‘colour’ property after calling the excuseMe() function. So remember your manners:
$("a").excuseMe().css("colour", "red");
Having made these changes, the $ symbol looks really silly and because £ is an invalid character in Javascript, I replaced the $ character by GBP. The result is a really great tool, which gives jQuery a more natural feeling for UK based developers.
So now I’ve had a rant, I’d like to share some other thoughts on jQuery…
jQuery object versus normal nodelist
Querying the DOM with jQuery returns a jQuery object with a nodelist in it. If you want for example to change the CSS of all the nodes, you can simply do this:
$(".foo").css("display", "none");
I see the advantages of jQuery’s approach here; first of all you don’t have do deal with nodelists or array’s if you don’t understand them. Besides that, it’s shorter and more readable. At least in some cases…
What if you want to change the CSS for a bunch of nodes and change some other styles on one particular node?
You will end up with something like this:
var foos = $(".foo");
$.each(foos, function(index, myFoo){
$(myFoo).css("color", "red");
if(myFoo.id === "bar"){
$(myFoo).css("color", "blue");
}
});
(You can also do a separate query for “.foo#bar”, but that’s an extra query, so less efficient.)
What confuses me here is that you first have to extract the node from the jQuery object:
$.each(foos, function(index, myFoo){
then put it back into a jQuery object again, just to be able to use jQuery methods on that node:
$(myFoo).css("
You always have to wrap a node in a jQuery object to be able to apply any jQuery action on it. In terms of performance that’s no big deal. jQuery’s performance is quite impressive, so you will probably never notice the time difference between wrapping a node in a jQuery object or leaving it as a “plain” node. However, if you start extracting nodes from the jQuery object and wrapping it back in a new one again, the readability of your code decreases. (James Padolsey wrote an interesting article, as well as a plugin, related to this topic). So why not just myFoo.css() instead of $(myFoo).css(). Why all the bling?
Dojo and MooTools (and probably a lot more frameworks) for example, don’t require you to wrap a node in some magic object, but still enable you to chain your actions.
What is this?
In Javascript the this keyword refers to its owner (PPK’s Quirksmode provides a lot of useful information about this). So if you write a simple function:
function foo(){
console.log(this); //will output window
}
This will output the window object in the console. Because that function is “owned” by the window object. If we use the same function and place it in a property of the “foo” object, the this keyword will refer to the “foo” object:
var foo = {};
foo.myMethod = function(){
console.log(this); //will output foo
};
foo.myMethod();
In Javascript there is one exception to this behaviour; in the case of an eventlistener, this will refer to to node where the event was fired from:
bar.addEventListener('click',function(){
console.log(this); //will output bar
},false);
That’s pretty much how the this keyword behaves in Javascript. It always refers to it’s owner object, except in the case of an eventlistener…
jQuery however makes it a bit more complicated.
var foo = ["apple", "orange", "banana"];
$.each(foo, function(){
console.log(this); //will output apple, then orange, and finally banana
});
In a jQuery.each loop, this refers to the current element. So that’s another exception in the behaviour of this. Yet, another confusing aspect. I thought a Javascript framework was meant to make things more consistent, to normalize them! For me, it is making this worse.
It’s not only complaining
There are obviously a lot of good parts of jQuery. All the magic from the jQuery object makes it easy to work with for beginners. And if you’re a more advanced user, you can definitely also use jQuery for the more nifty scripts. Besides that, jQuery has a huge active community that have together created a lot of great plugins and documentation, which can save you a lot of time…
Have you too wrestled with jQuery? Let me know your thoughts!
If you would like to know anymore about the aspects of jQuery I have discussed here; there is also a nice episode of the yayQuery podcast on this topic.
Re: jQuery object versus normal nodelist
Your trying to use jQuery like you would use Dojo. This is a mistake. A more jQuery way of doing what you were trying to do is:
$(".foo").css("color", "red").filter('#bar').css("color", "blue");
You need to stop trying to iterate over jQuery objects and let it do the iteration for you. jQuery methods will always apply themselves to each element in the object so there is no need to do it manually yourself.
Hey Edd, You’re completely right there, that is a more jQuery way of doing that, and. Clearly I’m still not completely used to the jQuery way of writing scripts like this. Like I said, with frameworks like Dojo and Mootools you can do chaining as well. But I have to admit, at least Dojo doesn’t go as far as jQuery with chaining your actions.
Still though, I can think of scenarios where you would have to wrap your node back in to a jQuery object again (eventhandlers?) to be able to use jQuery actions on that node. Maybe that example wasn’t the best to illustrate my point. Also, to be honest I’m getting used to the concept of the jQuery object, but I’m not in love with it (yet).