If you find this post useful, you can sign up to my mailing list, check out the other posts on my blog, or follow me on twitter. I've also got a couple of active side projects that you might like to check out:
- ippy.io - An app for creating beautiful resumes
- many.tools - A collection of useful utilities for designers and devs
The spread operator has been enthusiastically adopted by the JavaScript community since its inclusion in the language with ES6, with good reason! It vastly simplifies many common object and array manipulations patterns.
While the common uses are widely appreciated and utilised, it also facilitates some slightly more obscure patterns.
Such asβ¦
π 1) Conditionally Adding Properties to an Object
It may not be particularly common, but imagine that (for whatever reason) you want to conditionally add properties to an object. Specifically, you want to add the properties if they hold a truthy value, but exclude them if they are null, undefined, or contain a falsey value. How might you approach this?
A reasonable approach might be something like the following:
const firstName = 'Harrison'
const lastName = null
const address = '123 Street Rd'
const phoneNumber = null
const userInfo = {}
if (firstName) {
userInfo.firstName = firstName
}
if (lastName) {
userInfo.lastName = lastName
}
if (address) {
userInfo.address = address
}
if (phoneNumber) {
userInfo.phoneNumber = phoneNumber
}
console.log(userInfo)
// {
// firstName: 'Harrison',
// address: '123 Street Rd'
// }
There's nothing wrong with this approach - however using the spread operator, we can move the conditional logic inside the object literal.
The result is somewhat more concise, and in my opinion once you've seen it a few times is actually more readable.
Take a look:
const firstName = 'Harrison'
const lastName = null
const address = '123 Street Rd'
const phoneNumber = null
const userInfo = {
...firstName && { firstName },
...lastName && { lastName },
...address && { address },
...phoneNumber && { phoneNumber }
}
console.log(userInfo)
// {
// firstName: 'Harrison',
// address: '123 Street Rd'
// }
If you haven't seen this pattern before, it might take a second to grok what's going on. I'll try to explain:
Lets consider the first line inside the object literal, a case in which the property should be added to the object:
...firstName && { firstName }
Since firstName
was previously assigned the truthy value 'Harrison'
,
the expression firstName && { firstName }
will return { firstName: 'Harrison' }
. Both the left and right hand side of the &&
evaluate as truthy, and as such the right hand side is returned.
This returned object is then spread into the userInfo
object, resulting in the firstName property being successfully set.
Next, lets consider the alternate case, in which we attempt to assign a falsey value. Lets take the second line of the object literal:
...lastName && { lastName }
In this case, lastName
is null. This means that the expression lastName && { lastName }
short-circuits to returning the left hand side of the &&
, which in this case is null
.
We then attempt to spread null
into the userInfo
object. You might think this should result in an error, but it actually doesn't.
In fact, as far as I'm aware spreading any falsey value into an object is perfectly valid syntax, but will result in no change to the object. Try it out:
let obj = { ...null }
console.log(obj)
// {}
let obj = { ...undefined }
console.log(obj)
// {}
let obj = { ...false }
console.log(obj)
// {}
let obj = { ...'' }
console.log(obj)
// {}
let obj = { ...0 }
console.log(obj)
// {}
let obj = { ...{} }
console.log(obj)
// {}
let obj = { ...[] }
console.log(obj)
// {}
The end result of all this is that any truthy values will be added to the object, while any falsey values are left out!
To make the code more explicit we can use the same pattern, but refactor the truthy check into its own function:
const hasIfTruthy = (propertyName, property) => {
return property && { [propertyName]: property }
}
const firstName = 'Harrison'
const lastName = null
const address = '123 Street Rd'
const phoneNumber = null
const userInfo = {
...hasIfTruthy('firstName', firstName),
...hasIfTruthy('lastName', lastName),
...hasIfTruthy('address', address),
...hasIfTruthy('phoneNumber', phoneNumber)
}
console.log(userInfo)
// {
// firstName: 'Harrison',
// address: '123 Street Rd'
// }
Using this pattern, you can even completely alter the condition that dictates whether a property is included or excluded - it doesn't necessarily need to be based on just truthy-ness/falsy-ness.
π 2) Spreading an Array into an Object
So⦠I'm yet to think of a particularly compelling reason that you would actually do this (shout out in the comments if you have one), but you can totally spread an Array into an Object.
The result is that each array element is inserted into the object, with the key set to its respective array index.
Check it out:
const fruitsArray = ['apple', 'orange', 'banano']
const fruitsObject = { ...fruitsArray }
console.log(fruitsObject)
// {
// 0: 'apple',
// 1: 'orange',
// 2: 'banano'
// }
π 3) Spreading a String Into an Array (or an Object)
This one is actually pretty nifty, and is probably more widely known than the others. You can spread a string into an array!
The result is an array containing the individual characters from the string.
In my opinion this allows for a more pleasant syntax than the common 'string'.split('')
style.
Here it is:
const characters = [..."apple"]
console.log(characters)
// ['a', 'p', 'p', 'l', 'e']
And if you're feeling really wild, you can even spread a string into an object π
const characters = {..."apple"}
console.log(characters)
// {
// 0: 'a',
// 1: 'p',
// 2: 'p',
// 3: 'l',
// 4: 'e'
// }
Stay safe out there kids.
Know any other weird or wonderful uses for the JS spread operator? Let me know in the comments π
Top comments (15)
As spread operator acts as if we used String[Symbol.iterator], it is better to use spread operator instead of regular
String.prototype.split
to split given string into characters when the string may involve Unicode characters. It's not foolproof, but better.For example,
So, if you get asked to reverse a string with JS in an interview, following might be treated as too naive:
Following is slightly better:
JavaScript's unofficial motto.
π
Hi Harrison.
It is very nice article which highlights some of the unknown uses of spread operator. Thanks for this.
I think there is a typo in the code at 'const fruitsObject = { ...fruitsObject }'. Should it be const fruitsObject = { ...fruitsArray } ? Please check.
Thanks again
Vijay
Right you are! Thanks for picking up on that, Iβve updated the post π.
Thanks for reading!
Thanks for the post Harrison, but there is a part of me that would prefer an object which is missing a property, to instead contain something explicit, like null or better yet a failover. With that said, my way or this way we would still be checking downstream that something is not here OR is null or failover. But mine would not need gork time, maybe π€·ββοΈ (I'd do something else wierd instead)
Absolutely - I tend to agree that while there are some cases where this pattern is useful, itβs often better to keep a consistent object schema, and explicitly set the missing properties to null.
As with all things (especially somewhat obscure patterns), use with caution!
It's a hobby to know strange JavaScript, I can relate.
I am also interested in the obscure, checkout my labeled loops post, it's right up there in the do not do this camp.
Amazing article, thank you!
Personally, with the first example, I would also recommend using parens to help understand the order of operations.
Otherwise looking at
...firstName && { firstName },
was throwing me off thinkingfirstName
was first being spread!Thanks for sharing the article Harrison!
One small comment: in your last example the object should start with the key zero for the character 'a' instead of one.
Good catch! Thanks for pointing that out - Iβve updated the post π»
Thanks for updating, and thanks for just writing this! I didn't know about the first pattern π
String spreading is on fire! Thank you for sharing these interestings facts about this operator :)
Thanks for reading! π
spreading a string into an array sounds like it could be a good approach to set text sarcastically and then duct tape the array back into a string again.