为什么';在JavaScript中抛出错误是否符合逻辑?
这是一种非常常见和有用的做法:为什么';在JavaScript中抛出错误是否符合逻辑?,javascript,Javascript,这是一种非常常见和有用的做法: // default via value var un = undefined var v1 = un || 1 // default via a function call var myval = () => 1 var v2 = un || myval() 但在抛出错误时,它不起作用(SyntaxError): var v3 = un || throw new Error('un is not set!') 有没有办法以同样优雅的方式达到同样的效果
// default via value
var un = undefined
var v1 = un || 1
// default via a function call
var myval = () => 1
var v2 = un || myval()
但在抛出错误时,它不起作用(SyntaxError):
var v3 = un || throw new Error('un is not set!')
有没有办法以同样优雅的方式达到同样的效果?
这是很多样板代码:
if (!un) {
throw new Error('un is not set!')
}
var v3 = un
或者是否存在任何理论上的障碍,为什么这不可能,也永远不可能?您可以将异常的抛出移动到函数中,因为这是控制流的一种形式,而不是: 表达式是解析为值的任何有效代码单元
const throwError=函数(e){抛出新错误(e);};
var un=未定义,
v3=un | |投掷者('un未设置!')代码>throw
仅为语句;它可能不存在于需要表达式的位置。例如,出于类似的原因,您不能将if
语句放在那里
var something = false || if (cond) { /* something */ }
也是无效语法
只允许将表达式(计算为值的事物)指定给变量。如果您想抛出
,则必须将抛出
作为语句,这意味着您不能将其放在作业的右侧
我想一种方法是在| |
的右侧使用IIFE,允许您在该函数的第一行使用语句:
var un=未定义
var v2=un | |(()=>{throw new Error('nope')})()代码>您的问题是赋值需要一个表达式,但您给它一个语句
初始化/分配变量的语法为:
var|let|const <variableName> = <expression>
x
被赋予值“5”
函数调用
myFunc()
生成一个分配给x的值
函数的生成值是它的返回值-函数总是返回,如果没有显式返回,则返回未定义的
函数还有一个额外的好处,就是能够在它们的主体中包含语句——这将是您问题的解决方案——但稍后会有更多内容
声明
语句是执行动作的东西。例如:
环路
展开堆栈并停止当前帧的执行
那为什么我们不能两者兼而有之呢?
当您要为变量赋值时,您需要一个表达式,因为您希望该变量有一个值
如果你仔细想想,应该清楚的是,它永远不会与声明一起工作。给变量一个“动作”是胡说八道。这到底是什么意思
因此,不能使用throw
语句,因为它不生成值
你只能有一个或另一个。
要么你是(表达)
某事,要么你做(陈述)
某事
修理
您可以通过将任何语句包装到函数中将其转换为表达式,我建议使用IIFE(立即调用的函数表达式)
——基本上是一个调用自身的函数——来实现这一点
var x = 5 || (() => throw new Error())()
这是因为右侧现在是一个函数,而函数是一个产生值的表达式,在这种情况下,值是未定义的
,但是因为我们停止执行它,所以它并不重要
未来的可能性
从技术上讲,没有任何东西可以阻止这项工作
许多语言(c++,…)实际上已经将throw
视为一个表达式。有些(kotlin,…)甚至完全省略语句,并将所有内容都视为一个表达式
其他的(c#,php,…)提供了类似于?
null隐藏或?。
elvis操作符的解决方法来解决这个用例
也许将来我们会在ecmascript标准()中加入这些功能之一,直到那时,您最好使用如下函数:
function assertPresent(value, message)
{
if(!value) {
throw new Error(message);
} else {
return value;
}
}
正如其他答案所述,这是因为throw
是一种语句,不能在需要表达式的上下文中使用,例如在|
的右侧。正如其他人所说,您可以通过将异常包装到函数中并立即调用它来绕过这个问题,但我要说明的是,这样做是一个坏主意,因为这样做会使您的意图不那么清晰。额外的三行代码对于使代码的意图非常清晰和明确并不是什么大问题。我个人认为,throw
being statement only是一件好事,因为它鼓励编写更直接的代码,而不太可能导致其他开发人员在遇到您的代码时挠头
当您想为未定义的
、空的
和其他错误的值提供默认值或替代值时,|
默认习惯用法非常有用,但我认为当在分支意义上使用时,它会失去很多清晰性。所谓“分支意义”,我的意思是,如果你的意图是在某个条件成立的情况下做某件事(在本例中,做某件事是抛出一个异常),那么条件| |做某件事()
实际上并不是表达该意图的明确方式,即使它在功能上与if(!condition){do|u something()
相同。短路评估并不是每个开发人员都能立即看到的,默认值之所以被理解是因为它是Javascript中常用的习惯用法
我的一般经验法则是,如果函数有副作用(是的,异常被视为副作用,特别是因为它们基本上是非本地goto语句),那么应该使用if语句作为其条件,而不是|
或&
。你不是在打高尔夫球
一句话:哪一个会减少混乱
return value || (() => {throw new Error('an error occurred')})()
或
为了清晰起见,牺牲简洁通常是值得的。正如其他人所说,问题在于throw
是一个语句,而不是一个表达式
然而,实际上不需要这种二分法。有些语言中的一切都是一个表达式(没有语句),它们并不是因为
for (var i = 0; i < 10; i++) { /* loop body */ }
throw new Error()
var x = 5 || (() => throw new Error())()
function assertPresent(value, message)
{
if(!value) {
throw new Error(message);
} else {
return value;
}
}
return value || (() => {throw new Error('an error occurred')})()
if (!value) {
throw new Error('an error occurred')
}
return value
function error(x) { throw Error(x); }
let x = y.parent || error("No parent");