JavaScript Reference Errors and How to Prevent Them

published on 26 May 2022

When programming in JavaScript, you’ll commonly encounter reference errors. There are a number of reasons why you might get one, but fortunately, resolving such an error isn’t too difficult. It’s helpful to know what this error is and why it’s being thrown by the compiler because you’ll save yourself precious debugging time.

In this guide to JavaScript reference errors, you’ll learn how to identify and solve them as well as how to avoid this type of error in the future.

What Is a Reference Error?

In JavaScript, when you create or declare a variable, what you are doing is simply creating a reference to an object with an associated value. Here’s an example:

     const a = "Apple" 

The previous code tells the JavaScript compiler that whenever it sees the variable a, it should interpret it as its value—meaning, it should see a as the string with the value of Apple. When JavaScript encounters a variable that doesn’t have a declaration, though, it doesn’t know what to do, so it throws a reference error.

In essence, a reference error occurs when JavaScript tries to access a variable that doesn’t exist, hasn’t been defined, or doesn’t exist in the current scope from which you are trying to access it.

Why You Need to Understand Reference Errors

It’s important that you understand why JavaScript might throw such an error, especially for the following reasons:

- If you understand what’s going on and why, the error is easier and quicker to fix.

- It is possible to catch this type of error at build time if your code is properly structured.

- If you spend less time trying to understand why the error occurred, you can spend more time on programming, which improves your workflow.

Types of Reference Errors

There are a number of different types of reference errors, which can be triggered in different ways. The MDN JavaScript documentation specifies six different types of reference errors that can be triggered within your code, but this guide will focus on the four most important types.

Undeclared or Undefined Variable

When a variable reference cannot be found or is not declared, it causes a reference error. New developers are most likely to commit reference errors by forgetting to define variables before referencing them. Here’s an example:

    console.log(a)
    // ReferenceError a is not defined.

Similarly, declared variables that have been commented out may also cause reference errors when used, like this example:

  // const a = "apple"
     console.log(a)
  // ReferenceError a is not defined.

The solution to this reference error is to ensure that your variables are always declared before using them, as in the following example:

    let a = 'apple'
    console.log(a)
    // apple

Wrong Scope

In order for a variable to be available during execution, it must be present in the scope of that execution context—meaning, the variable has to be in the same scope or in a parent scope to be accessible by JavaScript. For example, variables defined inside a function are only accessible inside the function and cannot be accessed outside of it, as shown subsequently:

    function inScope() {
      let a = "apple";
    }
    console.log(a); 
    // ReferenceError a is not defined.

To avoid this type of reference error, make sure that the scope from which you’re trying to access a variable is the scope in which the variable exists:

    function inScope() {
      let a = "apple";
      console.log(a); 
    }
    inScope()
    // apple

Additionally, note that the let and const keywords are both block level scoped, while the var keyword is instead globally scoped when used outside a function and function scoped when used inside a function. This can cause certain reference errors when these keywords are used incorrectly.

Strict Mode (Silent Errors)

When you assign a value to a variable, JavaScript requires that the variable be declared using var, let, or const. If you use JavaScript in its default mode (without strict mode), declaring a variable without these keywords will result in a silent error—meaning, JavaScript will ignore it even though it is an error. Here’s an example:

    a = 'apple'
    console.log(a)
    // apple,

In strict mode, though, JavaScript will catch this error and throw a reference error:

    "use strict";
    a = "apple";
    console.log(a);
    // ReferenceError: a is not defined

To avoid silent errors, always use JavaScript in strict mode so as not to miss similar errors that are typically ignored in JavaScript’s default (or sloppy) mode.

Accessing of a Variable Before Its Declaration

Another way of triggering a reference error is by trying to access a variable declared with let or const before its actual declaration. This will throw a reference error because the variable hasn’t yet been initialized or read by JavaScript, as shown in the following code:

    console.log(a);
    let a = "apple";
    // ReferenceError: Cannot access 'a' before initialization

As you may have guessed, the solution is to ensure that a variable is always declared first before using so that JavaScript has access to it:

    let a = "apple";
    console.log(a);
    // apple

How to Fix Reference Errors

You have several options for addressing reference errors, including the following:

- Code editors and IDEs with syntax highlighting might be able to display such issues.

- Certain tools, such as ESLint, can detect specific patterns and enforce them.

- TypeScript can identify reference errors when the code compiles and provide recommendations on how to fix them.

- Static analysis can catch this type of error in your continuous improvement (CI) pipeline before your code is released to production.

How to Prevent Reference Errors

There are several best practices to follow to keep reference errors out of your projects:

- Use extensions that aid with IntelliSense or code completion, such as auto-suggestions, code hinting, and query hints.

- Use strict mode in JavaScript so that you won’t miss silent errors in sloppy mode.

- Avoid using the var keyword when declaring variables and, instead, use let or const.

- Make sure that variables are always declared before calling them.

How Meticulous Can Help

Errors and bugs can still sneak through even the most diligently written code. To prevent disruption to your application, you need tools and techniques to identify and prevent these errors before they hit production.

One tool to use is Meticulous, which is a tool to create frontend tests without writing code. Use the Meticulous CLI to record a user session and test a pull request or code change by replaying that user session on the old code and new code. Meticulous captures a screenshot at the end of each replay, and diffs the two to create a simple test. Meticulous records network calls at record-time and automatically mocks out all network calls at replay-time, meaning you don’t need a backend environment to replay against. You can also switch this network mocking off if you wish to hit a backend environment. 

You can integrate Meticulous tests into any CI system, or use our example on integrating Meticulous with GitHub. Read more at our docs at docs.meticulous.ai

Conclusion

Reference errors can slow down your JavaScript workflow, especially if you’re not aware of what those errors are or how to solve them. Fortunately, there are simple solutions to these errors, but the best strategy is to be aware of what triggers them so that you can avoid making these errors in your code.

Since mistakes still happen sometimes, you can take additional precautionary measures by choosing a code editor or IDE with intelligent highlighting and support, implementing ESLint to enforce specific patterns, using TypeScript for type checking, or using an automated error handling tool, like Meticulous. The more proactive you are about handling errors, the more you can optimize your team’s productivity.

Authored by David Herbert

Read more