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:
A variable being uninitialized
An identifier being misnamed
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
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>
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
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;
}
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
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();
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.