loading...

What is Set?

zacanger profile image Zac Anger ・2 min read

Originally posted on my blog.

Someone recently 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, or a _.get type of thing. I don't know Ember, so I'm not positive.)

And I said, how about this?

getNames: (contacts) =>
  [...new Set(
    contacts.map(({ contactInfo: { firstName, lastName }}) =>
      `${firstName} ${lastName}`))]

I like this version because it's concise, readable (to me, at least?), mutation-free, and declarative.

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 the contacts.map... 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 very large collection, because then you're creating a whole extra collection in the process, which is totally true.

There's a bit more background here on what JS's Set is supposed to be kind of like.

And underneath it sorta looks 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. Definitely play around with it!

Discussion

pic
Editor guide