Exceptions are one of the few examples of the successful use of inheritance. In this lesson, we'll learn how to create our own exceptions and intercept them.
Usually exceptions are used like this. Closer to the beginning of the program is the try/catch construct, which catches exceptions and shows the user an adequate message:
try {
doSomethingDangerous();
} catch (e) {
console.log(e);
}
But how do you know what's wrong? Sometimes, it's important. Different errors can lead to different program behavior. In addition, not all errors require processing at the current point in the program.
You can separate errors using different classes that inherit from the Error class.
// This method works only if Babel isn't used
class MyError extends Error {}
class AnotherError extends MyError {}
And unlike other examples of inheritance, exceptions rarely need to add or change behavior. The main purpose of using exception inheritance is to describe all possible types of errors.
Now let's see how we can take advantage of it:
try {
// Some code that might throw an exception
} catch (e) {
if (e instanceof MyError)
// Doing something
else if (e instanceof SomeError) {
// Doing something else
}
// In all other cases, we do something like throwing an exception again
throw e;
}
Hijacking any base exception automatically entails hijacking all descendants of the current class. For example, if you catch MyError in a catch block, that block will catch objects of that class and objects of all its descendants.
Almost every programming language has an unspoken rule about how to handle exception hierarchies. Any program must define its own high-level exception, which is inherited from Error. All other library exceptions are inherited from it. This approach allows you to isolate the error handling of a particular library with just one catch block.
But not all libraries in JavaScript use inheritance. The point is that before the es6 standard, there were no classes and no easy way to create “descendants” from the Error constructor. And, since many libraries are still implemented in the old standard, they solve the problem of determining the error type using a common property:
import axios from 'axios';
try {
client.get('https://hexlet.io');
} catch (e) {
if (e.isAxiosError) {
// All axios library errors will go here
}
// processing other errors
}
In some situations, the program may need to continue working regardless of whether an exception has occurred or not. If we only use try/catch, we can't do this without duplication. You have to put code both after the whole try/catch construct and in every catch block.
This has led to an expansion of the design itself, adding the finally block. This block is called at the very end in every case.
try {
// Some code
} catch (e) {
// Doing something
} finally {
// Called in any case
}
The Hexlet support team or other students will answer you.
A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.
Programming courses for beginners and experienced developers. Start training for free
Our graduates work in companies:
From a novice to a developer. Get a job or your money back!
Sign up or sign in
Ask questions if you want to discuss a theory or an exercise. Hexlet Support Team and experienced community members can help find answers and solve a problem.