In the process of JS code execution before ES3, once there is an error, the whole JS code will stop execution, so that the code is very unrobust.

Some high-level languages, such as Java or C#, provide exception handling mechanisms that handle exceptions as they occur without stopping the entire application.

From ES3, JS also provides a similar exception handling mechanism, so that JS code becomes more robust, even if there is an exception in the execution process, it can also make the program has a certain ability to recover the exception.

The Error object

When JavaScript parses or runs, the engine throws an error object whenever an error occurs. JavaScript natively provides the Error constructor, and all thrown errors are instances of that constructor.

const err = new Error('I'm a good person');
console.log(err.message) // "I am a good person"
Copy the code

In the code above, we call the Error() constructor to generate an instance object, Err. The Error() constructor takes an argument representing an Error message, which can be read from the instance’s message property.

The JavaScript language standard only mentions that the Error instance object must have a message attribute, which indicates the message when an Error occurs. Most JavaScript engines also provide name and stack attributes for Error instances, indicating the name of the Error and the stack of the Error, respectively, but these are non-standard and not available in every implementation.

  • Message: Error message (standard attribute)
  • Name: Error name (non-standard attribute)
  • Stack: Wrong stack (non-standard property)

Using the name and message attributes, you can get a general idea of what went wrong.

if (error.name) {
  console.log(error.name + ':' + error.message);
}
Copy the code

The stack property is used to view the stack when an error occurs.

function throwError() {
  throw new Error('Little mistake about to be made.');
}

function catchError() {
  try {
    throwError();
  } catch(e) {
    console.log(e.stack); // print stack trace
  }
}

catchError()

// Error: a small Error will be thrown out
// at throwError (
      
       :2:9)
      
// at catchError (
      
       :7:5)
      
// at 
      
       :13:1
      
Copy the code

In the above code, the innermost layer of the error stack is the throwError function, followed by the catchError function, and finally the environment in which the function is run.

Js built-in error type

The Error instance object is the most common type of Error, and JavaScript defines six derived objects on top of it.

SyntaxError object

SyntaxError objects are syntax errors that occur when parsing code.

// The variable name is incorrect
const 1aa;
// Uncaught SyntaxError: Invalid or unexpected token

// The parentheses are missing
console.log 'hi');
// Uncaught SyntaxError: Unexpected string
Copy the code

All errors in the above code are found during the parsing phase, so SyntaxError is raised. The first error message is “token is invalid” and the second error message is “string does not meet requirements”.

ReferenceError object

The ReferenceError object is an error that occurs when referring to a variable that does not exist.

// Use a variable that does not exist
unknownVariable
// Uncaught ReferenceError: unknownVariable is not defined
Copy the code

Another triggering scenario is to assign a value to an object that cannot be assigned, such as to the result of a function run.

// The left side of the equals sign is not a variable
console.log() = 1
// Uncaught ReferenceError: Invalid left-hand side in assignment
Copy the code

The above code assigns a value to the console.log result, which raises a ReferenceError.

TypeError object

A TypeError object is an error that occurs when a variable or parameter is not of the expected type. For example, using the new command on values of basic data types like strings, booleans, and numerals throws this error because the argument to the new command should be a constructor.

new 123
// Uncaught TypeError: 123 is not a constructor

const obj = {};
obj.unknownMethod()
// Uncaught TypeError: obj.unknownMethod is not a function
Copy the code

The second case of the above code, calling a method where the object does not exist, also raises TypeError because obJ. unknownMethod is undefined, not a function.

RangeError object

The RangeError object is an error that occurs when the value is outside the valid range. The Number object is out of range, and the function stack exceeds the maximum value.

// The array length must not be negative
new Array(-1)
// Uncaught RangeError: Invalid array length

// The Number object's method argument is out of range
const num = new Number(12.34)
num.toFixed(-1)
// Uncaught RangeError: toFixed() digits argument must be between 0 and 100
Copy the code

URIError object

The URIError object is an error thrown when arguments to urI-related functions are incorrect, It mainly involves encodeURI(), decodeURI(), encodeURIComponent(), decodeURIComponent(), escape() and unescape().

decodeURI('% 2')
// Uncaught URIError: URI malformed
Copy the code

Note: Escape () and unescape() are deprecated

EvalError object

An EvalError is thrown when the eval function is not executed correctly. This error type is no longer used, but is retained for compatibility with previous code.

conclusion

These six derived errors, along with the original Error object, are constructors. Developers can use them to manually generate instances of error objects. Each of these constructors takes an argument that represents an error message.

const err1 = new Error('Wrong! ');
const err2 = new RangeError('Error, variable out of valid range! ');
const err3 = new TypeError('Error, variable type invalid! ');

err1.message // "Error!"
err2.message // "Error, variable out of valid range!"
err3.message // "Error, invalid variable type!"
Copy the code

In general, different errors are handled differently. You can refer to the following handling methods. In practice, however, most developers do not take error types further.

try { 
  someFunction(); 
} catch (error){ 
  if (error instanceof TypeError) {// Handle type error
  } else if (error instanceof ReferenceError) {// Handle reference errors
  } else { 
      // Handle other errors}}Copy the code
new CustomError('Oh, that's a mistake.')
Copy the code

Throw exceptions

Throws an object of the js built-in error type

In most code execution, the browser (javascript engine) throws an exception when an error occurs, and the program either stops execution or is tried… Catch caught.

However, sometimes we can actively throw errors when we detect that something unreasonable is happening.

Use the throw keyword to throw an active exception.

throw new Error("Look, that's a mistake.");
console.log("It can't be executed here.")
Copy the code

Note:

  1. After thow is the exception object we’re going to throw. In the past, browsers threw exceptions when something went wrong, but now we throw them on our own initiative.
  2. Any exception object thrown, either by the browser or on its own initiative, will stop the program. If we want the program to continue, we can also use try… Catch, catch, catch
  3. Each error type can be passed a parameter that represents the actual error message.
  4. We can throw any type of exception we want at the appropriate time. Throw new SyntaxError(” SyntaxError…”) );

Look at the following code:

/* This function takes a number and returns its square. * /
function foo(num) {
    if(typeof num == "number") {return num * num;
    }else{
        throw new TypeError("Type error, you should pass in a number...")}}console.log(foo(33))
console.log(foo("abc"))
Copy the code

A throw can throw a value of any type. That is, it can take any value.

// Throws a string
throw 'the Error! ';
conole.log('Let's see if I can do this.')
/ / Uncaught Error!

// Throws a value
throw 42;
conole.log('Let's see if I can do this.')
// Uncaught 42

// Throws a Boolean value
throw true;
conole.log('Let's see if I can do this.')
// Uncaught true

// Throws an object
throw {
  toString: function () {
    return 'Error! '; }}; conole.log('Let's see if I can do this.')
/ / Uncaught {toString: ƒ}
Copy the code

Error object of custom type thrown

Not only can we throw an object of a built-in error type, we can also define a custom error type and then throw an object of a custom error type. If you want to customize the error type, you only need to inherit any OF the JS error types. Generally, you can inherit Error directly.

function CustomError(message) {
    this.message = message ?? 'Default error message prompt'
    this.name = 'CustomError'
}

CustomError.prototype = new Error(a);// If you want to write this sentence, you can try it out
try {
    throw new CustomError("Note: This is a custom error type")}catch (error){
    console.log(error.message)
}
Copy the code

The code above defines a CustomError object, CustomError, that inherits the Error object. This custom type of error can then be generated.

Exception handling

Basic try… Catch statement

ES3 began to introduce try-catch statements, the standard way of handling exceptions in JavaScript.

Grammar:

try{ 
  // Possible exception code
}catch(error){ 
  // Error code execution occurred
}
Copy the code

Look at the following code:

try{
    console.log(b);
    console.log("I'm not going to export it. Stop looking.")}catch(error){
    console.log("An error has occurred.")}console.log("I try catch the code after")
Copy the code

Description:

  1. Put potentially problematic code in a try statement. Any code could theoretically be written in a try statement, and if one line of code fails, the entire program’s execution flow is immediately switched to a catch statement.
  2. If one line of a try fails, no other statements in the try following that line of failed code are executed. Such as console.log(b) in the code above; This line of code will fail, immediately execute the code in the catch. So console.log(” I won’t print it, don’t look for it “) will not be executed
  3. Before executing the code in a catch, the JS engine automatically creates an error based on the type of error and passes it to the catch via the parameters following the catch. Different browsers create different error objects, but they all contain a message property, the value of which is some information about the error.
  4. After the code in catch completes, it continues to execute the following code, and the program does not stop.

Finally statement

In the try… In catch, if an error occurs in a try, the following JS statement is not executed. If no error occurs, the statement in the catch is not executed.

Javascript references other programming languages and also provides a finally statement: The statement in finally is executed at the end, regardless of whether the statement in the try has an error.

That is, a finally statement is executed after the try statement is executed without error. A catch statement is executed after the try statement is executed. A finally statement is executed after the catch statement is executed.

Grammar:

try{}catch(error){

}finally{}Copy the code
try{
    console.log(b);
    console.log("I'm not going to export it. Stop looking.")}catch(error){
    console.log("An error has occurred.")}finally{
    console.log("I'm going to do it regardless of what happens.")}console.log("I try catch the code after")
Copy the code

So in finally we can place the code we have to execute.

Note:

  1. In JS, if a finally statement is added, the catch statement can be omitted. So the following code is also correct.
  2. Without a catch statement, an error cannot be caught once it occurs, so the program stops immediately after the statement in finally is executed.
  3. Therefore, in practical use, it is best to carry the catch statement with you at all times.
try{
    console.log(b);
    console.log("I'm not going to export it. Stop looking.")}finally{
    console.log("I'm going to do it regardless of what happens.")}console.log("I try catch the code after")
Copy the code

Use cases

function returnTest(x) {
  try {
    console.log(x);
    return 'result';
  } finally {
    console.log('FINALLY'); }}const result = returnTest('hello')
console.log(result)
// hello
// FINALLY
// result
Copy the code

In the above code, the try block does not fail and the return statement is included, but the finally block still executes. Also, the return value of this function is result.

The following example shows that the return statement executes before the finally code and only returns after the finally code has finished executing.

let count = 0;
function countUp() {
  try {
    return count;
  } finally{ count++; }}console.log(countUp())
/ / 0
console.log(count)
/ / 1
Copy the code

The value of count in the return statement is retrieved before the finally block runs.

Try… catch… Finally The order in which the three are executed.

function f() {
  try {
    console.log(0);
    throw 'bug';
  } catch(e) {
    console.log(1);
    return true; // This sentence would have been deferred until the end of the finally block
    console.log(2); // Will not run
  } finally {
    console.log(3);
    return false; // This sentence overwrites the previous sentence return
    console.log(4); // Will not run
  }
  console.log(5); // Will not run
}

var result = f();
/ / 0
/ / 1
/ / 3

console.log(result) 
// false
Copy the code

In the above code, the finally block is executed before the catch block finishes execution.

In a catch block, a flag that triggers a transition to a finally block includes not only a return statement but also a throw statement.

function f() {
  try {
    throw 'Wrong! ';
  } catch(e) {
    console.log('Caught an internal error');
    throw e; // This sentence would have waited until finally finished
  } finally {
    return false; // Return directly}}try {
  const result = f();
  console.log(result)
} catch(e) {
  // Not executed here
  console.log('caught outer "bogus"');
}

// An internal error was caught
// false
Copy the code

In the above code, after entering the catch block, the first time a throw statement is encountered, the finally block is executed. The finally block contains a return false statement, so it returns directly and does not go back to the rest of the catch block.

Inside the try block, you can use the try block again.

try {
  try {
    consle.log('Hello world! '); / / an error
  } finally {
    console.log('Finally');
  }
  console.log('Will I run? ');
} catch (error) {
  console.error(error.message);
}
// Finally
// consle is not defined
Copy the code

In the code above, we have a try inside a try. The inner try gives an error (console misspelled), which executes the inner finally block and then throws an error that is caught by the outer catch.

Proper use of try… catch

When an error occurs in a try-catch statement, the browser assumes that the error has been handled and no longer reports the error. This is also the simplest case.

Try-catch is best for handling errors that are out of our control. Suppose you’re using a function in a large JavaScript library that can throw errors, intentionally or not. Since we can’t modify the library’s source code, we can put calls to this function in try-catch statements so that any errors that occur can be handled appropriately.

Using try-catch statements when you know your code will fail is not a good idea. For example, if an argument passed to a function is a string instead of a number, it will cause the function to fail, so you should check the type of the argument before deciding what to do. In this case, try-catch statements should not be used. Because the try… Catch statements are expensive.