JavaScript Error Handling, null, and undefined for Beginners

Navigate JavaScript Error Handling, null, and undefined: Essential tips for beginners to write more reliable and bug-free code.

avatar
InstructorZach Gollwitzer
Last UpdatedMarch 29, 2024
Estimated Read Time7 minutes

JavaScript Error types

I know, the rest of this lesson looks rather boring, but if you've made it this far, please stick around because understanding error types, NaN, null, and undefined values is super important!

A JavaScript error happens when you try to execute JavaScript code that is either invalid or is incapable of handling the values you have given to it.

In JavaScript, there are several different types of errors, but they all "inherit" (this is an object oriented programming term) from the Error object, which you can see the documentation for here.

While there are more than just three types, these three are the most common ones that you will see and need a high-level understanding of.

  • ReferenceError
  • SyntaxError
  • TypeError

JavaScript ReferenceError

Official docs

When you try to "reference", or "use" a value that doesn't exist, you'll get this error. Here's the simplest example:

const myVariable = 20;

console.log(anotherVariable); // ReferenceError

JavaScript tries to find a "reference" to anotherVariable in memory, but since we never declared it, it simply doesn't exist!

JavaScript SyntaxError

Official docs

When we talk about "syntax", we are talking about how we write our code. If you write invalid JavaScript code, the compiler won't know what to do and will throw a SyntaxError. This one is pretty easy to explain–just write some invalid JavaScript code! See if you can figure out what is wrong below.

const myObj = {
  prop1: 'some value';
  prop2: 'another value';
};

If you try to run this code, you're going to get a SyntaxError that says Unexpected token ';'. That is because instead of ;, you need , in your objects. Here is the correct way:

const myObj = {
  prop1: "some value",
  prop2: "another value",
};

JavaScript TypeError

Official docs

This is probably the hardest of the three to understand. It occurs when you try to perform an operation that cannot be done on a specific type of data. If you try to pass an incompatible argument into a function, attempt to modify an immutable value, or just use a value inappropriately, you will get this error.

It is confusing because there are many cases that seem like they would throw a TypeError, but don't. Consider this:

const myObj1 = { prop1: 20 };
const myObj2 = { prop1: 50 };

// Does not throw an error
const result = myObj1 + myObj2; // "[object Object][object Object]"

You can't add two objects right?? No, you can't, but it won't throw an error at you if you try. It will just combine the two objects together in a string. Logically speaking, this seems like a TypeError to me. But here are a few examples that actually do throw this error.

const myNumber = 50;
const myObject = {
  prop1: "some value",
};

myNumber.toUpperCase(); // TypeError: num.toUpperCase is not a function
myObject.prop1(); // TypeError: myObject.prop1 is not a function

In the first case, we are trying to use a String method on a number. In the second case, we are trying to invoke a function when we are really dealing with a String.

What is "Error Handling"

The last thing that I want to cover with errors is something very important, but lost on a lot of beginners (including myself years ago).

What is the point of "handling" errors, and what does that even mean?

Well let me paint a picture for you. Let's say that you built an application similar to Instagram and one of your users loses internet connectivity while posting a picture. Clearly, the code that allows the user to post that picture is not going to work because the user doesn't have internet access.

If we handle the error in our code, we can print something on the screen that says, "You are not connected to the internet. Please connect and try again".

If we DO NOT handle the error in our code, our app is going to crash and the user is going to have no idea what happened.

So the next question is... What errors are we trying to handle?

And this is where it is difficult for beginners to understand error handling. In most cases, the errors that we want to handle are ones caused by external code that we have no control over. We will cover this in depth when we get there later in the series, but for now, I'll just show you how to handle errors.

try {
  const num = 20;
  num.toUpperCase();
} catch (err) {
  // If the code in the try {} block throws an error,
  // we will reach this code block and `err` will represent the Error object
}

Of course the code above is useless and we would never write something like this, but it demonstrates the try/catch syntax that we can use for error handling in JavaScript.

Since we put num.toUpperCase() (which throws a TypeError) in the "try" block, our code runs just fine without being interrupted. We could even print some details about this error.

try {
  const num = 20;
  num.toUpperCase();
} catch (err) {
  console.log(err instanceof TypeError); // true
  console.log(err.message); // num.toUpperCase is not a function
}

As I mentioned, we will be revisiting error handling throughout this series, so consider this your brief introduction.

NaN, null, undefined in JavaScript

I'm going to keep this final section short and sweet. There are three "data types" that we have not spent much time on, and those are NaN, null, and undefined.

NaN - "Not a Number"

You will rarely see this or use this, but you should know what it is.

From the documentation, here are the most common scenarios that will return NaN.

const myString = "some string";

// 1. Trying to coerce a string to a number
Number(myString); // NaN

// 2. Performing an impossible math operation
Math.sqrt(-1); // NaN

// 3. Operand of an argument is NaN
Number(myString) + 20;

// 4. Trying to use an arithmetic operator (other than + ) on a string
myString * 2;

Like I said, you won't see or use this much.

null

Unlike NaN, you'll encounter null values all the time! A null value is a JavaScript primitive value (remember from earlier in this post?) and represents the intentional absence of a value. In other words, you can think of it like a "placeholder" value that must be set by the developer.

When using null in an operation, it behaves as a "falsey" value. See below.

let myVariable = null;

if (myVariable) {
  console.log("this line will not print");
} else {
  console.log("this line will print");
}

Here is the official documentation for null values.

undefined

Very similar to null, undefined is a primitive value that represents the absence of a value.

You will get an undefined value when you try to use a variable that exists, but is not defined yet (and has not been assigned a null value).

let myString;
const myObj = {};

console.log(myString); // undefined
console.log(myObj.someFunction); // undefined

myObj.someFunction(); // TypeError

Since we didn't intentionally initialize myString as a null value, it carries an undefined value.

The myObj example is a bit trickier. You might infer that because myObj does not yet have a someFunction property, it would throw an error. Instead, all object properties that have not been assigned carry a value of undefined. In the example, when we try to invoke this function, we get a TypeError because you cannot "invoke" and undefined value.

Like null, the undefined primitive is treated as a "falsey" value when used in a conditional.

let myVar;

if (myVar) {
  console.log("this line will not print");
} else {
  console.log("this line will print");
}

10 JavaScript Challenges

I have chosen 15 challenges for this lesson that will require you to apply the basics of the topics we covered here combined with the knowledge you acquired through prior lessons.

To get the most out of these challenges, I recommend watching my YouTube video where I solve all of them with you. I walk you through my thought process and hopefully fill in some gaps from these lessons.

Here are the challenges and solutions.