If you've worked with objects in JavaScript, you may have come across situations where you need to optionally add values to an existing object. To illustrate my example, I'd like to welcome the Spice Girls to this corner of the internet.
Traditionally, you could assign values like this:
function relationship(name, youGotWithMyFriends) {
var interestedParty = {
name: name
}
if(youGotWithMyFriends) {
interestedParty.lover = true
}
return interestedParty
}
// Later in our code...
var person = relationship('person', false)
console.log(person) // { name: 'person'}
var nextPerson = relationship('match', true)
console.log(nextPerson) // { name: 'match', lover: true }
As the Spice Girls clearly outlined for us in 'Wannabe', you'll need to get with their friends to be a lover.
Now, one could argue that you can add the lover
property to all the objects and have it be false by default. Totally valid, but for the purposes of this example, let's say that we don't want a lover
property unless it is true, and keep going down this path.
What if we had to add further properties with additional guard clauses that prevent assigning falsey values to our object? it might get a little unfun to have to write if
statements over and over.
Modernizing our approach, with ES6
With ES6, we gained access to the spread syntax. Useful for taking values from one collection and spreading them into another one, but our above example can also leverage this syntax!
Let's have another chat with the Spice Girls and see what they think about our fun new ES6 functionality...
function relationship(name, youGotWithMyFriends) {
return {
name,
...(youGotWithMyFriends && { lover: true }) // !!!
}
}
// Later in our code...
const person = relationship('person', false)
console.log(person) // { name: 'person'}
const nextPerson = relationship('match', true)
console.log(nextPerson) // { name: 'match', lover: true }
We get the same result! But umm...Spice Girls...
What's going on?
Let's go over our line that leverages the spread operator to add that property to the return object, ...(youGotWithMyFriends && { lover: true })
, and talk a bit about what's happening.
In the case of youGotWithMyFriends
being true
, you end up continuing in your code and hitting the { lover: true }
piece, and because the spread syntax is in use, it will spread the contents of that object to the object it is nested in, giving you the second console.log
value!
But what happens if that boolean is false
? Can you "spread" false on to an object without an error being thrown?
The spread syntax can be thought of as a shorthand, more straightforward Object.assign
function call. When you utilize it, it is like calling the function as follows:
Object.assign(targetObject, thingsToAddToTarget)
We can see how our first example works when we use Object.assign
, as thingsToAddToTarget
will just be our new object. But let's talk about the case of false being passed as the second argument:
const targetObject = {}
Object.assign(targetObject, false) // returns {}
Sometime during Object.assign
's implementation cycle, the team working on it decided that if the second argument is not an indexed value, instead of failing loudly, it will ignore what is passed in and return your original object, unmodified! Try passing a number, a null, or even undefined in your browser console as a second argument to see for yourself :).
I hope you enjoyed this little example of leveraging a cool ES6 feature, and that you can find use-cases in your code today.
Top comments (8)
Haha!! I read this title and wondered... hmmm π€... is this a Spice Girl reference? Yep, this is a Spice Girl reference. π
However, I'm pretty dang sure it's
youGottaGetWithMyFriends
as it's playing over and over in my head right now. πAlso yeah that's the lyric, but for the sake of making the example work, past tense :P
solid point π
I should probably title this a little differently to better encapsulate what lies in the post.
Marvelous post..I have been into these situations for so long but thought of what is under the hood in spread operator. And really
Object.assign
does that, amazing!. Thanks for sharing. Now on you are on my following list.Does using the spread
{..._}
operator orObject.assign()
duplicate the object in memory instead of simply extending the existing one?Good question! Object.assign does not duplicate the target object in memory - it adds on to the existing object, and in the case of clashing keys, the keys and their values from the added object will overwrite the existing one.
With that being the case, the same answer applies to the spread operator.
Wow, this is excellent! Could've used this a few weeks ago at work. Time to refactor! :D