This is the final part of my series which follows on from Do You Really Need jQuery? In this article, we’ll look at JavaScript equivalents for the more advanced methods jQuery provides…
Launching Scripts on Page Load
In the dim and distant past, developers would place scripts in the HTML <code>headcode> and use <code>window.onload = start;code> to launch an initial function. It worked but <code>window.onloadcode> only fires after all embedded files such images have been fully downloaded; you might be waiting some time for code to run.
jQuery provides a far more efficient method:
<code>$(start)code>
The start() function is executed as soon as the HTML has downloaded and the DOM is ready, but it won’t wait for other assets. Behind the scenes, it uses the native DOMContentLoaded event with fallbacks in jQuery 1.x for IE6/7/8:
<code>document.addEventListener("DOMContentLoaded", start);code>
I used to fret about this sort of nonsense. It’s unnecessary: simply load your script at the bottom of the page just before the closing <code></body>code> tag and you’ll know the DOM is ready.
forEach
jQuery allows you to run a custom function on all items in an array. (This includes collections of nodes. Although these may start life as a NodeList, jQuery copies them to an array-like object before they’re returned):
<code>$("p").each(function(i) { console.log("index " + i + ": " + this); });code>
<code>eachcode> is used internally when you apply multiple methods to the jQuery chain. This command would loop all <code><p>code> nodes twice:
<code>$("p").addClass("newclass").css({color:"#f00"});code>
The native <code>forEachcode> is supported in most browsers including IE9+. However, it only applies to arrays so we need to convert NodeLists by looping through all items or using the Array slice prototype:
<code>Array.prototype.slice.call(document.getElementsByTagName("p"));code>
Ughh. Personally, I prefer a short custom function which can be passed an array, NodeList or object with a callback. It iterates through the items passing each with its index to that function. This example automatically cancels further processing the first time the callback returns false:
<code>function Each(obj, fn) { if (obj.length) for (var i = 0, ol = obj.length, v = obj[0]; i < ol && fn(v, i) !== false; v = obj[++i]); else for (var p in obj) if (fn(obj[p], p) === false) break; };code>
Events
Event handling was awful in the pre-jQuery days. IE6/7/8 implemented a different event model and even those browsers which supposedly followed W3C standards had enough inconsistencies to make development awkward. jQuery still makes events easier to comprehend:
<code>$("#clickme").on("click", function(e) { console.log("you clicked " + e.target); e.preventDefault(); });code>
But the native equivalent isn’t too difficult:
<code>document.getElementById("clickme").addEventListener("click", function(e) { console.log("you clicked " + e.target); e.preventDefault(); });code>
This won’t work in IE6/7/8 but nor will jQuery 2.x. Most libraries provide a workaround which registers events using the oldIE attachEvent method. Alternatively, if you only require one event of a specific type on a node, simply apply the cross-browser DOM1 ‘on’ methods, e.g.
<code>document.getElementById("clickme").onclick = runSomething;code>
(Don’t forget to include a line such as <code>e = e ? e : window.event;code> at the top of your handler function to cope with the oldIE event object). Remember, none of this is required if you’re supporting IE9+.
jQuery provides non-standard types such as ‘focusin’ and ‘live’ events, i.e. matching elements added to the page by future operations will also have the event applied. jQuery achieves this by attaching a handler to a parent element (such as the page body) and analyzing the event object as it bubbles up through the DOM. You can do this yourself — it’s more efficient, uses less code and is standard JavaScript practice, e.g. rather than attaching a hover event to every table row, you attach it to the table, analyze the object and react accordingly.
If you prefer jQuery’s syntax, why not use Remy Sharp’s min.js? It provides the <code>$code> selector, chained <code>oncode> events, <code>triggercode> functionality and <code>forEachcode> support. The total weight: 617 characters for the minified version.
Ajax
When was the last time you developed a project which required XMLHttpRequest, script injection, GET requests, POST submissions, JSON handling and image loading? jQuery handles many situations and, while it’s flexible, you’ll rarely require all those options. Typical jQuery Ajax code:
<code>$.ajax({ url: "webservice", type: "POST", data: "a=1&b=2&c=3", success: function(d) { console.log(d); } }); code>
The native equivalent:
<code>var r = new XMLHttpRequest(); r.open("POST", "webservice", true); r.onreadystatechange = function () { if (r.readyState != 4 || r.status != 200) return; console.log(r.responseText); }; r.send("a=1&b=2&c=3"); code>
There are more options to consider — such as timeouts — so I would suggest wrapping native code in an easy-to-use function. However, you can optimize it for your project and implement some of the nicer XMLHttpRequest2 features such as binary data, upload progress and cross-origin requests which jQuery doesn’t (directly) implement.
Should You Use jQuery?
Only you can make that decision but using jQuery as a default starting point for every project will not necessarily be efficient or lead to elegant code.
jQuery has been immensely useful and was one of the primary reasons for the rebirth of front-end development. However, unlike specialist libraries for handling canvas, SVGs or other focused tasks, jQuery provides a generic set of tools — you’ll never need them all. The browser vendors have caught up and, unless you need to support oldIEs, jQuery is not the essential resource it once was. To put this it context, if you’ve migrated to jQuery 2.0 you probably don’t need jQuery.
I’ll leave you with a link to Vanilla JS; a library used by many of the top web companies which has a modular architecture and is smaller than all its competitors. The site is tongue-in-cheek but illustrates the point beautifully.