Logo

dev-resources.site

for different kinds of informations.

Harnessing the Power of Error Objects in JavaScript

Published at
3/22/2023
Categories
javascript
errors
exceptions
Author
90_10_dev
Categories
3 categories in total
javascript
open
errors
open
exceptions
open
Author
9 person written this
90_10_dev
open
Harnessing the Power of Error Objects in JavaScript

Photo by Sarah Kilian on Unsplash

Encountering errors is inevitable and JavaScript is no exception. Understanding and effectively utilising error objects can turn these seemingly annoying occurrences into valuable tools for debugging and error handling.

What are Error Objects?

Error objects are specialised objects that encapsulate information about an error that occurs during the execution of a script. They provide essential details about the error, such as a message describing the error, the type of error, and the location of the error in the source code. JavaScript has a built-in Error object, which serves as the base object for all error types.

Error objects have two primary properties: name and message. The name property refers to the error's type, and the message property contains a human-readable description of the error. In addition to these properties, the Error object also has a stack property, which returns a string representing the stack trace at the time the error was thrown.

function divide(a, b) {
    if (b === 0) {
      throw new Error("Division by zero");
    }
    return a / b;
}

function quotient(a, b) {
    return divide(a, b);
}

try {
    quotient(42, 0);
} catch (error) {
    console.error("Error message:", error.message);
     // prints: "Error message: Division by zero"

    console.error("Error stack trace:", error.stack);
    /* prints:
      Error stack trace: Error: Division by zero
        at divide (REPL24:3:11)
        at quotient (REPL28:2:10)
        at REPL35:2:3
    */
}
Enter fullscreen mode Exit fullscreen mode

Creating Custom Error Objects

Extend the Error Object

To create a custom error object, you can extend the built-in Error object using the following pattern:

class CustomError extends Error {
  constructor(message) {
    super(message);
    this.name = 'CustomError';
  }
}
Enter fullscreen mode Exit fullscreen mode

By extending the Error object, your custom error will inherit the properties and methods of the base Error object. This allows you to create more specific error types tailored to your application's needs.

Error.prototype

We can also extend the Error object by creating a custom constructor function. The constructor function should accept an error message as an argument and call the Error object's constructor with the message. This way, the new error object will have all the properties of the built-in Error object, along with any additional properties specified by the custom constructor function.

function CustomError(message) {
  this.name = 'CustomError';
  this.message = message || 'Default error message';
  this.stack = (new Error()).stack;
}

CustomError.prototype = Object.create(Error.prototype);
CustomError.prototype.constructor = CustomError;
Enter fullscreen mode Exit fullscreen mode

Throwing and Catching Errors

To throw an error, you can use the 'throw' statement followed by an error object:

throw new Error('Something went wrong');
Enter fullscreen mode Exit fullscreen mode

To catch and handle errors, JavaScript provides the 'try...catch' statement. The 'try' block contains the code that may generate an error, and the 'catch' block handles the error:

try {
  // Code that may throw an error
} catch (error) {
  console.error(error.message);
}
Enter fullscreen mode Exit fullscreen mode

Built-in Error Objects

The language also provides several other built-in error objects derived from the base Error object, including:

ReferenceError

Triggered when attempting to use a variable that has not been defined or is not in the current scope:

function greet() {
  try {
    console.log("Hello " + name);
  } catch (error) {
    if (error instanceof ReferenceError) {
      console.error("Error:", error.message);
    } else {
      // any other error types
      console.error("Unexpected error:", error.message);
    }
  }
}

greet(); // prints: "Error: name is not defined"
Enter fullscreen mode Exit fullscreen mode

TypeError

Triggered when attempting to perform an operation on a value of an incorrect type, such as calling a non-function as a function or accessing a property on a non-object:

const greeting = {
  hello: function () {
    return "Hello!";
  },
};

try {
    // prints: hello
    console.log(greeting["hello"]());
    // prints: TypeError: greeting.goodbye is not a function
    console.log(greeting["goodbye"]());
} catch (error) {
    if (error instanceof TypeError) {
        console.error("TypeError:", error.message);
    } else {
        // any other error types
        console.error("Unexpected error:", error.message);
    }
}
Enter fullscreen mode Exit fullscreen mode

RangeError

Triggered when providing a value that is outside the allowed range for a particular operation or data structure:

function createArray(size) {
    try {
        return new Array(size);
    } catch (error) {
        if (error instanceof RangeError) {
            console.error("RangeError:", error.message);
        } else {
            // any other error types
            console.error("Unexpected error:", error.message);
        }
    }
}

// prints: RangeError: Invalid array length
createArray(-3);

Enter fullscreen mode Exit fullscreen mode

SyntaxError

Triggered when there is an issue with the syntax of the code, typically during parsing or evaluation - a common occurence is when using eval():

function execute(code) {
    try {
        return eval(code);
    } catch (error) {
        if (error instanceof SyntaxError) {
            console.error("SyntaxError:", error.message);
        } else {
            // any other error types
            console.error("Unexpected error:", error.message);
        }
    }
}

// prints: "Hello, World!"
execute("console.log('Hello, World!');");

// prints: "SyntaxError: missing ) after argument list"
execute("console.log('Hello, World!';");
Enter fullscreen mode Exit fullscreen mode

Remember that using eval() is generally discouraged in modern JavaScript programming, as it can lead to security and performance issues.

EvalError

This is a deprecated error object related to the global eval() function - it is not thrown by the current ECMAScript specification with other error types such as SyntaxError, ReferenceError, or TypeError are thrown when issues encountered.

URIError

Thrown when a malformed URI is provided to certain global functions, such as encodeURI(), decodeURI(), encodeURIComponent(), or decodeURIComponent():

function decode(encodedURI) {
    try {
        return decodeURIComponent(encodedURI);
    } catch (error) {
        if (error instanceof URIError) {
            console.error("URIError:", error.message);
            return;
        }
        // any other error types
        console.error("Unexpected error:", error.message);
    }
}

// prints: "://example.com/test"
decode("%3A%2F%2Fexample.com/test");

// prints: "URIError: URI malformed"
decode("%C0%AFexample.com/test%");
Enter fullscreen mode Exit fullscreen mode

Best Practices for Using Error Objects

  • Always throw an instance of an error object instead of a plain string or number to ensure proper error handling.
  • Use appropriate built-in error types when throwing errors. E.g. throw a ReferenceError when encountering an issue with an undefined variable.
  • Create custom error objects for application-specific errors.
  • Utilize the 'stack' property of error objects for better debugging, especially in development environments.
  • Handle errors gracefully by providing fallback behavior or informative messages for users.

Take Away

Effectively utilising error objects in JavaScript can greatly enhance your error handling and debugging processes. By understanding the built-in error types, creating custom error objects, and implementing proper error handling techniques, you can develop more robust, resilient, and user-friendly applications. Embrace the power of error objects and turn those inevitable errors into opportunities for improvement.

exceptions Article's
30 articles in total
Favicon
Stop using try catch in your code
Favicon
Exception Handling in Python
Favicon
Ruby exceptions: tips & tricks
Favicon
Using Context Managers and Exception Handling for File Operations in Python
Favicon
common error code prefixes in ASP.NET
Favicon
Understanding and resolving errors in C#
Favicon
Body was inferred but the method does not allow inferred body parameters:error
Favicon
Error as Value vs. Exceptions
Favicon
Exception Handling in Spring Boot
Favicon
Passing erros throught microsservices (Java + Spring)
Favicon
The performance cost of pl/pgsql exception block in Postgres
Favicon
documented: make docstrings in your exceptions work
Favicon
10 Tips to Optimize Memory Usage and Avoid Common Exceptions in Java
Favicon
How to Implement Error Handling in Python with Try-Except Blocks
Favicon
When to catch an Exception?
Favicon
Laravel API Error Exception Handling Methodologies.
Favicon
C++23: two additional noexcept functions
Favicon
Binary size and exceptions
Favicon
Introduction aux exceptions en Java
Favicon
Harnessing the Power of Error Objects in JavaScript
Favicon
How to handle exceptions in Java ?
Favicon
Spring Boot: Everything you need to know, and what nobody told you. Part IV
Favicon
Top 10 Dotnet Exception Anti-Patterns in C#
Favicon
Exceptions in Java lambdas
Favicon
Namespaced errors for Ruby
Favicon
Better way to try...except...pass in Python
Favicon
Say "no" to silent failures in your methods
Favicon
Refactoring 004 - Remove Unhandled Exceptions
Favicon
Get out early with Perl statement modifiers
Favicon
Gérer les erreurs en Go 1.14+

Featured ones: