Understanding Error Messages in JavaScript

Introduction

When I began coding, error messages used to induce fear in me. I was afraid that each message was informing me of a convoluted problem; moreover, I was afraid that I couldn't resolve these problems. Where would I even begin?

I eventually calmed down and let my eyes guide me towards a natural starting point: An error message. This observation was enlightening for me. I began shifting my view of error messages as sources of cryptic information to sources of invaluable information. Error messages, in other words, existed to aide me in the process of problem solving.

In this context, I want to share my understanding of error messages. This blog post will describe only two types of errors--TypeError and ReferenceError--and their corresponding messages. I hope, even with this brief introduction to error messages, that my post will encourage readers to embrace them.

Let's begin this process of discovery through an analysis of one of the most common words used in these error messages: undefined.

An error message with undefined

Error messages containing the word undefined usually reference one of three occurrences:

  1. A variable being uninitialized

  2. An identifier being misnamed

  3. A data type being incorrectly assigned

Let's explore each occurrence with code examples. Try to notice a pattern between an error message and a corresponding code example.


A variable is uninitialized

1. Uncaught ReferenceError: _ is not defined

This error message is informing us that _ is not defined. In this instance, _ represents the library for Underscore.js. If we glance at our script tags (below), we will notice app.js is loaded prior to underscore.js.

<script type="text/javascript" src="app.js"></script>  
<script type="text/javascript" src="underscore.js"></script>  

The solution is to reverse the order of our script tags and load our dependency first. This change in load order will define _ prior to its use in app.js.

<script type="text/javascript" src="underscore.js"></script>  
<script type="text/javascript" src="app.js"></script>  


2. ReferenceError: myVar is not defined

This error message is informing us that myVar is not defined. When we look at the code below, we will notice that myVar appears only once when we are invoking isDefined. The problem is that we never declared myVar with the keyword var, which then considers myVar as a pointer.

function isDefined(value) {  
  if (!value) {
    throw new Error("You passed an undefined value");
  } 

  return "This is the value you passed" + value;
}

isDefined(myVar);  

The solution is to define (i.e., declare) myVar with the keyword var. Since we are declaring but uninitializing myVar, its initialized to a value of undefined.

var myVar;

function isDefined(value) {  
  if (!value) {
    throw new Error("You passed an undefined value");
  } 

  return "This is the value you passed" + value;
}

isDefined(myVar);  

An identifier is misnamed

1. ReferenceError: integer is not defined

This error message is informing us that a variable named integer is not defined. In this instance, we simply need to find the first instance we use the variable integer and follow the flow of the code in reverse order. We stop searching our code when we find a declaration for integer. The problem is that we never declared integer, but we did declare a local variable named integer1!

function addIntegers(integer1, integer2) {  
  return integer + integer2; 
}

The solution is to rename our local variable integer to integer1, which is defined.

function addIntegers(integer1, integer2) {  
  return integer1 + integer2; 
}


2. ReferenceError: person is not defined

This error message is informing us that a variable named person is not defined. In this instance, we made a simply typographic error: We defined Person but not person.

var Person = {};  
person.name = "Cho";  

The solution is to rename our local variable Person to person. We can also rename both to Person, but that's a bad design choice because the capitalized 'P' would imply we are dealing with a constructor.

var person = {};  
person.name = "Cho";  

A data type is incorrect

1. TypeError: string is not a function

This error message is informing us that a data type of string is not a function. The problem is that a string cannot be invoked as a function.

var sayName = "Cho S. Kim";

sayName();  

The solution is to search for every invocation of a function in our code. In this example, sayName is the string being invoked as a function. Wrap sayName in a function and return sayName's value in the function.

var sayName = function() {  
  return "Cho S. Kim";
};

sayName();  


2. TypeError: undefined is not a function

This error message is informing us that an undefined data type is being invoked as a function. In this example, we will notice that startEngine is a function, but it's invoked before it has been defined.

startEngine();

var startEngine = function() {  
  return "Brmmmmm";
};

The solution is to declare startEngine prior to invocation. This is one of many solutions; however, I prefer it. Declaring code prior to its use is always a good practice.

var startEngine = function() {  
  return "Brmmmmm";
};

startEngine();  

Conclusion

Error messages can be cryptic and frightening. If you feel this way, remind yourself that error messages exist to help us debug our code. They give us a natural starting point in the debugging process. This observation led me to a breakthrough in the way I approached errors; actually reading error messages led me towards becoming a better developer.