×
By the end of this chapter, you should be able to:
An error is a problem in your code that may or may not stop the code from running. An error in a JavaScript program occurs for one of two main reasons: either the code that is written is not valid JavaScript code, or the code is valid, but it is trying to do something that is not allowed. In the next sections we will talk about some common examples.
All errors in JavaScript are actually objects
that are created by a function called Error
. You can read more about it here. As MDN says, "error objects are thrown when runtime errors occur. The Error object can also be used as a base object for user-defined exceptions."
So what does this mean? A runtime error is an error that occurs when code is executed. For example, if you hop into the Chrome console and write some invalid JavaScript (e.g. let 8 = 9;
), you won't actually see any errors show up until you try to run the code.
JavaScript has many built-in errors, which we'll talk about in just a moment. But you can also create and throw your own errors in applications that you write (this is what is meant by a "user-defined exception").
Let's look at four common errors we encounter when writing JavaScript. You have probably seen quite a few of these before!
SyntaxError
- occurs when we make a mistake with our syntax:let x = "hello"; let wrongObj = { name: "foo" missingComma: true };
ReferenceError
- occurs when we try to access a variable that does not exist in that scope. In the example below, we will try to access a variable called amazing
which has not yet been initialized. We will then try to access a variable called secret
outside of its scope. Let's see what that looks like:amazing; // ReferenceError - does not exist in the global scope function defineSomething(){ let secret = "I'll never tell"; } defineSomething(); secret; // ReferenceError - only exists in the scope of the defineSomething function
TypeError
- occurs when you make incorrect use of certain types in javascript. That could mean trying to invoke something that is not a function, or accessing properties on undefined. Here are some very common examples (many of them we guarantee you will make!)undefined(); // TypeError - undefined is NOT a function! let obj = { name: "Elie" }; obj.something; // this actually returns undefined! What does that tell us? If you try to access a property on an object and it does not exist, you do NOT get a ReferenceError, you just get undefined obj.something.foo; // but when you try to access a property on `undefined`... well, that's a TypeError. obj.something(); this is a TypeError for the same reason that undefined() is, since obj.something is undefined!
RangeError
- occurs when we have a function that calls itself (also known as a recursive function). If we have too many functions that have been called (before they are returned) we run out of memory and cause a RangeError.function callMe(){ callMe(); } callMe(); // maximum call stack size exceeded. We will talk more about the call stack and recursion in a later section.
Recursion is a more advanced concept that we won't touch on much in this course. It's good to know about this error, but if you're not writing recursive functions it's much less likely that you'll encounter it.
When an error is thrown, our code stops executing. Sometimes we don't know if our code is going to throw an error or not, so instead of our code crashing and not continuing to run, we might want to gracefully handle our errors. We call this "catching" our errors. To do this we use a try / catch
statement. We place code inside of the try
block (a block is defined as code inside of a {}
) and if an error is thrown, the code moves to the catch
block. After the catch block, code continues to execute.
try { thisDoesNotExist; } catch(e) { console.log("The error is ", e); }
On the other hand, when developing applications or libraries, we sometimes want to throw an error when something is done incorrectly in our application. To return an error and stop code execution, we use the throw
keyword followed by an error object. Optionally, we can add a message string to the error to give more details about what went wrong.
throw ReferenceError("That variable does not exist!");
Another way to specify an error is to use the throw
keyword followed by a string:
throw "This will also be an error";
Let's write a small example to see what it would be like using throw
, try
, and catch
. In this example, all we are doing is generating a random number between 0 and 1. If that number is >= 0.5, we create an error and so we move to the catch
. However, our code continues to run even if an error happens.
try { if(Math.random() >= .5) { throw "Let's make an error!"; } console.log("Whew...we made it."); console.log("We can only get here if the random number is less than .5."); } catch(e){ console.log("The error is ", e); console.log("We can only get here if an error was thrown. (Random number is greater than .5)."); } console.log("Moving on.....");
finally
With our try/catch
block, we saw that the code in the try
block will move to the catch block if an error occurs inside of it. In our try/catch
statements, we can add one more special keyword called finally
. Inside of the finally
block, code will execute regardless of an error being thrown.
try { // let's randomly try to throw an error if(Math.random() >= .5){ // The following code will throw: // Uncaught TypeError: undefined is not a function(…) undefined(); } console.log("Whew, we made it"); } catch(e){ console.log("We didn't make it. The error message is", e.message); } finally { console.log("No matter what we will see this statement"); }
When you're ready, move on to Debugging with the Sources Tab