【问题标题】:What is the difference between `throw new Error` and `throw someObject`?`throw new Error` 和 `throw someObject` 有什么区别?
【发布时间】:2012-02-27 16:41:45
【问题描述】:

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

当我在下面的代码中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"},我可以在其中访问错误属性。

有什么区别?

是否如代码中所见的差异? like string 将仅作为字符串传递,将 object 作为对象传递,但语法会有所不同?

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

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

【问题讨论】:

  • 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

标签: javascript object error-handling exception-handling throw


【解决方案1】:

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

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

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,或者更准确地说是附带的属性。跨度>
【解决方案2】:

抛出“我是邪恶的”

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

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

throw 之后的控制台将永远无法到达终止原因。


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

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
}

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

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

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

【讨论】:

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

下面的文章可能会更详细地说明哪个是更好的选择; 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() 是否更可取?
【解决方案4】:

你首先提到这段代码:

throw new Error('sample')

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

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

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

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

【讨论】:

  • 第二个确实有效,只是不是很有用。它对传入的对象执行toString() 方法,导致错误中出现[object Object](正如Op 所写)。
【解决方案5】:

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) 以上会产生两种不同的结果:

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

【讨论】:

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

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

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

有和没有Error对象抛出错误的区别:


throw {'hehe':'haha'};

在 chrome devtools 中看起来像这样:

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


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

在 chrome devtools 中看起来像这样:

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

【讨论】:

  • 这个答案最有意义
【解决方案7】:

你可以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

【讨论】:

    【解决方案8】:

    反应行为

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

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

    示例

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

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

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

    throw "The application could not authenticate.";
    

    【讨论】:

      【解决方案9】:

      TLDR

      throw new Error('problem') 捕获了发生错误的地方的一些属性。

      throw 'problem' 没有

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

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

      所以在我的代码库中某处插入throw "test error" 会导致:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      【讨论】:

        【解决方案10】:

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

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

        总结:

        1. throw "My error":这会创建一个 Error 对象并返回从构造函数 "this" 对象中提取的原始数据。如果您尝试检查 catch 块中的 typeof,它会告诉您它是一个原始 typeof "string"

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

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

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

        【讨论】:

          【解决方案11】:

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

          【讨论】:

            【解决方案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');
            

            【讨论】:

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