0 / 91
Week 3 · Day 17 of 91

Conditions and validation

JavaScript Foundations I

Objective

Branch based on explicit rules and handle invalid input.

Variables are measured signals, functions are reusable circuit blocks, and control flow determines which path becomes active.

  • if, else if, else
  • truthy and falsy values
  • guard clauses

Why this matters

So far your programs run every line, top to bottom, every time. Today they start making decisions: do this if that, otherwise do something else. That is what makes a program respond to its input rather than repeat itself.

The specific job today is validation — checking a value before you compute with it. Yesterday you divided by a resistance. What happens if that resistance arrives as 0, or as the text "470", or not at all? By the end of the hour your code answers all three deliberately instead of producing a nonsense number.

The if statement

An if runs a block of code only when a condition is true.

const resistanceOhms = 470;

if (resistanceOhms > 1000) {
  console.log("High value");
}

Character by character: the keyword if, then a condition in parentheses, then a block in curly braces { }. The condition is any expression that produces a boolean — usually a comparison from Day 16. If it is true, the block runs. If not, JavaScript skips straight past the closing brace. Nothing prints above, because 470 is not greater than 1000.

else gives an alternative, and else if chains more conditions:

const toleranceBand = 5;

if (toleranceBand > 10) {
  console.log("big");
} else if (toleranceBand > 3) {
  console.log("medium");
} else {
  console.log("small");
}
medium

The chain is tested in order and stops at the first match. 5 > 10 is false, so it moves on; 5 > 3 is true, so medium prints and the rest of the chain — including else — is never considered. Order therefore changes behaviour: if you had put > 3 first, nothing would ever reach > 10.

A branch is a signal selector

An if/else if/else chain is a priority encoder: several inputs may be asserted, but exactly one output line goes active, and it is the highest-priority one that matched. The condition order is the priority order. Control flow decides which path in the circuit is live; nothing downstream of an unselected branch draws any current.

Truthy and falsy

JavaScript lets you put a non-boolean inside if ( ). It converts the value to true or false first. A value that converts to false is called falsy; everything else is truthy.

There are exactly six falsy values, and it is worth memorising the list:

false, 0, "" (empty string), null, undefined, NaN.

Everything else is truthy — including "0", "false", and -1.

console.log(Boolean(0), Boolean(""), Boolean(null));
console.log(Boolean(470), Boolean("0"), Boolean(-1));
false false false
true true true

NaN means Not a Number — the value you get from arithmetic that has no numeric answer, such as Number("abc"). Its type is confusingly number, so typeof alone will not catch it. Test for it with Number.isNaN(value).

`if (value)` is the wrong check for numbers

0 is falsy, so if (resistanceOhms) treats a genuine zero reading as "no value supplied". For numbers, always compare explicitly: if (resistanceOhms === 0), if (resistanceOhms > 0). Truthiness is convenient and it silently loses real data.

Combining conditions

Two operators join conditions:

  • || (OR) — true if either side is true.
  • && (AND) — true only if both sides are true.
  • ! (NOT) — flips a boolean.
const value = null;
console.log(value === undefined || value === null);
true

That line reads: "missing means it is either undefined or null."

Functions, just enough for today

Your deliverable is a function, so here is the minimum; tomorrow covers them properly.

function describe(value) {
  return `got ${value}`;
}

console.log(describe(470));
got 470

function declares one. describe is its name. value in the parentheses is a parameter — a name for whatever gets handed in when the function is called. The braces hold its body. return sends a value back to whoever called it and immediately stops the function. describe(470) is the call: it runs the body with value set to 470.

That "immediately stops" is what makes today's pattern work.

Guard clauses

A guard clause is an if at the top of a function that checks one precondition and returns early when it fails. The purpose is to exit before doing work that cannot be valid.

The alternative — nesting each success inside the previous check — drifts rightwards and gets hard to read:

// Harder to follow: the real work is buried
function check(value) {
  if (typeof value === "number") {
    if (value > 0) {
      return "valid";
    } else {
      return "not positive";
    }
  } else {
    return "not a number";
  }
}

Guards flatten it. Each failure is handled and dismissed, one per line, and the valid case is last with nothing left to worry about:

function check(value) {
  if (typeof value !== "number") return "not a number";
  if (value <= 0) return "not positive";
  return "valid";
}

The door checks before the fitting room

A shop checks your ticket at the door, not halfway through the fitting. Each guard is one checkpoint that turns you away immediately; whoever reaches the back of the shop has already passed everything.

Walkthrough

Create validate.js. Each guard produces a distinct message, so the output tells you which rule rejected the value.

function checkResistance(value) {
  if (value === undefined || value === null) {
    return "Missing: no resistance was provided.";
  }
  if (typeof value !== "number" || Number.isNaN(value)) {
    return "Invalid: resistance must be a number.";
  }
  if (value === 0) {
    return "Invalid: zero ohms is a short circuit.";
  }
  if (value < 0) {
    return "Invalid: resistance cannot be negative.";
  }
  return `Valid: ${value} ohms accepted.`;
}

console.log(checkResistance(undefined));
console.log(checkResistance(null));
console.log(checkResistance("470"));
console.log(checkResistance(0));
console.log(checkResistance(-10));
console.log(checkResistance(470));

Run node validate.js:

Missing: no resistance was provided.
Missing: no resistance was provided.
Invalid: resistance must be a number.
Invalid: zero ohms is a short circuit.
Invalid: resistance cannot be negative.
Valid: 470 ohms accepted.

Six calls, six outcomes, every branch proven to be reachable. Note the third: "470" looks like a resistance but is a string, and the type guard catches it before any division happens.

Checkpoint

Say what would happen if the zero check were moved below the negative check. (Nothing — they test different values, so both stay reachable. Now say what happens if you move the type guard to the bottom: "470" < 0 is false, so a string would reach the valid branch. Order matters when ranges overlap.)

Your turn

Deliverable: a function that rejects invalid values before calculation.

  1. In js-basics/, create validate.js and write checkResistance(value) from scratch — do not copy the walkthrough. Give each of the five cases its own message in your own words.
  2. Call it six times, covering: undefined, null, a string, 0, a negative, a valid number. Log each result. Confirm you get five different messages.
  3. Add a second function safeCurrent(volts, ohms). Guard first: return the string "Cannot compute: invalid resistance." if ohms is not a number, is zero, or is negative. Only after the guards, return volts / ohms.
  4. Call safeCurrent(9, 470) and safeCurrent(9, 0) and log both. The second must print your message, not Infinity.
  5. Add one guard on volts too, and prove it fires by calling safeCurrent("9", 470).
  6. Write a comment above the function listing the rules in the order they are checked.

Reviewer mode — after your six calls all pass

"Review my validation branches for unreachable cases and misleading messages." A useful review returns specific, actionable findings with evidence — the line, the input that reaches it, why it is wrong. If the reply is praise or a full rewrite, ask again for concrete defects. Confirm each finding by running the input yourself before you change anything.

Common pitfalls

  • Using = instead of ===. if (value = 0) assigns and then tests, so it is always falsy. Comparison is three characters.
  • Forgetting 0 is falsy. if (ohms) rejects a real zero. Compare explicitly.
  • One message for every failure. "Invalid input" tells you nothing at 2 a.m. One rule, one message.
  • Guards that can never fire. If an earlier condition already covers a later one, the later branch is dead code. Test every branch with a real input.

Verify it yourself

Open today's reference, MDN's Dynamic scripting with JavaScript, and find its section on making decisions in your code.

  1. MDN documents switch, an alternative to a long else if chain. When does it say switch suits the job better?
  2. Find MDN's list of falsy values. Does it match the six in this lesson exactly?

Write both answers as comments at the bottom of validate.js.

The hour

  1. 0–5 min Recall

    Without notes, state yesterday’s main idea and one unresolved question.

  2. 5–20 min Learn

    Read only the listed concept notes and official reference sections needed today.

  3. 20–48 min Build

    Validate resistor values and show distinct messages for missing, non-number, zero, negative, and valid input.

  4. 48–55 min Explain and verify

    Run the result, inspect evidence, and explain the data/control flow in your own words.

  5. 55–60 min Quiz and commit

    Complete the quiz, record one lesson, and commit the verified change when applicable.

What to hand in

Deliverable

A function that rejects invalid values before calculation.

Working with AI today

AI as skeptical reviewer

Provide existing work and ask for concrete defects, risks, missing tests, and unsupported assumptions—not praise.

Review my validation branches for unreachable cases and misleading messages.

References

End-of-day quiz

Q1 What is a guard clause used for?
Q2 Which result best proves today’s work is complete?
Q3 What should an AI code review primarily produce?

Explain-back gate

Pass the quiz above to unlock completion.

Quiz + explain-back checks required.