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

What is the difference between `throw new Error` and `throw someObject`?

提问人:Jayapal Chandran 提问时间:2/6/2012 最后编辑:Sebastian SimonJayapal Chandran 更新时间:11/20/2023 访问量:520373

问:

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

当我在以下代码中确实喜欢时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]

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

而当我这样做时

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

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

有何不同?

区别是否如代码所示?就像字符串一样,字符串将作为字符串传递,对象作为对象传递,但语法会有所不同?

我还没有探索过抛出错误对象......我只做过扔绳子。

除了上述两种方法之外,还有其他方法吗?

JavaScript 对象 错误处理 异常 抛出

评论

13赞 grantwparks 5/14/2013
throw new Error({prop:val}) 的问题在于这不是 Error 的有效构造。Error 具有 Hemant 所讨论的已知属性。
3赞 Bergi 6/10/2016
相关新闻: 抛出字符串而不是错误s
4赞 kitimenpolku 12/2/2020
基于 ecma262,它们都是相同的: tc39.es/ecma262/#sec-error-constructor 中的规范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.

答:

333赞 Hemant Metalia 2/6/2012 #1

javascript 中的“throw new Error”和“throw someObject”之间的区别在于,throw new Error 将传递给它的错误包装成以下格式 −

{ name: 'Error', message: '你在构造函数中传递的字符串' }

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

这里有一个很好的解释 The Error 对象和抛出你自己的错误

Error 对象

在发生错误时,我们可以从中提取什么?所有浏览器中的 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 种错误之一发生,还可以显式抛出自己的异常以强制按需发生异常。这对于创建您自己的错误定义以及何时应将控制权转移到捕获非常有用。

评论

361赞 user9993 3/22/2017
甚至没有回答这个问题,但投票最多的答案?
2赞 Hemant Metalia 3/16/2019
@user9993用户提出的问题当时是根据聊天情况寻求详细的了解,因此已经提供了相应的答案,并且对用户有用。这就是被接受和获得最多赞成票的原因。
15赞 Mörre 7/8/2019
@HemantMetalia 但他是对的,答案甚至没有丝毫尝试回答上述 OP 问题。如果在聊天中回答了一些非常不同的答案,而这些答案应该保留在聊天中,那么这里的问题和答案没有任何逻辑联系。
0赞 Mörre 7/8/2019
要回答最初的问题,对 Javascript 来说并不重要。但是,(和子类)是按约定使用的。默认情况下,它们还提供堆栈属性,尽管可以手动将其添加到任何其他属性中。所以这实际上主要是约定俗成的,程序流程不受你抛出的东西的影响,只是你很重要。你可以而且它的工作方式是一样的,只是不会有附加的堆栈跟踪和错误处理函数,报告者、调试器期望,或者附带的属性,更精确。Errorthrowthrow "grandmother down the stairs";Error
0赞 GHOST-34 12/4/2020
如果 Error 对象被传递给另一个具有自己的 catch 块的 promise,该怎么办?你会再次抛出一个新的 Error 对象,还是只是抛出已经是 Error 的返回对象。
88赞 Ed . 10/23/2012 #2

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

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

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

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

评论

0赞 Heisenberg 1/23/2021
如果我在 ExpressJS 中为 REST API 编写代码,浏览器的这个问题将不再存在。尽管如此,使用还是更可取的?throw new Error()
44赞 JackDev 8/8/2014 #3

您首先提到以下代码:

throw new Error('sample')

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

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

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

错误对象将具有“message”属性,即“sample”。

评论

22赞 cjn 10/24/2018
第二个确实有效,只是不是以一种非常有用的方式。它在传入的对象上执行方法,导致错误(正如 Op 所写的那样)。toString()[object Object]
281赞 Nishchit 12/20/2016 #4

抛出“我是邪恶的”

throw将在捕获错误时终止进一步的执行并公开消息字符串。

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

投掷后的控制台将永远不会因终止而到达。


throw new Error(“我是邪恶的”)

throw new Error公开一个包含两个参数 namemessage 的错误事件。它还终止了进一步的执行

try {
  throw new Error("I'm Evil")
  console.log("You'll never reach to me", 123465)
} catch (e) {
  console.log(e.name, e.message); // Error I'm Evil
}

throw Error(“我是邪恶的”)

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

try {
  throw Error("I'm Evil")
  console.log("You'll never reach to me", 123465)
} catch (e) {
  console.log(e.name, e.message); // Error I'm Evil
}

console.log(typeof(new Error("hello"))) // object
console.log(typeof(Error)) // function

评论

53赞 joedotnot 3/28/2018
“throw Error('whatever')”和“throw new Error('whatever')”之间的差异呢?
27赞 Nishchit 3/28/2018
Error 是功能性的,new Error 是一个构造函数。两者 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ 相同......
0赞 Nishchit 7/10/2019
@Mörre 从此链接查看此部分...developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/......Used as a function
2赞 Nishchit 7/11/2019
好的,我明白了。这是一个功能
9赞 JeneralJames 9/7/2021
@Mörre你在说什么??这两句话,“is functional”和“is a constructor”在事实上都是准确的,而且很有道理。从字面上看,这是两者之间唯一相关的区别。 只是抛出一些东西,它不在乎什么,可以是一个字符串,一个对象,一个类的实例()。这个答案得到了很多赞成票,因为这是唯一的正确答案。throw Errorthrow new Errorthrownew Something()
21赞 Mbanda 2/1/2019 #5

您可以作为对象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
63赞 David Dehghan 5/25/2019 #6

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

throw并且在功能上是等效的。但是,当您捕获它们并将它们序列化时,它们的序列化方式并不完全相同:throw Errorconsole.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!

评论

0赞 Menai Ala Eddine - Aladdin 8/24/2020
这又如何呢:是一样的吗?throw 'message'
2赞 nruth 8/26/2020
“throw 和 throw Error will 在功能上是等价的”——并非如此。一个人抛出一个字符串,像 Bugsnag 这样的东西会抱怨它,因为它无法从他们那里获得堆栈跟踪。你的意思是在功能上它会停止代码运行,还是它会抛出一些东西?无论哪种方式,它们在语义上都不同?
41赞 Willem van der Veen 7/16/2019 #7

构造函数用于创建错误对象。发生运行时错误时,将引发错误对象。Error 对象还可以用作用户定义的异常的基对象。Error

用户定义的错误是通过语句抛出的。程序控制将传递给调用堆栈中的第一个块。throwcatch

在有和没有 Error 对象的情况下抛出错误之间的区别:


throw {'hehe':'haha'};

在 chrome devtools 中,如下所示:

enter image description here

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


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

在 chrome devtools 中,如下所示:

enter image description here

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

评论

2赞 Gianfranco Fertino 12/28/2021
这个答案最有意义
7赞 El Mac 3/15/2020 #8

反应行为

除了其他答案之外,我还想展示 React 的一个区别。

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

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

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

Error screen in react

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

throw "The application could not authenticate.";
3赞 Steve Moretz 6/23/2020 #9

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

3赞 Emmanuel Onah 3/5/2021 #10

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

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

综上所述:

  1. throw “My error”:这将创建一个 Error 对象并返回从构造函数“this”对象中提取的原始数据。如果你尝试检查 catch 块中的 typeof,它会告诉你这是一个原始类型的“字符串”

  2. throw new Error(“My error”):这将返回一个对象,您可以在其中从 message 属性访问错误值。这里简单地说,“new 关键字”构造了一个“this”对象,并为其分配“{name:”Error“,message:”...“}”并返回它。当您尝试从 catch 块中检查 typeof 时,您将看到一个类型的“对象”。

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

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

16赞 Peter Nixey 5/11/2021 #11

顶级域名

throw new Error('problem')捕获发生错误的位置的多个属性。

throw 'problem'

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

使用 Error 对象允许您在抛出错误时捕获执行堆栈。因此,当错误被传递到错误处理树时,这个堆栈快照也会传递。

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

enter image description here

而结果是:throw new Error('test error')

enter image description here

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

除此之外,它还捕获 fileNamelineNumber 和 columnNumber 等属性。

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

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

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

enter image description here

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

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

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

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

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

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

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

因此,假设我使用一个 http 服务,它返回一个 500 HTTP 代码。我可能会将其视为一个错误,然后随后捕获并处理。throw "responseCode=500"

0赞 devCrow 11/10/2021 #12

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');

评论

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

该类包括调试信息(如错误的调用堆栈)作为其实例的属性。JS 解释器知道如何将实例序列化为信息丰富的错误消息字符串,并且其结构也可以由调试软件(例如浏览器开发工具)使用,以构建更丰富的错误 GUI 表示形式。这就是为什么抛出类的实例通常比简单地抛出更有用的原因,例如,抛出描述错误的字符串或表示错误代码的数字。ErrorErrorError

使用自定义错误

创建自己的子类特别有用,它允许您使用描述性名称和机器可读的名称唯一标识不同类型的错误。Error

  • 调试线索,
  • 用于更好地显示面向用户的错误消息的信息,或者
  • 有助于从错误中恢复的信息。

然后,在处理错误时,可以使用漂亮干净的运算符来检查发生了哪种错误。例如:instanceof

class DangerousWaterCurrent extends Error {
    constructor(waterSpeed){
        super(`These waters are moving at ${waterSpeed} metres per second - too fast to cross!`) // Provide a `message` argument to the Error() constructor
        this.waterSpeed = waterSpeed // This passes some context about why/how the error occurred back to whichever function is going to catch & handle it
    }
}

// ...later...

try {
    swimAcrossRiver(river)
} catch (thrownValue) {
    if (thrownValue instanceof DangerousWaterCurrent) {
        if (thrownValue.waterSpeed <= 3){ 
            paddleKayak(river)
        } else {
            constructBridge(river)
        }
    } else {
        throw thrownValue // "Re-throw" the error back up the execution chain, for someone else to handle
    }
}

new Error()Error()

有一种“方便”的速记方法可以创建 : 的实例,方法是调用 ,而不是像创建普通类的实例那样。这是语言设计者故意插入的规则例外。其他语言类也有类似的简写,例如 和 。它们还允许您调用这些类,就好像它们是函数而不是类一样。JS 不允许普通类这样做,即使它们实际上都是“类”语法糖下的函数。在 REPL 中尝试:ErrorError(message)new Error(message)Number()String()()

> class E extends Error {}
> Error(); "a value"
"a value"
> E(); "a value"
Uncaught TypeError: Class constructor E cannot be invoked without 'new'
    at <anonymous>:2:1

对设计的更广泛意见:就我个人而言,我认为这个设计决策是一个错误,因为它为 JavaScript 规则增加了更多的例外——这意味着程序员需要学习更多,语言翻译/口译员需要考虑更多。而不是C++ / Java的关键字,简单地调用一个类,就好像它是一个函数(如)应该具有关键字当前具有的属性:应该执行类的函数。在该函数中,应绑定到实例,然后隐式返回。然后,可以从语言中丢弃该关键字。这就是 Python 语法的工作方式,它更简单、更易读、更方便。newNumber("abc123")newconstructorthisnew

评论

5赞 Oleksandr Danylchenko 2/2/2023
这是唯一👍🏻足以涵盖 和 之间差异的答案new ErrorError