# Module 6 : Errors, exceptions, debugging, and troubleshooting

After completing Module 6, the student will:

* gain an understanding of the differences between syntactic, semantic, and logical errors;
    
* understand the concept of an exception and distinguish between the basic exceptions generated by JS when an error occurs: SyntaxError, ReferenceError, TypeError, RangeError;
    
* have the ability to handle exceptions using the try-catch-final statement;
    
* be able to generate their own exceptions using the throw statement;
    
* have the skills to use the debugger for basic analysis of their own code, including: step-by-step execution, viewing and modifying variables, measuring code execution time.
    

There are syntax errors, semantic errors (reference errors), and logical errors.

# Errors without exceptions?

In JavaScript, not all erroneous situations throw exceptions. Many of them are handled in a slightly different way. The best example is *arithmetic errors*.

```javascript
console.log(100 / 0); // -> Infinity
console.log(100 * "2"); // -> 200
console.log(100 * "abc"); // -> NaN
console.log(Math.pow("abc", "def")); // -> NaN
```

An attempt to perform an arithmetic operation on a string that does not represent a number (i.e. that cannot be converted) will result in `NaN` (not a number). At least two of these cases are clearly wrong (the first and the third), but instead of exceptions, the information about the error is the specific value that is returned.

The conclusion is quite simple – if you are learning about a new function or operator, you have to check in the documentation (e.g. on the MDN page) ***how they behave in the case of errors. Some of them will generate exceptions, while others will return some specific values.*** Depending on that, you will be able to properly prepare yourself for handling errors using the try method or simple conditional instructions. By the way, for the examples just shown, the most sensible solution would be to check if the provided values really are numbers (remember the `typeof` operator?)

## we cannot assume that the user will provide data in the format we require

it is our responsibility to anticipate potentially dangerous situations.

```javascript
let sX = prompt("Enter the first number");
let sY = prompt("Enter the second number");
let x = Number(sX);
let y = Number(sY);
if (Number.isFinite(x) && Number.isFinite(y) && y !== 0) {
    console.log(x / y);
} else {
    console.log("incorrect arguments");
}
```

We use the `Number.isFinite` method for this purpose. It returns `true` if the argument is a correct number, and `false` if it is, for example `Infinity` or `NaN`.

# Basic types of errors

## **1\. SyntaxError**

As we previously said, a `SyntaxError` appears when a code is ill-formed, when there are typos in the keywords, unmatching parentheses or brackets, etc. The code can’t even be executed, as JavaScript isn’t able to understand it.

```javascript
"use strict";
iff (true) { //-> Uncaught SyntaxError: Unexpected token '{'
    console.log("true");
}
```

In the example above, we’ve made a typo in the keyword `if`, adding an additional letter f. The JavaScript engine treats the unknown name as a function call (it finds the round brackets after iff) and is surprised by the presence of a curly bracket.

# **2\. ReferenceError**

It occurs when we try to access a function or a variable that doesn't exist.

```javascript
let a = b; // -> Uncaught ReferenceError: b is not defined
fun(); / -> Uncaught ReferenceError: fun is not defined
```

# **3\. TypeError**

you try to perform an operation on it that is not acceptable.

```javascript
const someConstValue = 5;
someConstValue = 7; // -> Uncaught TypeError: Assignment to constant variable.

let someNumber = 10;
someNumber.length(); // -> Uncaught TypeError: someNumber.length is not a function
```

# **The throw statement and custom errors**

To throw an exception, we use the throw instruction. It is followed by any value that will be treated as an exception. It can be, for example, a number, or one of the ready-made error objects (e.g. `RangeError`).

```javascript
console.log("start"); // -> start
try {
    throw 100;
} catch (error) {
    console.log(error); // -> 100
}
console.log("end"); // -> end
```

```javascript
Function factorial(n) {
    if (n > 20) {
        throw new RangeError("Max value 20");
    }
    let result = 1;
    for (; n > 1; n--) {
        result = result * n;
    }
    return result;
}

console.log(factorial(20)); // -> 2432902008176640000
console.log(factorial(1000)); // -> Uncaught RangeError: Max value 20
```

# Debugging - Hands on

Add `debugger;` in-between JavaScript code.

Open developer tools. Click on the number 15. This is how we set the breakpoint (the line will be highlighted). Click on the line number again if you want to remove the breakpoint (do not delete it yet).

```javascript
console.log("Before debugger");
debugger;
console.log("After debugger");
```

To be honest, when debugging code, we rarely use the debugger statement. Most often, at the place where the program should stop, we just indicate it using breakpoints set directly in the Developer Tools.

# **Call stack**

If you click on the name of the outer function on the Call Stack, you will be taken to the context of that function (note that the selection of the current line has changed). Try calling the same command again in the console:

```javascript
console.log(name); // -> outer
```

## **Watch** (or Watch expressions)

we can enter the name of the variable whose value changes we want to track. It allows us to view and modify the variables without using the console.
