What has jQuery ever done for us?

Orde Saunders' avatarby Orde Saunders


jQuery, right? It's good for cross browser compatibility but it's massively bloated.

jQuery 1.11 => 276k Uncompressed, development

Modern browsers can natively do all the stuff jQuery does so why bother including it?

jQuery has taken away our ability to do the simplest thing in JavaScript, without including a bloated library. It's made people lazy, they can't do anything without a jQuery plugin.

Browser compatibility

Icons of major browsers (and IE)

This is the elephant in the room: let's face it - everyone's using the latest version of Chrome these days and anyone who's not should have their internet access revoked.

Icons of major browsers (and IE) with all but Chrome crossed out

In fact, anyone who's anyone is running Canary anyway so we know they've got all the latest experimental APIs available to them so, even if it's not a final spec we can still use them.

Icons of major browsers (and IE) with all but Chrome Canary crossed out

So - just like during the glory days of IE6 - cross browser compatibility's not an issue these days. So all that code that jQuery has to deal with browser bugs is just bloat because we're not bothering with any of that. Anyone who's seen me talk before will know that writing code that runs in any browser is for boring losers, right?

Utility functions

A short history of JavaScript

  1. Written in 10 days
  2. Proof of concept shipped
  3. Reverse engineered (including bugs)
  4. Standardised to prevent embrace, extend, extinguish
  5. Becomes standard cross-platform runtime

So JS is a bit brain-dead in places, it's almost like someone only spent 10 days writing it and then the proof of concept was shipped and then someone else reverse engineered it faithfully reproducing all the bugs and then it got standardised to attempt to stop the second someone doing an embrace, extend, extinguish because they were worried the browser would become a cross platform runtime.

And then it became the standard cross-platform runtime anyway.


As a result of this difficult upbringing, jQuery has a bunch of helper functions to paper over these cracks. but Underscore has a bunch of those - and more - so we'll just include that.

underscore => 5k Minified, gzipped

jQuery 1.11 => 276k Uncompressed, development

Sure, it's another library but, unlike jQuery, it's not bloated - see, it's nearly 300k smaller!

So that's utility functions covered.

DOM Selection

document.querySelectorAll('element#id.class') FTW!

This is just like jQuery's $('element#id.class') CSS selector. Actually, jQuery uses document.querySelectorAll under the hood so insubstantiating all of jQuery just as a wrapper for a native function like this is a huge waste.

Yeah, sure jQuery extends the selectors you can use. I don't know what those extra selectors are but if I needed to know then I could Google it but I'm never going to use them anyway.

Let's use querySelectorAll to select a number of elements and perform an operation on each one. First, let's look at the bloated jQuery way:

$('#topnav li').each(function () {
 // Do code.

Now for some top-gun vanilla JS skillz. We're going to use querySelectorAll to select our objects.

document.querySelectorAll('#topnav li').forEach(function () {
  // Do code.

querySelectorAll returns a NodeList and we know we're in Chrome so we can just iterate over arrays using the native forEach, right?

TypeError: document.querySelectorAll(...).forEach is not a function

Well, no. That would be too easy. What querySelectorAll returns is an array like object that doesn't have Array in its prototype chain.

So what we need to do is use the forEach method from the array prototype:

Array.prototype.forEach.call(document.querySelectorAll('#topnav li'), function () {
  // Do code.

Now we can efficiently select DOM elements with some lightweight and easy to understand code we can move on to event handlers.

Event handlers

First off, the old jQuery way:

element.on('click', function (event) {
  // Do code.

In vanilla JS we have a method called element.addEventListener and this works just like the jQuery event handler:

element.addEventListener('click', function (event) {
  // Do code.

Actually, like querySelectorAll, this is actually what jQuery is using behind the scenes. So why are we loading in all of jQuery if all we're using is event handlers?

Now we can add events we can start removing them. Again, here's the jQuery way:


Just as we had addEventListener, vanilla JS gives us removeEventListener. So we can just use this to remove the handler, like jQuery.


Or not.

TypeError: Not enough arguments to EventTarget.removeEventListener.

For removeEventListener we need to also pass in the function signature of the callback we assigned to the event handler. This means that if we assigned an anonymous function we can't now unbind it. Even if we remove the element from the DOM the handlers stay in memory.

So - assuming we care about memory leaks - then we have to create our handlers as named functions and pass them in to addEventListner so we can then pass them into removeEventListener.

var listener = function (event) {
  // Do code.

element.addEventListener('click', listener);

element.removeEventListener('click', listener);

If removeEventListener is what jQuery is using for event handling then how come it can unbind anonymous functions and remove elements from the DOM including all bound handlers? What would we need to do to replicate that functionality? We'd need to maintain a registry of all event handlers bound to an element and then use that to clear the events.


This is where we load some Json data asynchronously using the XMLHttpRequest API. That's where the names comes from: Asynchronous Jason And XMLHttpRequest:

Asynchronous Json And XMLHttpRequest

I don't know where the XML comes from in this - maybe it's from when JavaScript was part of Java.

So here's jQuery's GET method, it's the simplest example of AJAX.

$.get('/my/url', function(data) {
  // Do code.

And here's the same thing in vanilla JS:

var request = new XMLHttpRequest;
request.open('GET', '/my/url');

request.onload = function() {
  if (request.status >= 200 && request.status < 400){
    // Do code.

We create a new XMLHttpRequest, we tell it what HTTP verb to use and what URL to hit, we assign a callback for when it finishes, in that callback we check that the request was actually a success and then - finally - we dispatch the request.

And this is just for the simplest possible use case. I'm not going to go any deeper into AJAX but suffice it to say that when you want to start moving non-trivial amounts of information back and forth without jQuery it gets very complicated.

All right...

Apart from:

  • Ajax
  • Event handling
  • DOM selection
  • Utility functions


  • Cross browser compatibility...

What has jQuery ever done for us!?

Still from the What have the Roman's ever done for us? sketch sketch in The Life of Brian