ChatGPT解决这个技术问题 Extra ChatGPT

`throw new Error` 和 `throw someObject` 有什么区别?

我想编写一个通用错误处理程序,它将捕获在任何代码实例中故意抛出的自定义错误。

当我在以下代码中执行 throw new Error('sample')

try {
    throw new Error({'hehe':'haha'});
    // throw new Error('hehe');
} catch(e) {
    alert(e);
    console.log(e);
}

日志在 Firefox 中显示为 Error: [object Object],我无法解析该对象。

对于第二个 throw,日志显示为:Error: hehe

而当我这样做的时候

try {
    throw ({'hehe':'haha'});
} catch(e) {
    alert(e);
    console.log(e);
}

控制台显示为:Object { hehe="haha"},我可以在其中访问错误属性。

有什么区别?

是代码中看到的差异吗?像字符串一样将作为字符串和对象作为对象传递,但语法会有所不同吗?

我还没有探索过抛出错误对象……我只做了抛出字符串。

除了上面提到的两种方法,还有其他方法吗?

throw new Error({prop:val}) 的问题在于它不是错误的有效构造。 Error 具有 Hemant 所讨论的已知属性。
基于 ecma262,它们都是相同的:creates and initializes a new Error object when called as a function rather than as a constructor. Thus the function call Error(…) is equivalent to the object creation expression new Error(…) with the same arguments. Spec in tc39.es/ecma262/#sec-error-constructor

H
Hemant Metalia

javascript中'throw new Error'和'throw someObject'之间的区别在于throw new Error以以下格式包装传递给它的错误 -

{ 名称:'错误',消息:'您在构造函数中传递的字符串'}

throw someObject 将按原样抛出对象,并且不允许从 try 块执行任何进一步的代码,即与 throw new Error 相同。

这是关于 The Error object and throwing your own errors 的一个很好的解释

错误对象

如果发生错误,我们可以从中提取什么?所有浏览器中的 Error 对象都支持以下两个属性:

name:错误的名称,或者更具体地说,错误所属的构造函数的名称。

message:错误的描述,此描述因浏览器而异。

name 属性可以返回六个可能的值,如前所述,它们对应于错误构造函数的名称。他们是:

Error Name          Description

EvalError           An error in the eval() function has occurred.

RangeError          Out of range number value has occurred.

ReferenceError      An illegal reference has occurred.

SyntaxError         A syntax error within code inside the eval() function has occurred.
                    All other syntax errors are not caught by try/catch/finally, and will
                    trigger the default browser error message associated with the error. 
                    To catch actual syntax errors, you may use the onerror event.

TypeError           An error in the expected variable type has occurred.

URIError            An error when encoding or decoding the URI has occurred 
                   (ie: when calling encodeURI()).

抛出你自己的错误(例外)

在控制自动从 try 块转移到 catch 块之前,无需等待 6 种类型的错误之一发生,您还可以显式抛出您自己的异常以强制其按需发生。这对于创建自己的错误定义以及何时应将控制权转移到 catch 非常有用。


哦是的。这是我在问这个问题之前错过的一件好事。无论如何,搜索与此相关的信息的用户将被清除。现在我很清楚什么是什么。 :) 谢谢。几天后我会回来投票。
甚至没有回答问题但最受好评的答案?
@user9993 用户 ho 提出的问题是根据当时的聊天寻求详细了解,因此已提供相应的答案并对用户有用。这就是接受和最多票的原因。
@HemantMetalia但他是对的,答案表明甚至没有像所述那样回答OPs问题的最轻微尝试。如果在聊天中回答了一些非常不同的答案,应该保留在聊天中,那么这里的问答没有任何逻辑联系。
为了回答最初的问题,Javascript 无关紧要。但是,Error(和子类)按惯例使用。默认情况下,它们还提供堆栈属性,尽管可以手动将其添加到任何其他属性。因此,这实际上主要是惯例,程序流程不受您抛出的内容的影响,只是您throw很重要。您可以使用 throw "grandmother down the stairs";,它的工作方式相同,只是不会附加堆栈跟踪和错误处理函数,报告者、调试器期望 Error 或更准确地说是附带的属性。
B
Brian Burns

扔“我是邪恶的”

throw终止进一步的执行和在 catch 错误时公开消息字符串。

try { throw "I'm Evil" console.log("You'll never get to me", 123465) } catch (e) { console.log(e); // 我很邪恶 }

抛出后的控制台永远不会达到终止原因。

抛出新错误(“我是邪恶的”)

throw new Error 使用两个参数 name & 公开一个错误事件消息。它还终止进一步的执行

try { throw new Error("I'm Evil") console.log("You'll never get to me", 123465) } catch (e) { console.log(e.name, e.message); // 错误我是邪恶的 }

抛出错误(“我是邪恶的”)

为了完整起见,这也有效,尽管在技术上不是正确的方法 -

try { throw Error("I'm Evil") console.log("You'll never get to me", 123465) } catch (e) { console.log(e.name, e.message); // 错误 I'm Evil } console.log(typeof(new Error("hello"))) // 对象 console.log(typeof(Error)) // 函数


“抛出错误('whatever')”和“抛出新错误('whatever')”之间的差异呢?两者都有效。
Error 是函数式的,new Error 是一个构造函数。两者都一样developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
@NishchitDhanani 我觉得奇怪的是,如此难以理解和错误的评论得到了赞成。 “错误是功能性的”和“新的错误是构造函数”都毫无意义和/或都是错误的。在这种情况下,尚不清楚该链接究竟应该“证明”什么。这是 Error 的 MDN 页面,好的,评论的连接在哪里?
好的,我明白了。这是一个功能。
@Mörre 你在说什么?这两个引用,“throw Error 是函数式的”和“throw new Error 是一个构造函数”在事实上都是准确的,并且很有意义。这实际上是两者之间唯一相关的区别。 throw 只是抛出一些东西,它不关心什么,可能是一个字符串、一个对象、一个类的实例 (new Something())。这个答案得到了很多赞成,因为它是唯一正确的答案。
E
Ed .

下面的文章可能会更详细地说明哪个是更好的选择; throw 'An error'throw new Error('An error')

http://www.nczonline.net/blog/2009/03/10/the-art-of-throwing-javascript-errors-part-2/

这表明后者 (new Error()) 更可靠,因为 Internet Explorer 和 Safari(不确定版本)等浏览器在使用前者时不会正确报告消息。

这样做会导致抛出错误,但并非所有浏览器都以您期望的方式响应。 Firefox、Opera 和 Chrome 都显示“未捕获的异常”消息,然后包含消息字符串。 Safari 和 Internet Explorer 只是抛出一个“未捕获的异常”错误并且根本不提供消息字符串。显然,从调试的角度来看,这是次优的。


如果我在 ExpressJS 中为 REST API 编写代码,浏览器的这个问题将不再存在。尽管如此,使用 throw new Error() 是否更可取?
P
Penny Liu

TLDR:它们等价于 Error(x) === new Error(x)

// this:
const x = Error('I was created using a function call!');
​​​​// has the same functionality as this:
const y = new Error('I was constructed via the "new" keyword!');

来源:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error

throwthrow Error 在功能上是等效的。但是当您捕获它们并将它们序列化为 console.log 时,它们的序列化方式并不完全相同:

throw 'Parameter is not a number!';
throw new Error('Parameter is not a number!');
throw Error('Parameter is not a number!');

Console.log(e) 以上将产生 2 个不同的结果:

Parameter is not a number!
Error: Parameter is not a number!
Error: Parameter is not a number!

这个怎么样:throw 'message'是一样的吗?
“throw 和 throw Error 在功能上是等价的”——并非如此。一个人抛出一个字符串,像 Bugsnag 这样的东西会抱怨,因为它无法从它们那里获得堆栈跟踪。你的意思是在功能上它会停止代码运行,或者它会抛出一些东西?无论哪种方式,它们在语义上都不同?
I
IonicBurger

您首先提到此代码:

throw new Error('sample')

然后在你的第一个例子中你写:

throw new Error({'hehe':'haha'}) 

第一个 Error 对象实际上很有用,因为它需要一个字符串值,在本例中为“sample”。第二个不会,因为您正在尝试传递一个对象,并且它需要一个字符串,并且不会显示有用的错误。

错误对象将具有“消息”属性,即“样本”。


第二个确实有效,只是不是很有用。它对传入的对象执行 toString() 方法,从而导致错误中的 [object Object](如 Op 所写)。
W
Willem van der Veen

Error 构造函数用于创建错误对象。发生运行时错误时抛出错误对象。 Error 对象也可以用作用户定义异常的基础对象。

用户定义的错误通过 throw 语句引发。程序控制将传递给调用堆栈中的第一个 catch 块。

使用和不使用 Error 对象引发错误的区别:

throw {'hehe':'haha'};

在 chrome devtools 中看起来像这样:

https://i.stack.imgur.com/6KJ40.png

Chrome 告诉我们有一个未捕获的错误,它只是一个 JS 对象。对象本身可能有关于错误的信息,但我们仍然不能立即知道它来自哪里。当我们处理代码和调试它时,它不是很有用。

throw new Error({'hehe':'haha'}); 

在 chrome devtools 中看起来像这样:

https://i.stack.imgur.com/687rC.png

当我们展开它时,Error 对象引发的错误会为我们提供堆栈跟踪。这为我们提供了有价值的信息,错误的确切来源在调试代码时通常是有价值的信息。进一步注意错误是 [object Object],这是因为 Error 构造函数需要一个消息字符串作为第一个参数。当它接收到一个对象时,它将强制它变成一个字符串。


这个答案最有意义
L
Lucas Dolsan

您可以 throw 作为对象

throw ({message: 'This Failed'})

然后例如在您的 try/catch

try {
//
} catch(e) {
    console.log(e); //{message: 'This Failed'}
    console.log(e.message); //This Failed
}

或者只是抛出一个字符串错误

throw ('Your error')

try {
//
} catch(e) {
    console.log(e); //Your error
}

throw new Error //only accept a string

P
Peter Nixey

TLDR

throw new Error('problem') 捕获发生错误的地方的许多属性。

throw 'problem' 没有

new Error('message') 捕获执行堆栈 + 其他

使用 Error 对象允许您在引发错误的位置捕获执行堆栈。因此,当错误被向上传递到错误处理树时,这个堆栈快照也是如此。

因此,在我的代码库中的某处插入 throw "test error" 会导致:

https://i.stack.imgur.com/TO2Ff.png

throw new Error('test error') 导致:

https://i.stack.imgur.com/I3P2A.png

您可以看到本机 Error 对象在我抛出错误时捕获了堆栈,并使其可用于捕获错误的任何内容。这使我在调试时更容易跟踪问题。

除此之外,它还捕获 fileName, lineNumber and columnNumber 等属性。

如果您使用堆栈跟踪,则异常跟踪器可以为您记录

在这种情况下,堆栈将被打印到浏览器控制台中,但如果您使用的是 Appsignal 或 Bugsnag 等 Javascript 错误记录工具,那么该堆栈也将在它们中可用。如果您检查错误对象,您可以直接访问堆栈快照:

err = new Error('test')
err.stack

https://i.stack.imgur.com/MwD7U.png

我用来决定使用哪种格式的启发式

当我不打算捕获异常时,我使用 new Error('problem')

当我因为应用程序中发生意外或越界而引发错误时,假设本地数据存储已损坏,我可能处于不想处理它的情况,但我确实想要标记它。在这种情况下,我将使用 Error 对象,所以我有那个堆栈快照。

通过使用 throw new Error('Datastore is corrupted'),可以更轻松地追溯发生的事情。

当我计划捕获异常时,我使用 throw 'problem'

编辑 - 在重新阅读本文时,我认为下一部分需要谨慎。非常具体地说明您选择捕获的错误通常是一个好主意,否则您最终可能会捕获到您真正想要一直冒泡的东西。一般来说,最好创建一个特定的错误类型并捕获该特定错误(或消息字符串)。这会让你没有预料到的错误浮出水面。”

如果错误是我计划捕获和处理的预期错误,那么我不会从堆栈快照中获得太多用途。

所以,假设我使用了一个 http 服务,它返回一个 500 HTTP 代码。我可以将此视为我 throw "responseCode=500" 然后随后捕获和处理的错误。


C
Community

反应行为

除了其他答案之外,我想展示 React 的一个不同之处。

如果我抛出 new Error() 并且我处于开发模式,我将看到错误屏幕和控制台日志。如果我抛出一个字符串文字,我只会在控制台中看到它并且可能会错过它,如果我不看控制台日志的话。

例子

在开发模式下将错误日志抛出到控制台并显示错误屏幕(该屏幕在生产中不可见)。

throw new Error("The application could not authenticate.");

https://i.stack.imgur.com/0EF3P.png

而以下代码仅登录到控制台:

throw "The application could not authenticate.";

E
Emmanuel Onah

这已经很老了,但希望任何搜索这个的人仍然可以从中学习:

首先也是著名的,在 javascript 中,我们有一个叫做 Primitive Wrapper 的东西;原始包装器获取原始数据并通过简单地使用“构造函数模式”以对象格式表示它。尽管如此,在原始包装器中,您可以决定将数据作为对象类型返回,或者您可以将其作为原始类型返回(在这种情况下,您现在得到了一个让 javascript 提取原始值的继续命令在这种情况下,您不使用 new 关键字)。

总之:

throw "My error":这会创建一个 Error 对象并返回从构造函数 "this" 对象中提取的原始数据。如果您尝试检查 catch 块中的 typeof,它会告诉您它的原始 typeof "string" throw new Error("My error"):这将返回一个对象,您可以在其中从 message 属性访问错误值。这里简单地发生的是,“new 关键字”构造了一个“this”对象并将“{name:”Error”,message:“...”} 分配给它并返回它。当您尝试从 catch 块中检查 typeof 时,您将看到一个 typeof “对象”。

注意:在将自定义对象显式传递给 throw 的情况下,它的行为就像您使用 new 关键字调用构造函数一样,因此,catch 块将返回自定义对象而不是消息属性值。例如: throw {name:"RangeError",message:"range is out of scope",environment:"Happened in testing function"}。

总之,使用任何适合你的东西,你知道你在做什么。但对我来说,如果我不需要太多数据而只需要错误,那么我会选择原始返回器。


S
Steve Moretz

throw something 适用于对象和字符串。但它比其他方法受支持较少。throw new Error("") 仅适用于字符串并将对象在 catch 块中变成无用的 [Object obj]。


b
buddemat

throw new Error() 适用于引发指定错误。但是如果你想做自定义错误处理,最好使用 throw { example: 'error' }

也就是说,如果您想知道指定的错误,请使用 throw new Error("example string") ,如果您想自定义处理错误,请使用 throw


function makeErrorResponse(err = {}, httpStatus, status, message, message) {
    const error = new Error();

    error.httpStatus = httpStatus;
    error.status = status;
    error.message = message;
    error.err = err;

    return error;
  }

throw makeErrorResponse({}, 500, 500, 'server error');

抛出不是 instanceof Error 的东西不是一个好主意,并且会使其余代码复杂化,因为现在您不能依赖可用的正常错误属性,也不能将错误追溯到其来源,因为它没有堆栈。虽然第二个示例还可以,但最好使用 use custom errors that inherit from Error。然后,您可以轻松地从这些扩展以获得更多级别的粒度,并使用 instanceof 轻松检查错误(特定错误或一类错误)。
我通过继承网络错误(如 api 错误、db 错误)的错误来使用自定义错误。正如您所说,自定义错误在调试时很有用。但是,如果没有启动服务器所需的文件或发生端口冲突错误,我认为用自己的错误而不是自定义错误停止服务器是正确的。