JavaScript Expressions: Shortening Logic with Expressions! blog post

JavaScript Expressions: Shortening Logic with Expressions!

Adam Lubek

25 Sep, 2019

JavaScript

7 minutes read

Today we’re going to have some fun with JavaScript Expressions, and explore some interesting syntaxes. JavaScript offers many ways of implementing logic, and you probably use them on a daily basis.

The most common way we’d typically write logic is using statements. For example, inside curly braces {}, using something like an if or else statement.

In this article though, we’ll explore an alternative way of writing logic using the ‘magic’ of JavaScript expressions, combined with commas and other pieces. If you’ve ever seen or wondered what wrapping code in brackets () will do, this post is for you. Prepare for expressions!

Please note! This way of writing is not the most readable, it’s opinionated and more difficult to read. But it will teach you more how JavaScript works so you can become a better developer – think about minified code for example, it’s the result of your beautiful JavaScript transformed into the most minimal of expressions to cut down the size of the file. So this is what we’ll almost be doing, there’s definitely value in exploring the JavaScript language capabilities!

Grab yourself a fresh StackBlitz JS project and follow along!

Once you've finished reading this post, do you want to learn even more?

javascript

Learn JavaScript for FREE!

We've created the best online course for you to fully master JavaScript using real-world examples and techniques you’ll find nowhere else.

  • ES2015 and beyond
  • Variables and Scoping
  • Strings, Numbers and Booleans
  • Conditional Statements
  • Operators
  • Modules
  • Arrays and Objects
  • Functions and Closures
  • Loops and Iteration
Get course Get javascript Basics

Further reading after this article: I’d recommend Expressions versus Statements for a deep-dive into the subject of expressions and statements!

Traditional statement based logic

Let’s take a function that accepts value and threshold as arguments and returns an array of values.

An array contains number 5 as initial value and pushes passed in value as a second value.

If passed in threshold is less than 10 then, a constructed array is returned. Else, number 7 is pushed onto an array and that array is then returned.

There is several ways to write this code but it roughly would look like this:

const doSomethingUsingStatements = (value, threshold) => {
  const arr = [5];
  arr.push(value);

  if (threshold < 10) {
    return arr;
  }

  arr.push(7);
  return arr;
}

Our code would then produce something like:

// Returns [5, 4, 7]
doSomethingUsingStatements(4, 10);

// Returns [5, 3]
doSomethingUsingStatements(3, 2);

Expression based implementation

Okay, get ready for expressions!

Our function signature will be the same but implementation details will vary. What we need first is an array containing number 5.

To achieve that, we will use immediately invoked function to which we will pass our array:

const fn = () => (arr => console.log(arr))([5]).

This code is equivalent to:

const fn = () => { const arr = [5]; console.log(arr); }

When we run this, we will see [5] in the console – but we will also notice undefined is also present. This is because both versions of the code are not returning anything other than logging passed in an array.

Now, our statement based implementation does not return anything (no return keyword) so by default it’ll return undefined.

With our expression however, the last evaluated expression is returned (which in this case is the console.log and returns nothing) which is why we see undefined in the console.

For a function to return something, we need to either use the return keyword (in our "statement based" function) or ensure that last listed expression will return a value (in our "expression based" implementation).

This basically means that we need to change the code to:

const fn = () => (arr => (console.log(arr), arr))([5]);
const fn = () => { const arr = [5]; console.log(arr); return arr; };

With the above implementations, we can notice that [5] is written twice to the console, first due to using console.log function and the second time due to [5] being returned from the function call.

It’s also important to notice additional parentheses enclosing (console.log(arr), arr) expression. This is due to the comma being used within the expression, and you can read more details about how this works in the subsection on commas in JavaScript!

Logic and Expressions

Looping back to our first code example, if we extract the "logic" inside the function, we’re left with:

{
  const arr = [5];
  arr.push(val);

  if (threshold < 10) {
    return arr;
  }

  arr.push(7);
  return arr;
}

In the expression form, we can instead write this logic as follows:

(arr.push(val), threshold < 10 ? arr : (arr.push(7), arr))

The first thing we do here is pushing the passed in value onto the output array, which produces [5, val].

Next, using a ternary operator, we check if the threshold parameter is below 10. If it is, we just return arr.

If the value is an above or equal threshold, we are pushing 7 onto return array and then return the array.

Putting the pieces together, our expression based implementation of our initial function is:

const doSomethingUsingExpressions = (val, threshold) => (
  (arr) => (arr.push(val), threshold < 10 ? arr : (arr.push(7), arr))
)([5]);

Yes I know, it’s harder to read, but you’re learning new things about JavaScript and can even get a little fancy in your own projects if you feel like it.

Expressions: a step further

There is one elegant ‘improvement’ that we can make to an expression based implementation.

Instead of returning array on both cases of the ternary operator, we can return the output array at the end of the expression and utilize a ‘do nothing’ function.

A do nothing function is literally:

() => {}

This function is used commonly used in functional programming when using a ternary construct and is available in many JS libraries (e.g. noop in RxJS).

Re-implementation of our expression utilizing noop function looks like this:

(arr.push(val), threshold < 10 ? () => {} : arr.push(7), arr)

Which in full form, is:

const doSomethingUsingExpressionsWithNoop = (val, threshold) => (
  (arr) => (arr.push(val), threshold < 10 ? () => {} : arr.push(7), arr)
)([5]);

This looks much more elegant (and follows separation of concerns) as it’s more clear where logic goes and where the return value is.

As a side note, a noop function is so commonly used that it could be easily extracted into separate function and used throughout the code:

const noop = () => {}

Giving us something like this:

const doSomethingUsingExpressionsWithNoop = (val, threshold) => (
  (arr) => (arr.push(val), threshold < 10 ? noop : arr.push(7), arr)
)([5]);

Note that noop does not need to be function at all, some ways of implementing noop are:

const noop = {};
const noop = undefined;
const noop = null;

All of the above will achieve the same result.

This could be refactored further into higher order function where we could remove a need for using ternary operator:

const whenTrue = (predicate, fn) => predicate() ? fn : undefined; 

…but that’s material for a separate blog post!

Anyway, check out the source code of what we’ve covered so far:

One more example

To consolidate our knowledge further, here’s how this way of writing logic can be used inside the array’s built-in reduce function.

A typical way of implementing logic inside a reduce function is to use statements like that:

const statementInReduce = vals.reduce((a, c) => {
  a.push(c);
  return a;
}, [4, 5]);

The key element here is:

{
  a.push(c);
  return a;
}

This, with expression based implementation, can be rewritten simply to:

(
  a.push(c),
  a
)

Which, inside full expression based reduce will look like:

const expressionInReduce = vals.reduce((a, c) => (a.push(c), a), [4, 5]);

I admit that this doesn’t save as much as it only saves us from explicitly utilizing a semicolon and writing explicit returns – but in more complex examples can improve the elegance of the code somewhat.

Check out the working source code!

Conclusion

Expressions offer an interesting option to alter the look of the code. I find it most useful when writing code that’s more of a functional programming style. I hope that you found this to be an interesting exploration into JavaScript capabilities!

About the author

Adam is a software engineer specializing in JavaScript and RxJS.

Love the post? Share it!

Lots of time and effort go into all our blogs, resources and demos,
we'd love it if you'd spare a moment to share them!

Explore our JavaScript courses

Get started today and join over 60,000 developers.