Boolean Values and Logical Operations in JavaScript

As we've mentioned before, there are two Boolean values in JavaScript, true and false. true indicates something is correct, and false indicates something is wrong.

Basic logical operators

Boolean values are often used in logical operations. There are three most fundamental logical operators we can apply to Boolean values in JavaScript, &&, ||, and !.

The && operator denotes logical and, it produces true only if both given arguments are true.

console.log(true && false); // -> false

console.log(false && true); // -> false

console.log(false && false); // -> false

console.log(true && true); // -> true

The || operator denotes logical or, it produces true if either one of the given arguments is true.

console.log(true || false); // -> true

console.log(false || true); // -> true

console.log(false || false); // -> false

console.log(true || true); // -> true

The ! operator denotes logical not, which flips the given argument.

console.log(!true); // -> false

console.log(!false); // -> true

Besides the basic and, or and not, there is also the conditional operator (?:) that works on three values.

true ? 1 : 2; // -> 1

false ? 1 : 2; // -> 2

If the argument before the question mark is true, this operation will return 1. If the value is false, this operation will return 2.

Precedence

So far, we've talked about arithmetic operations, comparisons, and logical operations. In fact, you can combine them together in one statement.

1 + 1 == 2 && 1 + 1 < 0;

The arithmetic operations have the highest priority, which produces:

2 == 2 && 2 < 0;

And the comparisons will be evaluated next:

true && false; // -> false

Which then produces false because one of the given arguments is false.

When there are multiple logical operators in one statement, the not operator (!) takes precedence, then the and operator (&&) will be evaluated, and finally the or operator (||). For example,

// prettier-ignore
!true || false && true;

In this case, the !true will be evaluated first:

// prettier-ignore
false || false && true;

And then false && true will be evaluated:

false || false;

Which gives false.

Truthy and falsy values

Previously, we mentioned that the logical operators deal with Boolean values, but in fact, they can also work on other data types, as JavaScript will attempt to convert them into Boolean values.

The values JavaScript can deal with can be classified as falsy and truthy. Any falsy values will be treated as false, while all other values will be treated as true.

The falsy values include: null, undefined, NaN, number 0, and empty string (""), while all other values are truthy values.

You can check if a value is truthy or falsy using the Boolean() function.

console.log("null: " + Boolean(null));
console.log("undefined: " + Boolean(undefined));
console.log("Number 0: " + Boolean(0));
console.log("String '0': " + Boolean("0"));
console.log("Empty string '': " + Boolean(""));
console.log("Space character: " + Boolean(" "));
console.log("Number 1: " + Boolean(1));
console.log("String '1': " + Boolean("1"));
null: false
undefined: false
Number 0: false
String '0': true
Empty string '': false
Space character: true
Number 1: true
String '1': true

check if falsy

This feature allows you to perform logical operations on basically anything. Take the || operator as an example. JavaScript will first try to convert the first argument. If it converts to true, then that argument will be returned in its original form.

console.log(1 || 0);
console.log("qwerty" || 2);
1
qwerty

In this case, the evaluation ends with the first argument, and the second argument will not be touched. Because one of the values is true, this statement guarantees to return true.

This is referred to as short-circuiting evaluation. This can be useful when you need to control whether or not an expression should be evaluated. For example,

true || console.log("Hello");
false || console.log("World");
World

The console.log() function will only be executed when the first argument is false.

On the other hand, if the first argument of the || operation converts to false, the second argument will be returned, even if the second argument is also falsy.

console.log(0 || 1);
console.log(0 || null);
1
null

The || operator finds the first truthy value

In practice, the || operator is often used to create fallback systems by chaining multiple operators together. The operation will return the first value that is truthy, which is -10 in the following example.

let a = null;
let b = "";
let c = -10;
let d = 0;

console.log(a || b || c || d);
-10

If no truthy values are found, the last value will be returned.

let a = null;
let b = "";
let c = 0;
let d = undefined;

console.log(a || b || c || d);
undefined

The && operator finds the first falsy value

The && operator, on the other hand, is often used to return the first falsy value in a chain.

let a = 123;
let b = "qwerty";
let c = 0;
let d = null;

console.log(a && b && c && d);
0

If no falsy values are found, the last value will be returned.

let a = 123;
let b = "qwerty";
let c = 100;
let d = 10;

console.log(a && b && c && d);
10

The nullish coalescing operator finds the first defined value

The nullish coalescing operator (??) returns the first defined value, which is a value that is not null or undefined.

let a = null;
let b;
let c = 0;
let d = 10;

console.log(a ?? b ?? c ?? d);
0

A variable that is declared but not given a value will be assigned undefined internally. We will discuss more about this behavior later.

In practice, it is used in a similar way as the logical or (||). You can use the nullish coalescing operator to create the same fallback system.

But, one important difference between them is that the || operator returns the first truthy value, while the ?? operator returns the first defined value. In our previous example, even though the number 0 is falsy, it is still a defined value, so 0 will be returned.

Practices

If you are new to programming, the logical operations can be quite challenging. So, in order to solidify what we've learned so far, let's end this lesson with some practice questions.

  • What is the output of the following code?
const x = 15;
const y = 25;

console.log(x > 10 && y < 30);
  • What is the output of the following code?
console.log(10 % 2 == 0 && 10 % 3 == 0);
  • What is the output of the following code?
const a = true;
const b = false;
const c = true;

// prettier-ignore
console.log(a && b || c);
  • What is the output of the following code?
const x = 2024;

console.log(x % 4 == 0 && (x % 100 !== 0 || x % 400 == 0));

The parentheses change the precedence of evaluation in a logical operation, just like in an arithmetic operation.

  • What is the output of the following code?
const x = 5;
const y = 10;

console.log(!(x > 3) && y < 20);
  • What is the output of the following code?
const x = 10;
const result = x > 5 ? "Greater than 5" : "Less than or equal to 5";

console.log(result);
  • What is the output of the following code?
const temperature = 25;
const weather = temperature > 30 ? "Hot" : temperature > 20 ? "Warm" : "Cool";

console.log(weather);

This question is a bit challenging. It has two chaining conditional operators. You should start from the left side. Ask yourself this question: Is the temperature greater than 30? If yes, return "Hot". If not, continue with the second conditional operation.

Good luck with this one!

  • What is the output of the following code?
const x = 0;
const y = false;
const z = "Hello";

console.log(x || y || z);
  • What is the output of the following code?
const isAdmin = true;
const isModerator = true;
const isLoggedIn = true;

console.log(isAdmin && isModerator && isLoggedIn);
  • What is the output of the following code?
const isAdmin = false;
const isModerator = true;
const username = isAdmin || isModerator || "Guest";

console.log(username);