Guard clauses in JavaScript

When using event delegation, you need to make sure the element that fired the event is the one you wanted. This commonly involves wrapping your event handler within a conditional statement. Guard clauses are a way to make this process much cleaner.

Given the following HTML, imagine that when one of the three paragraphs is clicked, I want to log its textContent to the console:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Example</title>
  </head>
  <body>
    <header>
      <h1>Example</h1>
    </header>
    <main>
      <p>This is a paragraph.</p>
      <p>This is another paragraph.</p>
      <p>This is yet another paragraph.</p>
    </main>
    <footer>
      <p>
        <small>Copyright &copy; Example</small>
      </p>
    </footer>
  </body>
</html>

Nested conditional statement

We could do something like the following. Notice that the code inside the logText() function is wrapped within a conditional statement:

// Get the main element
var main = document.querySelector("main");

/**
 * Log a paragraph's textContent
 * @param {Object} event The Event object
 */
function logText (event) {

  // Log the paragraph's textContent
  if (event.target.tagName === "P") {
    console.log(event.target.textContent);
  }

}

// Log paragraphs' textContent on click
main.addEventListener("click", logText);

For a simple function like this, it’s perfectly readable. But when you have a lot of code inside the conditional statement, the extra indentation is a bit annoying to deal with.

Guard clause

Instead, we can use a guard clause. If the event.target is NOT a paragraph, we can just quit the function and do nothing else:

/**
 * Log a paragraph's textContent
 * @param {Object} event The Event object
 */
function logText (event) {

  // If not a paragraph, do nothing
  if (event.target.tagName !== "P") return;

  // Log the paragraph's textContent
  console.log(event.target.textContent);

}

My friend and mentor, Chris Ferdinandi, first taught me this. I believe he first learned it from Todd Motto.

It works because the return statement immediately ceases execution of the function. Anything that comes after the return statement will not run. We’re not explicitly returning a value, so the function just returns undefined. You could return a value if you needed to, though.

I like to put the return statement on one line. If you prefer, you can still use curly braces {} like you normally would:

// If not a paragraph, do nothing
if (event.target.tagName !== "P") {
  return;
}

If you have questions, feedback, or any other suggestions, please do email me. I'd love to hear from you!