DEV Community

Shameel Uddin
Shameel Uddin

Posted on

πŸ’‘ JavaScript Hack: Conditionally Add Properties within Objects

πŸš€ Attention JavaScript Enthusiasts! πŸš€

Are you tired of writing lengthy code to conditionally add properties to JavaScript objects? 😫 I've got an elegant shortcut for you that will not only simplify your code but also make it more readable and maintainable! πŸ€“βœ¨

Traditional Approach:

Let's say you're working on a finance app, and you want to create an object representing a financial transaction with properties like transactionType, amount, and date. However, not all properties are relevant for every transaction, and you want to add them only if they exist.

Here's the traditional way to do it:

const transaction = {};

if (transactionType) {
  transaction.transactionType = transactionType;
}

if (amount) {
  transaction.amount = amount;
}

if (date) {
  transaction.date = date;
}
Enter fullscreen mode Exit fullscreen mode

The Elegant Shortcut:

JavaScript offers a concise and elegant solution to this problem using the spread (...) operator and object literal shorthand:

const transaction = {
  ...(transactionType && { transactionType }),
  ...(amount && { amount }),
  ...(date && { date }),
};
Enter fullscreen mode Exit fullscreen mode

Benefits of the Shortcut

Using this elegant shortcut offers several advantages:

  1. Conciseness: The code is much shorter and easier to read, reducing redundancy and improving maintainability.

  2. Scalability: It scales effortlessly as you add more properties or conditions without cluttering your code.

  3. Readability: The intent of your code is clearer, making it easier for others (and your future self) to understand.

Conclusion

This one-liner efficiently adds properties to your object if and only if they exist. It's shorter, more readable, and scales effortlessly as your codebase grows.

So, the next time you're working with JavaScript objects, remember this fantastic shortcut to streamline your code and impress your colleagues! πŸ˜ŽπŸ‘¨β€πŸ’Ό

I hope you learned something from this :-)

Follow me for more such content:
LinkedIn: https://www.linkedin.com/in/shameeluddin/
Github: https://github.com/Shameel123

Top comments (14)

Collapse
 
the_riz profile image
Rich Winter

I actually don't find this easier to read.
At all.

Plus you'll end up with strange situations like where you're testing for a value which will exist but be null or 0.

Less code is better, but not at the sacrifice of legibility.

Perhaps you should consider the relatively new ?? operator?

Collapse
 
shameel profile image
Shameel Uddin

You have raised two concerns Readability and Validation:

  1. Readability:
    Initially when I got introduced to this, I also found it a bit tricky just like I found IIFE tricky especially with async/await but I guess we should evolve with respect to time and try to understand different cool ways to make code concise.

  2. Validation
    For this current context, if you get 0 then it won't pass in "if" check either, so proper validation and the concerns need to be taken place with respect to the context wherever we are applying our methods/techniques.

It's just a shortcut way of doing what I used to do in "if blocks" especially when making an API endpoint and you have to check and verify if any query parameter is available then add it as a filter to the DB.

Collapse
 
rahulladumor profile image
Rahul Ladumor

Hey Shameel,

Thanks a ton for sharing this trick! πŸš€ I've been coding in JavaScript for a while, but I never came across this elegant way to conditionally add properties to objects. It’s going to make my code so much cleaner and more efficient. Can't wait to try this out in my next project. Keep these tips coming!

Collapse
 
shameel profile image
Shameel Uddin

Thanks a lot for the appreciation :)

Collapse
 
nvdweem profile image
Niels van de Weem • Edited

Probably a microoptimisation to take this into account, but the 'more readable' variant is 99.5% slower when the values are truthy and 95% slower when falsy according to jsbench.me (tested on a phone).

Other than that, if this is something you do often, just create a addIfNotFalsy method that does the if condition and use that.

function addPropertyIfNotFalsy(target, property, val) {
    if (val) {
        target[property]=val;
    }
}

const transaction = {};
addPropertyIfNotFalsy(transaction, 'transactionType', transactionType);
addPropertyIfNotFalsy(transaction, 'amount', amount);
addPropertyIfNotFalsy(transaction, 'date', date);
Enter fullscreen mode Exit fullscreen mode

Not accounting for the helper method, this is (compared to the shortcut):

  1. Almost as slow (only 91% slower than the initial version instead of the 99.5%)
  2. As concise and way more descriptive (if conciseness is considered to be less characters, replace the method and variable name to be less descriptive but more concise)
  3. Scales just as well, even allows the variable to have another name from the key without losing conciseness
  4. It's actually readable without knowing some strange quirk (you don't have to lookup what {...false} is supposed to do according to the specs)

This post did teach me that the {...false} situation is covered by the specs.

Collapse
 
kcko profile image
Kcko

I absolutely agree.

The code shown in the article is slow and unreadable.

Your solution is the best.

Collapse
 
sonn51280 profile image
sonn51280

good idea

Collapse
 
miketalbot profile image
Mike Talbot ⭐ • Edited

So as others have mentioned this is a bad idea because it's using falseyness to skip adding the property - that feels like it's really going to lead to some dodgy bugs with zeroes and "" etc. Surely the right way is to skip the property if it's not defined.

If your resultant object is going to be a property of a GraphQL request, or the object is going to be stringified then just setting the property to undefined will mean that it isn't actually persisted or used. It would however be present in an in query for the object. This isn't a problem for me so my code for this would read:

     const transaction = { transactionType, amount, date }
Enter fullscreen mode Exit fullscreen mode

I wouldn't be storing any extra data and the fact that this temporary version of the object has a couple of extra properties is a lot less memory and garbage usage than creating all of those temp objects.

Collapse
 
akashkava profile image
Akash Kava

Slow, too many spread operators involve for in operator internally which is unnecessary overhead.

Collapse
 
urielsouza29 profile image
Uriel dos Santos Souza

For of, iterator

Collapse
 
akashkava profile image
Akash Kava

For of is only for iterable, spread operator for an object would use for in, object may not be iterable.

Thread Thread
 
urielsouza29 profile image
Uriel dos Santos Souza

Yes!

Spreading includes properties whose keys are symbols (which are ignored by Object.keys(), Object.values() and Object.entries()):


const symbolKey = Symbol('symbolKey');
const obj = {
  stringKey: 1,
  [symbolKey]: 2,
};

{...obj, anotherStringKey: 3},

  {
    stringKey: 1,
    [symbolKey]: 2,
    anotherStringKey: 3,
  }
/////////////////////////
const symbolKey2 = Symbol('symbolKey');

const object = { a: 1, b: 2, c: 3 , [symbolKey2]: 2,};


for (const property in object) {
  console.log(`${property}: ${object[property]}`);
}
// "a: 1"
//"b: 2"
//"c: 3"

Enter fullscreen mode Exit fullscreen mode
Collapse
 
kcko profile image
Kcko

Absolutely agree.

Collapse
 
brenohq profile image
Breno Henrique

"more readable and maintainable" rofl