DEV Community

Snippets for Vanilla JS Coding

Lea Rosema (she/her) on July 21, 2018

When coding in VanillaJS, I usually create shortcuts for document.querySelector and document.querySelectorAll. I also like to declare D as a shortc...
Collapse
 
1hko profile image
1hko • Edited

Instead of startNode||D I would recommend default arguments – it's exactly the reason they were added to the language

const $$ = (selector, elem = D) =>
  elem.querySelectorAll(selector)
Collapse
 
learosema profile image
Lea Rosema (she/her)

Good point :)

Collapse
 
learosema profile image
Lea Rosema (she/her) • Edited

Another option is to attach the on method plus Array.prototype.map to the NodeList prototype instead:

const $$ = (selector, startNode = D) => startNode.querySelectorAll(selector)
NodeList.prototype.map = Array.prototype.map
NodeList.prototype.on = function(type, listener, options) {
  this.map(el => {
    if (el instanceof Element) {
      el.addEventListener(type, listener, options)
    }
  })
  return this // for chaining
}

This keeps the Array prototype clean =).

Collapse
 
the_fln profile image
Francois Lanthier Nadeau

Short but sweet post, Lea! 🙌

Found it while researching our story on vanilla JS. Also been working on an open source list of paid & free quality resources for devs to learn vanilla JS--open for PRs. Maybe I should add an "article" section with content such as yours?

Collapse
 
learosema profile image
Lea Rosema (she/her)

Hi Franck, thank you! I love your list of resources for Vanilla JS. Feel free to add it as you like :)

Collapse
 
hjfitz profile image
Harry

I like that you monkey-patch Array#on - but is there ever an instance that a NodeList returned from querySelector wouldn't return an Element?

What I'm trying to ask is:

Is if (el instanceof Element) a necessary check?

Collapse
 
learosema profile image
Lea Rosema (she/her)

The reason I did the check is that NodeList gets converted into an Array via the $$ function. NodeLists are read-only and always contain Element elements, so it is safe to call addEventListener on them without the check. Arrays are not read-only and the array elements are not safe from reassignment.

Collapse
 
kapouer profile image
Jérémy Lal

Hi, ignoring with which document you're working is a quick way to bang your head to the wall. Always keep a reference to which document you're in:

HTMLDocument.prototype.$ = HTMLDocument.prototype.querySelector
HTMLDocument.prototype.$$ = HTMLDocument.prototype.querySelectorAll

A shorthand for document, why not:

window.doc = window.document
doc.$("body")
doc.$$("script")

Everything's nice now, you need to work off-line ?

var offdoc = doc.cloneNode()
// mind that some browsers don't create offdoc.documentElement so
if (!offdoc.documentElement) offdoc.appendChild(offdoc.createElement('html'))
offdoc.documentElement.innerHTML = '<head></head><body></body>'
// this won't load the file
offdoc.head.insertAdjacentHTML('beforeEnd', '<script src="toto.js"></script>')
// and this still works
offdoc.$('script')
Collapse
 
learosema profile image
Lea Rosema (she/her) • Edited

In this case, another option is to define another shortcut for documents other than document. For example, you can move the $ function definition inside a function that takes a document as a parameter:

function insertScriptIntoDocument(doc, jsfile) { 
  const $o = doc.querySelector.bind(doc)
  const script = document.createElement('script')
  script.setAttribute('src', jsFile)
  $o`head`.insertAdjacentHTML('beforeEnd', script)
}
Collapse
 
ben profile image
Ben Halpern

Great tips

Collapse
 
efeichen profile image
Kenneth Chen • Edited

Another Lea happens to have made something similar: blissfuljs.com/

Collapse
 
learosema profile image
Lea Rosema (she/her) • Edited

Yes, Bliss.js by Lea Verou also provide the $ and $$ shortcuts for querySelector and querySelectorAll, plus more functions that make it a fully-fledged, powerful and lightweight framework.

Collapse
 
brianemilius profile image
Brian Emilius

Love it!
Definitely going to incorporate this in my snippet library.

Collapse
 
flykasual profile image
Johannes Nielsen

Great article!
I am not sure how I feel about altering built-in prototypes, I generally like to keep those clean. But the jquery-like syntax and the ability to chain event listeners without having to actually use jQuery is super sweet! 👌

Collapse
 
itaditya profile image
Aditya Agarwal

We should avoid mutating the Array prototype though. That's why MooTools SmooshGate happened. Good post though, short and simple