DEV Community

Cover image for Making Sense of Syntax
Laurie
Laurie

Posted on • Originally published at laurieontech.com

Making Sense of Syntax

I was reviewing a bit of code the other day and came across a set of syntax I hadn't seen before. It looked like this:

!!{...obj, ...obj2}.item
Enter fullscreen mode Exit fullscreen mode

There are pieces of this code I recognize. But all together? Not so much.

Object Spread

If we go by order of operations the first thing we need to look at is the spread piece of this expression.

{...obj, ...obj2}
Enter fullscreen mode Exit fullscreen mode

Luckily I've written that post before. It's taking two objects and creating a single object with all the unique key value pairs between them.

What comes next?

This was the first thing I needed to figure out. I was pretty confident the next piece of syntax to execute was the .item selector, but I wasn't positive.

Turns out that is correct. Since the result of our spread expression is an object, we're accessing the value of the item key in that object.

To break it down we can write it this way.

const newObj = {...obj, ...obj2}
const item = newObj.item
Enter fullscreen mode Exit fullscreen mode

Bang Bang

This may be the most unfamiliar bit of syntax. ! means NOT in JavaScript, but was does !! mean? It actually means NOT NOT. It's guaranteeing that the result of the expression is always true or false.

I found this article to be the best explanation but I'll try to summarize here.

In JavaScript we have falsy values and truthy values. null, for example, is falsy. That means this statement is true.

!null === true
Enter fullscreen mode Exit fullscreen mode

If we add another ! we discover the expression is equivalent to false.

!!null === false
Enter fullscreen mode Exit fullscreen mode

So !! is telling us whether our expression is truthy or falsy.

All together

Let's look at our original example.

!!{...obj, ...obj2}.item
Enter fullscreen mode Exit fullscreen mode

If we break it down it's doing this.

const newObj = {...obj, ...obj2}
const item = newObj.item
if (item) {
    return true
} else {
    return false
}
Enter fullscreen mode Exit fullscreen mode

The result depends entirely on our objects. Let's look at two options.

Example 1:

const obj = {
    item: null
}
const obj2 = {
    key: "thing"
}
Enter fullscreen mode Exit fullscreen mode

In this case, the expression is false, because null is falsy.

Example 2:

const obj = {
    key: false
}
const obj2 = {
    item: "some value"
}
Enter fullscreen mode Exit fullscreen mode

In this example, the expression is true! "some value" is truthy.

Pretty cool

What do you think? Not sure how often I'd use it, but it's a neat bit of code. Allows us to look through a number of objects and determine if we have a legitimate value for a particular key.

Latest comments (17)

Collapse
 
sirseanofloxley profile image
Sean Allin Newell

I have really started to prefer functions to provide clarity:

isTruthy(
  pluck(
    'item',
    merge(obj, obj2)
  )
);

What's powerful here is if this is common place, make a helper!

const eitherHasItem = (a, b) =>
  isTruthy(pluck('item', merge(a, b)));

eitherHasItem(obj, obj2); //true|false
Collapse
 
josefrichter profile image
Josef Richter

Somehow this 1 line of code is in fact 50 lines, because it requires explanatory article :-) Readable > Pretty cool.

Collapse
 
harrisgca profile image
Glenn Harris

Boolean({...x,...y}.item) does the same thing, and I prefer it because the intent is more clear at a glance.

Collapse
 
pentacular profile image
pentacular

!!x is just a less readable version of x != false.

{...a, ...b }.c is just a less efficient version of b.c ll a.c.

Collapse
 
juliang profile image
Julian Garamendy

hmmm

const a = { c: 42 }
const b = { c : 0 }

const x1 = !!{...a, ...b}.c // false
const x2 = !!{...b, ...a}.c // true
const x3 = b.c || a.c // 42
const x4 = a.c || b.c // 42
Collapse
 
pentacular profile image
pentacular

Fair point -- although to really answer this we need to understand what the original code is trying to achieve to see what the actual problem domain is.

b.c ?? a.c might be sufficient, depending on how you want to deal with nullish values.

('c' in b ? b.c : a.c) might also do.

But whatever you're trying to do, it's unlikely that merging two objects to look up a property is the most reasonable option. :)

Thread Thread
 
perpetual_education profile image
perpetual . education

we need to understand what the original code is trying to achieve

This is what the code should describe (not just to you - but to your average programmer)

Thread Thread
 
pentacular profile image
pentacular

I don't think that's a reasonable expectation.

The code will describe the what and the how, but I have yet to see a programming language which encapsulates the why of it.

If your argument is that it should contain comments which explain why this is being done, then I agree.

In which case, I guess your point is that the snippet provided is defective because it lacks this. :)

Collapse
 
perpetual_education profile image
perpetual . education

It depends who you talk to! ;)

Collapse
 
raibtoffoletto profile image
Raí B. Toffoletto

I'll start using it for sure, it seems a good way to assert you are dealing with the right type in JS. Thanks for the article.

Collapse
 
heyrohit profile image
Rohit Gupta

I personally use it all the time now that I've been using typescript. This makes perfect sense.

Collapse
 
kant312 profile image
Quentin Delcourt

3 lines of clear code > 1 line of cryptic code
😛

Collapse
 
ascorbic profile image
Matt Kane

I wrote the code that Laurie reviewed, and I do agree with everyone criticising it. The spreads in particular are very inefficient. In my defense, perhaps I should explain what the code was actually doing. The real obj1 and obj2 were actually packageJson.devDependencies and packageJson.dependencies, and originally I had been creating a combined list of dependencies, which I was then using elsewhere. When I simplified it into a single check, I didn't then also refactor out the spread. But that's what code reviews are for! The version that I ended up committing was something like:

function isGatsbySite(packageJson) {
    return !!(packageJson.dependencies?.gatsby || packageJson.devDependencies?.gatsby)
}

...except it was actually TypeScript. The !! was because the return value was a boolean. I supposed I could've used a Boolean cast there. 🤷‍♂️

Collapse
 
laurieontech profile image
Laurie

I’d argue that it was a reasonable way of doing it. Was there a way to simplify it? Sure. But it wasn’t egregious. Plus, I learned something :)

Collapse
 
kant312 profile image
Quentin Delcourt

Thanks for the answer, nice to know the "behind the scenes" 😄
I think in another comment Sebastian mentioned that depending on the target audience of the code, it may or may not be relevant to use some code conventions.
Personally when I see "!!" I know what it means but the first time I encountered it I was really puzzled 🙂
But again, context is everything. In this case, I'd say that the fact that the function is named "isGatsbySite" is more than enough to clarify the code.

Collapse
 
codemouse92 profile image
Jason C. McDonald

Oh, that's a keeper. :D

Collapse
 
coffeecraftcode profile image
Christina Gorton

Now that you have explained it I might use it for personal code but I definitely wouldn't have easily recognized what was going on without this explanation. Soo depending on the team I am working with I might not use it if I think it would confuse others on my team.