Collections
Section titled Collectionsdiscord.js comes with a utility class known as Collection
. It extends JavaScript's native Map
class, so it has all the Map
features and more!
If you're not familiar with Map
, read MDN's page on it before continuing. You should be familiar with Array
methods as well. We will also use some ES6 features, so read up here if you do not know what they are.
A Map
allows for an association between unique keys and their values. For example, how can you transform every value or filter the entries in a Map
easily? This is the point of the Collection
class!
Array-like Methods
Section titled Array-like MethodsMany of the methods on Collection
correspond to their namesake in Array
. One of them is find
:
_10// Assume we have an array of users and a collection of the same users._10array.find((u) => u.discriminator === '1000');_10collection.find((u) => u.discriminator === '1000');
_10// Assume we have an array of users and a collection of the same users._10array.find((u) => u.discriminator === '1000');_10collection.find((u) => u.discriminator === '1000');
The interface of the callback function is very similar between the two. For arrays, callbacks usually pass the parameters (value, index, array)
, where value
is the value iterated to, index
is the current index, and array
is the array. For collections, you would have (value, key, collection)
. Here, value
is the same, but key
is the key of the value, and collection
is the collection itself instead.
Methods that follow this philosophy of staying close to the Array
interface are as follows:
find
filter
- Note that this returns aCollection
rather than anArray
.map
- Yet this returns anArray
of values instead of aCollection
!every
some
reduce
concat
sort
Converting to Array
Section titled Converting to ArraySince Collection
extends Map
, it is an iterable, and can be converted to an Array
through either Array.from()
or spread syntax (...collection
).
_11// For values._11Array.from(collection.values());_11[...collection.values()];_11_11// For keys._11Array.from(collection.keys());_11[...collection.keys()];_11_11// For [key, value] pairs._11Array.from(collection);_11[...collection];
_11// For values._11Array.from(collection.values());_11[...collection.values()];_11_11// For keys._11Array.from(collection.keys());_11[...collection.keys()];_11_11// For [key, value] pairs._11Array.from(collection);_11[...collection];
Many people convert Collections to Arrays way too much! This can lead to unnecessary and confusing code. Before you use Array.from()
or similar, ask yourself if whatever you are trying to do can't be done with the given Map
or Collection
methods or with a for-of loop.
Extra Utilities
Section titled Extra UtilitiesSome methods are not from Array
and are instead entirely new to standard JavaScript.
_16// A random value._16collection.random();_16_16// The first value._16collection.first();_16_16// The first 5 values._16collection.first(5);_16_16// Similar to `first`, but from the end._16collection.last();_16collection.last(2);_16_16// Removes anything that meets the condition from the collection._16// Sort of like `filter`, but in-place._16collection.sweep((user) => user.username === 'Bob');
_16// A random value._16collection.random();_16_16// The first value._16collection.first();_16_16// The first 5 values._16collection.first(5);_16_16// Similar to `first`, but from the end._16collection.last();_16collection.last(2);_16_16// Removes anything that meets the condition from the collection._16// Sort of like `filter`, but in-place._16collection.sweep((user) => user.username === 'Bob');
A more complicated method is partition
, which splits a single Collection into two new Collections based on the provided function. You can think of it as two _filter
_s, but done at the same time:
_10// `bots` is a Collection of users where their `bot` property was true._10// `humans` is a Collection where the property was false instead!_10const [bots, humans] = collection.partition((u) => u.bot);_10_10// Both return true._10bots.every((b) => b.bot);_10humans.every((h) => !h.bot);
_10// `bots` is a Collection of users where their `bot` property was true._10// `humans` is a Collection where the property was false instead!_10const [bots, humans] = collection.partition((u) => u.bot);_10_10// Both return true._10bots.every((b) => b.bot);_10humans.every((h) => !h.bot);