Sometimes your JavaScript code doesn't run as expected, resulting in errors. There can be various reasons for these errors, such as:
These errors, occurring while the script is running, are known as runtime errors. A well-designed application should handle such errors gracefully by providing clear and informative messages to the user.
JavaScript provides the try-catch
statement to catch and handle runtime errors gracefully:
Place the code that may cause an error inside the try
block. If an error occurs, code execution jumps to the catch
block, where you can handle the error appropriately:
If no error occurs in the try
block, the catch
block is skipped, and the program continues executing after the try-catch
statement.
Here's an example to demonstrate how the try-catch
statement works:
try {
var greet = "Hi, there!";
document.write(greet);
// Trying to access a non-existent variable
document.write(welcome);
// If error occurred following line won't execute
alert("All statements are executed successfully.");
} catch(error) {
// Handle the error
alert("Caught error: " + error.message);
}
// Continue execution
document.write("<p>Hello World!</p>");
The script above will display the error in an alert dialog box instead of printing it to the browser console. Additionally, the program continues executing despite the occurrence of an error.
It's important to note that the catch
keyword is followed by an identifier in parentheses. This identifier acts like a function parameter. When an error occurs, the JavaScript interpreter creates an object containing details about the error. This error object is then passed as an argument to catch
for handling.
Tip: Using the try-catch
statement in JavaScript helps manage exceptions, which are signals indicating unexpected conditions or errors during program execution. The terms "exception" and "error" are often used interchangeably.
The try-catch
statement in JavaScript can include a finally
clause. Code inside the finally
block executes regardless of whether an error occurs in the preceding try
block or not.
Here's an example that always shows the total time taken to complete the execution:
// Assigning the value returned by the prompt dialog box to a variable
var num = prompt("Enter a positive integer between 0 to 100");
// Storing the time when execution start
var start = Date.now();
try {
if(num > 0 && num <= 100) {
alert(Math.pow(num, num)); // the base to the exponent power
} else {
throw new Error("An invalid value is entered!");
}
} catch(e) {
alert(e.message);
} finally {
// Displaying the time taken to execute the code
alert("Execution took: " + (Date.now() - start) + "ms");
}
Previously, we've seen errors that are automatically raised by the JavaScript parser when an issue occurs. However, you can also intentionally throw an error using the throw
statement.
The syntax for the throw
statement is straightforward: throw expression;
The expression
can be an object or any value of any data type. It's advisable to use objects, particularly those with name
and message
properties. The JavaScript built-in Error()
constructor provides a convenient way to create such error objects. Here are a few examples:
throw 123;
throw "Missing values!";
throw true;
throw { name: "InvalidParameter", message: "Parameter is not a number!" };
throw new Error("Something went wrong!");
Note: When using JavaScript's built-in error constructor functions (e.g., Error()
, TypeError()
, etc.) to create error objects, the name
property corresponds to the name of the constructor, and the message
property equals the argument passed to the constructor function.
We're about to define a function called squareRoot()
to calculate the square root of a number. Normally, you'd use JavaScript's built-in Math.sqrt()
function for this purpose. However, a drawback is that it returns NaN
(Not a Number) for negative numbers, without clarifying what went wrong.
To address this issue, we'll implement a solution where a custom error is thrown if a negative number is provided.
function squareRoot(number) {
// Throw error if number is negative
if(number < 0) {
throw new Error("Sorry, can't calculate square root of a negative number.");
} else {
return Math.sqrt(number);
}
}
try {
squareRoot(16);
squareRoot(625);
squareRoot(-9);
squareRoot(100);
// If error is thrown following line won't execute
alert("All calculations are performed successfully.");
} catch(e) {
// Handle the error
alert(e.message);
}
Tip: Theoretically, the square root of negative numbers can be computed using imaginary numbers, where i
is defined as i2 = -1
. For example, the square root of -4
would be 2i
, and 3i
for -9
. However, JavaScript does not support imaginary numbers.
The Error
object serves as the foundational type for all errors in JavaScript. It includes two primary properties: name
, which specifies the type of error, and message
, which provides a detailed description of the error.
JavaScript programs can encounter various types of errors during execution. Common ones include RangeError
, ReferenceError
, SyntaxError
, TypeError
, and URIError
.
The next section provides an in-depth explanation of each of these error types:
A RangeError
occurs when a number is used outside the permissible range of values. For instance, attempting to create an array with a negative length will trigger a RangeError
.
var num = 12.735;
num.toFixed(200); // throws a range error (allowable range from 0 to 100)
var array = new Array(-1); // throws a range error
A ReferenceError
usually happens when attempting to access a variable or object that hasn't been defined or doesn't exist. Below is an example illustrating when a ReferenceError
occurs.
var firstName = "Harry";
console.log(firstname); // throws a reference error (variable names are case-sensitive)
undefinedObj.getValues(); // throws a reference error
nonexistentArray.length; // throws a reference error
A SyntaxError
occurs during runtime when there's a syntax issue in your JavaScript code. This could happen if a closing bracket is missing, loops are incorrectly structured, or similar problems arise.
var array = ["a", "b", "c"];
document.write(array.slice(2); // throws a syntax error (missing bracket)
alert("Hello World!'); // throws a syntax error (quote mismatch)
A TypeError
is triggered when a value does not match the expected type. This can occur when attempting to use a string method on a number, invoking an array method on a string, or similar mismatches.
var num = 123;
num.toLowerCase(); /* throws a type error (since toLowerCase() is a string method, a number can't be converted to lowercase) */
var greet = "Hello World!"
greet.join() // throws a type error (since join() is an array method)
A URIError
occurs when an invalid Uniform Resource Identifier (URI) is provided to URI-related functions like encodeURI()
or decodeURI()
. This error is thrown to indicate issues with URI handling in JavaScript.
var a = "%E6%A2%B";
decodeURI(a); // throws a URI error
var b = "\uD800";
encodeURI(b); // throws a URI error
Note: Another error type, EvalError
, was historically thrown when an error occurred during code execution using the eval()
function. However, JavaScript no longer throws this error, though the object remains for backward compatibility purposes.
The specific error types can also be manually thrown using their respective constructors and the throw
statement. For instance, to throw a TypeError
, you can utilize the TypeError()
constructor as shown:
var num = prompt("Please enter a number");
try {
if(num != "" && num !== null && isFinite(+num)) {
alert(Math.exp(num));
} else {
throw new TypeError("You have not entered a number.");
}
} catch(e) {
alert(e.name);
alert(e.message);
alert(e.stack); // non-standard property
}
The Error
object also includes some non-standard properties. One commonly used property is stack
, which provides a stack trace for the error. It's useful for debugging but should not be used on production websites.