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

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

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

然而当我这样做的时候

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

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

有什么不同?

区别是否如代码中所示?比如字符串会作为字符串传递而对象作为对象但语法会有所不同?

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

除了以上两种方法,还有别的办法吗?

435656 次浏览

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

{name: '错误',消息:'传入构造函数的字符串' } < / p >

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

下面是关于Error对象,并抛出自己的错误的一个很好的解释

错误对象

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

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

  • 消息:错误的描述,该描述因浏览器而异。

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的定义非常有用。

下面的文章可能会更详细地说明哪个是更好的选择;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只是抛出一个“未捕获的异常”错误,根本不提供消息字符串。显然,从调试的角度来看,这是次优的。

你首先提到了这段代码:

throw new Error('sample')

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

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

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

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

投掷“我是邪恶的”;

throw终止进一步执行在上暴露错误消息字符串。

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

后的控制台将永远无法到达,导致终止。


抛出新的错误("I'm Evil")

throw new Error暴露有两个参数的错误事件# EYZ2。它还会终止进一步的执行

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
}

抛出错误(“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作为对象

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

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

来源:# EYZ0

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!

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

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

有和没有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构造函数期望将消息字符串作为第一个参数。当它接收到一个对象时,它会将其强制转换为一个字符串。

的反应行为

除了其他的答案,我还想说明React的一个不同之处。

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

例子

在控制台而且中抛出错误日志会在开发模式下显示一个错误屏幕(在生产环境中不可见)。

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

Error screen in react

而下面的代码只能登录到控制台:

throw "The application could not authenticate.";

throw something既适用于对象也适用于字符串。但是它比另一种方法更不受支持。throw new Error("")只对字符串有效,并在catch块中将对象变成无用的[Object obj]。

这是相当古老的,但希望任何搜索它的人仍然可以从中学到东西:

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

总而言之:

  1. throw "My Error ":这将创建一个Error对象,并返回从构造函数"this"对象。如果你试着检查catch块中的typeof,它会告诉你它是一个基本类型"string"

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

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

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

TLDR

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对象在抛出错误时捕获堆栈,并使捕获错误的任何对象都可以使用它。这使我在调试时更容易跟踪问题。

除此之外,它还捕获诸如#EYZ0, #EYZ1和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",然后随后捕捉和处理。

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

Error包括调试信息,就像遇到错误时的当前调用堆栈,JS解释器知道如何将其序列化为一个信息字符串,并且可以被调试软件(如浏览器开发工具)用于构造错误的GUI表示。这就是为什么抛出Error类的实例通常比简单抛出(例如,描述错误的字符串或表示错误代码的数字)更有用。

使用自定义错误

创建自己的Error子类特别有用,它允许您使用描述性名称唯一地标识不同类型的错误。然后,当你处理错误时,你可以使用漂亮干净的instanceof操作符来检查错误发生的什么样。例如:

class ShoesTooBig extends Error {}
class DangerousWaterCurrent extends Error {
constructor(waterSpeed){
super() // Provide no `message` argument to the Error() constructor
this.waterSpeed = waterSpeed // In metres per second. This passes some context about why/how the error occurred back to whichever function is going to catch & handle it.
}
}


// ...later...


try {
swimAcrossRiver(footwear, roilingRiver)
} catch (thrownValue) {
if (thrownValue instanceof DangerousWaterCurrent) {
constructDam(roilingRiver, thrownValue.waterSpeed)
} else {
throw thrownValue // "Re-throw" the error back up the execution chain, for someone else to handle
}
}

new Error() vs Error()

有一个“方便”;创建Error实例的简便方法:调用Error(message),而不是new Error(message),就像创建普通类的实例一样。这是由语言设计者故意插入到规则中的异常。其他语言类也有类似的缩写,如Number()String()。它们还允许您使用()调用这些类,就像它们是函数一样,而不是类。JS不允许普通的类这样做,尽管它们实际上都是在“类”语法糖下的函数。在REPL中试试:

> class E extends Error {}
undefined
> 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的new关键字,简单地调用一个类,就像它是一个函数一样(在Number("abc123")中)应该执行类的constructor函数,并将this绑定到实例,就像通常发生的new关键字一样(这是Python的语法工作方式,它最终更易于阅读和方便)。