So, someone asked in a Slack channel how they might clean up the following code:
getNames (contacts) {
let contacts_set = []
contacts.forEach((contact) => {
let firstName = get(contact, 'contactInfo.firstName')
let lastName = get(contact, 'contactInfo.lastName')
let fullName = `${firstName} ${lastName}`
if (contacts_set.includes(fullName)) {
return
} else {
contacts_set.push(fullName)
}
set(this, 'contactsSet', contactsSet)
})
}
Note that the get
and set
going on here seemed to be Ember-specific. I
don't know Ember so don't ask me.
And I said, how about this?
getNames: (contacts) =>
[...new Set(
contacts.map(({ contactInfo: { firstName, lastName }}) =>
`${firstName} ${lastName}`))]
I like this version because it's very concise and still readable (to me). It also doesn't do mutation-y stuff, which is a good thing.
And then someone else asked:
Can some one eli5 what
Set
is that's referenced above?
Which made me realise that a lot of folks still aren't using a lot of the nice new things from ES2015, so I explained a bit. Here's how I understand it.
Set is a new (in ES2015) iterable builtin (like Array, String, TypedArray). Map is also new in 2015. Set is to Array as Map is to Object, kinda.
For practical usage Set is basically Array but unique, and with different
methods. add
, has
, delete
, size
, and some others. There's a lot more
info on
MDN.
You can pass Set
an iterable, which is why the thing I have above works
(because thing inside new Set()
results in an array).
In that case Set
isn't being used for too much besides just the fact that
it's Set
(so it only holds unique values). Someone else pointed out in the
same channel that maybe it's not the best idea if you have a lot of values,
because then you're creating another thing, which is totally true.
There's a bit more background
here on what JS's Set
is
suppose to be kind of like.
And underneath it sorta looks vaguely like this:
class Set {
constructor () {
this.storage = []
}
add (a) {
if (!this.storage.includes(a)) {
this.storage.push(a)
}
}
has (a) {
return this.storage.includes(a)
}
remove (a) {
this.storage.splice(this.storage.indexOf(a), 1)
}
}
That's a lot of stuff, but mostly you can think of Set
as a thing that's
like Array
but it only holds unique things.
There's also a WeakSet
which can only hold objects. I haven't really found a
valid use case for WeakSet
and WeakMap
yet, personally.
Set
turns out to be pretty useful. I've used it a few times at work (with
appropriate polyfills) without any problems, and I use it in a few places in
zeelib, my sort-of-sometimes-popular
utility library. Definitely play around with it!