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 | Ordered | Keyed | Item inclusion Test | Key inclusion test | It's a.... |
---|---|---|---|---|---|
Set | no | no | yes | (N/A) | "... pocket of things" |
Array | yes | numbers | yes | no(2) | "...rolodex of cards" |
Object | no | strings(4) | no | yes | "...dictionary of words (and words my dad knows)" |
Map | yes(1) | any(3) | no | yes | "...free association of stuff with stuff" |
- 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.
- 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.
- The Javascript Map can hold anything; Collection Maps cannot have arrays as keys.
- 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:
Type | KeyIterator | ItemIterator | StoreIterator |
---|---|---|---|
Arrays | keys() | values() | entries() |
Objects | Object.keys(target)[Symbol.iterator]() | Object.values(target)[Symbol.iterator]() | Object.entries(target)[Symbol.iterator]() |
Maps | keys() | values() | entries() |
Symbols | NA | values() | 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.