ChatGPT解决这个技术问题 Extra ChatGPT

为什么`finally`中的返回会覆盖`try`?

try/catch 块中的 return 语句如何工作?

function example() {
    try {
        return true;
    }
    finally {
        return false;
    }
}

我希望这个函数的输出是 true,但实际上是 false

对于其他人,在 catch 块中执行 return false,而不是 finally。
finally 不是用于逻辑,而是用于清理,例如释放资源。 return 语句不适合在 finally 中使用。

J
Jaeeun Lee

最后总是执行。这就是它的用途,这意味着它的返回值会在您的情况下使用。

您需要更改代码,使其更像这样:

function example() { 
    var returnState = false; // initialization value is really up to the design
    try { 
        returnState = true; 
    } 
    catch {
        returnState = false;
    }
    finally { 
        return returnState; 
    } 
} 

一般来说,你永远不想在一个函数中有多个 return 语句,这样的事情就是原因。


我认为拥有多个 return 语句并不总是坏事 - 有关更多讨论,请参阅 stackoverflow.com/questions/36707/…
我也不同意一次退货规则。但是,您永远不应该从 finally 返回(在 C# 中,甚至不允许这样做)。
@erikkallen - 这是一个很好的观点。最好在 TCF 块之外返回,但示例代码会有点强制:)
@Castrohenge - 这不是一个硬性规定,但该线程中的大多数 copunter 示例都非常人为,我看到的唯一有效案例是“保护条款”(本质上是检查顶部输入数据的模式函数并有条件地返回)。这是一个完全有效的案例,但实际上这些回报应该是例外(同样不是硬性和快速性)。
实际上在 IE6 和 IE7 中,由于一个非常严重的浏览器错误,finally 并不总是在所有情况下都执行。具体来说——如果在没有被更高级别的 try-catch 包围的 try-finally 块中引发异常,则 finally 块将不会执行。这是一个测试用例 jsfiddle.net/niallsmart/aFjKq。此问题已在 IE8 中修复。
c
chharvey

根据 ECMA-262(2009 年 12 月第 5 版),第 96 页:

产生式 TryStatement : try Block finally 的评估如下:设 B 为评估 Block 的结果。令 F 为 Final 评估的结果。如果 F.type 正常,返回 B。返回 F。

从第 36 页开始:

Completion 类型用于解释执行非本地控制转移的语句(break、continue、return 和 throw)的行为。 Completion 类型的值是 (type, value, target) 形式的三元组,其中 type 是 normal、break、continue、return 或 throw 之一,value 是任何 ECMAScript 语言值或空值,target 是任何 ECMAScript 标识符或空的。

很明显,return false 会将 finally 的完成类型设置为 return,这会导致 try ... finally 执行 4。返回 F


在阅读了对这个问题的各种“基本上正确但不知何故模糊且不明确”的答案之后,这个问题实际上是有道理的。关键是在 try+catch 结束时“发生”的任何事情(返回或抛出或只是正常流程)在运行 finally 部分时都会被记住,然后只有在 finally 结束时没有任何事情发生时才会真正发生。
d
djdd87

当您使用 finally 时,该块中的任何代码都会在方法退出之前触发。因为您在 finally 块中使用了 return,所以它调用 return false 并覆盖 try 块中的前一个 return true

(术语可能不太正确。)


M
Mihey Mik

finally 块重写了 try 块返回(形象地说)。

只是想指出,如果你从 finally 返回一些东西,那么它将从函数中返回。但是如果在 finally 中没有'return' 字 - 它将返回来自 try 块的值;

function example() {
    try {
        return true;
    }
    finally {
       console.log('finally')
    }
}
console.log(example());
// -> finally
// -> true

所以 -finally- return 重写了 -try- return 的返回值。


F
Flame

我将在这里给出一个稍微不同的答案:是的,tryfinally 块都被执行,并且 finally 优先于函数的实际“返回”值。但是,这些返回值并不总是在您的代码中使用。

原因如下:

下面的示例将使用 Express.js 中的 res.send(),它创建一个 HTTP 响应并分派它。

你的 try 和 finally 块都会像这样执行这个函数:

try {
    // Get DB records etc.
    return res.send('try');
} catch(e) {
    // log errors
} finally {
    return res.send('finally');
}

此代码将在您的浏览器中显示字符串 try。此外,该示例将在您的控制台中显示错误。 res.send() 函数被调用两次。任何作为函数的东西都会发生这种情况。 try-catch-finally 块会让未经训练的人混淆这个事实,因为(个人)我只将 return 值与函数范围相关联。

恕我直言,您最好的选择是永远不要在 finally 块中使用 return。它会使您的代码过于复杂并可能掩盖错误。

事实上,在 PHPStorm 中有一个默认的代码检查规则设置,它为此给出了“警告”:

https://www.jetbrains.com/help/phpstorm/javascript-and-typescript-return-inside-finally-block.html

那你最后用什么?

我只会使用 finally 来清理东西。任何对函数的返回值不重要的东西。

如果您考虑一下,这可能是有道理的,因为当您依赖 finally 下的一行代码时,您假设 trycatch 中可能存在错误。但是最后两个是错误处理的实际构建块。只需在 trycatch 中使用 return


强烈同意这个答案 - 只会补充说,如果您遇到返回行为问题,只需将返回放在 finally 块之外!它总是在那里运行,除非你在 try/catch 中返回!我认为最好在 try/catch 行为之外使用另一种语言结构,因为这种奇怪之处,比如 do {/*stuff*/} always {/*clean up*/)
a
anishMarokey

为什么你得到错误是你在 finally 块中返回。 finally 块应该始终执行。所以您的 return true 更改为 return false

function example() {
    try {
        return true;
    }
    catch {
        return false;
    }
}

T
Tho

从 finally 块返回 如果 finally 块返回一个值,该值将成为整个 try-catch-finally 语句的返回值,而不管 try 和 catch 块中的任何 return 语句

参考:developer.mozilla.org


M
Manoj Govindan

据我所知,无论您在 try 中是否有 return 语句,finally始终 都会执行。因此,您会在 finally 块中获得 return 语句返回的值。

我在 Ubuntu 中使用 Firefox 3.6.10 和 Chrome 6.0.472.63 对此进行了测试。此代码在其他浏览器中的行为可能会有所不同。


D
Darko Z

finally 应该总是在 try catch 块的末尾运行,这样(根据规范)就是你得到错误返回的原因。请记住,不同的浏览器完全有可能具有不同的实现。


IE8、Firefox 3.6 和 Chrome 6:都一样 ;)
T
Thomas Karlsson

那这个呢?

doubleReturn();

function doubleReturn() {
  let sex = 'boy';

  try {
    return sex;

    console.log('this never gets called...');
  } catch (e) {} finally {
    sex = 'girl'; 

    alert(sex);
  }
}