1

How can I reduce this if statement in JavaScript

if(obj.attributes && obj.attributes.email === 'test@test.com') { ... }
ajp76054
  • 33
  • 4
  • if it's possible that `obj.attributes` is undefined, you can't - well, you can use try/catch, but thta's probably MORE code – Bravo Oct 25 '18 at 22:38
  • Frankly that looks fine to me as is, it's clear and concise already. Although fwiw you can use the shorter but arguably worse: `if ((obj.attributes || {}).email === "test@test.com") { ... }` – CRice Oct 25 '18 at 22:39
  • There's nothing wrong with that check. One possible alternative is `if((obj.attributes || {email:''}).email === 'test@test.com') { ... }` but that looks worse. – JohanP Oct 25 '18 at 22:39
  • There's no easy way to do it. Workarounds exist, but they're only really worth it for longer chains - the way I usually do it would be about as long in this case anyway, and probably harder to read. – John Montgomery Oct 25 '18 at 22:39
  • Related: [Null-safe property access (and conditional assignment) in ES6/2015](https://stackoverflow.com/questions/32139078/null-safe-property-access-and-conditional-assignment-in-es6-2015), which if we ever get optional chaining, you could use `obj.attributes?.email === ...`. – CRice Oct 25 '18 at 22:48

2 Answers2

1

The line by it self is clear, however if you are looking a way to write less && operator inside you can always put things outside of the comparison such as.

var attributes = obj.attributes || {};
if ( attributes.email === 'test@test.com' ) {
}

This makes sense if you need to make multiple checks instead of a single one, however if is a single comparison it seems like the code you already have is okay as you are making sure attributes is defined before accessing an undefined property.

On the other hand if you have support for ES 2015 you can destruct stuff like:

const { attributes = {} } = obj;
if ( attributes.email === 'test@test.com' ) {
}
Crisoforo Gaspar
  • 3,740
  • 2
  • 21
  • 27
0

You can create a reusable get function using Array.reduce(). The function parameters are a path, the object, and a defaultValue (default defaultValue is undefined). It will iterate the path, and try to extract the value, if it fails, it will return the defaultValue:

const get = (path, obj, defaultValue) => obj ? 
  path.reduce((r, k) => r && typeof r === 'object' ? r[k] : defaultValue, obj) 
  : 
  defaultValue;

if(get(['attributes', 'email'], null) === 'test@test.com') { console.log(1) }
if(get(['attributes', 'email'], {}) === 'test@test.com') { console.log(2) }
if(get(['attributes', 'email'], { attributes: {} }) === 'test@test.com') { console.log(3) }
if(get(['attributes', 'email'], { attributes: { email: 'test@test.com' } }) === 'test@test.com') { console.log(4) }

There is a TC39 stage proposal called "Optional Chaining for JavaScript". If it will make it's way to the language, it will add an the optional chaining operator - ?. Now if attributes don't exist, it will return undefined.

Example: obj.attributes?.email

It's usable today via babel plugin.

Ori Drori
  • 183,571
  • 29
  • 224
  • 209