Dlaczego zwrot w argumencie „w końcu” zastępuje „try”?

100

Jak działa instrukcja return w bloku try / catch?

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

Oczekuję, że dane wyjściowe tej funkcji będą true, ale zamiast tego jest false!

bonfo
źródło
Dla innych zrób return false w bloku catch, nie ostatecznie.
habibhassani

Odpowiedzi:

95

Wreszcie zawsze wykonuje. Do tego służy, co oznacza, że ​​zwrot jest używany w twoim przypadku.

Będziesz chciał zmienić swój kod, aby wyglądał bardziej tak:

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

Ogólnie rzecz biorąc, nigdy nie chcesz mieć więcej niż jednej instrukcji return w funkcji, takie są przyczyny.

annakata
źródło
47
Twierdzę, że posiadanie więcej niż jednej instrukcji return nie zawsze jest złe - więcej dyskusji znajdziesz na stackoverflow.com/questions/36707/ ...
Castrohenge
5
Ja również nie zgadzam się z zasadą jednego powrotu. Jednak nigdy nie powinieneś wracać z końca (w C # to nawet nie jest dozwolone).
erikkallen
@erikkallen - to dobra uwaga. Powrót poza blok TCF byłby najlepszy, ale przykładowy kod byłby nieco wymuszony :)
annakata
1
@Castrohenge - nie jest to sztywna i szybka reguła, ale większość przykładów copunterów w tym wątku jest dość wymyślona, ​​a jedyny prawidłowy przypadek, jaki widzę, to „klauzula ochronna” (zasadniczo schemat sprawdzania danych wejściowych na początku funkcji i zwracając warunkowo). To doskonale uzasadniony przypadek, ale tak naprawdę te zwroty powinny być wyjątkami (znowu nie są trudne i szybkie).
annakata
1
Właściwie w IE6 i IE7 ostatecznie nie zawsze uruchamia się we wszystkich przypadkach z powodu dość poważnego błędu przeglądarki. W szczególności - jeśli wyjątek zostanie zgłoszony w bloku try-final, który nie jest otoczony przez try-catch wyższego poziomu, ostatni blok nie zostanie wykonany. Oto przypadek testowy jsfiddle.net/niallsmart/aFjKq . Ten problem został rozwiązany w IE8.
Niall Smart
44

Według ECMA-262 (z dnia 5 grudnia 2009 r.), S. 96:

Produkcja TryStatement : try Block Finallyjest oceniana w następujący sposób:

  1. Niech B będzie wynikiem oceny bloku.
  2. Niech F będzie wynikiem oceny Ostatecznie.
  3. Jeśli F.typ jest normalny, zwróć B.
  4. Powrót F.

A ze strony 36:

Rodzaj budowy służy do wyjaśnienia zachowań oświadczenia ( break, continue, returni throw), które wykonują nielokalnych transfery kontroli. Wartości rodzaju budowy są trójki postaci (typ, wartości docelowej) , gdzie rodzaj jest jednym z normal, break, continue, return, a throw, wartość jest dowolna wartość język ECMAScript lub pusty i cel jest każdy identyfikator ECMAScript lub pusty.

To jasne, że return falsebyłoby ustawić typ zakończenia wreszcie jako zwrot , które powodują try ... finallyzrobić 4. Zwrot F .

livibetter
źródło
2
Po przeczytaniu wszelkiego rodzaju „w zasadzie poprawnych, ale w jakiś sposób gąbczastych i niewyjaśnionych” odpowiedzi na to pytanie, ten faktycznie nabrał sensu. Kluczową kwestią było to, że cokolwiek „wydarzy się” na końcu try + catch (powrót lub rzut lub po prostu normalny przepływ) jest zapamiętywane podczas wykonywania ostatniej części, a następnie faktycznie dzieje się tylko wtedy, gdy nic się nie dzieje na końcu.
PreventRage
14

Kiedy używasz finally, każdy kod w tym bloku jest uruchamiany przed zakończeniem metody. Ponieważ używasz powrotu w finallybloku, wywołuje on return falsei zastępuje poprzedni return truewtry bloku.

(Terminologia może nie być do końca poprawna).

djdd87
źródło
4

Ostateczne przepisywanie bloku spróbuj powrotu bloku (mówiąc w przenośni).

Chciałem tylko zaznaczyć, że jeśli w końcu coś zwrócisz, to zostanie to zwrócone z funkcji. Ale jeśli w końcu nie ma słowa 'return' - zostanie zwrócona wartość z bloku try;

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

Zatem return-w końcu- przepisuje zwrot z -try- return.

Mihey Mik
źródło
3

dlaczego otrzymujesz fałsz, czy wróciłeś w ostatnim bloku. ostatecznie blok powinien być wykonywany zawsze. więc twoje return truezmiany wreturn false

function example() {
    try {
        return true;
    }
    catch {
        return false;
    }
}
anishMarokey
źródło
1

O ile wiem, finallyblok zawsze jest wykonywany, niezależnie od tego, czy w returnśrodku znajduje się instrukcja, tryczy nie. Ergo, otrzymujesz wartość zwróconą przez returninstrukcję wewnątrz końcowego bloku.

Przetestowałem to w Firefoksie 3.6.10 i Chrome 6.0.472.63 w Ubuntu. Możliwe, że ten kod może zachowywać się inaczej w innych przeglądarkach.

Manoj Govindan
źródło
1

Wracając z ostatecznego bloku

Jeśli finally-block zwraca wartość, ta wartość staje się wartością zwracaną całej try-catch-finallyinstrukcji, niezależnie od jakichkolwiek returninstrukcji w tryi catch-blocks

Źródła: developer.mozilla.org

Chociaż
źródło
1

Podam tutaj nieco inną odpowiedź: Tak, zarówno blok , jak tryi finallysą wykonywane i finallymają pierwszeństwo przed rzeczywistą wartością „zwracaną” funkcji. Jednak te wartości zwracane nie zawsze są używane w kodzie.

Dlatego:

  • Poniższy przykład użyje res.send()z Express.js, który tworzy odpowiedź HTTP i wysyła ją.
  • Twój tryi finallyblok wykonają tę funkcję w następujący sposób:
try {
    // Get DB records etc.
    return res.send('try');
} catch(e) {
    // log errors
} finally {
    return res.send('finally');
}

Ten kod pokaże ciąg tryw Twojej przeglądarce. TAKŻE przykład pokaże błąd w twojej konsoli. res.send()Funkcja jest wywoływana dwukrotnie . Stanie się tak w przypadku wszystkiego, co jest funkcją. Blokada try-catch-last zaciemni ten fakt niewprawnym okiem, ponieważ (osobiście) kojarzę tylkoreturn wartości z zakresami funkcji.

Imho najlepiej jest nigdy nie używać returnwewnątrz finallybloku . Zbyt mocno skomplikuje Twój kod i potencjalnie maskuje błędy.

W rzeczywistości istnieje domyślna reguła inspekcji kodu ustawiona w PHPStorm, która daje „Ostrzeżenie” w tym przypadku:

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

Więc czego używasz finally ?

użyłbym finally tylko do porządkowania rzeczy. Wszystko, co nie jest krytyczne dla wartości zwracanej przez funkcję.

Może to mieć sens, jeśli się nad tym zastanowisz, ponieważ gdy polegasz na wierszu kodu poniżej finally, zakładasz, że mogą wystąpić błędy w trylub catch. Ale te ostatnie 2 są faktycznymi elementami składowymi obsługi błędów. Po prostu użyj returnin tryi catchzamiast.

Płomień
źródło
-2

Ostatecznie powinien ZAWSZE działać na końcu bloku try catch, więc (zgodnie ze specyfikacją) jest powodem zwracania wartości false. Należy pamiętać, że jest całkowicie możliwe, że różne przeglądarki mają różne implementacje.

Darko Z
źródło
IE8, Firefox 3.6 i Chrome 6: wszystko to samo;)
bonfo
-3

A co z tym?

doubleReturn();

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

  try {
    return sex;

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

    alert(sex);
  }
}
Thomas Karlsson
źródło