frontend May 29

(Il)logical operators in JavaScript

5 min read –
programming code web developers

Through the years of my formal education, I’ve covered the basics of Logic and Boolean algebra multiple times (CS in primary school, high school and college, Logic in high school and college). This conditioned me to think that logical operators work with logical values (i.e. TRUE and FALSE) – not so in JavaScript 😅.

Truth(y) and False/y

All values in JS (Ruby and Python have similar classification), based on their truthiness, are separated into two sets: truthy and falsy. A truthy value is a value that is considered true when encountered in a Boolean context (e.g. an if statement). All values are truthy unless they are defined as falsy.

Falsy values in JS are:

  1. False (makes sense XD)
  2. null
  3. undefined
  4. 0
  5. NaN
  6. ” (also “” and “)
  7. document.all (you can ignore this one)

You can test this by using Boolean(value) function in your browser console.

NB. Some languages (namely PHP) treat “0” as false. But in JavaScript, a non-empty string is always true.

Boolean('0')
// -> true
Boolean(' ') // any non-empty string is true
// -> true

Logical operators

There are three logical operators in JavaScript: || (OR), && (AND) and ! (NOT).

As I hinted in the introduction: “The value produced by a && or || operator is not necessarily of boolean type. The value produced will always be the value of one of the two operand expressions.ES5.1 documentation

1.) OR (||)

In most other programming languages and classical logic, the logical OR is meant to manipulate boolean values only. If any of its arguments are true, it returns true, otherwise, it returns false. It will work the same way in JS if we use it just with logical values:

Boolean(true || true)
// -> true
Boolean(true || false)
// -> true
Boolean(false || true)
// -> true
Boolean(false || false)
// -> false

But the real fun starts when we use it on random values. In this case, the || operator returns the first truthy value it encounters, going from left to right. If all the arguments of || operator are false/falsy, it will return the last evaluated falsy value (the rightmost one).

console.log(false || 'This is the first truthy value')
// 'This is the first truthy value'
console.log(5 || "This won't get logged")
// 5
console.log(null || NaN || 'It works with multiple arguments as well' || 0)
// 'It works with multiple arguments as well'
console.log('' || undefined || 0) /* It will return 0. Since all the values are falsy, and 0 is the last one */
// 0

NOTE: The evaluation stops once a truthy value is reached. This is known as Short-circuit evaluation (programmers with C background will find this familiar from the subtle difference between | and ||, or & and &&). We need to take this into account since there may be side effects that won’t show up if the evaluation doesn’t reach them. (We’ll refer to this later in the applications section).

let x;
true || (x=1);
console.log(x);
// undefined
// it's undefined because (x=1) wasn't evaluated 

2.) AND (&&)

Standard logical AND operator returns true if and only if all the arguments are true, it returns false otherwise. In JS && returns the first falsy value it evaluates. If all the values are truthy, it will return the last one evaluated, the rightmost one.

console.log('This will evaluate to' && null && "Because it's the first falsy value")
// null
console.log({} && 7 && "I'll be returned, because all the arguments are truthy")
// "I'll be returned, because all the arguments are truthy"

NOTE: We can combine && and || to unleash its full potential. But we need to take care of the operator precedence: && operations will evaluate before the || once.

null && 'This will not be evaluated'
||
'But this will, because the expression before this one will evaluate to a falsy value'
&&
`Finally, this will be returned. Because this is the last truthy value in a && operator`
// Finally, this will be returned. Because this is ...

Same as in mathematics❤️ we can affect the precedence by the use of parentheses:

null && ("Expressions in here don't matter" || 16) && 
 "Because we're in a big && expression"
// -> null

3.) NOT(!)

Negation operator ! unlike && or || takes only a single argument or an expression. First, it converts the argument to a boolean value (a truthy value to true and a falsy one to false) and then returns its inverse.

!true
// -> false
!false
// -> true
!'Danilo'
// -> false
!0
// -> true

If you’re combining it with other logical operators take into account that the ! has the highest precedence of all the logical operators so it always executes first, before && or ||.

! is also known as the “bang” operator so don’t be surprised if you stumble upon a reference to the “bang” or the “bang bang”/”double bang” operator 🤓.

Applying our newfound superpowers

The first time I came upon this JS functionality I thought it was cool 😎 but couldn’t find any useful application. Now there is hardly a day without me using one of these awesome features.

NOTE: Although these applications might be cool 😎 you should first and foremost consult with your company’s style guides. Your code will be as good as useless if none of your colleagues can understand it.

  • Converting to boolean: A double NOT !! can be used for converting a value to boolean type. It’s a shorthand way to implement the built-in Boolean function.
return {
  loggedIn: !!state.user.token,
  user: { firstName, lastName},
};
  • Conditional rendering: While learning React I came upon this pattern more times than I can count
{ isLoading
  ? <p>Loading...</p>
  : null
}

Altho it serves its purpose, the null in the ternary operator is there only to satisfy syntactical rules.

Conditional rendering with a && operator is way more elegant (Loading… paragraph will render only if the isLoading variable contains a truthy value)

{ isLoading && <p>Loading...</p>}
  • Missing data: if you’ve ever come upon “Cannot read property <propertyName> of undefined” error in your console you are not the only one :D. In my React apps this sometimes happens if I use destructuring of the data I’m fetching from the API
const {
  user: {
    token,
    role,
  },
  getGfnyIds,
} = this.props;

If the user wasn’t passed as a prop to this component reading the token and role from it will throw an error.

We can prevent it with this pattern. This code won’t throw the error since we won’t even try to read the token property of user if the user is undefined. (Once we get the data the component will rerender & display all the necessary data as it was meant to).

const {
  user,
  getGfnyIds,
} = this.props;

const token = user && user.token;
const role = user && user.role;

Wrap-up

There are numerous ways that haven’t been mentioned to utilize the functionality of logical operators but these are the ones I use the most.

If you’d like to solidify your newfound knowledge at the end of this article are some cool interactive exercises.

Now that you understand how logical operators in JS work remember: “with great power comes great responsibility”. Don’t overuse these features. Although I can’t remember when was the last time I used ternary operator, the if the statement is still a good friend of mine – as they say, “If it ain’t broken, don’t fix it.”