One of the more frustrating things about using JavaScript in the browser is the number of different collection types that you need to deal with. When using native APIs and 3rd party libraries, it’s easy to encounter 3 or more different types of collections, including NodeLists, HTMLCollections, jQuery Objects, and plain arrays.
let a = document.querySelectorAll('div')
a instanceOf NodeList //true
let b = document.getElementsByTagName('div')
b instanceOf HTMLCollection //true
let c = $('div')
c instanceOf jQuery // true
let d = ['button1', 'button2', 'button3'].map(id => document.getElementById(id));
d instance of Array //true
This ends up mattering in practice because not every function that is available on Array is available on NodeList, HTMLCollections, and jQuery objects.
let ids = document.querySelectorAll('div').map(el => el.id)
// Uncaught TypeError: document.querySelectorAll(...).map is not a function
ids = document.getElementsByTagName('div').map(el => el.id)
// Uncaught TypeError: document.getElementsByTagName(...).map is not a function
let numDivs = $('div').reduce((count, el) => count + 1, 0);
// Uncaught TypeError: $(...).reduce is not a function
Since we can’t use native array methods on these alternate collections, we end up having to be very careful about knowing where we’ve retrieved data from, and how to convert those collections or how to work around their limitations.
It’s useful to know about these distinctions, but in practice dealing with them is a pain. One of the nice properties of lodash is that it abstracts over these incompatibilities.
let ids = _.map(document.querySelectorAll('div'), el => el.id);
// ['container', 'left-box', 'right-box']
ids = _.map(document.getElementssByTagName('div'), el => el.id);
// ['container', 'left-box', 'right-box']
let numDivs = _.reduce($('div'), (count, el) => count + 1, 0));
// 3
For methods that iterate over a collection lodash treats all array-like objects (essentially anything with a length property) the same and iterates over their numerical properties from 0 to length-1. This provides a nice consistency when working with DOM APIs and removes the mental overhead from managing their inconsistencies.