As Javascript exists it has been burdened by inertia and a long development process; it is becoming more consistent but there is still a host of missing functionality.

Some small examples:

  • You cannot iterate over objects
  • forEach exists for maps and arrays but not objects or strings
  • reduce ony exists for arrays
  • you can delete items by key, but not by value
  • You can sort arrays, but not maps
  • You can push/pop/shift/unshift arrays, but no other collection type

Type sort forEach map reduce
Array yes yes yes no
Object no no no no
Map no yes no no
Set NA yes no no

You can accomplish a lot of these as equivalents with for...in operators -- however functional allow you to inject functionality in ways that procedural code can't, as easily. Reduce, especially, takes a LOT of code to replicate.

Uninterruptible looping

In addition, functions like forEach, map, and reduce are impossible to interrupt, meaning, you loop through a lot of values you may not care for. I put a stopper into the loopers here to let you bail from these routines whenever you want to.

Limited Reflection

Additionally, methods like typeof provide very poor type information considering how many object types exist in the modern lexicon you have to do a lot of instanceof's to know what a thing is. Typescript can help narrow the focus by creating type requirements, but it's a static system - and Javascript is capable of a lot of dynamism. see Types for more details.


This module makes behavior consistent across multiple store forms, and provides detailed feedback for the base values.

For the last few years I have been using a hodgepodge of Lodash, Maps and a rolling library of custom introspection functions to get all the functionality I've baked into Collect.

Worth noting -- only Array has "end" operations like push/pop/shift/unshift, and even arrays don't have a first/last retriever.

Type OrderedKeyedItem inclusion TestKey inclusion testIt's a....
Setnonoyes(N/A)"... pocket of things"
Arrayyesnumbersyesno(2)"...rolodex of cards"
Objectnostrings(4)noyes"...dictionary of words (and words my dad knows)"
Mapyes(1)any(3)noyes"...free association of stuff with stuff"
  1. items' keys in a map are ordered in the same order they came in, but this is really not a design feature of a map nor a quality of a set theory map.
  2. you can indirectly test for keys with length knowing all arrays start with zero. But you aren't guaranteed that there is a thing in a given index til you get it.
  3. The Javascript Map can hold anything; Collection Maps cannot have arrays as keys.
  4. Objects can also have symbol keys, but apart from iterators, its not common practice to do so, and Object collections only allow for strings in key fields.

Its frustratingly impossible to find a row with all yes: an ordered keyed native collection type with key and item inclusion tests and a wide selection of key types.

Inconsistent iterators

Iterators, a more recent feature, have a very inconsistent application pattern:

TypeKeyIteratorItemIteratorStoreIterator
Arrayskeys()values()entries()
ObjectsObject.keys(target)[Symbol.iterator]()Object.values(target)[Symbol.iterator]()Object.entries(target)[Symbol.iterator]()
Mapskeys()values()entries()
SymbolsNAvalues()NA

This is a side effect of the fact that Objects have been in use long before the idea of modern JS I/O, and only sometimes are used to store/retrieve data. But along with everything else in Collect, the iterator differences can be made explicit in this library.