DEV Community

Ahmad Awais ⚡️
Ahmad Awais ⚡️

Posted on

Use $ & $$ Instead of document.querySelector/All in JavaScript without jQuery

I started writing JavaScript code because of WordPress back in 2007. JavaScript was not what it is today. It would behave differently on different browsers and there were too many hacks around basic stuff to keep up with all the changes all the time.

So, many of us decided to rely on jQuery — a simple JavaScript library with one single form of syntax that just worked everywhere in all the browsers.

Fast forward to 2019, as a full-time JavaScript Developer Advocate — I advocate modern JavaScript. Because it's super awesome. Though at times I miss the simplicity of jQuery in things like you'd just need a $ sign to pick up an element and do stuff to it.

Now with JavaScript, I find myself doing document.querySelector multiple times in an application. Well, guess what, there's an easy way to just bind that $ sign to your document's document.querySelector.

gif

Here's how you go about it.



const $ = document.querySelector.bind(document);
const $$ = document.querySelectorAll.bind(document);


Enter fullscreen mode Exit fullscreen mode

Now you can use the following:




// Change the background color of a class.
$('.class').style.background="#BADA55";

// Change the inner HTML of an ID.
$('#id').innerHTML="<span>Cool beans!</span>";

// Select all images on the webpage.
$$('img')

// Print the image addresses for all the images on a webpage.
$$('img').forEach(img => console.log(img.src))


Enter fullscreen mode Exit fullscreen mode

Use your code for good and have fun! :)
Peace! ✌️

Latest comments (31)

Collapse
 
londomloto profile image
Roso Sasongko

...and finally we returned to jQuery

Collapse
 
tormodvm profile image
Tormod Vold Mikkelsen

This is my take on it. It checks whether I'm asking for an id or not, and if I am, it returns just that one element. If not, the NodeList is made into an array.

const $ = (q, d = document) => 
  /#\S+$/.test(q)                       // check if query asks for ID
  ? d.querySelector.bind(d)(q)          // if so, return one element
  : [...d.querySelectorAll.bind(d)(q)]  // else, return all elements in an array.
Collapse
 
alfiqmiq profile image
Marek
const $ = (selector, base = document) => {
   let elements = base.querySelectorAll(selector);
   return (elements.length == 1) ? elements[0] : elements;
}
Collapse
 
lazarljubenovic profile image
Lazar Ljubenović

I made a module exactly for these purposes just recently: gimme back my dollars! It has a very distinctive name.

Collapse
 
flozero profile image
florent giraud

I already did this in some projects that's cool !
But one point to take care is about performance.
Because querySelector do a lot more jobs thant getElementsById or class so if you dont care about perf you solution is perfect

Collapse
 
maxart2501 profile image
Massimo Artizzu

Watch out that querySelectorAll returns a NodeList object, whereas $$ in the console returns an array.

So if you're used to call all the sweet array prototype methods, you might fall short!

Solution: wrap everything in Array.from.

Collapse
 
ahmadawais profile image
Ahmad Awais ⚡️

Thanks for reminding us :)

Collapse
 
webreflection profile image
Andrea Giammarchi

Chrome has its own Console Utilities API Reference where $ and $$ are offered regardless, among other utils, unless the global scope has been overwritten with something else (i.e. jQuery).

The API for $ and $$ is more jQuery-ish, and if you'd like to reproduce it its like:

const $ = (css, parent = document) => parent.querySelector(css);
const $$ = (css, parent = document) => parent.querySelectorAll(css);
Enter fullscreen mode Exit fullscreen mode

To avoid needing polyfills for forEach or Symbol.iterator on NodeList collections, you can also go ahead and convert the static collection as Array so that all methods, including filter and map can be used.

const $$ = (css, parent = document) =>
  Array.from(parent.querySelectorAll(css));
Enter fullscreen mode Exit fullscreen mode

If you don't have Array.from in your debug session, or you are after a thin layer that works across browsers, you can go for the following:

function $(css, parent) {
  return (parent || document).querySelector(css);
}

function $$(css, parent) {
  var nodes = (parent || document).querySelectorAll(css);
  return Array.prototype.slice.call(nodes, 0);
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
stebeus profile image
Stebeus

Sorry for replying an old post, but how does this method of aliasing these two query selectors compares to the OP's post for development, especially for the parent parameter?

Collapse
 
intrnl profile image
intrnl

Isn't $ and $$ already binded to querySelector and querySelectorAll from the start though? Which means that binding it again seems unnecessary.

or I suppose the default binding is recent..?

Collapse
 
hendrasan profile image
Hendra Susanto

Instead of using 2 different constants, what about checking the length of the selector first like this:

const $ = s => document.querySelectorAll.bind(document)(s).length > 1 ? document.querySelectorAll.bind(document)(s) : document.querySelector.bind(document)(s);

or something like that to make it much more similar to jQuery $?

Collapse
 
capsule profile image
Thibaut Allender

From a performance perspective, that would double the amount of work for every selector. Going from jQuery to Vanilla JS is mostly about being more performant, so that looks like an anti-pattern.

Collapse
 
ahmadawais profile image
Ahmad Awais ⚡️

Can you explain how would that be the double amount of work? It's just one extra call.

Thread Thread
 
capsule profile image
Thibaut Allender

It's 2 calls instead of one, so it's double.

Collapse
 
itachiuchiha profile image
Itachi Uchiha

I'm using document.querySelectorAll for all elements. Even for id elements.

Actually, you can use querySelectorAll for id elements. It will work for one element. There must not be multiple elements in a document that have the same id value.

const $ = document.querySelectorAll.bind(document)

const testEl = $("#test")

testEl.forEach(el => {
    console.log(el)
})