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
.
1console.log(true && false); // -> false
2
3console.log(false && true); // -> false
4
5console.log(false && false); // -> false
6
7console.log(true && true); // -> true
The ||
operator denotes logical or
, it produces true
if either one of the given arguments is true
.
1console.log(true || false); // -> true
2
3console.log(false || true); // -> true
4
5console.log(false || false); // -> false
6
7console.log(true || true); // -> true
The !
operator denotes logical not
, which flips the given argument.
1console.log(!true); // -> false
2
3console.log(!false); // -> true
Besides the basic and
, or
and not
, there is also the conditional operator (?:
) that works on three values.
1true ? 1 : 2; // -> 1
2
3false ? 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.
11 + 1 == 2 && 1 + 1 < 0;
The arithmetic operations have the highest priority, which produces:
12 == 2 && 2 < 0;
And the comparisons will be evaluated next:
1true && 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,
1// prettier-ignore
2!true || false && true;
In this case, the !true
will be evaluated first:
1// prettier-ignore
2false || false && true;
And then false && true
will be evaluated:
1false || 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.
1console.log("null: " + Boolean(null));
2console.log("undefined: " + Boolean(undefined));
3console.log("Number 0: " + Boolean(0));
4console.log("String '0': " + Boolean("0"));
5console.log("Empty string '': " + Boolean(""));
6console.log("Space character: " + Boolean(" "));
7console.log("Number 1: " + Boolean(1));
8console.log("String '1': " + Boolean("1"));
1null: false
2undefined: false
3Number 0: false
4String '0': true
5Empty string '': false
6Space character: true
7Number 1: true
8String '1': true
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.
1console.log(1 || 0);
2console.log("qwerty" || 2);
11
2qwerty
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,
1true || console.log("Hello");
2false || console.log("World");
1World
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.
1console.log(0 || 1);
2console.log(0 || null);
11
2null
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.
1let a = null;
2let b = "";
3let c = -10;
4let d = 0;
5
6console.log(a || b || c || d);
1-10
If no truthy values are found, the last value will be returned.
1let a = null;
2let b = "";
3let c = 0;
4let d = undefined;
5
6console.log(a || b || c || d);
1undefined
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.
1let a = 123;
2let b = "qwerty";
3let c = 0;
4let d = null;
5
6console.log(a && b && c && d);
10
If no falsy values are found, the last value will be returned.
1let a = 123;
2let b = "qwerty";
3let c = 100;
4let d = 10;
5
6console.log(a && b && c && d);
110
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
.
1let a = null;
2let b;
3let c = 0;
4let d = 10;
5
6console.log(a ?? b ?? c ?? d);
10
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?
1const x = 15;
2const y = 25;
3
4console.log(x > 10 && y < 30);
- What is the output of the following code?
1console.log(10 % 2 == 0 && 10 % 3 == 0);
- What is the output of the following code?
1const a = true;
2const b = false;
3const c = true;
4
5// prettier-ignore
6console.log(a && b || c);
- What is the output of the following code?
1const x = 2024;
2
3console.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?
1const x = 5;
2const y = 10;
3
4console.log(!(x > 3) && y < 20);
- What is the output of the following code?
1const x = 10;
2const result = x > 5 ? "Greater than 5" : "Less than or equal to 5";
3
4console.log(result);
- What is the output of the following code?
1const temperature = 25;
2const weather = temperature > 30 ? "Hot" : temperature > 20 ? "Warm" : "Cool";
3
4console.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?
1const x = 0;
2const y = false;
3const z = "Hello";
4
5console.log(x || y || z);
- What is the output of the following code?
1const isAdmin = true;
2const isModerator = true;
3const isLoggedIn = true;
4
5console.log(isAdmin && isModerator && isLoggedIn);
- What is the output of the following code?
1const isAdmin = false;
2const isModerator = true;
3const username = isAdmin || isModerator || "Guest";
4
5console.log(username);