`finally`のリターンが` try`をオーバーライドするのはなぜですか?


94

try / catchブロック内のreturnステートメントはどのように機能しますか?

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

この関数の出力がになることを期待していますがtrue、代わりにfalse


その他の場合は、最終的にではなく、catchブロックでfalseを返します。
habibhassani

回答:


91

最後に常に実行します。それはそれが目的であり、それはそれがあなたのケースでリターンが使われることを意味します。

コードを変更して、次のようにします。

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

一般的に言えば、関数内に複数のreturnステートメントを含めることは決してありません。これが理由です。


45
複数のreturnステートメントがあることは必ずしも悪いことではないと主張します-詳細については、stackoverflow.com / questions / 36707 / …を参照してください。
カストロヘンジ

5
私も、1つの返品ルールに同意しません。ただし、finallyから戻ることはできません(C#では許可されていません)。
erikkallen 2010年

@erikkallen-それは良い点です。TCFブロックの外で戻るのが最善ですが、サンプルコードは少し強制されます:)
annakata

1
@Castrohenge-それは難しい規則ではありませんが、そのスレッドのコプンターの例のほとんどはかなり不自然であり、私が見る唯一の有効なケースは「ガード節」です(本質的には、上部の入力データをチェックするパターン)関数と条件付きで戻る)。これは完全に有効なケースですが、実際にはこれらのリターンは例外です(これも難しくはありません)。
アナカタ

1
実際、IE6とIE7では、かなり深刻なブラウザのバグにより、すべてのケースで常に実行されるとは限りません。具体的には、より高いレベルのtry-catchで囲まれていないtry-finallyブロックで例外がスローされた場合、finallyブロックは実行されません。テストケースjsfiddle.net/niallsmart/aFjKqを次に示します。この問題はIE8で修正されました。
Niall Smart

43

ECMA-262(2009年12月5日)によると、96ページ:

生産TryStatement : try Block Finallyは次のように評価されます。

  1. Bをブロックの評価結果とする。
  2. 最後にFを評価した結果をFとします。
  3. F.typeが正常であれば、Bを返します。
  4. Fを返します。

そして36ページから:

完了型は、(文の動作を説明するために使用されbreakcontinuereturnおよびthrowコントロールの非ローカル転送を行います)。完了型の値は、フォームのトリプルである(タイプ、値、ターゲット)タイプの一つでありnormalbreakcontinuereturn、またはthrow値は任意のECMAScript言語値または空であり、ターゲットは、任意のECMAScript識別子または空です。

最終的にreturn false完了タイプをreturnとして設定することは明らかですこれにより、4が実行されます。Fを返します。try ... finally


2
この質問に対する「基本的には正しいが、なんだかフワフワで不明確な」答えをすべて読んだ後、これは実際に理にかなっています。重要な点は、try + catch(returnまたはthrowまたは通常のフロー)の最後に "発生した"ことはすべて、finally部分の実行中に記憶され、finallyの最後に何も起こらない場合にのみ実際に発生することです。
PreventRage

14

を使用するとfinally、そのブロック内のコードはメソッドが終了する前に起動します。finallyブロック内でreturnを使用しているので、ブロック内のreturn false前のものを呼び出してオーバーライドします。return truetry

(用語が正しくない場合があります。)


3

falseになる理由は、finallyブロックで返されることです。最後に、ブロックは常に実行する必要があります。だからあなたのreturn true変更return false

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

3

finallyブロックは、tryブロックのリターンを書き換えます(比喩的に言えば)。

指摘したいのは、最終的に何かを返すと、関数から返されるということです。しかし、最終的に「リターン」という単語がない場合は、tryブロックから値が返されます。

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

したがって、-finally- returnは-try- の戻り値を書き換えreturnます。


1

私の知る限り、finallyブロックreturn内部にステートメントがあるかどうかに関係なく、常に実行されますtry。エルゴ、あなたはreturn finallyブロック内ステートメント。

私はこれをFirefox 3.6.10とChrome 6.0.472.63の両方でUbuntuでテストしました。このコードは他のブラウザでは異なる動作をする可能性があります。


1

ここで少し異なる答えを出そうと思います。はい、ブロックtryfinallyブロックの両方が実行され、finally関数の実際の「戻り値」よりも優先されます。ただし、これらの戻り値は常にコードで使用されるわけではありません。

理由は次のとおりです。

  • 以下の例では、 res.send()では、HTTP応答を作成してディスパッチするExpress.jsします。
  • あなたtryfinallyブロックは両方ともこのようにこの関数を実行します:
try {
    // Get DB records etc.
    return res.send('try');
} catch(e) {
    // log errors
} finally {
    return res.send('finally');
}

このコードはtry、ブラウザに文字列を表示します。また、この例ではコンソールにエラーが表示されます。res.send()関数が呼び出され二回。これは、関数であるすべてのもので発生します。(個人的に)私はreturn値を関数スコープに関連付けるだけなので、try-catch-finallyブロックはこの事実を訓練されていない目に難読化します。

あなたの最善の策はブロック内で使用returnfinallyないことです。コードが複雑になり、エラーが隠される可能性があります。

実際、PHPStormにはデフォルトのコードインスペクションルール設定があり、これに対して「警告」が表示されます。

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

それであなたは何に使うfinallyのですか?

私はfinallyものをきれいにするためだけに使うでしょう。関数の戻り値にとって重要ではないもの。

考えてみれば理にかなっているかもしれません。なぜなら、の下のコード行に依存しているときはfinallytryまたはにエラーがある可能性があると想定しているからですcatch。しかし、最後の2つは、エラー処理の実際のビルディングブロックです。代わりにreturnin tryを使用してくださいcatch


0

最終ブロックからの復帰

場合finally-ブロックが値を返す、この値は、全体の戻り値となりtry-catch-finallyかかわらず、いずれかのステートメント return内の文trycatch-blocks

リファレンス:developer.mozilla.org


-2

最後に、常に試行キャッチブロックの最後で実行することになっているため、仕様により、falseが返されます。ブラウザーごとに実装が異なる可能性は十分にあります。


IE8、Firefox 3.6、Chrome 6:すべて同じ;)
bonfo

-3

これはどうですか?

doubleReturn();

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

  try {
    return sex;

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

    alert(sex);
  }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.