为什么 JavaScript try/finally 块会导致函数显然 return 两次?
Why do JavaScript try/finally blocks cause function to apparently return twice?
finally 块总是最后执行,return 语句 return 控制返回函数调用的位置。当在 try/finally 块内部一起使用时,该函数出现两次 return 而不是一次,当在 if-else 块内部使用时,finally 块的 return 值生效。同一个方法调用 returning 两次吗?
function print(value) {
console.log(value);
return value;
}
function testWrapped() {
try {
return print(true);
} finally {
return print(false);
}
}
function test() {
try {
return true;
} finally {
return false;
}
}
console.log("Result with wrapped value");
testWrapped();
console.log("Result when used inside an if statement:");
if (test()) {
console.log("true");
} else {
console.log("false");
}
以上代码产生以下输出:
Result with wrapped value
true
false
Result when used inside an if statement:
false
这是因为您使用的是 finally
而不是 catch
最后将在 try 或 catch 之后执行。
在条件块中,它将 return 最后评估的项目 false
并执行您的其他块。
参见:https://www.w3schools.com/jsref/jsref_try_catch.asp
The try statement allows you to define a block of code to be tested
for errors while it is being executed.
The catch statement allows you to define a block of code to be
executed, if an error occurs in the try block.
The finally statement lets you execute code, after try and catch,
regardless of the result.
两者都被评估,但实际上只有第二个被返回。
由于print()
的评价有输出到控制台的side-effect,可以看到评价。但是如果你要 console.log(testWrapped())
你会在两个评估值之后看到返回值。
您的代码相当于:
try {
result1 = print(true);
return result1;
}
finally {
result2 = print(false);
return result2;
}
希望这能让您更清楚地了解正在发生的事情。
深入了解,spec 说:
TryStatement : try
Block Finally
- Let B be the result of evaluating Block.
- Let F be the result of evaluating Finally.
- If F.[[type]] is normal, let F be B.
- If F.[[type]] is return, or F.[[type]] is throw, return Completion(F).
- If F.[[value]] is not empty, return Completion(F).
- Return Completion{[[type]]: F.[[type]], [[value]]: undefined, [[target]]: F.[[target]]}.
将此应用于您的 testWrapped()
代码,
try
块被评估。 print(true)
的副作用发生了,因此 true
将出现在控制台中。 try
块 returns,因此对其求值的结果是 Completion,类型为 return,值为 无论 print(true) 是什么:true。 这还没有 returned。
finally
块被评估。同样的事情:false
在控制台中,Completion{[[type]]: return, [[value]]: false}.
- "If F.[[type]] is normal" 不是。接下来。
- 这是 return 实际发生的地方,它是
finally
块中的 return:false。最终结果:true false
在控制台中,testWrapped()
return 为假。
和 if
语句:
test
的 try
块被评估: Completion{[[type]]: return, [[value]] : 真}.
test
的 finally
块被评估:Completion{[[type]]: return, [[value]] : 假}.
- 纳达。
finally
的完成是 returned: false。 test()
的计算结果为 false
,然后执行 else
块。
finally 块总是最后执行,return 语句 return 控制返回函数调用的位置。当在 try/finally 块内部一起使用时,该函数出现两次 return 而不是一次,当在 if-else 块内部使用时,finally 块的 return 值生效。同一个方法调用 returning 两次吗?
function print(value) {
console.log(value);
return value;
}
function testWrapped() {
try {
return print(true);
} finally {
return print(false);
}
}
function test() {
try {
return true;
} finally {
return false;
}
}
console.log("Result with wrapped value");
testWrapped();
console.log("Result when used inside an if statement:");
if (test()) {
console.log("true");
} else {
console.log("false");
}
以上代码产生以下输出:
Result with wrapped value
true
false
Result when used inside an if statement:
false
这是因为您使用的是 finally
而不是 catch
最后将在 try 或 catch 之后执行。
在条件块中,它将 return 最后评估的项目 false
并执行您的其他块。
参见:https://www.w3schools.com/jsref/jsref_try_catch.asp
The try statement allows you to define a block of code to be tested for errors while it is being executed.
The catch statement allows you to define a block of code to be executed, if an error occurs in the try block.
The finally statement lets you execute code, after try and catch, regardless of the result.
两者都被评估,但实际上只有第二个被返回。
由于print()
的评价有输出到控制台的side-effect,可以看到评价。但是如果你要 console.log(testWrapped())
你会在两个评估值之后看到返回值。
您的代码相当于:
try {
result1 = print(true);
return result1;
}
finally {
result2 = print(false);
return result2;
}
希望这能让您更清楚地了解正在发生的事情。
深入了解,spec 说:
TryStatement :
try
Block Finally
- Let B be the result of evaluating Block.
- Let F be the result of evaluating Finally.
- If F.[[type]] is normal, let F be B.
- If F.[[type]] is return, or F.[[type]] is throw, return Completion(F).
- If F.[[value]] is not empty, return Completion(F).
- Return Completion{[[type]]: F.[[type]], [[value]]: undefined, [[target]]: F.[[target]]}.
将此应用于您的 testWrapped()
代码,
try
块被评估。print(true)
的副作用发生了,因此true
将出现在控制台中。try
块 returns,因此对其求值的结果是 Completion,类型为 return,值为 无论 print(true) 是什么:true。 这还没有 returned。finally
块被评估。同样的事情:false
在控制台中,Completion{[[type]]: return, [[value]]: false}.- "If F.[[type]] is normal" 不是。接下来。
- 这是 return 实际发生的地方,它是
finally
块中的 return:false。最终结果:true false
在控制台中,testWrapped()
return 为假。
和 if
语句:
test
的try
块被评估: Completion{[[type]]: return, [[value]] : 真}.test
的finally
块被评估:Completion{[[type]]: return, [[value]] : 假}.- 纳达。
finally
的完成是 returned: false。test()
的计算结果为false
,然后执行else
块。