抛出字符串而不是错误

既然我们可以在 Javascript 中抛出任何带有 throw关键字的内容,那么我们就不能直接抛出一个错误消息字符串吗?

有人知道这里面有什么陷阱吗?

让我为此添加一些背景知识: 在 JavaScript 世界中,人们通常依赖于参数检查,而不是使用 try-catch 机制,因此使用 throw只抛出致命错误是有意义的。尽管如此,为了能够捕获一些系统错误,我必须为自己的错误使用不同的类,而不是创建 Error 的子类,我认为我应该只使用 String。

41356 次浏览

You can throw errors with messages, you know.

try {
throw new Error("This is an error");
} catch (e) {
alert(e.message); // This is an error
}

But you can actually throw strings:

try {
throw "This is an error";
} catch (e) {
alert(e); // This is an error
}

While it is okay possible to throw any value, it is generally considered poor form to throw anything other than an instance of Error or one of its subclasses. There are several reasons for this:

  1. Catching code may expect the thrown object to have the usual message, stacktrace, and name properties that appear on Errors.
  2. Lack of a stacktrace makes debugging problematic, especially in the case of uncaught exceptions / unhandled rejections. E.g. Debugging an "Uncaught [Object object]" error can be particularly painful.

Yes, you can throw other values, but it's not a good practice.

Does anyone know any catch in this?

A string is not an error object, and does not convey any useful debugging information. Devtools rely on that, such as the file and line where the error was created, the stacktrace at the throw location etc, which are available as properties on Error objects.

Whenever you think of throwing a primitive string value, throw a new Error("<the string>") instead.

As others have mentioned above, if you are not throwing an Error object, then you must have try/catch blocks to trap these objects and handle them appropriately or else be in a world of hurt for debugging.

However, when it comes to throwing Errors for non-error handling purposes like controlling program flow, this may be a helpful way to utilize throw without an Error.

When using throws to control program flow, it can be inefficient in any language as the runtime will often do a lot of heavy lifting to unwind call stack information and serialize the data so its available to the user land scope. By avoiding Error creation, you can avoid this performance hit. The key is that you must have a handler up the call stack that knows how to handle this situation. For instance if you throw {isHardStop: true, stopCode: SOME_CODE} and design the handlers to detect this, you may be able to flatten out some of your code or choose cleaner syntax.

Your handler for this ladder case could be structured like:

try { ... } catch(thr) {
if(!thr){
// Is not Error or Json - Handle accordingly
} else if(thr.isHardStop){
// Handle the stop
} else {
// Most likely a real error. Handle accordingly
}
}

Although you can throw any type of data that you’d like, this is not optimal when debugging. A JS Error object contains all kind of information regarding the Error and a message. Whereas a string can only contain a message.

This additional information includes:

  1. fileName: from which file the error was thrown
  2. Linenumber: from which line the error was thrown
  3. stacktrace: from which function the error was called

Here is for example a stacktrace from chrome devtools:

enter image description here