cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

Logical operators

Learn JavaScript's &&, ||, and ! operators: truthy and falsy decisions, short-circuit evaluation, operand return values, guard patterns, and safe defaults.

By the end, you can
  • 01
    Read logical expressionsPredict how &&, ||, and ! combine truthy and falsy values.
  • 02
    Trace short-circuitingKnow when JavaScript skips the right side of an expression.
  • 03
    Use practical patternsWrite guard calls and defaults without being surprised by 0, '', null, or undefined.

Three operators, one idea

Logical operators help JavaScript answer questions like “do we have both requirements?”, “do we have at least one usable value?”, and “is this not true?” The three operators are && (and), || (or), and ! (not).

They build on truthy and falsy values from Booleans & truthiness. A value like "Ada", 10, or [] is truthy. The eight falsy values are false, 0, -0, 0n, "", null, undefined, and NaN.

One-sentence definition

Logical operators test truthiness, may skip the right side, and—except for !—return one of the original operands.

Real-life analogy&& is a security door

Imagine a door that needs a badge and a PIN. If the badge is missing, the guard does not bother asking for the PIN. The first missing requirement already decides the answer.

In real life: A guard asks for a badge
In JavaScript: The left operand of &&
In real life: Then the guard asks for a PIN
In JavaScript: The right operand of &&
In real life: No badge? Stop immediately
In JavaScript: A falsy left value short-circuits
In real life: Badge and PIN? Enter
In JavaScript: Both operands must be truthy

Where the analogy stops: A real guard might ask questions in any order. JavaScript always evaluates left to right for these operators.

This lesson goes deeper than a boolean truth table. You will step through skipped function calls, experiment with the exact returned value, use guards and defaults, and see why the next lesson’s ?? fixes the classic 0 || 10 bug.

&&, ||, and !

TABLES

With plain booleans, the operators are easy to read. a && b means both must be truthy. a || b means at least one must be truthy. !a flips truthiness and always gives the boolean true or false.

Boolean truth table for && and ||
ExpressionWhen it is trueExamples
a && bOnly when a and b are both truetrue && true → true; true && false → false
a || bWhen a or b (or both) are truefalse || true → true; false || false → false
!aWhen a is falsy!false → true; !true → false

But JavaScript usually meets values that are not already booleans. It asks “truthy or falsy?” for the decision, then keeps the actual value around. That is why "cat" && 10 returns 10, not true.

Boolean conversion versus logical return value
CodeTruthiness decisionReturned value
Boolean("cat")The string is truthytrue because Boolean() converts
"cat" && 10Left is truthy, so use the right side10, the actual right operand
0 || "Guest"Left is falsy, so use the right side"Guest", the actual right operand
!"cat"The string is truthy, then flippedfalse, because ! always returns a boolean

Short-circuit evaluation

STEP THROUGH

Short-circuiting means JavaScript stops as soon as the result is known. The right side might not run at all. This matters when the right side is a function call, a property read, or anything with a side effect.

Real-life analogy|| is a keyring

The || operator is like trying keys on a keyring. The first key that opens the lock wins. You do not keep trying keys after the door is open.

In real life: Try the front-door key
In JavaScript: Evaluate the left operand
In real life: It opens? Stop trying keys
In JavaScript: Truthy left value short-circuits ||
In real life: It fails? Try the next key
In JavaScript: Falsy left value makes JavaScript evaluate the right operand

Where the analogy stops: A person might try keys randomly. JavaScript tries operands left to right and stops by fixed rules.

Watch short-circuiting skip real code
Step 0 of 4Ready
Your turn: follow the blue line

Predict which helper runs. Then step through the real recording: the skipped helper will have no frame at all.

Running in
  1. script
Next: line 8
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
function checkBadge() {  console.log("badge checked");  return "";}function checkPin() {  console.log("PIN checked");  return "pin-ok";const result = checkBadge() && checkPin();console.log(result);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
Choose which logical expression to record

Changing the choice starts a fresh recording. Predict which helper will never run.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Watch the skipped function: no log, no return value, no frame. That is real JavaScript control flow, not just a display trick. This is why isLoggedIn && showDashboard() calls the function only when the guard is truthy.

Does the right side run?
  • "badge" && checkPin()
  • 0 && saveScore()
  • "Ada" || "Guest"
  • "" || "Guest"
  • user && user.name
  • null && user.name
Try it yourself
0 of 6 correct

Sort each expression by whether JavaScript evaluates the right operand.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

They return operands, not booleans

INTERACTIVE

This is the rule that surprises beginners and helps professionals write compact code: && and || return the value that decided the expression. They do not hand you a yes/no card unless one operand was already a boolean.

  • a && b returns a if a is falsy; otherwise it returns b.
  • a || b returns a if a is truthy; otherwise it returns b.
  • !a always returns a boolean. !!a is a common way to convert truthiness to exactly true or false.
What does it really return?
Playground sourcePop out in the code editor (opens in a new tab)JavaScript
const left = "cat";const right = 10;console.log(left && right);console.log(Boolean(left && right));console.log(!left);console.log(!!left);
Actual result"cat" && 10
Returned operand
10
Boolean(result)
true
!left
false
!!left
true
Try it yourself

The expression returns 10. Boolean(result) is true. !left is false, and !!left is true.

Choose operands that are truthy or falsy. The first line proves that && and || hand back one original operand; the second line shows its Boolean conversion.
Arrays are truthy

An empty array [] looks empty, but it is still an object, and objects are truthy. Try [] || "fallback" in the playground: the array wins.

Precedence and De Morgan

STEP THROUGH

Precedence decides which operator groups first when there are no parentheses. For logical operators, remember this order: ! binds tightest, then &&, then ||. So true || false && false is true || (false && false), which is true.

Step through precedence
Step 0 of 4Ready
Your turn: follow the blue line

Step through the four lines to see precedence and one De Morgan rewrite.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
console.log(true || false && false);console.log((true || false) && false);console.log(!(true && false) === (!true || !false));
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Parentheses are often better than relying on memory. They make your intent visible to the next person reading the code, including future you.

Precedence examplesPop out in the code editor (opens in a new tab)JavaScript
console.log(!false && false);console.log(true || false && false);console.log((true || false) && false);console.log(!(true && false) === (!true || !false));

De Morgan’s laws help you move ! inward: !(a && b) has the same boolean meaning as !a || !b. In words, “not both requirements passed” means “the badge failed or the PIN failed.”

Guard and default patterns

INTERACTIVE

Short-circuiting creates two beginner-friendly patterns. A guard only continues when the left side is safe: user && user.name avoids reading name from null. A default chooses a backup: name || "Guest" uses Guest when name is falsy.

Guards and defaults in one tiny profile
Guard and default sourcePop out in the code editor (opens in a new tab)JavaScript
const user = { name: "Ada" };const missingUser = null;console.log(user && user.name);console.log(missingUser && missingUser.name);console.log("" || "Guest");console.log(0 || 10);
Profile resultnull user
user && user.name
null
name || "Guest"
"Guest"
count || 10
10
count ?? 10
0
Try it yourself

user && user.name gives null. name || "Guest" gives "Guest". count || 10 gives 10, while the next lesson's count ?? 10 would keep 0.

This playground previews two common patterns and one common bug: || treats 0 as missing. The next lesson teaches ?? for null-or-undefined defaults.

The default pattern is useful, but it treats every falsy value as missing. That is sometimes wrong: 0 || 10 returns 10, even when 0 is a real count. The next lesson, Nullish coalescing & optional chaining, teaches ?? for “only default when the value is null or undefined,” and ?. for replacing long guard chains.

Guard and default examplesPop out in the code editor (opens in a new tab)JavaScript
const user = { name: "Ada" };const missingUser = null;console.log(user && user.name);console.log(missingUser && missingUser.name);console.log("" || "Guest");console.log(0 || 10);

Where you’ll use this

Logical operators appear anywhere code needs a small decision inside an expression. You will see them in setup checks, display defaults, conditional calls, and validation.

  • isLoggedIn && showDashboard() — call a function only when a condition is truthy.
  • const label = nickname || "Guest"; — display a fallback when the primary value is empty.
  • const city = user && user.address && user.address.city; — older guard chains; next lesson replaces this with user?.address?.city.
  • if (isAdmin && hasToken) { ... } — when a statement reads clearer than a clever expression.
Use an if when clarity wins

Short-circuit calls are handy for tiny actions. If you need several lines, an if statement is clearer and easier to debug. Control flow gets its own module soon.

Common misconceptions

  • “Logical operators always return booleans.” Only ! does. && and || return operands.
  • “The right side always runs.” Short-circuiting may skip it completely.
  • “Falsy means useless.” 0 and "" can be valid data. Be careful with || defaults.
  • “!!x is the same as x.” It has the same truthiness, but the value becomes exactly true or false.
  • “Precedence is obvious.” It is easy to misread mixed && and ||. Parentheses are cheap.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upPredict the operands

Predict all three console outputs before you run the code.

Starter codePop out in the code editor (opens in a new tab)JavaScript
console.log("cat" && 10);
console.log(0 || "fallback");
console.log(!"");

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeFind the default bug

    Find the surprising output, then rewrite the default in the solution.

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    const count = 0;
    console.log(count || 10);

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeWrite a null guard

      Use && so the property read only happens when user exists.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      const user = null;
      console.log(user && user.name);

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeSimplify a tiny nested if

        Trace the && chain and decide whether the function call runs.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        const isLoggedIn = true;
        const hasPlan = true;
        function showDashboard() { console.log("dashboard"); }
        isLoggedIn && hasPlan && showDashboard();

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeApply De Morgan

          Rewrite the condition without changing its boolean meaning.

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          const hasBadge = true;
          const hasPin = false;
          console.log(!(hasBadge && hasPin));
          console.log(!hasBadge || !hasPin);

          Answer, then press Check. Spacing and letter case don’t matter.

            Check your understanding

            7 QUESTIONS
            Logical operators quiz · 7 questionsScore: first tries count
            1. Question 1 of 7What does cat && dog print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log("cat" && "dog");

              Choose an answer to see the explanation.

            2. Question 2 of 7Which expression skips the function call?

              Choose an answer to see the explanation.

            3. Question 3 of 7What does an empty-name default print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log("" || "Guest");

              Choose an answer to see the explanation.

            4. Question 4 of 7What does !0 print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log(!0);

              Choose an answer to see the explanation.

            5. Question 5 of 7How is true || false && false grouped?

              Choose an answer to see the explanation.

            6. Question 6 of 7What is the safer next-lesson fix for count || 10 when 0 should be kept?

              Choose an answer to see the explanation.

            7. Question 7 of 7Which rewrite matches !(hasBadge && hasPin)?

              Choose an answer to see the explanation.

            Key takeaways

            • && needs both sides to be truthy; it stops on the first falsy operand.
            • || needs one truthy side; it stops on the first truthy operand.
            • ! flips truthiness and always returns a boolean.
            • && and || return operands, not converted booleans.
            • Use guards and defaults carefully; 0 and "" are falsy but often meaningful.

            Logical operators combine truthy/falsy decisions with left-to-right short-circuiting, returning the operand that decides the expression.

            Up next: Nullish coalescing & optional chaining.

            CompleteFrontend Clear concepts. Working examples.